-2

I've been trying various methods, but the .Net code seems to be converting the strings and keys to binary before decrypting and the's tripping me up. I've read over and over that AES is essentially Rijndael, so I've been using the open SSL library built into Ruby 1.9.3.

RijndaelManaged crypto = new RijndaelManaged();
crypto.Padding = PaddingMode.PKCS7;
crypto.Key = ASCIIEncoding.ASCII.GetBytes(secretKey);
crypto.IV = ASCIIEncoding.ASCII.GetBytes(initializationVector);

byte[] byteArray = new byte[stringToDecrypt.Length / 2];
for (int i = 0; i < stringToDecrypt.Length / 2; i++)
{
  int index = (Convert.ToInt32(stringToDecrypt.Substring(i * 2, 2), 16));
  byteArray[i] = (byte)index;
}

MemoryStream memStream = new MemoryStream();
CryptoStream cryStream = new CryptoStream(memStream, crypto.CreateDecryptor(), CryptoStreamMode.Write);
cryStream.Write(byteArray, 0, byteArray.Length);
cryStream.FlushFinalBlock();

StringBuilder stringBuilder = new StringBuilder();

foreach (byte dByte in memStream.ToArray())
{
  stringBuilder.Append((char)dByte);
}

return stringBuilder.ToString();

Here's my current Ruby code which is not doing the trick. It runs (except for the last line) but gives me back garbage.

I'm fairly certain the issue is with the MemoryStream/CryptoStream functions, but I've not a clue where to start with Ruby on this.

text = Base64.encode64(cipher_text)
cypher = OpenSSL::Cipher::AES.new(256, :CBC)
cypher.decrypt
cypher.key = Base64.encode64("<cypher key>")
cypher.iv = Base64.encode64("<cypher iv>")
cypher.padding = 1
aes = cypher.update(cipher_text)
aes << cypher.final

I also tried this. I figured if this doesn't work the encryption is not simply Rijndael with PKCS7 padding but other obfuscation.

cypher = OpenSSL::Cipher::AES.new(256, :CBC)
cypher.decrypt
cypher.key = "<cypher key>"
cypher.iv = "<cypher iv>"
cypher.padding = 1
cypher.update(cipher_text)
Miriam H.
  • 671
  • 2
  • 8
  • 25
  • What's the question? Are you just looking for the ruby version of this? – Neil Smith Sep 02 '14 at 22:00
  • Sorry @Smith.h.Neil I added my current code. I've got an operating function that gives me garbage. I think the problem is the MemoryStream/CryptoStream. Not sure where to start as far as translating this into ruby. – Miriam H. Sep 02 '14 at 23:07

2 Answers2

1

Your Ruby code outputs the same as your C# code, as long as the key, the IV, and the ciphertext are the same.

Try this in your C#:

crypto.Key = new byte[32];
crypto.IV = new byte[16];
byteArray = new byte[] { 0x7d, 0x7f, 0x06, 0x32, 0xd6, 0x43, 0x03, 0x64, 0x85, 0x64, 0xcc, 0x81, 0xae, 0xfa, 0x29, 0xf5 };

and this in your Ruby:

cypher.key = "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0"
cypher.iv = "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0"
text = "\x7d\x7f\x06\x32\xd6\x43\x03\x64\x85\x64\xcc\x81\xae\xfa\x29\xf5"

and you will find that it works fine.

Whatever is in your C# byte arrays, you want byte for byte in your Ruby strings, for these values. That is where you are having the problem -- you are not using the same values.

EDIT:

Here is a better example. Try this in C#:

crypto.Key = ASCIIEncoding.ASCII.GetBytes("the quick brown fox jumps over t");
crypto.IV = ASCIIEncoding.ASCII.GetBytes("the quick brown ");
byteArray = new byte[] { 0xf8, 0x8b, 0xf1, 0x24, 0x65, 0x14, 0x0d, 0xe5, 0x25, 0xf1, 0xa4, 0x91, 0x45, 0x51, 0x73, 0x8e };

and this in Ruby:

cypher.key = "the quick brown fox jumps over t"
cypher.iv = "the quick brown "
text = [0xf8, 0x8b, 0xf1, 0x24, 0x65, 0x14, 0x0d, 0xe5, 0x25, 0xf1, 0xa4, 0x91, 0x45, 0x51, 0x73, 0x8e].map {|x| x.chr }.join

That last line makes the ciphertext into the ASCII string "\xF8\x8B\xF1$e\x14\r\xE5%\xF1\xA4\x91EQs\x8E". The Ruby OpenSSL library wants the key, iv, and ciphertext as strings. (I guess you could call the encoding 8-bit ASCII.)

That ciphertext I am giving is just an example, and produces the plaintext "hello\n".

Jim Flood
  • 8,144
  • 3
  • 36
  • 48
  • The string, key and iv were provide to me as plain text. If they are converted to byte arrays(?), the Ruby should work? – Miriam H. Sep 04 '14 at 14:39
  • No, you just use them as strings. See my edit above in my answer. – Jim Flood Sep 05 '14 at 16:45
  • Oh, OK. So how do I replicate the C# byte array code block into Ruby? I think that's where I am the most confused. – Miriam H. Sep 07 '14 at 16:37
  • Search for information on Ruby pack/unpack, and you'll find lots of examples of going from bytes to strings and back. I would start there. – Jim Flood Sep 08 '14 at 19:40
0

I just had to tackle this same basic problem and thought I'd add a little to the conversation for whomever comes along next in the mix.

The big difficulties that came up for me were ambiguities in what exactly the C# libraries were doing behind the scenes. (Correct options are first and bold in lists of options below)

Specifically, what 'mode' of AES encryption does new AesManaged().CreateEncryptor() use (CBC, CFB, OFB, CTR, or ECB)?

And what type does new SHA256Managed().ComputeHash() return? (raw-bytes, hex-encoded, base64-encoded?)

Also, does the C# program automatically add final padding to the encrypted stream? (Yes, No)

In an effort to find these answers and get a match to the C# library's results, I wrote Ruby code to enumerate all (30) of these possibilities and spit out the output. Maybe this will help someone, someday...

def self.encode(data, key, iv, opts={})
    # Setup our default strategies and apply overrides if specified
    aes_type = opts[:aes_type] || :CBC
    sha_method = opts[:sha_method] || :digest
    final_padded = (opts[:final_padded].nil?) ? true : opts[:final_padded]
    cipher = OpenSSL::Cipher::AES256.new(aes_type)
    cipher.encrypt
    cipher.key = Digest::SHA256.send(sha_method, key)
    cipher.iv = iv
    r = cipher.update(data) 
    (r << cipher.final) if final_padded
    Base64.encode64(r)
end

# Try all the different ways that AES-256 encryption might be interpreted
def self.encode_possibilities(data, key, iv)
    results = {}
    [:CBC, :CFB, :OFB, :CTR, :ECB].each do |type|
        [:digest, :base64digest, :hexdigest].each do |sha_type|
            [true, false].each do |final_padded|
                r = encode(data, key, iv, 
                                        aes_type: type, 
                                        sha_method: sha_type, 
                                        final_padded: final_padded)
                results["AES(#{type})-SHA-ENCODING(#{sha_type})-FINAL(#{final_padded})"] = r
            end
        end
    end
    puts "\n"
    results.each{|k,v| puts "#{k}  ==>  #{v}"}
    puts "\n"
end
Darren Hicks
  • 4,946
  • 1
  • 32
  • 35