How to make Ruby AES-256-CBC and PHP MCRYPT_RIJNDAEL_128 play well together

前端 未结 4 659
梦如初夏
梦如初夏 2020-12-05 16:17

I\'m generating data to send from a Ruby stack to a PHP stack. I\'m using the OpenSSL::Cipher library on the Ruby side and the \'mcrypt\' library in PHP. When I encrypt us

相关标签:
4条回答
  • 2020-12-05 16:45

    I don't know PHP, but reading through related questions on the sidebar, I see Converting Ruby AES256 decrypt function to PHP. This includes a reference to this page, pointing out that the 128 in MCRYPT_RIJNDAEL_128 refers to the block size of the encryption, not the key size. You'll notice that the key size that you've passed between ruby and PHP is 256 bits in both cases. In other words, this seems to be the expected behavior, and you are using the larger key already.

    #!/usr/bin/ruby
    require 'base64'
    
    puts((Base64.decode64("RIvFgoi9xZaHS/0Bp0J9WDRyND6Z7jrd3btiAfcQ8Y0=").length * 8).to_s)
    

    HTH

    0 讨论(0)
  • 2020-12-05 16:45

    I had troubles because the PHP was using a password smaller than 8 characters. In this case one needs to add the 0, to make it compatible with PHP:

    mcrypt-encrypt manual page "key

    The key with which the data will be encrypted. If it's smaller than the required keysize, it is padded with '\0'. It is better not to use ASCII strings for keys. http://php.net/manual/en/function.mcrypt-encrypt.php It is recommended to use the mhash functions to create a key from a string."

    require 'openssl'
    cipher = OpenSSL::Cipher.new('DES-ECB')
    cipher.encrypt
    key =  'passwrd'[0...7].ljust(8, 0.chr)  #Pad the key smaller than 8 chars
    cipher.key = key
    encrypted = cipher.update('33')
    encrypted << cipher.final
    dec = Base64.encode64(encrypted).strip()
    
    0 讨论(0)
  • 2020-12-05 16:59

    I wrote an example that somebody else may find explanatory of the discussion above:

    $ cat publisher.rb

    #!/usr/bin/env ruby
    
    require 'openssl'
    require 'base64'
    
    key = '7fc4d85e2e4193b842bb0541de51a497'
    
    cipher = OpenSSL::Cipher::Cipher.new('aes-128-cbc')
    cipher.encrypt()
    iv = cipher.random_iv
    
    cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
    cipher.encrypt()
    cipher.key = key
    cipher.iv = iv
    crypt = cipher.update('This is my text')
    crypt << cipher.final()
    
    puts [Base64.encode64(crypt).strip(), Base64.encode64(iv).strip()].join('|')
    

    $ cat consumer.php

    $key256 = '7fc4d85e2e4193b842bb0541de51a497';
    
    $fd = fopen("php://stdin", "r");
    $tokens = '';
    while (!feof($fd))
      $tokens .= fread($fd, 1024);
    fclose($fd);
    
    $tokens = explode('|', trim($tokens));
    $crypt = $tokens[0];
    $iv = $tokens[1];
    
    $crypttext = base64_decode($crypt);
    $iv = base64_decode($iv);
    $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key256, $crypttext, MCRYPT_MODE_CBC, $iv);
    
    print $decrypted ."\n";
    

    To test it, from command line try:

    $ ruby publisher.rb | php consumer.php

    This is my text

    0 讨论(0)
  • 2020-12-05 17:03

    Let me show you some code.

    PHP code:

    $privateKey = "1234567890123456"; # the size is 16.
    $data = "hello";
    $iv = "0123456789012345";
    
    $result = mcrypt_encrypt(
      MCRYPT_RIJNDAEL_128, $privateKey, $data, MCRYPT_MODE_CBC, $iv
    )
    
    $base64str = base64_encode($result);
    $base64str = str_replace("+", "-",  $base64str);
    $base64str = str_replace("/","_",  $base64str);
    
    # => f-WffBXnf122NcVBUZ6Rlg==
    

    Ruby code:

    require 'base64'
    require 'openssl'
    
    private_key = "1234567890123456"
    data = "hello"
    iv = "0123456789012345"
    
    cipher = OpenSSL::Cipher::AES.new(128, :CBC) 
    cipher.encrypt
    
    cipher.padding = 0 # we must disable padding in ruby.
    cipher.key = private_key
    cipher.iv = iv
    block_size = cipher.block_size
    
    # Add padding by yourself.
    data = data + "\0" * (block_size - data.bytesize % block_size)
    result = cipher.update(data) + cipher.final
    
    Base64.urlsafe_encode64(result)
    # ==> f-WffBXnf122NcVBUZ6Rlg==
    

    As you can see I am using AES-128 in ruby because the size of private_key is 16. So you have to use AES-256 if the size of your private_key is 32.

    Formula: size_of_private_key * 8.

    0 讨论(0)
提交回复
热议问题