2012-02-08 8 views
6

私の必要条件は次のとおりです:PHPで暗号化されたものが、Rubyで暗号化された同じ文字列と一致しないのはなぜですか?

AES暗号化(ランダムivを含む)を使用してPHPで文字列を暗号化し、Base64でエンコードし、URLパラメータとして渡すことができるようにURLエンコードする必要があります。

私はPHPとRubyの両方で同じ結果を得ようとしていますが、動作させることはできません。ここで

function encryptData($data,$iv){ 
    $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, ''); 
    $iv_size = mcrypt_enc_get_iv_size($cipher); 
    if (mcrypt_generic_init($cipher, 'g6zys8dlvvut6b1omxc5w15gnfad3jhb', $iv) != -1){ 
     $cipherText = mcrypt_generic($cipher,$data); 
     mcrypt_generic_deinit($cipher); 
     return $cipherText; 
    } 
    else { 
     return false; 
    } 
} 
$data = 'Mary had a little lamb'; 
$iv = '96b88a5f0b9efb43'; 
$crypted_base64 = base64_encode(encryptData($data, $iv)); 

私のRubyのコードは次のとおりです:

は、ここに私のPHPコードである

module AESCrypt 
    def AESCrypt.encrypt(data, key, iv) 
    aes = OpenSSL::Cipher::Cipher.new("aes-256-cbc") 
    aes.encrypt 
    aes.key = key 
    aes.iv = iv 
    aes.update(data) + aes.final  
    end 
end 

plaintext = "Mary had a little lamb" 
iv = "96b88a5f0b9efb43" 
@crypted = AESCrypt::encrypt(plaintext, "g6zys8dlvvut6b1omxc5w15gnfad3jhb", iv) 
@crypted_base64 = Base64.encode64(@crypted) 
@crypted_base64_url = CGI.escape(@crypted_base64) 

腹立たしいものは、両方のコードサンプルは似てではなく、同一のハッシュを生成することです。例えば、上記のコードは、(Base64エンコード、URLエンコードされていない)を生成:

PHP:/aRCGgLBMOOAarjjtfTW2Qg2OtbPDLhx3KmgfgMzDJU=

をルビー:/aRCGgLBMOOAarjjtfTW2XIZhZ9VjBx8PdozxSL8IE0=

誰も私が間違ってここにやっているかを説明することはできますか?また、PHPコードではなくRubyコードを修正する方が簡単です(私はRubyの人でPHPではなく)。だから、もしあなたがRubyでPHPとよく似たソリューションを提供したいのであれば、私は最も感謝しています。

ああ、また、実際にはivは本当にランダムですが、この例では出力を比較できるように永久に同じに設定しています。

EDIT:オイゲン・Rieckの答えに

おかげで、私は解決策に到着しました。 Rubyはブロックを埋めますが、PHPはそうではありません。手動で行う必要があります。以下にPHPコードを変更し、あなたが上記のRubyコードを簡単に解読できる暗号化された文字列を取得:

$iv = '96b88a5f0b9efb43'; 
$data = 'Mary had a little lamb'; 

function encryptData($data,$iv){ 
    $key = 'g6zys8dlvvut6b1omxc5w15gnfad3jhb'; 
    $padded_data = pkcs5_pad($data); 
    $cryptogram = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $padded_data, MCRYPT_MODE_CBC, $iv); 
    return $cryptogram; 
} 

function pkcs5_pad ($text, $blocksize){ 
    $pad = $blocksize - (strlen($text) % $blocksize); 
    return $text . str_repeat(chr($pad), $pad); 
} 
+2

解決策には役に立ちませんが、これはブロックパディングと関係があります(出力文字列は最初のn文字で同じなので)。ブロックサイズに基づいてプレーンテキストに手動でパディングを追加することをお勧めします。 – Mikk

+2

RubyコードがAES-256を呼び出しています。 PHPコードがAES-128を呼び出しています。これが正しいと確信していますか?あなたのIVは明らかに128です。 – Charles

+0

@Charles私はこれも理解していません。しかし、これは物事が働く唯一の方法です。AES-256を呼び出すようにPHPを切り替えると、RubyはOpenSSLから「不正な復号化」エラーを引き起こします。 (以下の答えに私のコメントに記載されたスレッドを参照してください。) また、[this](http://www.chilkatsoft.com/p/php_aes.asp)は、PHPの暗号の奇妙なことを詳しく説明しています。私はそれがあなたの質問をクリアすると思う。 – John

答えて

8

が判明し、これは非常に簡単です:詰め物が犯人です。

AESはブロック暗号であるため、固定サイズのブロックで動作します。つまり、最後のブロックには常に詰め込みが行われ、標準についての良いことは、選択する数が非常に多いということです。 PHPはゼロ埋め込みを使用するので、Rubyが何を使用しているかを調べるには、AESCryptを調べなければなりません。

さまざまなJS AESライブラリとPHPに同じ問題があります。これは私を血のような赤い怒りにさせてくれました。

最初の部分(情報を持っている)が同じで、2番目の部分(パディングを運んでいる)が異なる理由はこれで説明します。

+0

PHPはゼロ埋め込み(つまり、パディングなし)を使用しているか、ゼロ埋め込み(つまり、最後のブロックを000000で埋めている)を使用していることを意味しますか? 今日私は[この質問]を追跡しました(http://stackoverflow.com/questions/1864700/part-ii-how-to-make-ruby-aes-256-cbc-and-php-mcrypt-rijndael-128 -play-well-toge)は、Rubyがブロックを埋めるが、mcryptはブロックしないことを示しているようだ。私は私の最終的な答えを含む上記の質問を編集しました。 – John

+2

@John **パディングを使用しないことは不可能です:定義によるブロック暗号には、完全なデータブロックが必要です。したがって、「パディングなし」はオプションではありません。 PHPは不完全なブロックに0x00を埋め込みますが、これは唯一の可能性ではありません。 IIRC OpenSSLはRFC1423を使用します。例えば、詳細はhttp://www.chilkatsoft.com/p/p_119.asp –

関連する問題