Mes fonctions de chiffrement / déchiffrement AES ne fonctionnent pas avec ivecs aléatoires

StackOverflow https://stackoverflow.com/questions/2541971

  •  23-09-2019
  •  | 
  •  

Question

Je me suis ennuyé et écrit un wrapper autour de OpenSSL pour chiffrement AES avec moins de travail. Si je le fais comme ceci: http://pastebin.com/V1eqz4jp (IVEC = 0)
Tout fonctionne très bien, mais le IVEC par défaut est tous les 0, ce qui a des problèmes de sécurité. Puisque je passe les données de retour comme une chaîne de toute façon, je me suis dit, pourquoi ne pas générer un IVEC aléatoire et le coller à l'avant, le programme Rapportez-quand je déchiffré la chaîne? Pour une raison quelconque, il ne fonctionne pas bien.

Et bien en fait, il fonctionne presque. Il semble décrypter le milieu de la chaîne, mais pas le début ou fin :

String is: 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
Encrypting..
���l%%1u���B!
�����`pN)�ɶ���[l�ӏ��{�Q�?�2�/�HԵ�y"�=Z�Cu����l%%1u���B!

Decrypting..
String is: �%���G*�5J�0��0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF

Je n'ai honnêtement aucune idée de ce qui va mal. Peut-être une erreur stupide, ou je suis peut-être manque quelque chose au sujet de AES?

Voici le code: (modifié pour incorporer la solution de Steve Jessop à mon premier problème)

/*!
 * Simple AES
 * Brendan Long
 * March 29, 2010
 * 
 * Simplified encryption and decryption using OpenSSL's AES library.
 * Remember to compile with -lcrypto and link against the library
 * g++ (your stuff) -lcrypto simpleAes.cpp (or simpleAes.o)
 *
 * Implementation note: Using the default ivec (0) is not secure. For
 *                      the full security that AES offers, use a different
 *                      ivec each time (it does not need to be secret,
 *                      just different.
 *
 * This code is released into the public domain. Yada yada..
 * Read this for details: http://creativecommons.org/licenses/publicdomain/
 *
 * If for some reason public domain isn't good enough, you may use, alter,
 * distribute or do anything else you want with this code with no restrictions.
 */

#include <openssl/aes.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>

bool seed = true;

/*!
 * Encrypts a string using AES with a 256 bit key
 * Note: If the key is less than 32 bytes, it will be null padded.
 *       If the key is greater than 32 bytes, it will be truncated
 * \param in The string to encrypt
 * \param key The key to encrypt with
 * \return The encrypted data
 */
std::string aes_encrypt(std::string in, std::string key){

    // Seed the random number generator once
    if(seed){
        srand( (unsigned int) time(NULL));
        seed = false;
    }

    // Generate a random ivec
    unsigned char ivec[16];
    for(int i=0; i<16; i++){
        ivec[i] = (unsigned char) rand();
    }

     // Round up to AES_BLOCK_SIZE
    size_t textLength = ((in.length() / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;

    // Always pad the key to 32 bits.. because we can
    if(key.length() < 32){
        key.append(32 - key.length(), '\0');
    }

    // Get some space ready for the output
    unsigned char *output = new unsigned char[textLength];

    // Generate a key
    AES_KEY *aesKey = new AES_KEY;
    AES_set_encrypt_key((unsigned char*)key.c_str(), 256, aesKey);

    // Encrypt the data
    AES_cbc_encrypt((unsigned char*)in.c_str(), output, in.length() + 1, aesKey, ivec, AES_ENCRYPT);

    // Make the data into a string
    std::string ret((char*) output, textLength);

    // Add the ivec to the front
    ret = std::string((char*)ivec, 16) + ret;

    // Clean up
    delete output;
    delete aesKey;

    return ret;
}

/*!
 * Decrypts a string using AES with a 256 bit key
 * Note: If the key is less than 32 bytes, it will be null padded.
 *       If the key is greater than 32 bytes, it will be truncated
 * \param in The string to decrypt
 * \param key The key to decrypt with
 * \return The decrypted data
 */
std::string aes_decrypt(std::string in, std::string key){

    // Get the ivec from the front
    unsigned char ivec[16];
    for(int i=0;i<16; i++){
        ivec[i] = in[i];
    }

    in = in.substr(16);

    // Always pad the key to 32 bits.. because we can
    if(key.length() < 32){
        key.append(32 - key.length(), '\0');
    }

    // Create some space for output
    unsigned char *output = new unsigned char[in.length()]; 

    // Generate a key
    AES_KEY *aesKey = new AES_KEY;
    AES_set_decrypt_key((unsigned char*)key.c_str(), 256, aesKey); // key length is in bits, so 32 * 8 = 256

    // Decrypt the data
    AES_cbc_encrypt((unsigned char*)in.c_str(), output, in.length(), aesKey, ivec, AES_DECRYPT);

    // Make the output into a string
    std::string ret((char*) output);

    // Clean up
    delete output;
    delete aesKey;

    return ret;
}
Était-ce utile?

La solution 3

Un de mes amis a compris le problème. Je fais ceci:

  1. générer un nombre aléatoire et le stocker dans ivec
  2. Chiffrer les données avec ivec
  3. Append IVEC au début des données de sortie

Le problème est que l'étape 2 change le contenu de IVEC. Je essentiellement le stockage des nombres aléatoires au début de ma chaîne. La solution a été d'ajouter ceci:

unsigned char ivec[16];
// set ivec to random numbers
std::string ivecString((char*) ivec, 16);
// encrypt data
return ivecString + encryptedData;

Autres conseils

Vous devez enregistrer le IVEC [16] en « sortie » avant de le chiffrer. Ca y est ...

Je voudrais aussi ajouter que ce sera beaucoup plus simple de travailler avec char * au lieu de chaîne.

Cette ligne est erroné:

std::string ret((char*) output);

Les données déchiffrées ne dispose pas d'une terminaison NUL, puisque vous avez crypté octets de in.length(). Cela représente les ordures à la fin, mais pas les ordures au début. Il peut y avoir d'autres problèmes.

En général, vous ne pouvez pas traiter la sortie de l'étage de chiffrement en tant que chaîne, à moins que vous effectuez une étape supplémentaire, comme la base 64 codant pour la sortie. Tout octet de sortie pourrait être un NUL.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top