#微碼分享#AES演算法的C++包裝類

一見發表於2019-01-24

AES為Advanced Encryption Standard的縮寫,中文名:高階加密標準,在密碼學中又稱Rijndael加密法,是美國聯邦政府採用的一種區塊加密標準,用來替代DES。基於std::string實現的C++包裝類,使用得應用AES演算法十分簡單。完整原始碼連結:
​https://github.com/eyjian/libmooon/blob/master/include/mooon/utils/aes_helper.h
https://github.com/eyjian/libmooon/blob/master/src/utils/aes_helper.cpp​

aes_helper.h標頭檔案

// 高階加密標準(Advanced Encryption Standard),
// 在密碼學中又稱Rijndael加密法,是美國聯邦政府採用的一種區塊加密標準,用來替代DES
class CAESHelper
{
public:
    // 加密資料塊分組長度,必須為128位元(金鑰長度可以是128位元、192位元、256位元中的任意一個)
    static int aes_block_size;

public:
    // key 金鑰
    //
    // 因為AES要求key長度只能為128或192或256位元中的一種,即16位元組或24位元組或32位元組中的一種,
    // 當key的長度不足16位元組時,CAESHelper自動補0足16位元組,
    // 當key的長度間於16位元組和24位元組時,CAESHelper自動補0足24位元組,
    // 當key的長度間於24位元組和32位元組時,CAESHelper自動補0足32位元組,
    // 當key的長度超出32位元組時,CAESHelper自動擷取前32位元組作為金鑰
    CAESHelper(const std::string& key);
    ~CAESHelper();

    void encrypt(const std::string& in, std::string* out);
    void decrypt(const std::string& in, std::string* out);

private:
    // flag 為true表示加密,為false表示解密
    void aes(bool flag, const std::string& in, std::string* out, void* aes_key);

private:
    void* _encrypt_key;
    void* _decrypt_key;
    std::string _key;
};

aes_helper.cpp實現檔案

#if MOOON_HAVE_OPENSSL == 1
int CAESHelper::aes_block_size = AES_BLOCK_SIZE; // 16
#else
int CAESHelper::aes_block_size = 0;
#endif // MOOON_HAVE_OPENSSL

static std::string errcode2errmsg(int errcode)
{
    std::string errmsg;

    if (0 == errcode)
        errmsg = "success";
    else if (-1 == errcode)
        errmsg = "userkey is empty";
    else if (-2 == errcode)
        errmsg = "length of userkey is invalid";
    else
        errmsg = "unknown error";
    return errmsg;
}

CAESHelper::CAESHelper(const std::string& key)
{
    _encrypt_key = NULL;
    _decrypt_key = NULL;
    _key = key;

    const std::string::size_type LEN16 = 16;
    const std::string::size_type LEN24 = 24;
    const std::string::size_type LEN32 = 32;
    const std::string::size_type len = key.size();
    if ((len != LEN16) &&
        (len != LEN24) &&
        (len != LEN32))
    {
        if (len < LEN16)
            _key.resize(LEN16);
        else if (len < LEN24)
            _key.resize(LEN24);
        else if (len < LEN32)
            _key.resize(LEN32);
        else
            _key.resize(LEN32);
    }
}

CAESHelper::~CAESHelper()
{
#if MOOON_HAVE_OPENSSL == 1
    delete (AES_KEY*)_encrypt_key;
    delete (AES_KEY*)_decrypt_key;
#endif // MOOON_HAVE_OPENSSL
}

void CAESHelper::encrypt(const std::string& in, std::string* out)
{
#if MOOON_HAVE_OPENSSL == 1
    if (NULL == _encrypt_key)
    {
        _encrypt_key = new AES_KEY;

        const int errcode = AES_set_encrypt_key((const unsigned char*)(_key.data()), (int)(_key.size()*8), (AES_KEY*)_encrypt_key);
        if (errcode != 0) // 理論上不會返回非0,因為建構函式已經處理好了key的長度
        {
            delete (AES_KEY*)_encrypt_key;
            _encrypt_key = NULL;
            THROW_EXCEPTION(errcode2errmsg(errcode), errcode);
        }
    }

    aes(true, in, out, _encrypt_key);
#endif // MOOON_HAVE_OPENSSL
}

void CAESHelper::decrypt(const std::string& in, std::string* out)
{
#if MOOON_HAVE_OPENSSL == 1
    if (NULL == _decrypt_key)
    {
        _decrypt_key = new AES_KEY;

        const int errcode = AES_set_decrypt_key((const unsigned char*)(_key.data()), (int)(_key.size()*8), (AES_KEY*)_decrypt_key);
        if (errcode != 0) // 理論上不會返回非0,因為建構函式已經處理好了key的長度
        {
            delete (AES_KEY*)_decrypt_key;
            _decrypt_key = NULL;
            THROW_EXCEPTION(errcode2errmsg(errcode), errcode);
        }
    }

    aes(false, in, out, _decrypt_key);
#endif // MOOON_HAVE_OPENSSL
}

void CAESHelper::aes(bool flag, const std::string& in, std::string* out, void* aes_key)
{
#if MOOON_HAVE_OPENSSL == 1
    AES_KEY* aes_key_ = (AES_KEY*)aes_key;

    std::string in_tmp = in;
    if (in.size() % AES_BLOCK_SIZE != 0)
    {
        std::string::size_type tmp_size = in.size() + (AES_BLOCK_SIZE - in.size() % AES_BLOCK_SIZE);
        in_tmp.resize(tmp_size);
    }

    const char* in_p = in_tmp.data();
    out->resize(in_tmp.size());
    char* out_p = const_cast<char*>(out->data());

    for (std::string::size_type i=0; i<in.size(); i+=AES_BLOCK_SIZE)
    {
        char out_tmp[AES_BLOCK_SIZE];

        if (flag)
            AES_encrypt((const unsigned char*)(in_p), (unsigned char*)(out_tmp), aes_key_);
        else
            AES_decrypt((const unsigned char*)(in_p), (unsigned char*)(out_tmp), aes_key_);

        in_p += AES_BLOCK_SIZE;
        memcpy(out_p+i, out_tmp, AES_BLOCK_SIZE);
    }
#else
    *out = '\0'; // 需要加上這一句,不然難區分HAVE_OPENSSL值是否為1或不為1的情況
#endif // MOOON_HAVE_OPENSSL
}

 

相關文章