bugfix> c++ > 投稿

nodejsでこのAES c ++復号化を再実装しました。

「バッファ」には暗号化されたコンテンツが含まれます。 「decryptKey」には、「バッファ」を復号化するためのキーが含まれています。 「expectedOutput」には、予想される出力が含まれています。

ノードによってスローされる不正な復号化例外をバイパスするには、cryptオブジェクトのautoPaddingを無効にする必要がありました。

簡単にするために、c ++コードを追加し、3つの異なるアルゴリズム(AES-128-ECB、AES-192-ECB、AES-256-ECB)にテストを追加しました。解読結果はいずれもC ++出力と一致しません。

私は何が欠けていますか? 

var crypto = require('crypto');
var buffer = new Buffer([
    0x5e,0x51,0xa3,0x53,0x9d,0xe7,0xe5,0xd3,
    0xee,0x30,0xbb,0xf8,0x0c,0x72,0x9f,0x80
]);

var decryptKey = new Buffer([
    0x36, 0x46, 0xb4, 0xf6, 
    0x8e, 0x6d, 0xdc, 0xf4, 
    0xb0, 0x31, 0x7e, 0x81, 
    0x6b, 0x5d, 0x96, 0x55
])
/*
After looking to my C++ code I noticed that despite of providing a 32 length key the 128 argument ensures that only the first 16 bytes are used
var decryptKey = new Buffer([
    0x36, 0x46, 0xb4, 0xf6, 
    0x8e, 0x6d, 0xdc, 0xf4, 
    0xb0, 0x31, 0x7e, 0x81, 
    0x6b, 0x5d, 0x96, 0x55, // 16
    0x15, 0x9c, 0x78, 0x54, 
    0x8c, 0xca, 0x3e, 0x39, 
    0x2d, 0x49, 0x75, 0x5d, 
    0xa1, 0x1a, 0xc3, 0xe3  // 32
])*/
var expectedOutput = new Buffer([
    0xc8,0x6c,0x8f,0x2b,0xe8,0x21,0xc4,0x2e,
    0xfb,0x4a,0x8e,0x8b,0xc3,0x94,0x19,0xc2
]);
// aes_context aes_ctx;
function decrypt(data, password, algorithm, padding){
  if (padding === void 0) padding = true;
  algorithm = algorithm || 'aes-128-ecb';
  //aes_setkey_dec( &aes_ctx, digest, 128 );
  var crypt = crypto.createDecipher(algorithm,password);
  crypt.setAutoPadding(padding);
  // aes_crypt_ecb( &aes_ctx, AES_DECRYPT, buffer, buffer );
  var res = crypt.update(data, null, 'hex')
  res += crypt.final('hex');
  return new Buffer(res,'hex');
}
// aes_setkey_dec( &aes_ctx, digest, 128 );
var algoList = [
    'aes-128-ecb',
    'aes-192-ecb',
    'aes-256-ecb'
];
for (var i = 0; i<= 1; i++){
    console.log('\n ******* AUTO PADDING: ' + (padding ? 'ON': 'OFF') + ' ********* ');
    var padding = i === 0;
    for (let algo of algoList){
        try {
            var output = decrypt(buffer, decryptKey, algo, padding);
            console.log(algo + ' => ' + output.toString('hex') + ' < ' + (Buffer.compare(expectedOutput, output) === 0 ? 'ok' : 'ko'))
        } catch (err){
            console.log('Failed to perform ' + algo + ' with autopadding ' + (padding ? ' on ': ' off ') + ' due to ' + err.message);
        }
    }
}
/*
 ******* AUTO PADDING: OFF *********
Failed to perform aes-128-ecb with autopadding  on  due to error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
Failed to perform aes-192-ecb with autopadding  on  due to error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
Failed to perform aes-256-ecb with autopadding  on  due to error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
 ******* AUTO PADDING: ON *********
aes-128-ecb => d9817f142f9bca262b67f6a6be570345 < ko
aes-192-ecb => 9181784373bb6060c04c9ba75de26322 < ko
aes-256-ecb => c5945203368de477e5f0dbeedeb2189f < ko
*/

Heres C ++コード

