Как сделать шифрование с использованием AES в Openssl
Я пытаюсь написать пример программы для шифрования AES с помощью Openssl. Я попытался пройти документацию Openssl (это боль), не мог понять много. Я просмотрел код и нашел API, с помощью которого я написал небольшую программу, как показано ниже (пропустите номера строк). Я не вижу никакого шифрования... Я что-то пропустил?
PS: У меня нет ошибок при компиляции.
1 #include <stdio.h>
2 #include <openssl/aes.h>
3
4 static const unsigned char key[] = {
5 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
6 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
7 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
8 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
9 };
10
11 void main()
12 {
13 unsigned char text[]="virident";
14 unsigned char out[10];
15 unsigned char decout[10];
16
17 AES_KEY wctx;
18
19 AES_set_encrypt_key(key, 128, &wctx);
20 AES_encrypt(text, out, &wctx);
21
22 printf("encryp data = %s\n", out);
23
24 AES_decrypt(out, decout, &wctx);
25 printf(" Decrypted o/p: %s \n", decout);
26
27
28 }
Пожалуйста, помогите мне разобраться в этом...
Ответы
Ответ 1
Проверьте эту ссылку, у нее есть пример кода для шифрования/дешифрования данных с использованием AES256CBC с использованием EVP API.
https://github.com/saju/misc/blob/master/misc/openssl_aes.c
Также вы можете проверить использование AES256 CBC в подробном проекте с открытым исходным кодом, разработанном мной в https://github.com/llubu/mpro
Код достаточно подробный с комментариями, и если вам все еще нужно много объяснений по поводу самого API, я предлагаю проверить эту книгу Сетевая безопасность с OpenSSL от Viega/Messier/Chandra (google это вы легко найти pdf этого..) прочитайте главу 6, которая относится к симметричным шифрам, использующим API EVP. Это помогло мне реально понять причины использования различных функций и структур EVP.
и если вы хотите глубоко погрузиться в криптографическую библиотеку Openssl, я предлагаю загрузить код с веб-сайта openssl (версия, установленная на вашем компьютере), а затем посмотрите на реализацию EVP и aeh api.
Еще одно предложение из кода, который вы выложили выше, я вижу, что вы используете api из aes.h
вместо этого используйте EVP.check причины для этого здесь OpenSSL, используя EVP против алгоритма API для симметричного криптования, который хорошо объяснил Даниэль в одном из вопросов, заданных мной.
Ответ 2
Я не знаю, что с тобой случилось, но наверняка вам нужно позвонить AES_set_decrypt_key()
перед расшифровкой сообщения. Также не пытайтесь распечатать как% s, потому что зашифрованное сообщение больше не состоит из символов ascii. Например:
static const unsigned char key[] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
int main()
{
unsigned char text[]="hello world!";
unsigned char enc_out[80];
unsigned char dec_out[80];
AES_KEY enc_key, dec_key;
AES_set_encrypt_key(key, 128, &enc_key);
AES_encrypt(text, enc_out, &enc_key);
AES_set_decrypt_key(key,128,&dec_key);
AES_decrypt(enc_out, dec_out, &dec_key);
int i;
printf("original:\t");
for(i=0;*(text+i)!=0x00;i++)
printf("%X ",*(text+i));
printf("\nencrypted:\t");
for(i=0;*(enc_out+i)!=0x00;i++)
printf("%X ",*(enc_out+i));
printf("\ndecrypted:\t");
for(i=0;*(dec_out+i)!=0x00;i++)
printf("%X ",*(dec_out+i));
printf("\n");
return 0;
}
U1: ваш ключ 192 бит, не так ли?
Ответ 3
Я пытаюсь написать пример программы для шифрования AES с помощью Openssl.
Этот ответ довольно популярен, поэтому я собираюсь предложить что-то более современное, так как OpenSSL добавил некоторые способы работы, которые, вероятно, помогут вам.
Во-первых, не используйте AES_encrypt
и AES_decrypt
. Они являются низкими и сложнее в использовании. Кроме того, это программная процедура, и она будет никогда использовать аппаратное ускорение, например AES-NI. Наконец, его предметом проблем с энтериантами на некоторых неясных платформах.
Вместо этого используйте интерфейсы EVP_*
. Функции EVP_*
используют аппаратное ускорение, например AES-NI, если они доступны. И это не страдает от проблем, возникающих на неясных платформах.
Во-вторых, вы можете использовать такой режим, как CBC, но зашифрованный текст не будет иметь целостности и достоверности. Поэтому вам обычно нужен такой режим, как EAX, CCM или GCM. (Или вы вручную должны применить HMAC после шифрования под отдельным ключом.)
В-третьих, в OpenSSL есть страница вики, которая, вероятно, вас заинтересовала: EVP Authenticated Encryption and Decryption. Он использует режим GCM.
Наконец, здесь программа для шифрования с использованием AES/GCM. На ней основан пример Wiki OpenSSL.
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/err.h>
#include <string.h>
int main(int arc, char *argv[])
{
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
/* Set up the key and iv. Do I need to say to not hard code these in a real application? :-) */
/* A 256 bit key */
static const unsigned char key[] = "01234567890123456789012345678901";
/* A 128 bit IV */
static const unsigned char iv[] = "0123456789012345";
/* Message to be encrypted */
unsigned char plaintext[] = "The quick brown fox jumps over the lazy dog";
/* Some additional data to be authenticated */
static const unsigned char aad[] = "Some AAD data";
/* Buffer for ciphertext. Ensure the buffer is long enough for the
* ciphertext which may be longer than the plaintext, dependant on the
* algorithm and mode
*/
unsigned char ciphertext[128];
/* Buffer for the decrypted text */
unsigned char decryptedtext[128];
/* Buffer for the tag */
unsigned char tag[16];
int decryptedtext_len = 0, ciphertext_len = 0;
/* Encrypt the plaintext */
ciphertext_len = encrypt(plaintext, strlen(plaintext), aad, strlen(aad), key, iv, ciphertext, tag);
/* Do something useful with the ciphertext here */
printf("Ciphertext is:\n");
BIO_dump_fp(stdout, ciphertext, ciphertext_len);
printf("Tag is:\n");
BIO_dump_fp(stdout, tag, 14);
/* Mess with stuff */
/* ciphertext[0] ^= 1; */
/* tag[0] ^= 1; */
/* Decrypt the ciphertext */
decryptedtext_len = decrypt(ciphertext, ciphertext_len, aad, strlen(aad), tag, key, iv, decryptedtext);
if(decryptedtext_len < 0)
{
/* Verify error */
printf("Decrypted text failed to verify\n");
}
else
{
/* Add a NULL terminator. We are expecting printable text */
decryptedtext[decryptedtext_len] = '\0';
/* Show the decrypted text */
printf("Decrypted text is:\n");
printf("%s\n", decryptedtext);
}
/* Remove error strings */
ERR_free_strings();
return 0;
}
void handleErrors(void)
{
unsigned long errCode;
printf("An error occurred\n");
while(errCode = ERR_get_error())
{
char *err = ERR_error_string(errCode, NULL);
printf("%s\n", err);
}
abort();
}
int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *aad,
int aad_len, unsigned char *key, unsigned char *iv,
unsigned char *ciphertext, unsigned char *tag)
{
EVP_CIPHER_CTX *ctx = NULL;
int len = 0, ciphertext_len = 0;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
/* Initialise the encryption operation. */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
handleErrors();
/* Set IV length if default 12 bytes (96 bits) is not appropriate */
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL))
handleErrors();
/* Initialise key and IV */
if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();
/* Provide any AAD data. This can be called zero or more times as
* required
*/
if(aad && aad_len > 0)
{
if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
handleErrors();
}
/* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(plaintext)
{
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;
}
/* Finalise the encryption. Normally ciphertext bytes may be written at
* this stage, but this does not occur in GCM mode
*/
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
ciphertext_len += len;
/* Get the tag */
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
handleErrors();
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *aad,
int aad_len, unsigned char *tag, unsigned char *key, unsigned char *iv,
unsigned char *plaintext)
{
EVP_CIPHER_CTX *ctx = NULL;
int len = 0, plaintext_len = 0, ret;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
/* Initialise the decryption operation. */
if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
handleErrors();
/* Set IV length. Not necessary if this is 12 bytes (96 bits) */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL))
handleErrors();
/* Initialise key and IV */
if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();
/* Provide any AAD data. This can be called zero or more times as
* required
*/
if(aad && aad_len > 0)
{
if(!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
handleErrors();
}
/* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(ciphertext)
{
if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
handleErrors();
plaintext_len = len;
}
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
handleErrors();
/* Finalise the decryption. A positive return value indicates success,
* anything else is a failure - the plaintext is not trustworthy.
*/
ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
if(ret > 0)
{
/* Success */
plaintext_len += len;
return plaintext_len;
}
else
{
/* Verify failed */
return -1;
}
}
Ответ 4
Мое предложение - запустить
openssl enc -aes-256-cbc -in plain.txt -out encrypted.bin
под отладчиком и посмотреть, что именно он делает.
openssl.c - единственное реальное руководство/начало/справочное руководство OpenSSL. Вся другая документация - это просто ссылка на API.
U1: Я предполагаю, что вы не устанавливаете другие необходимые параметры, такие как режим работы (дополнение).
U2: это, вероятно, дубликат этого вопроса:
AES CTR 256 Шифрование Режим работы на OpenSSL
и ответы там, скорее всего, помогут.