43 votes

Comment faire du cryptage en utilisant AES dans Openssl

J'essaie d'écrire un exemple de programme pour faire du cryptage AES en utilisant Openssl. J'ai essayé de consulter la documentation d'Openssl (c'est pénible), mais je n'ai pas trouvé grand chose. J'ai parcouru le code et j'ai trouvé les API que j'ai utilisées pour écrire un petit programme comme ci-dessous (veuillez omettre les numéros de ligne). Je ne vois pas de cryptage se produire... Est-ce que j'ai manqué quelque chose ?

PS : Je n'obtiens 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 }

Aidez-moi à résoudre ce problème...

36voto

abhi Points 886

Consultez ce lien qui contient un exemple de code pour crypter/décrypter des données à l'aide de AES256CBC en utilisant 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é que j'ai développé à l'adresse suivante https://github.com/llubu/mpro

Le code est suffisamment détaillé avec des commentaires et si vous avez encore besoin d'explications sur l'API elle-même, je vous suggère de consulter ce livre. Sécurité des réseaux avec OpenSSL par Viega/Messier/Chandra (google le vous trouverez facilement un pdf de cela..) lisez le chapitre 6 qui est spécifique aux ciphers symétriques utilisant l'API EVP Cela m'a beaucoup aidé à comprendre les raisons de l'utilisation des différentes fonctions et structures de EVP.

Et si vous voulez vous plonger dans la bibliothèque cryptographique Openssl, je vous suggère de télécharger le code à partir du site Web de la Commission européenne. site web d'openssl (la version installée sur votre machine) et regardez ensuite dans l'implémentation de l'EVP et de l'api aeh.

Une autre suggestion : à partir du code que vous avez posté ci-dessus, je vois que vous utilisez l'api de aes.h. au lieu d'utiliser EVP. Vérifiez la raison pour laquelle vous faites cela ici OpenSSL utilise EVP vs. algorithme API pour la crypto symétrique joliment expliqué par Daniel dans l'une des questions que j'ai posées

34voto

jww Points 9514

J'essaie d'écrire un exemple de programme pour faire du cryptage AES en utilisant Openssl.

Cette réponse est assez populaire, je vais donc proposer quelque chose de plus à jour depuis qu'OpenSSL a ajouté certains modes de fonctionnement qui vous seront probablement utiles.

D'abord, n'utilisez pas AES_encrypt y AES_decrypt . Ils sont de bas niveau et plus difficiles à utiliser. De plus, il s'agit d'une routine uniquement logicielle, et elle sera jamais utiliser l'accélération matérielle, comme AES-NI. Enfin, il est sujet à des problèmes d'endianess sur certaines plateformes obscures.

Au lieu de cela, utilisez le EVP_* interfaces. Le site EVP_* Les fonctions utilisent l'accélération matérielle, comme AES-NI, si elle est disponible. Et il ne souffre pas de problèmes d'endianess sur les plateformes obscures.

Deuxièmement, vous pouvez utiliser un mode comme CBC, mais le texte chiffré manquera de garanties d'intégrité et d'authenticité. Il faut donc généralement utiliser un mode comme EAX, CCM ou GCM. (Ou vous devez appliquer manuellement un HMAC après le chiffrement sous une clé distincte).

Troisièmement, OpenSSL possède une page wiki qui vous intéressera probablement : Cryptage et décryptage authentifiés par EVP . Il utilise le mode GCM.

Enfin, voici le programme pour crypter en utilisant AES/GCM. L'exemple du 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;
    }
}

20voto

user975612 Points 321

Je ne sais pas ce qui ne va pas avec le tien mais une chose est sûre, tu dois appeler AES_set_decrypt_key() avant de décrypter le message. N'essayez pas non plus d'imprimer en tant que %s car le message crypté n'est plus composé de 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 de 192 bits n'est-ce pas...

8voto

MK. Points 11889

Ma suggestion est d'exécuter

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/guide de démarrage/référence dont dispose OpenSSL. Toute autre documentation n'est qu'une référence à l'API.

U1 : Je pense que vous ne définissez pas d'autres options nécessaires, comme le mode de fonctionnement (rembourrage).

U2 : il s'agit probablement d'un doublon de cette question : Chiffrement AES CTR 256 Mode de fonctionnement sur OpenSSL et les réponses qui s'y trouvent vous aideront probablement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X