Jabu
Jabu

Reputation: 135

How to decrypt using a passphrase and salt using the crypto++ lib?

I'm trying to decrypt a string that has been encrypted using openssl, evp_aes_128_cbc, and a password/salt

I have succeeded decrypting it using openssl, but not using the crypto++ lib.

The key generated on the crypto++ matches the openssl key but the iv's doesnt.

The code result in an exception in the line stf.MessageEnd();

its breaks in the crypto++ file filter.cpp at:

            if (length != s)
                throw InvalidCiphertext("StreamTransformationFilter: ciphertext length is not a multiple of block size");

where length is 24 and s is 16...


c++/openssl encryption function:

    #include <openssl/rand.h>
    #include <openssl/evp.h>
    #include <openssl/bio.h>

     std::string stringToBase64(const std::string& input) 
     {
        BIO* bio = BIO_new(BIO_s_mem());
    
        BIO* base64 = BIO_new(BIO_f_base64());
        BIO_set_flags(base64, BIO_FLAGS_BASE64_NO_NL);  // No line breaks
    
        BIO* bio_chain = BIO_push(base64, bio);    
        BIO_write(bio_chain, input.c_str(), input.length());
        BIO_flush(bio_chain);
    
        char* encoded_data;
        long encoded_length = BIO_get_mem_data(bio, &encoded_data);
    
        std::string base64_string(encoded_data, static_cast<size_t>(encoded_length));
    
        // Free the BIOs
        BIO_free_all(bio_chain);    
        return base64_string;
    }

   
    std::string encrypt(std::string str, const char* password, const char* salt)
    {
        unsigned char key[EVP_MAX_KEY_LENGTH];

    unsigned char derived[32]; // 32 bytes for both key and IV

    if(!PKCS5_PBKDF2_HMAC(reinterpret_cast<const char*>(password), strlen(password), 
      reinterpret_cast<const unsigned char *>(salt), strlen(salt), 
      1000, EVP_sha1(), 32, derived)) // Derive 32 bytes
    {
        EVP_CIPHER_CTX_free(ctx);
        return std::string();
    }

    unsigned char key[EVP_MAX_KEY_LENGTH];
    unsigned char iv[EVP_MAX_IV_LENGTH];

    // Use the first 16 bytes as the key
    memcpy(key, derived, 16);
    // Use the remaining 16 bytes as the IV
    memcpy(iv, derived + 16, 16);

    if (EVP_CipherInit(ctx, EVP_aes_128_cbc(), key, iv, true) != 1) 
    {
        EVP_CIPHER_CTX_free(ctx);
        return std::string();
    }
        
        const int MAX_BUFFER_SIZE = str.size();
        int len = 0;
        int outLen;
        
        int blocksize = EVP_CIPHER_CTX_block_size(ctx);
        std::string cipherBuf;
        cipherBuf.resize(MAX_BUFFER_SIZE + blocksize);
            
        if (EVP_CipherUpdate(ctx, reinterpret_cast<uchar *>(cipherBuf.data()), &outLen, reinterpret_cast<uchar *>(str.data()), str.size()) != 1)
        {
            EVP_CIPHER_CTX_free(ctx);
            return std::string();
        }        
        len += outLen;
      
        if (EVP_CipherFinal(ctx, reinterpret_cast<uchar *> (cipherBuf.data() + len), &outLen) != 1)
        {
            EVP_CIPHER_CTX_free(ctx);
            return std::string();     
        }        
        len += outLen;
         
        cipherBuf.resize(len);
        EVP_CIPHER_CTX_free(ctx); // Cleanup
    
        str = stringToBase64(cipherBuf); 
        memset(cipherBuf.data(), 0, MAX_BUFFER_SIZE + blocksize); // Clear cipherBuf    
        return str;
    }
    
    int main(int argc, char* argv[])
    {
        const char* password = "password123";
        const char* salt = "salt123";

        std::string enc = ecrypt("test123", password, salt);

        size_t saltLen = strlen(salt);
        std::string derived_key(16 + saltLen, '\0'); // AES-128

        CryptoPP::PKCS5_PBKDF2_HMAC<CryptoPP::SHA1> pbkdf;
        pbkdf.DeriveKey(reinterpret_cast<byte*>(&derived_key[0]), derived_key.size(), 0,
                        reinterpret_cast<const byte*>(password), 
                        strLen(password), 
                        reinterpret_cast<const byte*>(salt), 
                        saltLen, 1000); // '1000' same as on the openssl function
        
        CryptoPP::SecByteBlock key(16), iv(saltLen);
        std::memcpy(key.data(), derived_key.data(), key.size());
        std::memcpy(iv.data(), derived_key.data() + saltLen, iv.size());
        
        CryptoPP::HexEncoder encoder;
        std::string key_hex, iv_hex;

        encoder.Attach(new CryptoPP::StringSink(key_hex));
        encoder.Put(key.data(), key.size());
        encoder.MessageEnd();

        encoder.Attach(new CryptoPP::StringSink(iv_hex));
        encoder.Put(iv.data(), iv.size());
        encoder.MessageEnd();

        std::cout << "Key: " << key_hex;
        std::cout << "IV: " << iv_hex;

        
        CryptoPP::AES::Decryption aesDecryption(key, key.size());
        CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv);
      
        std::string dec;
        CryptoPP::StreamTransformationFilter stf(cbcDecryption,  new CryptoPP::StringSink(dec));
        stf.Put(reinterpret_cast<const unsigned char*>(enc.data()), enc.size());
        stf.MessageEnd();
    }

Upvotes: 0

Views: 132

Answers (0)

Related Questions