使用Crypto ++将IV和数据连接到Base64字符串中?

时间:2019-10-16 13:05:35

标签: encryption base64 aes crypto++ cbc-mode

我需要将字符串加密为AES / CBC。为了以后能够对其解密,我必须将IV存储在最终结果中,该结果必须是base64字符串。

我设法使用此answer和Crypto ++示例:

std::string String::AESEncryptString(std::string str, std::string key)
{
    std::string encoded;
    std::string b64Result = "";

    AutoSeededRandomPool prng;

    unsigned char iv[AES::BLOCKSIZE];
    prng.GenerateBlock(iv, sizeof(iv));

    StringSink output(encoded);

    // Put the IV at the begining of the output
    StringSource(iv, sizeof(iv), true,
        new Redirector(output)
    );

    try {
        CBC_Mode<AES>::Encryption encryptor((unsigned char *)key.c_str(), key.length(), iv);

        StringSource s(str, true, 
            new StreamTransformationFilter(encryptor, 
                new Redirector(output), StreamTransformationFilter::PKCS_PADDING
            )
        );

        // Convert to b64
        StringSource (encoded, true,
            new Base64Encoder(
                new StringSink(b64Result),
                false // do not append a newline
            )
        );

        return b64Result;
    } catch (const Exception& e) {
        return "";
    }
}

要解密base64字符串,我首先提取IV,然后解密其余数据:

std::string String::AESDecryptString(std::string str, std::string key)
{
    unsigned char iv[AES::BLOCKSIZE];

    std::string b64decoded;
    std::string decoded;

    try {
        StringSource(str, true,
            new Base64Decoder(
                new StringSink(b64decoded)
            )
        );

        StringSource ss(b64decoded, false);

        // Get the IV
        ArraySink ivSink(iv, sizeof(iv));
        ss.Attach(new Redirector(ivSink));
        ss.Pump(AES::BLOCKSIZE);


        CBC_Mode<AES>::Decryption decryptor((unsigned char *)key.c_str(), key.length(), iv);


        ByteQueue queue;
        ss.Detach(
            new StreamTransformationFilter(decryptor,
                new Redirector(queue)
            )
        );
        ss.PumpAll(); // Pump remainder bytes

        StringSink decodedSink(decoded);
        queue.TransferTo(decodedSink);
        return decoded;
    }
    catch (const Exception& e) {
        return "";
    }
}

一切都很好,但是当我发现Crypto ++和流水线范例时,我觉得我可能已经完成了很多步骤来实现自己想要的。

是否有更简洁或更有效的方法?

2 个答案:

答案 0 :(得分:1)

您可以将这两个步骤合并为一个 StringSource 调用:

StringSource s(str, true, 
  new StreamTransformationFilter(
    encryptor, 
    new Base64Encoder(
      new StringSink(b64Result),
      false // do not append a newline
    ),
    StreamTransformationFilter::PKCS_PADDING
  )
);
StringSource s(
  str, true,
  new Base64Decoder(
    new StreamTransformationFilter(decryptor, new StringSink(decoded))
  )
);

答案 1 :(得分:0)

创建用于链接的锚点类。跟随this

#include <iostream>
#include <string>
#include <cstdlib>
#include <cryptopp/osrng.h>
#include <cryptopp/base64.h>
#include <cryptopp/aes.h>
#include <cryptopp/filters.h>
#include <cryptopp/modes.h>
#include <cryptopp/cryptlib.h>

#ifndef CRYPTOPP_NO_GLOBAL_BYTE
namespace CryptoPP { typedef unsigned char byte; }
#endif  // CRYPTOPP_NO_GLOBAL_BYTE

const std::string seckey = "this-has-16-char";

class Anchor : public CryptoPP::Bufferless<CryptoPP::Filter>
{
public:
    Anchor(CryptoPP::BufferedTransformation* attachment = NULL) { Detach(attachment); };
    size_t Put2(const CryptoPP::byte * inString, size_t length, int messageEnd, bool blocking )
    {
        return AttachedTransformation()->Put2(inString, length, messageEnd, blocking );
    }
};

/**
* Encode : return encoded
*
*/
bool Encode(const std::string& input, std::string& output)
{
    if (seckey.length()!=CryptoPP::AES::DEFAULT_KEYLENGTH) return false;
    unsigned char iv[CryptoPP::AES::BLOCKSIZE];
    // CryptoPP::AutoSeededRandomPool prng;
    // prng.GenerateBlock(iv, sizeof(iv));
    memcpy(iv, "this-also-has-16", CryptoPP::AES::BLOCKSIZE);
    output.clear();

    try {

        Anchor anchor;

        // Put the IV at the begining of the output
        anchor.Attach(new CryptoPP::StringSink(output));
        anchor.Put( iv, sizeof(iv) );
        anchor.MessageEnd();
        anchor.Detach();

        CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encryptor((unsigned char *)seckey.c_str(), seckey.length(), iv);
        anchor.Attach(new CryptoPP::StreamTransformationFilter(encryptor,NULL, CryptoPP::StreamTransformationFilter::PKCS_PADDING));
        anchor.Attach(new CryptoPP::Base64Encoder(NULL, false));
        anchor.Attach(new CryptoPP::StringSink(output));

        anchor.Put( (CryptoPP::byte*)input.c_str(), input.length() );
        anchor.MessageEnd();
    }
    catch (const CryptoPP::Exception& e) {
        return false;
    }
    return true;
}

/**
* Decode : return decoded
*
*/
bool Decode(const std::string& input, std::string& output)
{
    if (seckey.length()!=CryptoPP::AES::DEFAULT_KEYLENGTH) return false;
    if (input.length()<=CryptoPP::AES::BLOCKSIZE) return false; // no iv
    unsigned char iv[CryptoPP::AES::BLOCKSIZE];
    memcpy(iv, input.c_str(), CryptoPP::AES::BLOCKSIZE);

    try {
        // Convert from b64 and decode
        CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decryptor((unsigned char *)seckey.c_str(), seckey.length(), iv);

        Anchor anchor;
        anchor.Attach(new CryptoPP::Base64Decoder());
        anchor.Attach(new CryptoPP::StreamTransformationFilter( decryptor, NULL));
        anchor.Attach(new CryptoPP::StringSink(output));

        anchor.Put( (const CryptoPP::byte*)&input[CryptoPP::AES::BLOCKSIZE], input.length()-CryptoPP::AES::BLOCKSIZE );
        anchor.MessageEnd();

    }
    catch (const CryptoPP::Exception& e) {
        return false;
    }
    return true;
}

int main()
{

    std::string input = "The five boxing wizards jump quickly.";
    std::string output;
    bool status = Encode(input,output);
    if (status) std::cerr << "Encoded: " << output << std::endl;
    input.clear();
    status = Decode(output,input);
    if (status) std::cerr << "Decoded: " << input << std::endl;

}