tasos-py / AES-Encryption-Classes

AES encryption in Python, PHP, C#, Java, C++, F#, Ruby, Scala, Node.js
MIT License
145 stars 58 forks source link

Mac Check Failed #4

Closed amplitudesxd closed 3 years ago

amplitudesxd commented 3 years ago

Hey! I'm encrypting data with the C++ library and decrypting it with the NodeJS one.

My code is following: C++

AesEncryption aes("cbc", 256);
CryptoPP::SecByteBlock enc = aes.encrypt("hello world!", "CsXamjES6yFqPK5SnE8eEYy9xmcukmdj");
std::string output(enc.begin(), enc.end());

NodeJS

console.log(new aes("cbc", 256).decrypt("uGIGGWzNyLaGPfKnCvk8wZRegciYx6hWjMemR0VEmOcvPgZ3hdmiK1UPS2TGgH1ORMOprISIcqfPL4xlF6paLXobLuxdzV8pJr0z8idXcxI=", "CsXamjES6yFqPK5SnE8eEYy9xmcukmdj"));

When I call the NodeJS function, I get Mac check failed! - Both passwords are the same so I'm confused as to why this happens.

tasos-py commented 3 years ago

I don't understand either. I can't decrypt the ciphertext you provided neither with Node nor with CPP, but I have no problems with other ciphertexts produced by CPP (using CryptoPP v7.0.0, g++ v8.1.0, Node v10.13.0). Can you decrypt this ciphertext with the same code that produced it? Does this happen often or only this time?

amplitudesxd commented 3 years ago

Hey, thanks for the response.

It decrypts perfectly with the code that produced it.

Decryption code:

CryptoPP::SecByteBlock decrypted = aes.decrypt("2q6UGDYQE8QtFGHpIsrCiRld6iWEO4u+N2pgXq0MiuG4bEEXKz0oYYp33/DeY8I6CxY3EyxhSJXcDia5/uT4Ajv05eWHskWskh6WJ+wtB1M=", "CsXamjES6yFqPK5SnE8eEYy9xmcukmdj");

It happens every time I try to decrypt.

amplitudesxd commented 3 years ago

I'm using Node v12.21.0, CryptoPP v8.5.0 and MSVC v19.24.28316.

amplitudesxd commented 3 years ago

I also tested downgrading CryptoPP to v7.0.0 (what you are using), it's still throwing the same error.

tasos-py commented 3 years ago

That's very useful, but I'm afraid I still don't see the problem. I disabled MAC verification, but decryption fails anyway, so I think this is probably a key generation error. Unfortunately, I can't reproduce it (with VS v15.9.24, C++17) so I'll need your help. I created those two pastebin files - cpp and node that log keys and other data; if you could run them, they may give us the info we need to solve this.

amplitudesxd commented 3 years ago

Hey, thanks again for the response. Heres the output of both of those.

c++

AES key: 'aad7a257fc13679a71b73fd00cdd7ea976f44b139bfcafb3cb157b0082663915'
MAC key: 'ae16ca689193f21b6cac7568ecd5136e5cd069c05fc28a3da09c68caf914d847'
password: '"CsXamjES6yFqPK5SnE8eEYy9xmcukmdj"'
iterations: '20000'
salt: '02ecaca663ca99b8fab7e73341ad3a16'

resulting key: AuyspmPKmbj6t+czQa06Fp7+zRCxUw7bOosTphjaE34k3S9RbHPKO3vvvK7x0Hhieogm5w6WX80VdL8KK1uiw5U8rHJMMTcoQpwI2K4EyyU=

nodejs:

2|index  | AES key: '77f8c9d624f9561975270fa315dc888eb03597907429f4a05677fa7daff37854'
2|index  | MAC key: 'b8dbcc319d7638dc979131bd671a2dc856f8f7f27955fc3a8136839a9d889f5e'
2|index  | password: 'CsXamjES6yFqPK5SnE8eEYy9xmcukmdj'
2|index  | iterations: '20000'
2|index  | salt: '02ecaca663ca99b8fab7e73341ad3a16'
2|index  | Mac check failed!
tasos-py commented 3 years ago

Okay, so this is clearly a key generation issue. Strange because all inputs are same, plus it doesn't happen on my machine. Let me do some research on PKCS5_PBKDF2_HMAC and I'll get back to you.

