OpenSSL implementato AES non secondo il NIST?

2

Ho utilizzato il codice di crittografia / decrittografia dal link .

I vettori di test NIST ( link ) per AES non producono il risultato previsto. Posso sapere quale potrebbe essere la ragione e come farla funzionare secondo i vettori di test NIST?

Per motivi di leggibilità, aggiungerò il seguente codice: #include

#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>


int main(int arc, char *argv[])
{
/* Set up the key and iv. Do I need to say to not hard code these in a
* real application? :-)
*/

/* A 256 bit key */
unsigned char ***key** = "0000000000000000000000000000000000000000000000000000000000000000";

/* A 128 bit IV */
unsigned char ***iv** = "00000000000000000000000000000000";

/* Message to be encrypted */
unsigned char *plaintext =
"80000000000000000000000000000000";

/* 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];

int decryptedtext_len, ciphertext_len;

/* Initialise the library */
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);

/* Encrypt the plaintext */
ciphertext_len = encrypt(plaintext, strlen(plaintext), key, iv,
ciphertext);

/* Do something useful with the ciphertext here */
printf("Ciphertext is:\n");
BIO_dump_fp(stdout, ciphertext, ciphertext_len);

/* Decrypt the ciphertext */
decryptedtext_len = decrypt(ciphertext, ciphertext_len, key, iv,
decryptedtext);

/* Add a NULL terminator. We are expecting printable text */
decryptedtext[decryptedtext_len] = '
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>


int main(int arc, char *argv[])
{
/* Set up the key and iv. Do I need to say to not hard code these in a
* real application? :-)
*/

/* A 256 bit key */
unsigned char ***key** = "0000000000000000000000000000000000000000000000000000000000000000";

/* A 128 bit IV */
unsigned char ***iv** = "00000000000000000000000000000000";

/* Message to be encrypted */
unsigned char *plaintext =
"80000000000000000000000000000000";

/* 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];

int decryptedtext_len, ciphertext_len;

/* Initialise the library */
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);

/* Encrypt the plaintext */
ciphertext_len = encrypt(plaintext, strlen(plaintext), key, iv,
ciphertext);

/* Do something useful with the ciphertext here */
printf("Ciphertext is:\n");
BIO_dump_fp(stdout, ciphertext, ciphertext_len);

/* Decrypt the ciphertext */
decryptedtext_len = decrypt(ciphertext, ciphertext_len, key, iv,
decryptedtext);

/* Add a NULL terminator. We are expecting printable text */
decryptedtext[decryptedtext_len] = '%pre%';

/* Show the decrypted text */
printf("Decrypted text is:\n");
printf("%s\n", decryptedtext);

/* Clean up */
EVP_cleanup();
ERR_free_strings();

return 0;
}

void handleErrors(void)
{
ERR_print_errors_fp(stderr);
abort();
}

int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
unsigned char *iv, unsigned char *ciphertext)
{
EVP_CIPHER_CTX *ctx;

int len;

int ciphertext_len;

/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();

/* Initialise the encryption operation. IMPORTANT - ensure you use a key
 * and IV size appropriate for your cipher
 * In this example we are using 256 bit AES (i.e. a 256 bit key). The
 * IV size for *most* modes is the same as the block size. For AES this
 * is 128 bits */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
handleErrors();

/* Provide the message to be encrypted, and obtain the encrypted output.
 * EVP_EncryptUpdate can be called multiple times if necessary
 */
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;

/* Finalise the encryption. Further ciphertext bytes may be written at
 * this stage.
 */
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
ciphertext_len += len;

/* Clean up */
EVP_CIPHER_CTX_free(ctx);

return ciphertext_len;
}

int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
unsigned char *iv, unsigned char *plaintext)
{
EVP_CIPHER_CTX *ctx;

int len;

int plaintext_len;

/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();

/* Initialise the decryption operation. IMPORTANT - ensure you use a key
 * and IV size appropriate for your cipher
 * In this example we are using 256 bit AES (i.e. a 256 bit key). The
 * IV size for *most* modes is the same as the block size. For AES this
 * is 128 bits */
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
handleErrors();

/* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
handleErrors();
plaintext_len = len;

/* Finalise the decryption. Further plaintext bytes may be written at
 * this stage.
 */
if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors();
plaintext_len += len;

/* Clean up */
EVP_CIPHER_CTX_free(ctx);

return plaintext_len;
}
'; /* Show the decrypted text */ printf("Decrypted text is:\n"); printf("%s\n", decryptedtext); /* Clean up */ EVP_cleanup(); ERR_free_strings(); return 0; } void handleErrors(void) { ERR_print_errors_fp(stderr); abort(); } int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext) { EVP_CIPHER_CTX *ctx; int len; int ciphertext_len; /* Create and initialise the context */ if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors(); /* Initialise the encryption operation. IMPORTANT - ensure you use a key * and IV size appropriate for your cipher * In this example we are using 256 bit AES (i.e. a 256 bit key). The * IV size for *most* modes is the same as the block size. For AES this * is 128 bits */ if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) handleErrors(); /* Provide the message to be encrypted, and obtain the encrypted output. * EVP_EncryptUpdate can be called multiple times if necessary */ if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) handleErrors(); ciphertext_len = len; /* Finalise the encryption. Further ciphertext bytes may be written at * this stage. */ if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors(); ciphertext_len += len; /* Clean up */ EVP_CIPHER_CTX_free(ctx); return ciphertext_len; } int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext) { EVP_CIPHER_CTX *ctx; int len; int plaintext_len; /* Create and initialise the context */ if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors(); /* Initialise the decryption operation. IMPORTANT - ensure you use a key * and IV size appropriate for your cipher * In this example we are using 256 bit AES (i.e. a 256 bit key). The * IV size for *most* modes is the same as the block size. For AES this * is 128 bits */ if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) handleErrors(); /* Provide the message to be decrypted, and obtain the plaintext output. * EVP_DecryptUpdate can be called multiple times if necessary */ if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) handleErrors(); plaintext_len = len; /* Finalise the decryption. Further plaintext bytes may be written at * this stage. */ if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors(); plaintext_len += len; /* Clean up */ EVP_CIPHER_CTX_free(ctx); return plaintext_len; }

