Изучив предыдущую статью, я уже знаком с основными операциями с файлами. В этой статье в основном изучается использование языка C для шифрования и дешифрования файлов.
В языке C файлы в основном делятся на текстовые файлы и двоичные файлы, поэтому эти два файла в основном зашифрованы и дешифрованы.
Шифрование и дешифрование текстовых файлов
/* Шифрование XOR для каждого символа Правило: 1 ^ 1 = 0, 0 ^ 0 = 0, 1 ^ 0 = 1, 0 ^ 1 = 1 то же, что и 0, отличается от 1 */ void crpypt(char file_path[],char crpypt_path[] )< // открываем файл FILE *file_p = fopen(file_path,»r»); FILE *crpy_p = fopen(crpypt_path,»w»); // Читаем по одному символу за раз char ch; //EOF:end of file while ((ch = fgetc(file_p)) != EOF) < // Запись (операция исключающее ИЛИ) fputc(ch ^ 9, crpy_p); >//неисправность fclose(file_p); fclose(crpy_p); printf(«Шифрование завершено»); > Скопировать код
void main()< char *path = «D:\mytest.txt»; char *crpypt_path = «D:\crpypt_mytest.txt»; char *decrypt_path = «D:\decrpypt_mytest.txt»; crpypt(path,crpypt_path); getchar(); > Скопировать код
Получить зашифрованный файл
Шифруем файлы и пароли аки Царь с GPG и Pass!
Расшифровка текстового файла
void decrpypt(char crypt_path[], char decrypt_path[])< // открываем файл FILE *crpypt_p = fopen(crypt_path, «r»); FILE *decrpypt_p = fopen(decrypt_path, «w»); // Читаем по одному символу за раз char ch; //EOF:end of file while ((ch = fgetc(crpypt_p)) != EOF) < // Запись (операция исключающее ИЛИ) fputc(ch ^ 9, decrpypt_p); >//неисправность fclose(crpypt_p); fclose(decrpypt_p); printf(«Расшифровка завершена»); > Скопировать код
void main()< char *path = «D:\mytest.txt»; char *crpypt_path = «D:\crpypt_mytest.txt»; char *decrypt_path = «D:\decrpypt_mytest.txt»; decrpypt(crpypt_path, decrypt_path); getchar(); > Скопировать код
Вышесказанное предназначено для шифрования и дешифрования текстовых файлов, алгоритм: операция XOR над символами текстовых файлов.
Шифрование и дешифрование двоичных файлов
Шифрование двоичных файлов
/* Шифрование и дешифрование двоичных файлов При чтении данных в двоичном файле следует читать по одному символу за раз XOR для каждого символа */ /* Шифрование и дешифрование двоичных файлов При чтении данных в двоичном файле следует читать по одному символу за раз XOR для каждого символа */ void crpypt(char file_path[], char crpypt_path[], char password[])< // открываем файл FILE *file_p = fopen(file_path, «rb»); FILE *crpy_p = fopen(crpypt_path, «wb»); // Читаем по одному символу за раз int ch; int i = 0; // Повторно используем буквы в пароле для операции XOR int pw_len = strlen (password); // Длина пароля while ((ch = fgetc(file_p)) != EOF) < //End of File // Запись (операция исключающее ИЛИ) fputc(ch ^ password[i % pw_len], crpy_p); i++; >//неисправность fclose(file_p); fclose(crpy_p); printf(«Шифрование завершено»); > Скопировать код
/* Пароль: пароль */ void main()< char *path = «D:\timg.jpg»; char *crpypt_path = «D:\crpypt_timg.jpg»; char *decrypt_path = «D:\decrpypt_timg.jpg»; crpypt(path, crpypt_path, «password»); getchar(); > Скопировать код
Расшифровка двоичного файла
Принципы шифрования и криптографии. Расшифруйте послание!
// Расшифровать void decrpypt(char crypt_path[], char decrypt_path[], char password[])< // открываем файл FILE *crpypt_p = fopen(crypt_path, «rb»); FILE *decrpypt_p = fopen(decrypt_path, «wb»); // Читаем по одному символу за раз int ch; // Повторно используем буквы в пароле для операции XOR int i = 0; // Длина пароля int pw_len = strlen(password); //EOF:end of file while ((ch = fgetc(crpypt_p)) != EOF) < // Запись (операция исключающее ИЛИ) fputc(ch ^ password[i % pw_len], decrpypt_p); i++; >//неисправность fclose(crpypt_p); fclose(decrpypt_p); printf(«Расшифровка завершена»); > /* Пароль: пароль */ void main()< char *path = «D:\timg.jpg»; char *crpypt_path = «D:\crpypt_timg.jpg»; char *decrypt_path = «D:\decrpypt_timg.jpg»; decrpypt(crpypt_path, decrypt_path, «password»); getchar(); > Скопировать код
Здесь для загрузки двоичных файлов и шифрования текстовых файлов используется один и тот же алгоритм: операция XOR.
Примечание. Чтение и запись двоичного файла и текстового файла различаются. Использование чтения и записи текстового файла: «r», «w» Двоичные файлы для чтения и записи используются соответственно: «rb», «wb».
Выше приведен пример использования операции XOR для шифрования и дешифрования файлов.
Источник: russianblogs.com
Pycrypto в Python: шифрование и дешифрование данных
Pycrypto — это модуль Python, предоставляющий криптографические услуги. Модуль Pycrypto представляет собой набор безопасных хэш-функций, таких как RIPEMD160 и SHA256, и различных алгоритмов шифрования, таких как AES, DES, RSA, ElGamal и т. д. Например, AES является быстрым, надежным и фактическим стандартом для симметричного шифрования.
AES-шифрование
Advanced Encryption Standard(AES) — это симметричный блочный шифр.
AES включает в себя три блочных шифра:
AES-128 использует 128-битный ключ для шифрования и дешифрования блока сообщений, AES-192 использует 192-битный ключ, а AES-256 использует 256-битный ключ для шифрования и дешифрования сообщений.
Каждый шифр шифрует и дешифрует данные блоками по 128 бит, используя криптографические ключи на 128, 192 и 256 бит.
Симметричные, также известные как секретный ключ, шифры используют один и тот же ключ для шифрования и дешифрования, поэтому отправитель и получатель должны знать и использовать один и тот же секретный ключ.
Ключи любой длины могут использоваться для защиты конфиденциального и секретного уровней. Для совершенно секретной информации требуются 192-битные или 256-битные ключи.
В этом примере мы увидим шифрование AES и дешифрование 16-байтового текста.
Шаги для создания шифрования и дешифрования в Python
Чтобы использовать шифрование и дешифрование AES в Python, мы должны выполнить следующие шаги.
- Генерация секретного ключа.
- Генерация вектора инициализации.
- Создание шифра AES.
- Зашифровать сообщение с помощью AES.
- Расшифровать сообщение.
Генерация секретного ключа
Шифрование AES требует надежного ключа. Чем сильнее ключ, тем сильнее ваше шифрование. Это, пожалуй, самое слабое звено в цепи. Чтобы сгенерировать секретный ключ, мы будем использовать метод urandom() модуля os.
Функция Python os.urandom() используется для генерации строки случайного размера в байтах, подходящей для криптографического использования, или, можно сказать, этот метод генерирует строку, содержащую случайные символы.
Источник: python-lab.ru
Симметричное шифрование
Симметричные криптосистемы (симметричное шифрование) — это способ шифрования, в котором один и тот же криптографический ключ применяется для шифрования и дешифровывания. При асимметричном шифровании криптографические ключи шифрования и дешифрирования отличаются; шифрование осуществляется с помощью открытого ключа, а дешифрование с помощью закрытого ключа.
Определение шифра
Рассмотрим реализацию симметричного шифрования в java на примере алгоритма AES. В первую очередь нам понадобится определяющий алгоритм шифрования класс javax.crypto.Cipher, реализующий базовые функции популярных криптографических алгоритомов. Для получения экземпляра данного класса используется статистический метод Cipher.getInstance(), которому в качестве параметра передается наименование криптографического алгоритма шифрования. В простейшем случае пример создания экземпляра Java Cipher мог бы выглядеть следующим образом :
Cipher cipher = Cipher.getInstance(«AES»);
Однако, согласно документации JCA (Java Cryptography Architecture), в разделе «Creating a Cipher Object» указано, что для того, чтобы получить экземпляр Cipher нужно указать не просто алгоритм шифрования, а «трансформацию». Формат описания «трансформации» выглядит следующим образом: «algorithm/mode/padding» :
- algorithm – наименование алгоритма согласно Cipher (Encryption) Algorithms (в примере используем AES);
- mode – режим шифрования; например, ECB или CBC (представлены ниже);
- padding – отступ/разбивка.
Параметр «padding» определяет, какой объём данных составляет 1 блок. Каждый блок данных шифруется отдельно. Так, например, padding, равный PKCS5Padding, определяет размер одного блока в 2 байта (16 бит).
Режимы шифрования
Режим шифрования определяет детали шифрования данных, которые косвенно влияют на алгоритм шифрования. Режимы шифрования могут использоваться в нескольких различных алгоритмах шифрования как метод, добавляемый к основному алгоритму. Поэтому режимы шифрования рассматриваются не отдельно от самих алгоритмов шифрования, а скорее как их «дополнения». Наиболее известные режимы шифрования :
ECB | Electronic Codebook (режим электронной кодовой книги) |
CBC | Cipher Block Chaining (режим сцепления блоков шифротекста) |
CFB | Cipher Feedback (режим обратной связи по шифротексту) |
OFB | Output Feedback (режим обратной связи по выходу) |
CTR | Counter (режим счетчика) |
Отдельные алгоритмы шифрования могут работать в разных режимах.
В примере, рассмотренном ниже, при создании экземпляра Cipher будем использовать трансформацию «AES/ECB/PKCS5Padding». То есть, алгоритм шифрования – AES, режим шифрования – ECB, размер блока – 2 байта (PKCS5Padding).
Инициализация шифра
Прежде чем использовать Cipher для шифрования или дешифрирования текста, его необходимо инициализировать. Инициализация Cipher выполняется вызовом его метода init(int opmode, Key key), принимающего два параметра :
- режим opmode, имеющий одно из значений Cipher.ENCRYPT_MODE или Cipher.DECRYPT_MODE;
- секретный ключ типа java.security.Key.
Следующий код формирует экземпляр cipher для шифрования текста. Для дешифрирования текста необходимо определить режим Cipher.DECRYPT_MODE.
Cipher cipher = Cipher.getInstance(«AES/ECB/PKCS5Padding»); // Экземпляр cipher для шифрования текста cipher.init(Cipher.ENCRYPT_MODE, secretKey);
Создание секретного ключа
Рассмотрим метод создания секретного ключа createSecretKey(), листинг которого представлен ниже. В методе сначала формируется массив bytes с использованием генератора псевдослучайныйх значений SecureRandom.
После этого для массива bytes создается дайджест сообщения MessageDigest. Размер дайджеста составляет 20 байт, из которых выделяются первые 16 байт методом копирования в новый массив (copyOf) утилитой Arrays. Экземпляр секретного ключа SecretKeySpec создается для алгоритма «AES». Закомментированный в методе код позволяет вывести в консоль сгенерированный массив псевдослучайных значений.
private SecretKeySpec createSecretKey() < SecretKeySpec sks = null; byte[] bytes = new byte[16]; SecureRandom random = new SecureRandom(); random.nextBytes(bytes); // System.out.println(«random : » + // DatatypeConverter.printHexBinary(bytes)); try < MessageDigest md; byte[] key; md = MessageDigest.getInstance(«SHA-1»); key = md.digest(bytes); key = Arrays.copyOf(key, 16); sks = new SecretKeySpec(key, «AES»); >catch (NoSuchAlgorithmException e) < >return sks; >
Ключ алгоритма симметричного шифрования должен храниться в тайне обеими участниками. Алгоритм шифрования выбирается сторонами до начала обмена криптованными сообщениями. В методе createSecretKey таким ключом является переменная key. Ключ используется для создания SecretKeySpec, который необходим для инициализации Cipher.
Шифрование и дешифрирование
Для шифрования и дешифрования данных с помощью экземпляра Cipher, используется один из методов update() или doFinal(). Класс Cipher имеет несколько переопределенных методов update() и doFinal(), которые принимают разные параметры. Следующий пример демонстрирует использование метода doFinal() для шифрования текста :
byte[] plainText = «Hello, World!».getBytes(«UTF-8»); byte[] cipherText = cipher.doFinal(plainText); System.out.println(«encrypted text : » + DatatypeConverter.printHexBinary(cipherText));
Для дешифрирования текст будет выглядеть примерно также, за исключением того, что экземпляр Cipher должен быть инициализирован соответствующим образом :
byte[] plainText = cipher.doFinal(cipherText);
Листинг примера CryptoExample
В примере CryptoExample представлены 2 метода : encrypt и decrypt. Исходный код метода createSecretKey рассмотрен выше. Алгоритм функционирования данных методов понятен из представленного выше описания. Дополнительно в методах encrypt и decrypt представлен код шифрования и дешифрирования с использованием утилиты java.util.Base64, которая появилась в Java 8.
Base64 — стандарт кодирования двоичных данных при помощи только 64 символов ASCII. Алфавит кодирования содержит текстово-цифровые латинские символы A-Z, a-z и 0-9 (62 знака) и 2 дополнительных символа, зависящих от системы реализации. Т.е. весь диапазон закодированных символов укладывается в английский алфавит, цифры и двух спецсимволов. Таким образом, из каждых 3 исходных байтов утилита Base64 формирует 4 символа, увеличивая размер текста на Cipher cipher; String transformation = «AES/ECB/PKCS5Padding»; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public CryptoExample() <>//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public byte[] encrypt(SecretKeySpec secretKey, byte[] plainText) < try < cipher = Cipher.getInstance(transformation); cipher.init(Cipher.ENCRYPT_MODE, secretKey); return cipher.doFinal(plainText); // return Base64.getEncoder() // .encode(cipher.doFinal(plainText)); >catch (Exception e) < >return null; > //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public byte[] decrypt(SecretKeySpec secretKey, byte[] encryptedText) < try < cipher = Cipher.getInstance(transformation); cipher.init(Cipher.DECRYPT_MODE, secretKey); return cipher.doFinal(encryptedText); // return cipher.doFinal(Base64.getDecoder() // .decode(encryptedText)); >catch (Exception e) <> return null; > //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ private SecretKeySpec createSecretKey() < // исходный код представлен выше . . . >//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public static void main(String[] args) throws Exception < CryptoExample cryptoEx = new CryptoExample(); SecretKeySpec key = cryptoEx.createSecretKey(); String text = «decrypt!decrypt!decrypt!decrypt!»; byte[] enc = cryptoEx.encrypt(key, text.getBytes()); System.out.println(«Original text: ‘» + text + «‘»); System.out.println(«Encrypted text :n» + DatatypeConverter.printHexBinary(enc)); byte[] bytes = cryptoEx.decrypt(key, enc); if (bytes != null) < String plainAfter = new String(bytes); System.out.println(«Text after decryption: ‘» + plainAfter + «‘»); >> >
Ну, и теперь смотрим на результат выполнения примера. В консоль были выведены следующие сообщения :
random : 992DE79A44047FCD641EC2F9F1A2056D Original text: ‘decrypt!decrypt!decrypt!decrypt!’ Encrypted text : CF2949AFAA65F0E2E8926364D56FBBFA CF2949AFAA65F0E2E8926364D56FBBFA 6C1647F049941345172F0083EF997201 Text after decryption: ‘decrypt!decrypt!decrypt!decrypt!’
Кодированный текст (Encrypted text) для наглядности, разделен на 3 части. После первых 2-х частей из 32 символов вставлены символы пробела и переносом », далее остальная часть кодированного текста.
В принципе, кодированный текст был восстановлен правильно. Но вот сам кодированный текст имеет 2 повторения (блоков также 2; остался неприятный осадок). Как это можно исправить? Можно использовать утилиту Base64, которая преобразует исходный текст и повторений не будет. Для этого можно снять комментарии в методах encrypt, decrypt.
Но мы должны быть уверены, что у пользователя используется Java 8. Проще изменить режим шифрования – CBC (Cipher Block Chaining).
Режим шифрования CBC вводит понятие Initialization Vector, представленный классом IvParameterSpec. В данном режиме результат генерации предыдущего блока используется для генерации следующего.
Но чтобы использовать режим шифрования CBC требуется несложная доработка кода, связанная с инициализацией шифра Cipher. Для этого определяем массив из 16 байт sec_bytes, которые будем заполнять псевдослучайными значениями в конструкторе класса. При нициализации шифра будем использовать этот массив для формирования IvParameterSpec. Ниже представлены изменения кода примера для использования режима CBC.
// String transformation = «AES/ECB/PKCS5Padding»; String transformation = «AES/CBC/PKCS5Padding»; byte[] sec_bytes = new byte[16]; . . . //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public CryptoUtil() < SecureRandom random = new SecureRandom(); random.nextBytes(sec_bytes); >//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public byte[] encrypt(SecretKeySpec secretKey, byte[] plainText) < try < cipher = Cipher.getInstance(transformation); if (transformation.contains(«ECB»)) cipher.init(Cipher.ENCRYPT_MODE, secretKey); else < IvParameterSpec ivSpec; ivSpec = new IvParameterSpec(sec_bytes); cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec); >// return Base64.getEncoder() // .encode(cipher.doFinal(plainText)); return cipher.doFinal(plainText); > catch (Exception e) < System.out.println(e.getMessage()); >return null; > //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public byte[] decrypt(SecretKeySpec secretKey, byte[] encryptedText) < try < cipher = Cipher.getInstance(transformation); if (transformation.contains(«ECB»)) cipher.init(Cipher.DECRYPT_MODE, secretKey); else < IvParameterSpec ivSpec; ivSpec = new IvParameterSpec(sec_bytes); cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec); >// return cipher.doFinal(Base64.getDecoder() // .decode(encryptedText)); return cipher.doFinal(encryptedText); > catch (Exception e) < System.out.println(e.getMessage()); >return null; >
После доработки повторения в кодированном тексте отсутствуют, результат шифрования и дешифрирования радует.
random : 5B1E804043C2068B9602285172800C3E Original text: ‘decrypt!decrypt!decrypt!decrypt!’ Encrypted text : F0802F50C5E41CFEE3F1F5EA71224771 8F1BCDF65519472EDCD6DE11FB0E14A1 D3A493CF59D7F2BB197CA90025E05203 Text after decryption: ‘decrypt!decrypt!decrypt!decrypt!’
Полагаю, что данная статья помогла Вам решить задачу симметричного шифрования и дешифрирования. Ну, а вопрос передачи секретного ключа каждый решает самостоятельно.
Источник: java-online.ru