Ни один из этих ответов на самом деле не представляет собой какую-либо форму разумного шифрования.
Что вы на самом деле хотите сделать, так это использовать некоторую форму аутентифицированного шифрования и некоторую форму алгоритма создания безопасного ключа.Моя личная рекомендация libsodium .Он обеспечивает очень хорошие значения по умолчанию и API, который относительно сложно ошибиться.
Есть несколько различных способов сделать это:
- Шифрование секретным ключом со случайным ключом Шифрование с проверкой подлинности
- Шифрование секретным ключом с помощью ключа, полученного из ключевой фразы Получение ключа
- Гибридное шифрование с соглашением о ключах. Шифрование с открытым ключом
Все эти возможности интегрированы в libsodium и реализуются с относительной легкостью.
Следующие примеры кода взяты непосредственно из документация libsodium .
для 1:
#define MESSAGE ((const unsigned char *) "test")
#define MESSAGE_LEN 4
#define CIPHERTEXT_LEN (crypto_secretbox_MACBYTES + MESSAGE_LEN)
unsigned char nonce[crypto_secretbox_NONCEBYTES];
unsigned char key[crypto_secretbox_KEYBYTES];
unsigned char ciphertext[CIPHERTEXT_LEN];
/* Generate a secure random key and nonce */
randombytes_buf(nonce, sizeof nonce);
randombytes_buf(key, sizeof key);
/* Encrypt the message with the given nonce and key, putting the result in ciphertext */
crypto_secretbox_easy(ciphertext, MESSAGE, MESSAGE_LEN, nonce, key);
unsigned char decrypted[MESSAGE_LEN];
if (crypto_secretbox_open_easy(decrypted, ciphertext, CIPHERTEXT_LEN, nonce, key) != 0) {
/* If we get here, the Message was a forgery. This means someone (or the network) somehow tried to tamper with the message*/
}
для 2: (извлечение ключа из пароля)
#define PASSWORD "Correct Horse Battery Staple"
#define KEY_LEN crypto_secretbox_KEYBYTES
unsigned char salt[crypto_pwhash_SALTBYTES];
unsigned char key[KEY_LEN];
/* Choose a random salt */
randombytes_buf(salt, sizeof salt);
if (crypto_pwhash
(key, sizeof key, PASSWORD, strlen(PASSWORD), salt,
crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE,
crypto_pwhash_ALG_DEFAULT) != 0) {
/* out of memory */
}
Теперь массив ключейсодержит ключ, который подходит для использования в приведенном выше примере кода.Вместо randombytes_buf(key, sizeof key)
для генерации случайного ключа мы сгенерировали ключ, полученный из пользовательского пароля, и используем его для шифрования.
3 - «самый сложный» из 3 типов.Это то, что вы используете, если две стороны общаются.Каждая из сторон генерирует «пару ключей», которая содержит открытый и секретный ключи.С этими парами ключей они могут вместе договориться о «общем ключе», который они могут использовать для шифрования (и подписывания) данных друг для друга:
#define MESSAGE (const unsigned char *) "test"
#define MESSAGE_LEN 4
#define CIPHERTEXT_LEN (crypto_box_MACBYTES + MESSAGE_LEN)
unsigned char alice_publickey[crypto_box_PUBLICKEYBYTES];
unsigned char alice_secretkey[crypto_box_SECRETKEYBYTES];
crypto_box_keypair(alice_publickey, alice_secretkey);
unsigned char bob_publickey[crypto_box_PUBLICKEYBYTES];
unsigned char bob_secretkey[crypto_box_SECRETKEYBYTES];
crypto_box_keypair(bob_publickey, bob_secretkey);
unsigned char nonce[crypto_box_NONCEBYTES];
unsigned char ciphertext[CIPHERTEXT_LEN];
randombytes_buf(nonce, sizeof nonce);
if (crypto_box_easy(ciphertext, MESSAGE, MESSAGE_LEN, nonce,
bob_publickey, alice_secretkey) != 0) {
/* error */
}
unsigned char decrypted[MESSAGE_LEN];
if (crypto_box_open_easy(decrypted, ciphertext, CIPHERTEXT_LEN, nonce,
alice_publickey, bob_secretkey) != 0) {
/* message for Bob pretending to be from Alice has been forged! */
}
Этот код сначала генерирует обе пары ключей (обычно это происходитна машине Боба и Алисы по отдельности, и они посылали друг другу свой открытый ключ, сохраняя при этом свой секретный ключ, ну, в общем, секрет).
Затем генерируется случайный одноразовый номер, ивызов crypto_box_easy(...)
шифрует сообщение от Алисы к Бобу (используя открытый ключ Боба для шифрования и секретный ключ Алисы для создания подписи).
Затем (после возможной отправки сообщения черезсеть), вызов crypto_box_open_easy(...)
используется Бобом для расшифровки сообщения (используя его собственный секретный ключ для расшифровки и открытый ключ Алисы для проверки подписи).Если проверка сообщения по какой-то причине не удалась (кто-то пытался ее подделать), это указывается ненулевым кодом возврата.