#include "aes.h"
#include "sha2.h"
int main(int argc, char *argv[]) {

    unsigned char data[16] = { 
        0x5e,0x51,0xa3,0x53,0x9d,0xe7,0xe5,0xd3,0xee,0x30,0xbb,0xf8,0x0c,0x72,0x9f,0x80 
    };
    unsigned char key[32] = {
        0x36, 0x46, 0xb4, 0xf6,
        0x8e, 0x6d, 0xdc, 0xf4,
        0xb0, 0x31, 0x7e, 0x81,
        0x6b, 0x5d, 0x96, 0x55, // 16
        0x15, 0x9c, 0x78, 0x54,
        0x8c, 0xca, 0x3e, 0x39,
        0x2d, 0x49, 0x75, 0x5d,
        0xa1, 0x1a, 0xc3, 0xe3  // 32
    };
    aes_context aes_ctx;
    aes_setkey_dec(&aes_ctx, key, 128);
    aes_crypt_ecb(&aes_ctx, AES_DECRYPT, data, data);
    for (int i = 0; i< sizeof(data); ++i)
        std::cout << std::hex << (int)data[i];
    /* Output => c86c8f2be821c42efb4a8e8bc39419c2*/
}

参照:

  • https://tls.mbed.org/discussions/generic/question-about-using-aes
  • http://aes.online-domain-tools.com/link/133660agcLyPgFri4s/ -オンラインでの復号化の例

以下の回答に基づいたソリューション

var crypto = require('crypto')
var buffer = new Buffer([
    0x5e,0x51,0xa3,0x53,0x9d,0xe7,0xe5,0xd3,
    0xee,0x30,0xbb,0xf8,0x0c,0x72,0x9f,0x80
]);

var decryptKey = new Buffer([
    0x36, 0x46, 0xb4, 0xf6, 
    0x8e, 0x6d, 0xdc, 0xf4, 
    0xb0, 0x31, 0x7e, 0x81, 
    0x6b, 0x5d, 0x96, 0x55
])
var expectedOutput = new Buffer([
    0xc8,0x6c,0x8f,0x2b,0xe8,0x21,0xc4,0x2e,
    0xfb,0x4a,0x8e,0x8b,0xc3,0x94,0x19,0xc2
]);
// aes_context aes_ctx;
function decrypt(data, password, algorithm, padding){
  if (padding === void 0) padding = true;
  algorithm = algorithm || 'aes-128-ecb';
  //aes_setkey_dec( &aes_ctx, digest, 128 );
  var crypt = crypto.createDecipheriv(algorithm,password, new Buffer([]));//new Buffer(32).fill(0).byteLength
  crypt.setAutoPadding(padding);
  // aes_crypt_ecb( &aes_ctx, AES_DECRYPT, buffer, buffer );
  var res = crypt.update(data, null,'hex')
  + crypt.final('hex');
  return new Buffer(res,'hex');
}
// aes_setkey_dec( &aes_ctx, digest, 128 );
var output = decrypt(buffer, decryptKey, 'aes-128-ecb', false);
console.log(Buffer.compare(expectedOutput, output) === 0 ? 'ok' : 'ko');

回答 2 件
  • 非推奨  crypto.createDecypher()  派生する からのキーパスワード 引数:

    The implementation of crypto.createDecipher()  OpenSSL関数 EVP_BytesToKey を使用してキーを導出します  ダイジェストアルゴリズムをMD5に設定し、1回繰り返し、ソルトなし。

    代わりに欲しいのは キー。そのために使用する必要があります crypto.createDecipheriv()  代わりに:

     var crypt = crypto.createDecipheriv(algorithm,password,new Buffer([]));
    
    

    (ECBモードでは、IVを空にすることができます)

    もちろん、キーの長さは要求されたアルゴリズム(128、192、または256ビット)と一致する必要があります。キーは128ビットなので、aes-128-ecbのみが機能します。

  • false を渡す必要がある理由   setAutoPadding へ  あなたの暗号文はじゃない パッド入り。暗号文を生成する暗号化コードは含まれていませんが、PKCS#7パディングを使用して暗号化された場合、長さが1ブロックサイズのプレーンテキストは暗号文を生成するため、その長さからパディングされないことがわかりますあれは あなたが持っている単一のブロックではなく、長さのブロックサイズ。

    これが aes_crypt_ecb で復号化される理由   aes_crypt_ecb のように見えることです  個々のブロックの暗号化/復号化を実行するだけです。じゃない パディングまたはパディング解除を行います。ただし、 true が渡された場合、Javscriptコード   setAutoPadding へ  関数は、パディング(おそらくPKCS#7)を期待しています。あなたの暗号化はじゃない 使用されたパディング。

    理想的には、暗号化を行うときに適切なパディングを使用するように暗号化コードを変更する必要があります。これは、パディングを使用しないよりもはるかに安全だからです。そうでない場合は、 setAutoPadding への呼び出しを確認する必要があります   false を渡している  復号化を行うとき、Javascriptはパディングがないことを認識します。

あなたの答え