L'output che ottengo è:

Il testo cifrato è:

0000 - 0d d2 52 e5 3c 69 ad 57-f2 93 1c 2b 0b 1b 84 a6 ..R.

0010 - 3e c8 b7 ca c5 67 65 82-16 df ac 51 cc ae d7 20 > .... ge .... Q ...

0020 - 6a 2a 39 fd 8f f9 2a b7-e5 6d 27 47 c5 36 ef 65 j * 9 ... * .. m'G.6.e

Il testo decrittografato è:

80000000000000000000000000000000

Ma secondo NIST Test Vector, l'output dovrebbe essere: ddc6bf790c15760d8d9aeb6f9a75fd4e

    
posta RSH 10.04.2015 - 09:04
fonte

1 risposta

4

Non ho testato OpenSSL ma sono abbastanza sicuro che implementa correttamente AES-CBC. Il tuo programma, ovviamente, utilizza ovviamente dati diversi, quindi non sorprende che tu ottenga risultati diversi.

I vettori test sono distribuiti in esadecimale. Ad esempio

KEY = 0000000000000000000000000000000000000000000000000000000000000000
IV = 00000000000000000000000000000000
PLAINTEXT = 80000000000000000000000000000000
CIPHERTEXT = ddc6bf790c15760d8d9aeb6f9a75fd4e

ha una chiave da 32 byte (la dimensione giusta per AES-256) in cui tutti i byte hanno il valore 0. Analogamente il IV da 16 byte ha tutti i byte 0, il testo in chiaro consiste in un byte con il valore 0x80 = 128 seguito da 15 byte con il valore 0 e il testo cifrato è la stringa da 16 byte specificata.

Il tuo programma sta utilizzando dati che nella notazione NIST è

KEY = 3030303030303030303030303030303030303030303030303030303030303030
IV = 30303030303030303030303030303030
PLAINTEXT = 38303030303030303030303030303030

Cioè, la tua chiave è composta da 64 byte ognuno dei quali è il codice ASCII del carattere 0 , ecc.

Il risultato del tuo calcolo è corretto, a proposito (con il quale intendo l'output che hai postato è corretto per i dati nel tuo programma). Tuttavia ci sono parecchie cose da tenere in considerazione riguardo alle dimensioni che sarebbero importanti in un programma reale. La tua variabile key contiene una matrice da 65 byte (64 byte 0x30=48='0' (cifra zero) più un byte null terminante) - questo funziona perché il calcolo utilizza solo i primi 32 byte dell'array ma rende confuso il programma. Lo stesso vale per la IV. Per il testo in chiaro, si calcola la lunghezza con strlen ; tieni presente che funziona solo se i dati non contengono byte null, quindi funziona se i tuoi dati sono una stringa C ma non per dati binari arbitrari. Elencate 48 byte di output, ma avete alimentato 32 byte di input, quindi l'output è in realtà solo 32 byte.

Nel caso in cui tu sia confuso riguardo alle dimensioni dell'output: ogni blocco di input nella crittografia CBC restituisce un blocco di output. In pratica, l'output della crittografia CBC è maggiore perché non contiene solo l'output dell'algoritmo CBC, per due ragioni. Primo, l'IV viene solitamente inviato come prefisso al testo cifrato, quindi c'è un blocco aggiuntivo all'inizio del testo cifrato che è l'IV. In altre parole, un "messaggio crittografato CBC" di solito consiste nell'IV seguito dall'effettivo output dell'algoritmo CBC. In secondo luogo, CBC specifica solo come crittografare i dati la cui dimensione è un multiplo della dimensione del blocco (16 byte per AES indipendentemente dalle dimensioni della chiave). Pertanto, per crittografare dati di dimensioni arbitrarie, è necessario applicare un algoritmo di riempimento per ottenere un numero intero di blocchi e quindi applicare CBC al risultato dell'algoritmo di riempimento. Le funzioni OpenSSL che utilizzi applicano Padding PKCS # 7 (una scelta comune), dando come risultato la dimensione dell'output viene arrotondata a un numero intero di blocchi o, quando la dimensione dell'ingresso è un numero intero di blocchi, un ulteriore blocco di output. Per riassumere:

              CBC
32 bytes ------------> 32 bytes

           PKCS#7 padding                CBC                 preprend IV
32 bytes -----------------> 48 bytes -----------> 48 bytes ---------------> 64 bytes
    
risposta data 10.04.2015 - 15:47
fonte

Leggi altre domande sui tag