web-dev-qa-db-fra.com

Comment faire du cryptage avec AES dans Openssl

J'essaie d'écrire un exemple de programme pour effectuer le cryptage AES avec Openssl. J'ai essayé de passer par la documentation OpenSL (c'est une douleur), je ne pouvais pas comprendre beaucoup. J'ai parcouru le code et découvert l'API à l'aide de laquelle j'ai écrit un petit programme comme ci-dessous (veuillez omettre les numéros de ligne). Je ne vois pas de chiffrement en cours ... quelque chose me manque-t-il?

PS: Je ne reçois aucune erreur lors de la compilation.

  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 }

S'il vous plaît aidez-moi à comprendre cela ...

36
pkumarn

Consultez ce lien. Il contient un exemple de code pour chiffrer/déchiffrer des données à l'aide de l'AES256CBC à l'aide de l'API EVP.

https://github.com/saju/misc/blob/master/misc/openssl_aes.c

Vous pouvez également vérifier l’utilisation de AES256 CBC dans un projet Open Source détaillé développé par moi à l’adresse suivante: https://github.com/llubu/mpro

Le code est suffisamment détaillé avec des commentaires et si vous avez encore besoin de nombreuses explications sur l'API, je vous suggère de consulter ce livre Sécurité réseau avec OpenSSL de Viega/Messier/Chandra (Google, vous trouverez facilement un pdf de ceci ..), lisez le chapitre 6, qui est spécifique aux chiffreurs symétriques utilisant l’API EVP .. Cela m’a beaucoup aidé à comprendre les raisons de l’utilisation de diverses fonctions et structures du PVE.

et si vous voulez plonger profondément dans la bibliothèque cryptographique Openssl, je vous suggère de télécharger le code à partir du site Web openssl (la version installée sur votre ordinateur), puis regardez dans la mise en œuvre de la mise en œuvre de EVP et aeh api.

Une autre suggestion du code que vous avez posté ci-dessus, je vois que vous utilisez l'api de aes.h à la place, utilisez EVP.ch pour en expliquer la raison ici OpenSSL utilisant EVP contre API pour un cryptage symétrique bien expliqué par Daniel dans l'une des questions posées par moi ..

33
abhi

J'essaie d'écrire un exemple de programme pour effectuer le cryptage AES avec Openssl.

Cette réponse est un peu populaire, je vais donc proposer quelque chose de plus à jour, car OpenSSL a ajouté quelques modes de fonctionnement qui vous aideront probablement.

Tout d'abord, n'utilisez pas AES_encrypt Et AES_decrypt. Ils sont de faible niveau et difficiles à utiliser. De plus, il s’agit d’une routine logicielle uniquement, qui utilisera jamais, comme AES-NI. Enfin, il est question d’endianesses sur des plateformes obscures.

Utilisez plutôt les interfaces EVP_*. Les fonctions EVP_* Utilisent l'accélération matérielle, comme AES-NI, si disponible. Et il ne souffre pas de problèmes de support sur des plateformes obscures.

Deuxièmement, vous pouvez utiliser un mode tel que CBC, mais le texte crypté manquera d’assurances d’intégrité et d’authenticité. Donc, vous voulez généralement un mode comme EAX, CCM ou GCM. (Ou vous devez appliquer manuellement un HMAC après le cryptage sous une clé séparée.)

Troisièmement, OpenSSL a une page wiki qui vous intéressera probablement: EVP Authenticated Encryption and Decryption . Il utilise le mode GCM.

Enfin, voici le programme à chiffrer avec AES/GCM. L'exemple de wiki OpenSSL est basé sur celui-ci.

#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;
    }
}
26
jww

Je ne sais pas ce qui ne va pas chez vous, mais une chose est sûre, vous devez appeler AES_set_decrypt_key() avant de déchiffrer le message. Aussi, n'essayez pas d'imprimer en tant que% s car le message chiffré n'est plus composé par des caractères ascii. Par exemple:

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: votre clé est 192 bit n'est-ce pas ...

20
user975612

Ma suggestion est de courir

openssl enc -aes-256-cbc -in plain.txt -out encrypted.bin

sous le débogueur et voir ce qu’il fait exactement. openssl.c est le seul véritable tutoriel/démarrage/guide de référence disponible sur OpenSSL. Toute autre documentation est juste une référence d'API.

U1: Mon hypothèse est que vous ne définissez pas d'autres options obligatoires, telles que le mode de fonctionnement (remplissage).

U2: il s’agit probablement d’une copie de la question suivante: Mode de fonctionnement du chiffrement AES CTR 256 sous OpenSSL et les réponses à cette question seront probablement utiles.

8
MK.