2017-08-16 22 views
2

JavaScriptを使用してPHP文字列の暗号化を複製しようとしています。ここではPHPのコードは次のとおりです。私はJavaScriptでそれを複製しようとすると、JavaScriptのDuplicate php openssl_encrypt

<?php 

$iv = "123456789"; 
$key = "aaaaaaaaaaaaaaaa"; 
$input = "texttexttexttext"; 

$encrypted = openssl_encrypt($input, "AES-256-CBC", $key, 0, $iv); 

echo $encrypted; 
// "ZwY1i+vqP3acszeDiscCTx/R4a6d2AtkcInmN9OTCNE=" 

しかし、それは別の暗号文を与える:

var aesjs = require("aes-js"); 
var base64 = require("js-base64"); 

var iv = aesjs.utils.utf8.toBytes("123456789"); 
var key = aesjs.utils.utf8.toBytes("aaaaaaaaaaaaaaaa"); 
var text = aesjs.utils.utf8.toBytes("texttexttexttext"); 

var aesCbc = new aesjs.ModeOfOperation.cbc(key, iv); 
var encryptedBytes = aesCbc.encrypt(text); 

var b64encoded = base64.Base64.encode(encryptedBytes); 

console.log(b64encoded); 
// "MTcyLDIsNjAsMTU5LDcxLDEwLDE4Myw4LDE…wyMTIsMjIyLDk3LDEyNCw1MywxNzIsMjIy" 

私はそれが同じ出力を与えるようにする方法について見当もつかない。何か案は?いくつかの物事がうまく行っている

+0

'MTcyLDIsNjAsMTU5LDcxLDEwLDE4Myw4LDE ...'は '172,2,60,159,71,10,183,8,1 ...'にデコードします。 'base64.Base64.encode()'は 'encryptedBytes'の*文字列表現*をエンコードしているようです。 'console.log(encryptedBytes.toString( 'base64'));'を試したときの出力は? – dsprenkels

+0

ちょっとしたアイデア:PHPでは明示的に256ビットのキーを使用しています。 aesjsでは、キーの長さはキー変数からのバイト数/ビット数によって決定されるようです - あなたの場合、256ではなく16 * 8 = 128ビットです。 – gus27

答えて

5

まず、JavaScriptコードからの出力は、実際に文字列172,2,60,159,71,10,183,8,1,…、いない生のバイトバッファのエンコーディングのbase64エンコーディングです。私は実際に慣用的にこの問題を解決する方法を知りませんが、aes.js進コード化ユーティリティ関数を使用することにより、我々は、base64に変換することができます

var hex = aesjs.utils.hex.fromBytes(encryptedBytes); 
var buf = Buffer.from(hex, 'hex'); 

console.log(buf.toString('base64')); 
// rAI8n0cKtwiu1N5hfDWs3g== 

問題がaes.jsにあなたはAES128暗号化を使用していることです(aaaaaaaaaaaaaaaaの長さは128ビットですが)、PHPコードでAES256暗号化を使用しています。ほとんどは、同じ出力を持つ

$encrypted = openssl_encrypt($input, "AES-128-CBC", $key, 0, $iv); 
echo $encrypted; 
// rAI8n0cKtwiu1N5hfDWs3rPbz0UmvlbW+LJliYox03c= 

我々は:私たちは、PHPコード(またはJSコード)を更新する必要があります。しかし、PHPの出力は2倍長くなります。何が起こった?

まあ、OpenSSL uses PKCS#7 padding。しかし、Javascriptコードはパディングされていません。これを修正するには、JavaScriptテキストにPKCS#7パディングを使用する必要があります。このためにはpkcs7モジュールを使用できます。もう1つの選択肢は、CBCモードの代わりにカウンター(CTR)モードでAESを使用することです(オプションの場合)。

これは私が最終的に持っているPHPコードです:

<?php 
$iv = "123456789"; 
$key = "aaaaaaaaaaaaaaaa"; 
$input = "texttexttexttext"; 
$encrypted = openssl_encrypt($input, "AES-128-CBC", $key, 0, $iv); 
echo $encrypted; 
// output: 'rAI8n0cKtwiu1N5hfDWs3rPbz0UmvlbW+LJliYox03c=' 

そして、これは、JavaScriptのコードです:ので、PKCSは#、私は個人的にCTRモードを使用して好むPS

var aesjs = require("aes-js"); 
var base64 = require("js-base64"); 
var pkcs7 = require("pkcs7"); 

var iv = aesjs.utils.utf8.toBytes("123456789"); 
var key = aesjs.utils.utf8.toBytes("aaaaaaaaaaaaaaaa"); 
var text = aesjs.utils.utf8.toBytes("texttexttexttext"); 

var aesCbc = new aesjs.ModeOfOperation.cbc(key, iv); 
var encryptedBytes = aesCbc.encrypt(pkcs7.pad(text)); 

var hex = aesjs.utils.hex.fromBytes(encryptedBytes); 
var buf = Buffer.from(hex, 'hex'); 

console.log(buf.toString('base64')); 
// output: 'rAI8n0cKtwiu1N5hfDWs3rPbz0UmvlbW+LJliYox03c=' 

7つの実装では、暗号化を中断するpadding oraclesが公開されることがあります。 (良いはずのpkcs#7ライブラリをチェックしましたが、please don't try to implement this yourself