Pergunta

Esta questão é uma continuação da minha última, sobre Como fazer o ruby ??AES-256-CBC e PHP MCRYPT_RIJNDAEL_128 jogar bem juntos . Eu tenho que trabalhar agora, mas eu ainda estou lutando para ir a outra direção. O PHP criptograma gerado parece ter toda a informação que foi fornecida, mas eu não posso obter o código Ruby para decifrá-lo sem erros.

Aqui está o código PHP que estou usando para gerar o criptograma:

$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='

Então aqui está a tentativa de decifrar em 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

O que é realmente frustrante sobre isso é que é possível obter toda a cleartext fora dessa string encriptada. Repetindo o acima, mas adicionando uma almofada absurdo o criptograma:

  >> 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

No meu caso uso real do cleartext é estruturado (a string JSON, já que você pergunta), então eu me sinto confortável a este ponto que eu poderia dizer usar este esquema e detectar a entrada mal criptografada sem executar o cipher.final. No entanto, não pode tolerar esse tipo de remendo no meu código, então eu gostaria de entender como fazer a alça código Ruby o bloco final graciosamente.

Foi útil?

Solução

O problema é que mcrypt não é acolchoar o último bloco, enquanto os usos de ligação OpenSSL de Ruby o método de preenchimento OpenSSL padrão, que é PKCS estofamento. Eu realmente não posso melhorar a descrição da documentação do OpenSSL:

PKCS preenchimento funciona adicionando n estofamento bytes de valor n para perfazer o total de comprimento dos dados de um múltiplo do tamanho do bloco. preenchimento é sempre adicionados por isso, se os dados já estão um múltiplo do tamanho do bloco n vai igualar o tamanho do bloco. Por exemplo, se o tamanho do bloco é de 8 e 11 bytes são a ser encriptada, em seguida, 5 bytes de enchimento de valor 5 será adicionado.

Você precisará adicionar manualmente o preenchimento adequado para o final do texto puro em PHP antes de criptografar. Para fazer isso, passar o seu $cleartext através desta função pkcs5_pad no lado do PHP antes de criptografá-lo (passando 16 como o tamanho de bloco).

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

Se você também ir por outro caminho (criptografar em Ruby e descriptografar com mcrypt), você vai ter que retirar o estofo bytes depois de descriptografar.

Nota lateral: A razão que você tem que adicionar preenchimento mesmo que o texto puro já é um múltiplo do tamanho de bloco (um bloco inteiro de estofamento), é para que quando você está decifrando você sabe que o último byte do último bloco é sempre a quantidade de preenchimento acrescentou. Caso contrário, você não poderia dizer a diferença entre texto puro com um único byte preenchimento e um texto puro sem preenchimento bytes que só aconteceu a final no valor 0x01.

Outras dicas

Parece PHP almofadas \0 o texto puro antes de criptografá-lo. Você pode definir Ruby para desativar o preenchimento.

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

Este trabalho vontade, mas, em seguida, você deve tirar o preenchimento off manualmente.

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?"
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top