web-dev-qa-db-ja.com

node.jsでAES256を復号化すると、誤った最終ブロック長が返される

これを使用して Gist Node.js 0.8.7でAES256を正常に復号化できました。次に、Node.js 0.10.24にアップグレードすると、次のエラーが表示されます。

TypeError:エラー:0606506D:デジタルエンベロープルーチン:EVP_DecryptFinal_ex:間違った最終ブロック長
at Decipheriv.Cipher.final(crypto.js:292:27)

Gistからの復号化コードを次に示します(便宜上、ここに示します)。

var crypto = require('crypto');

var AESCrypt = {};

AESCrypt.decrypt = function(cryptkey, iv, encryptdata) {
encryptdata = new Buffer(encryptdata, 'base64').toString('binary');

var decipher = crypto.createDecipheriv('aes-256-cbc', cryptkey, iv),
decoded = decipher.update(encryptdata);

decoded += decipher.final();
return decoded;
}

AESCrypt.encrypt = function(cryptkey, iv, cleardata) {
var encipher = crypto.createCipheriv('aes-256-cbc', cryptkey, iv),
encryptdata = encipher.update(cleardata);

encryptdata += encipher.final();
encode_encryptdata = new Buffer(encryptdata, 'binary').toString('base64');
return encode_encryptdata;
}

var cryptkey = crypto.createHash('sha256').update('Nixnogen').digest(),
iv = 'a2xhcgAAAAAAAAAA',
buf = "Here is some data for the encrypt", // 32 chars
enc = AESCrypt.encrypt(cryptkey, iv, buf);
var dec = AESCrypt.decrypt(cryptkey, iv, enc);

console.warn("encrypt length: ", enc.length);
console.warn("encrypt in Base64:", enc);
console.warn("decrypt all: " + dec);
13
Justin Cloud

OK、それで、スイッチのCryptoが0.8から0.10に変更されました Cryptoメソッドは、バイナリエンコードされた文字列ではなく、デフォルトでBufferオブジェクトを返します

つまり、上記のコードはエンコーディングを指定する必要があります。

これらの4行:

decoded = decipher.update(encryptdata);
decoded += decipher.final();
encryptdata = encipher.update(cleardata);
encryptdata += encipher.final();

に変更されます:

decoded = decipher.update(encryptdata, 'binary', 'utf8');
decoded += decipher.final('utf8');
encryptdata = encipher.update(cleardata, 'utf8', 'binary');
encryptdata += encipher.final('binary');

これでうまくいきましたが、他の提案も受け入れます。

25
Justin Cloud

あなたの答えが述べるように、エンコーディングを指定しない限り、これらの関数は現在バッファーで動作します。つまり、binaryでエンコードされた文字列を完全に回避し、何かの文字列を厳密に必要とするまで、すべてをバッファとして扱うほうがよいでしょう。このようにして、テキスト以外のコンテンツを処理するために暗号化ヘルパーを使用することもできます。

var crypto = require('crypto');

var AESCrypt = {};

AESCrypt.decrypt = function(cryptkey, iv, encryptdata) {
    var decipher = crypto.createDecipheriv('aes-256-cbc', cryptkey, iv);
    return Buffer.concat([
        decipher.update(encryptdata),
        decipher.final()
    ]);
}

AESCrypt.encrypt = function(cryptkey, iv, cleardata) {
    var encipher = crypto.createCipheriv('aes-256-cbc', cryptkey, iv);
    return Buffer.concat([
        encipher.update(cleardata),
        encipher.final()
    ]);
}

var cryptkey = crypto.createHash('sha256').update('Nixnogen').digest(),
iv = new Buffer('a2xhcgAAAAAAAAAA'),
buf = new Buffer("Here is some data for the encrypt"), // 32 chars
enc = AESCrypt.encrypt(cryptkey, iv, buf);
var dec = AESCrypt.decrypt(cryptkey, iv, enc);

console.warn("encrypt length: ", enc.length);
console.warn("encrypt in Base64:", enc.toString('base64'));
console.warn("decrypt all: " + dec.toString('utf8'));
13
loganfsmyth

私の問題は、自分の復号化関数に渡した文字列が空であることでした。空の文字列のチェックを組み込みましたが、メッセージを再度受信しませんでした。

decrypt: function(text){
                if(text.length == 0){
                    return text;
                }
                return this.decipher.update(text, 'hex', 'utf8') + this.decipher.final('utf8');
            }
3
Lanklaas