amplitudesxd commented 3 years ago

Thank you!

tasos-py commented 3 years ago

So, I could't find many problems with CryptoPP::PKCS5_PBKDF2_HMAC, except from this bug: https://www.mail-archive.com/cryptopp-users@googlegroups.com/msg07221.html However, I don't know if that's causing the error; the versions I'm testing with (7.0 and 8.2) still have this code, but it doesn't affect my results.

Since I can't reproduce your results, I'll have to ask for your help one more time. I've copied the example code from https://www.cryptopp.com/wiki/PKCS5_PBKDF2_HMAC and the keys() method from my code, hoping to isolate the issue. Could you give it a try?

#include <iostream>
#include <string>
#include <cassert>

#include <cryptopp/hex.h>
#include <cryptopp/sha.h>
#include <cryptopp/pwdbased.h>

std::string hex_encode(const unsigned char* data, unsigned int size) {
    std::string hex;
    CryptoPP::ArraySource(data, size, true, new CryptoPP::HexEncoder(new CryptoPP::StringSink(hex), NULL, false));
    return hex;
}

/// Code from https://www.cryptopp.com/wiki/PKCS5_PBKDF2_HMAC, section "Sample Program"
void pbkdf2_sha512(const CryptoPP::byte* password, const CryptoPP::byte* salt, unsigned int iterations, CryptoPP::byte* dkey, unsigned int dkeyLen) {
    CryptoPP::byte unused = 0;
    CryptoPP::PKCS5_PBKDF2_HMAC<CryptoPP::SHA512> kdf;
    kdf.DeriveKey(
        dkey, dkeyLen, unused, password, strlen((const char*)password),
        salt, strlen((const char*)salt), iterations, 0.0f
    );
}

/// Code from https://github.com/tasos-py/AES-Encryption-Classes/blob/master/aes_encryption_cpp/aes_encryption.cpp#L341
void AesEncryption_keys(CryptoPP::SecByteBlock password, const unsigned char* salt, unsigned int iterations, CryptoPP::SecByteBlock& dkey) {
    CryptoPP::SecByteBlock dkey2(dkey.size());
    CryptoPP::PKCS5_PBKDF2_HMAC<CryptoPP::SHA512> kdf;
    kdf.DeriveKey(
        dkey2.data(), dkey2.size(), 0x00, password, password.size(),
        salt, strlen((const char*)salt), iterations
    );
    dkey.Assign(dkey2.begin(), dkey.size());
}

int main(int argc, char* argv[]) {
    // test vectors taken from https://fossies.org/linux/nettle/testsuite/pbkdf2-test.c line 97
    unsigned char password[] = "password";
    unsigned char salt[] = "NaCL";
    unsigned int iterations = 1;
    unsigned int dkeyLen = 64;
    std::string correctDkey = "73decfa58aa2e84f94771a75736bb88bd3c7b38270cfb50cb390ed78b305656af8148e52452b2216b2b8098b761fc6336060a09f76415e9f71ea47f9e9064306";

    unsigned char dkey[dkeyLen];
    pbkdf2_sha512(password, salt, iterations, dkey, dkeyLen);
    std::cout << "dkey A " << hex_encode(dkey, sizeof(dkey)) << std::endl;

    CryptoPP::SecByteBlock dkey2(dkeyLen);
    AesEncryption_keys(CryptoPP::SecByteBlock(password, strlen((const char*)password)), salt, iterations, dkey2);
    std::cout << "dkey B " << hex_encode(dkey2.data(), dkey2.size()) << std::endl;

    assert(hex_encode(dkey, sizeof(dkey)) == correctDkey);
    assert(hex_encode(dkey2.data(), dkey2.size()) == correctDkey);

    return 0;
}

I couldn't find official test vectors for PBKDF2-HMAC-SHA512 so I copied them from https://fossies.org/linux/nettle/testsuite/pbkdf2-test.c, but they are valid.

tasos-py commented 3 years ago

Oops, wrong button!

amplitudesxd commented 3 years ago

Hey, I'm sorry for not replying sooner - I've been pretty busy recently.

I had to reset my PC, now its working perfectly - I'm not too sure as to exactly what fixed it, but I'm guessing it could potentially be something to do with one of the libraries I had installed?

Thanks for all the help you've given me, its much appreciated :)