AES CBC crypter/décrypter seulement décrypte les 16 premiers octets
Je suis en train de faire un certain travail avec AES-CBC et openssl et pour l'instant, je suis bloqué sur un problème que je ne peux pas deviner ce qui ne va pas (comme toujours).
Donné un message de moins de 16 octets de longueur le processus de chiffrement et de déchiffrement, qui fonctionne bien, mais lorsque le message est plus que de 16 octets, le déchiffrement ne fonctionne que sur les 16 premiers octets.
Quand je l'appelle aes.exe stackoverflow stackoverflow
la sortie est:
Using:
IVector = |000102030405060708090a0b0c0d0e0f|
Key = |737461636b6f766572666c6f770d0e0f101112131415161718191a1b1c1d1e1f|
Encrypted = |6c65219594c0dae778f9b5e84f018db6|
Encrypting : stackoverflow
With Key : stackoverflow
Becomes : ??????¤le!òö++þx¨ÁÞO?ìÂ.
Using:
IVector = |000102030405060708090a0b0c0d0e0f|
Key = |737461636b6f766572666c6f770d0e0f101112131415161718191a1b1c1d1e1f|
Decrypted = |737461636b6f766572666c6f77|
Decrypting : ??????¤le!òö++þx¨ÁÞO?ìÂ
With Key : stackoverflow
Becomes : stackoverflow
Quand je l'appelle aes.exe stackoverflowstackoverflow stackoverflow
la sortie est:
Using:
IVector = |000102030405060708090a0b0c0d0e0f|
Key = |737461636b6f766572666c6f770d0e0f101112131415161718191a1b1c1d1e1f|
Encrypted = |46172e3f7fabdcfc6c8b3e65aef175cddf8164236faf706112c15f5e765e49a5|
Encrypting : stackoverflowstackoverflow
With Key : stackoverflow
Becomes : ??????¤F?.?¦½_³lï>e«±u-¯üd#o»pa?-_^v^IÑ.
Using:
IVector = |000102030405060708090a0b0c0d0e0f|
Key = |737461636b6f766572666c6f770d0e0f101112131415161718191a1b1c1d1e1f|
Decrypted = |737461636b6f766572666c6f77737461257d434a1edcbc970bf5346ea2fc7bc2|
Decrypting : ??????¤F?.?¦½_³lï>e«±u-¯üd#o»pa?-_^v^IÑ
With Key : stackoverflow
Becomes : stackoverflowsta%}CJ?_+ù?§4nó³{ -.
Je suis fournissant un hasard IV pour chaque chiffrement/déchiffrement d'appel et de normaliser le mot de passe à 32 octets dans les deux cas; ce que je suis absent? quelqu'un sait?
Le code source:
#include <vector>
#include <string>
#include <iostream>
//Make a Key of exactly 32 bytes, truncates or adds values if it's necessary
std::string AES_NormalizeKey(const void *const apBuffer, size_t aSize)
{
static const unsigned char key32[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
const char *const Buffer = reinterpret_cast<const char *>(apBuffer);
std::string Result(reinterpret_cast<const char *>(key32), 32);
std::copy(Buffer, Buffer + ((aSize < 32)? aSize: 32), Result.begin());
return Result;
}
//Encrypt using AES cbc
std::string AESEncrypt(const void *const apBuffer, size_t aBufferSize, const void *const apKey, size_t aKeySize, std::string &aIVector)
{
//Create IVector.
unsigned char AES_IVector[16] = {0};
std::srand(static_cast<int>(time(NULL)));
std::generate(std::begin(AES_IVector), std::end(AES_IVector), std::rand);
std::copy(std::begin(AES_IVector), std::end(AES_IVector), aIVector.begin());
//Create key.
const std::string Key(AES_NormalizeKey(apKey, aKeySize));
AES_KEY EncryptKey;
AES_set_encrypt_key(reinterpret_cast<const unsigned char *>(Key.c_str()), 256, &EncryptKey);
//Encrypt.
unsigned char AES_Encrypted[1024] = {0};
AES_cbc_encrypt(static_cast<const unsigned char *>(apBuffer), AES_Encrypted, aBufferSize, &EncryptKey, AES_IVector, AES_ENCRYPT);
const std::string Encrypted(reinterpret_cast<const char *>(AES_Encrypted), ((aBufferSize / 16) + 1) * 16);
//Finish.
return Encrypted;
};
//Decrypt using AES cbc
std::string AESDecrypt(const void *const apBuffer, size_t aBufferSize, const void *const apKey, size_t aKeySize, std::string &aIVector)
{
//Read IVector.
unsigned char AES_IVector[16] = {0};
std::copy(aIVector.begin(), aIVector.end(), std::begin(AES_IVector));
//Create Key.
const std::string Key(AES_NormalizeKey(apKey, aKeySize));
AES_KEY DecryptKey;
AES_set_decrypt_key(reinterpret_cast<const unsigned char *>(Key.c_str()), 256, &DecryptKey);
//Decrypt.
unsigned char AES_Decrypted[1024] = {0};
AES_cbc_encrypt(static_cast<const unsigned char *>(apBuffer), AES_Decrypted, aBufferSize, &DecryptKey, AES_IVector, AES_DECRYPT);
const std::string Decrypted(reinterpret_cast<const char *>(AES_Decrypted));
//Finish.
return Decrypted;
};
//Entry point
int main(unsigned int argc, char **argv)
{
typedef std::vector<const std::string> vs;
vs a;
for (vs::size_type Index = 0; Index < argc; ++Index)
{
a.push_back(argv[Index]);
}
if (a.size() == 3)
{
std::string IV("");
std::string e(AESEncrypt(a.at(1).c_str(), a.at(1).size(), a.at(2).c_str(), a.at(2).size()), IV);
std::cout << "Encrypting : " << a.at(1) << "\n"
<< "With Key : " << a.at(2) << "\n"
<< "Becomes : " << e << ".\n";
std::string d(AESDecrypt(e.c_str(), e.size(), a.at(2).c_str(), a.at(2).size()), IV);
std::cout << "Decrypting : " << e << "\n"
<< "With Key : " << a.at(2) << "\n"
<< "Becomes : " << d << ".\n";
}
return 0;
}
- Vous ne devez pas utiliser
AES_encrypt
et amis. Vous devriez être en utilisantEVP_*
fonctions. Voir EVP Symétrique de Chiffrement et de Déchiffrement sur la OpenSSL wiki. En fait, vous devriez probablement être authentifié à l'aide de chiffrement, car il fournit à la fois la confidentialité et l'authenticité. Voir EVP Authentifié de Chiffrement et de Déchiffrement sur la OpenSSL wiki.
Vous devez vous connecter pour publier un commentaire.
Votre code est presque correct, sauf que le vecteur d'initialisation est écrasé en raison d'une corruption de la mémoire de la longueur du texte chiffré est arrondie de manière incorrecte, et std::string::data() doit être utilisé au lieu de std::string::c_str() lors de l'utilisation de std::string dans un tableau d'octets. Le Vecteur d'Initialisation est copié dans le vide de la chaîne d'écraser la pile. Ensuite, le Vecteur d'Initialisation est écrasée si une valeur différente est utilisée par AESDecrypt. J'ai inclus le code source qui intègre indiv suggestions et corrige ces problèmes. Lors de l'exécution avec
il produit la sortie suivante:
data
au lieu dec_str
est un très bon point!Je n'ai pas de réponse concrète, mais voici une astuce qui ne rentrent pas dans un commentaire. Chiffrer et déchiffrer exiger la même clé et IV de travail. La sortie de la fonction encrypt doit aller dans l'entrée de la décrypter la fonction.
Afin de corriger votre problème, vous avez besoin d'imprimer vos entrées à la fonction de crypter et de les imprimer sa sortie. Alors vous avez besoin pour imprimer les données d'entrée pour le décrypter la fonction et de l'impression à sa sortie. Texte brut est une mauvaise façon de le faire, parce que vous ne pouvez pas voir ce que les octets sont vraiment. Afin d'impression à la clé, IV, et les données en tant que valeurs hexadécimales.
L'appeler de la sorte:
J'utiliserais
std::vector<unsigned char>
au lieu destd::string
de tenir arbitraire d'octets. Définir la quantité d'espace que vous voulez avec le constructeur ou leresize()
méthode (resize(), pas de réserve()!). Si vous appelez une fonction de l'API qui veut ununsigned char *
, il suffit de passer&vec[0]
, où vec est votre objet vectoriel. Votre code est beaucoup plus propre.E. g.,
std::string Encrypted
n'est pas le problème, je sais que sur le paramètre n surstd::string
constructeur et le((aBufferSize / 16) + 1) * 16)
est là sur le but, la cause de chiffrement AES crée toujours des morceaux de plusieurs de 16bytes de données, de sorte que si le message est 12bytes le chiffrement de 16 et si le message est 17bytes de données de chiffrement sont de 32 octets. Je vais mettre l'intermédiaire des octets sur hexa comme conseillé.std::string
constructeur a travaillé avec des données binaires et len
paramètre. Merci pour le tuyau et j'ai édité ma réponse en conséquence.