0

I am trying to reimplement C# code in Ruby. The following code (with different secrets) works to decrypt the file:

using System.IO;
using System.Security.Cryptography;
using System.Text;

public static class Decrypt {
  private const string KEY = "FOOBARB";

  private static readonly byte[] IV = {
    126, 36, 216, 236, 247, 79, 205, 111, 240, 119, 197, 10, 19, 216, 139, 91
  };

  public static Stream ReadEncryptedFile(string filePath) {
    var fs = new FileStream(
      filePath,
      FileMode.OpenOrCreate,
      FileAccess.ReadWrite
    );

    byte[] key = new UnicodeEncoding().GetBytes(KEY);
    byte[] vector = IV;

    using (var rijndaelEncryption = new RijndaelManaged()) {
      var decryptor = rijndaelEncryption.CreateDecryptor(key, vector);
      return new CryptoStream(fs, decryptor, CryptoStreamMode.Read);
    }
  }

  public static void Main() {
    var crReader = ReadEncryptedFile(
      "/path/to/file"
    );
    StreamReader reader = new StreamReader(crReader);
    System.Console.WriteLine(reader.ReadToEnd());
  }
}

I know that CBC is the correct cipher mode because System.Console.WriteLine(rijndaelEncryption.Mode) returns CBC. I know the input and output block size is 256 bits because decryptor.OutputBlockSize and decryptor.InputBlockSize both return 16 32. (I realize the key size also enters in and indeed defines the distinction between AES and Rijndael as discussed here—but I'm not sure exactly how that works.)

Anyway, I get a in 'key=': key length too short (OpenSSL::Cipher::CipherError) when I run the following Ruby code (I have also tried the 128-bit and 192-bit versions of AES/CBC, though that shouldn't make the difference here):

require 'openssl'

f = File.read(
  'path/to/file'
)

key = 'FOOBARB'

iv = [126, 36, 216, 236, 247, 79, 205, 111, 240, 119, 197, 10, 19, 216, 139, 91]
     .pack('c*')

cipher = OpenSSL::Cipher.new('AES-256-CBC')

cipher.decrypt

cipher.key = key
cipher.iv = iv

puts cipher.update(f)

So, I think, three questions:

  1. How does C# pad a 56-bit key to make it work with an algorithm requiring at least a 128-bit key?
  2. Are the differences between Rijndael and AES fatal to my trying to use Ruby's OpenSSL library for this task?
  3. Once/if I get the key working, am I going to need to worry about character encoding as described here?

Thank you.

Ethan Kent
  • 381
  • 1
  • 4
  • 20
  • To 1: It *probably* pads with 0x00 (`'\0'`) until the key has 16 bytes. Also, check your math in this statement: *"I know the input and output block size is 256 bits because decryptor.OutputBlockSize and decryptor.InputBlockSize both return 16."* It should be 128 bits. – Artjom B. Oct 13 '16 at 19:33

1 Answers1

0

If you are trying to use AES with Rijndael you need to set the block size to 128-bits (16-bytes), that is the only block size AES supports. Many Rijndael implementation calling conventions specify the block size with the key size is determined buy the key supplied.

AES key sizes are 128, 192 or 256 bits, it is best to supply exactly the correct size, don't rely on implementation dependednt key padding.

zaph
  • 111,848
  • 21
  • 189
  • 228
  • To clarify a bit: C# code is being used to generate the encrypted files by another party. It's not clear that we can have that changed. I know that the C# code shown in the listing above works to decrypt it. I'm trying to understand why my C# code works—how an apparently too-short key is nevertheless decrypting the encrypted file. – Ethan Kent Oct 13 '16 at 16:54
  • You need to determine the block size the other side is using. It is really a better idea to use AES (Rijndael with a block size of 128-bits), especially for interoperability. Further is is necessary to use a random IV, generally prefixed to the encrypted data, a fixed IV can leak information if used with the same key multiple times. – zaph Oct 13 '16 at 17:00