10

この質問は、 RubyAES-256-CBCとPHPMCRYPT_RIJNDAEL_128を一緒にうまく機能させる方法に関する私の最後の質問の続きです。私は今それを機能させていますが、私はまだ他の方向に進むのに苦労しています。PHPで生成された暗号文には、提供されたすべての情報が含まれているようですが、Rubyコードでエラーなしに復号化することはできません。

暗号文の生成に使用しているPHPコードは次のとおりです。

$cleartext = "Who's the clever boy?";
$key = base64_decode("6sEwMG/aKdBk5Fa2rR6vVw==\n");
$iv = base64_decode("vCkaypm5tPmtP3TF7aWrug==");
$cryptogram = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $cleartext, MCRYPT_MODE_CBC, $iv);
$result = base64_encode($cryptogram);
print "\n'$result'\n";

RESULT
'JM0OxMINPTnF1vwXdI3XdKI0KlVx210CvpJllFja+GM='

次に、Rubyで復号化する試みを示します。

>> cipher = OpenSSL::Cipher::Cipher.new('aes-128-cbc')
>> cipher.key = Base64.decode64("6sEwMG/aKdBk5Fa2rR6vVw==\n")
>> cipher.iv = Base64.decode64("vCkaypm5tPmtP3TF7aWrug==")
>> cryptogram = Base64.decode64('JM0OxMINPTnF1vwXdI3XdKI0KlVx210CvpJllFja+GM=')
>> cleartext = cipher.update(cryptogram)
=> "Who's the clever"
>> cleartext << cipher.final
OpenSSL::Cipher::CipherError: bad decrypt
 from (irb):100:in `final'
 from (irb):100

これについて本当にイライラするのは、暗号化された文字列からクリアテキスト全体を取得できることです。上記を繰り返しますが、暗号文にナンセンスパッドを追加します。

  >> cleartext = cipher.update(cryptogram + 'pad')
  => "Who's the clever boy?\000\000\000\000\000\000\000\000\000\000\000"
  >> cleartext << cipher.final
  OpenSSL::Cipher::CipherError: bad decrypt
   from (irb):119:in `final'
   from (irb):119

私の実際のユースケースでは、クリアテキストは構造化されているので(あなたが尋ねたので、JSON文字列)、このスキームを使用して、を実行せずに暗号化が不十分な入力を検出できるという点で安心cipher.finalです。ただし、コード内でこの種のクラッジを許容することはできないため、ルビーコードで最後のブロックを適切に処理する方法を理解したいと思います。

4

2 に答える 2

15

問題はmcrypt、最後のブロックがパディングされていないことですが、RubyのOpenSSLバインディングは、デフォルトのOpenSSLパディング方法であるPKCSパディングを使用します。OpenSSLドキュメントの説明を実際に改善することはできません。

PKCSパディングは、値nのn個のパディングバイトを追加して、データの全長をブロックサイズの倍数にすることで機能します。パディングは常に追加されるため、データがすでにブロックサイズの倍数である場合、nはブロックサイズと等しくなります。たとえば、ブロックサイズが8で、11バイトを暗号化する場合、値5の5つのパディングバイトが追加されます。

暗号化する前に、PHPのクリアテキストの最後に適切なパディングを手動で追加する必要があります。これを行うには、暗号化する前に(ブロックサイズとして渡す)、PHP側で$cleartextこの関数を通過させます。pkcs5_pad16

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

逆の方法(Rubyで暗号化してmcryptで復号化する)も行う場合は、復号化後にパディングバイトを削除する必要があります。

補足:クリアテキストがすでにブロックサイズ(パディングのブロック全体)の倍数である場合でもパディングを追加する必要がある理由は、復号化するときに、最後のブロックの最後のバイトが常に量であることがわかるようにするためですパディングの追加。そうしないと、1つのパディングバイトがあるクリアテキストと、たまたま値で終わったばかりのパディングバイトがないクリアテキストの違いがわかりません0x01

于 2009-12-09T00:02:02.543 に答える
0

PHP\0は、暗号化する前にクリアテキストを埋めているようです。パディングを無効にするようにRubyを設定できます。

http://www.ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/Cipher.html#method-i-padding-3D

これは機能しますが、手動でパディングを取り除く必要があります。

1.9.3p125 :008 > cipher = OpenSSL::Cipher::Cipher.new('aes-128-cbc')
 => #<OpenSSL::Cipher::Cipher:0x0000000561ee78>
1.9.3p125 :009 > cipher.decrypt
 => #<OpenSSL::Cipher::Cipher:0x0000000561ee78>
1.9.3p125 :010 > cipher.padding = 0
 => 0
1.9.3p125 :011 > cipher.key = Base64.decode64("6sEwMG/aKdBk5Fa2rR6vVw==\n")
 => "\xEA\xC100o\xDA)\xD0d\xE4V\xB6\xAD\x1E\xAFW"
1.9.3p125 :012 > cipher.iv = Base64.decode64("vCkaypm5tPmtP3TF7aWrug==")
 => "\xBC)\x1A\xCA\x99\xB9\xB4\xF9\xAD?t\xC5\xED\xA5\xAB\xBA"
1.9.3p125 :013 > cryptogram =  Base64.decode64('JM0OxMINPTnF1vwXdI3XdI2j8NJ8kr+Du0fnkxorNl0=')
 => "$\xCD\x0E\xC4\xC2\r=9\xC5\xD6\xFC\x17t\x8D\xD7t\x8D\xA3\xF0\xD2|\x92\xBF\x83\xBBG\xE7\x93\x1A+6]"
1.9.3p125 :014 > cleartext = cipher.update(cryptogram)
 => "Who's the clever girl?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
1.9.3p125 :015 > cleartext << cipher.final
 => "Who's the clever girl?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"



1.9.3p125 :042 > cleartext.strip
 => "Who's the clever girl?"
于 2013-07-26T19:58:25.563 に答える