5

私はAES CBCとopensslでいくつかの作業を行っていますが、今のところ、何が悪いのか推測できないという問題に悩まされています(いつものように)。

メッセージの長さが 16 バイト未満の場合、暗号化と復号化のプロセスは正常に機能しますが、メッセージが 16 バイトを超える場合、復号化は最初の 16 バイトでのみ機能します。

私が呼び出すとaes.exe stackoverflow stackoverflow、出力は次のとおりです。

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

私が呼び出すとaes.exe stackoverflowstackoverflow stackoverflow、出力は次のとおりです。

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ó³{-.

暗号化/復号化の呼び出しごとにランダムな IV を提供し、両方の場合でパスワードを 32 バイトに正規化しています。私は何が欠けていますか?誰か知ってる?

ソースコード:

#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;
}
4

2 に答える 2

6

初期化ベクトルがメモリの破損のために上書きされ、暗号文の長さが正しく丸められず、std :: string ::c_strの代わりにstd::string :: data()を使用する必要があることを除いて、コードはほぼ正しいです。 ()std::stringをバイト配列として使用する場合。初期化ベクトルが空の文字列にコピーされ、スタックが上書きされます。次に、初期化ベクトルが上書きされるため、AESDecryptによって異なる値が使用されます。indivの提案を取り入れ、これらの問題を修正するソースコードを含めました。で実行する場合

aes「HelloWorld!」スタックオーバーフロー
次の出力が生成されます。

(正規化されたキー:737461636b6f766572666c6f770d0e0f101112131415161718191a1b1c1d1e1f)
暗号化:Hello World!
キー付き:stackoverflow
Init Vec:d8b1657d9e2317c93430994f59bb54eb
になる:��Йw�H���}�; E
(正規化されたキー:737461636b6f766572666c6f770d0e0f101112131415161718191a1b1c1d1e1f)
復号化:��Йw�H���}�; E
キー付き:stackoverflow
Init Vec:d8b1657d9e2317c93430994f59bb54eb
になる:Hello World!
#include <vector>
#include <string>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <initializer_list>
#include <openssl/aes.h>

typedef unsigned char byte;

template <size_t multiple> size_t round_up(const size_t len)
{
    if (len % multiple == 0) return len;
    else return ((len / multiple) + 1) * multiple;
}

std::ostream &print_buffer_as_hex(std::ostream &o, const unsigned char *buf, size_t size)
{
    o << std::hex << std::setfill('0');
    for( size_t i = 0; i < size; ++i )
    {
        o << std::setw(2) << static_cast<unsigned int>(buf[i]);
    }
    return o << std::dec;
}

inline std::ostream &operator<<(std::ostream &o, const std::vector<byte> &buf)
{
    return print_buffer_as_hex(o, reinterpret_cast<const unsigned char*>(&buf[0]), buf.size());
}

// 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::vector<byte> &aIVector)
{
    // Create IVector.
    unsigned char AES_IVector[AES_BLOCK_SIZE] = {0};
    std::srand(static_cast<int>(time(NULL)));
    std::generate(std::begin(AES_IVector), std::end(AES_IVector), std::rand);
    aIVector.resize(sizeof(AES_IVector));
    std::copy(std::begin(AES_IVector), std::end(AES_IVector), aIVector.begin());

    // Create key.
    const std::string Key(AES_NormalizeKey(apKey, aKeySize));
    std::cout << "(Normalized key: ";
    print_buffer_as_hex(std::cout, (const unsigned char*)Key.data(), Key.size()) << ")\n";
    AES_KEY EncryptKey;
    AES_set_encrypt_key(reinterpret_cast<const unsigned char *>(Key.data()), 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), round_up<AES_BLOCK_SIZE>(aBufferSize));

    // 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::vector<byte> &aIVector)
{
    // Read IVector.
    unsigned char AES_IVector[AES_BLOCK_SIZE] = {0};
    std::copy(aIVector.begin(), aIVector.end(), std::begin(AES_IVector));

    // Create Key.
    const std::string Key(AES_NormalizeKey(apKey, aKeySize));
    std::cout << "(Normalized key: ";
    print_buffer_as_hex(std::cout, (const unsigned char*)Key.data(), Key.size()) << ")\n";
    AES_KEY DecryptKey;
    AES_set_decrypt_key(reinterpret_cast<const unsigned char *>(Key.data()), 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(int argc, char **argv)
{
    typedef std::vector<std::string> vs;
    vs a;

    for (vs::size_type Index = 0; Index < static_cast<unsigned>(argc); ++Index)
    {
        a.push_back(argv[Index]);
    }

    if (a.size() == 3)
    {
        std::vector<byte> IV;

        std::string e(AESEncrypt(a.at(1).data(), a.at(1).size(), a.at(2).data(), a.at(2).size(), IV));
            std::cout << "Encrypting : " << a.at(1) << "\n"
                      << "With Key   : " << a.at(2) << "\n"
                      << "Init Vec   : " << IV << "\n"
                      << "Becomes    : " << e << "\n";

        std::string d(AESDecrypt(e.data(), e.size(), a.at(2).data(), a.at(2).size(), IV));
            std::cout << "Decrypting : " << e << "\n"
                      << "With Key   : " << a.at(2) << "\n"
                      << "Init Vec   : " << IV << "\n"
                      << "Becomes    : " << d << "\n";
    }
    std::cout.flush();

    return 0;
}
于 2012-08-19T16:30:46.950 に答える
0

具体的な答えはありませんが、コメントに収まらないヒントを次に示します。暗号化と復号化が機能するには、同じキーと IV が必要です。暗号化関数の出力は、復号化関数の入力に入る必要があります。

したがって、問題をデバッグするには、入力を暗号化関数に出力し、その出力を出力する必要があります。次に、入力データを復号化関数に出力し、その出力を出力する必要があります。プレーンテキストは、バイトが実際に何であるかがわからないため、これを行うには悪い方法です。そのため、キー、IV、およびデータを 16 進数値として出力します。

#include <iostream>
#include <iomanip>
...
std::ostream &print_buffer_as_hex(std::ostream &o, const unsigned char *buf, size_t size)
{
    for( int i = 0; i < size; ++i )
    {
        o << std::hex << std::setw(2) << std::setfill('0') << static_cast<unsigned int>(buf[i]) << std::dec;
    }
    o << "\n";

    return o;
}

次のように呼び出します。

print_buffer_as_hex(std::cout, reinterpret_cast<const char *>(AES_Encrypted), ((aBufferSize / 16) + 1) * 16);

任意のバイトを保持するstd::vector<unsigned char>代わりに使用します。コンストラクターまたはメソッド (resize() であり、reserve() ではありません!)std::stringを使用して、必要なスペースの量を設定します。resize()を必要とする API 関数を呼び出す場合はunsigned char *、 を渡すだけ&vec[0]です。ここで、vec はベクター オブジェクトです。あなたのコードはずっときれいに見えます。

例えば、

std::vector<unsigned char> iv(16);
std::srand(static_cast<int>(time(NULL)));
std::generate(iv.begin(), iv.end(), std::rand);

print_buffer_as_hex(std::cout, &iv[0], iv.size()); 
于 2012-08-08T17:43:06.993 に答える