1

I'm currently trying to convert this c# code into ruby, but I'm having difficulty with the hex conversion that is being used

public static string Decrypt(string hexString, string key, string iv)
{
var bytes = Enumerable.Range(0, hexString.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hexString.Substring(x, 2), 16))
.ToArray();
//===== AES provider
var provider = new AesCryptoServiceProvider();
provider.Mode = CipherMode.CBC;
provider.Key = Encoding.UTF8.GetBytes(key);
provider.IV = Encoding.UTF8.GetBytes(iv);
var transform = provider.CreateDecryptor();
using (var ms = new MemoryStream(bytes))
{
using (var cs = new CryptoStream(ms, transform, CryptoStreamMode.Read))
{
using (var sr = new StreamReader(cs))
{
cs.Flush();
var plainText = sr.ReadToEnd();
return plainText;
}
}

Here is a fiddle of the working code: https://dotnetfiddle.net/JI8SID

With these inputs:

var iv =  "8E394493F1E54545";
var key = "36D65EA1F6A849AF9964E0BAA98096B3";
var encrypted = "0A1D18A104A568FDE4770E0B816870C6";

I should be getting:

"testing"

My code is below, but I keep getting a key length too short (OpenSSL::Cipher::CipherError). I'm guessing there's something wrong with my hex_to_bin conversion, but it is stumping me.

require 'openssl'

def hex_to_bin(str)
  str.scan(/../).map { |x| x.hex.chr }.join
end

def decrypt(data, hex_key, hex_iv)
  decipher = OpenSSL::Cipher::AES256.new(:CBC)
  decipher.decrypt
  decipher.key = hex_to_bin(hex_key)
  decipher.iv = hex_to_bin(hex_iv)
  (decipher.update(hex_to_bin(data)) + decipher.final)
end

iv =  "8E394493F1E54545"
key = "36D65EA1F6A849AF9964E0BAA98096B3"
encrypted = "0A1D18A104A568FDE4770E0B816870C6"

puts decrypt(encrypted, key, iv)

Thank you in advance!

Tuckie
  • 23
  • 5
  • Your .NET code isn't converting that string into the equivalent bytes; you should look at a StringToByteArray implementation that converts each 2-character pair into a byte. (And then you need a key string that's twice as long.) – Joe Jun 24 '16 at 00:36
  • see: http://stackoverflow.com/questions/321370/how-can-i-convert-a-hex-string-to-a-byte-array – Joe Jun 24 '16 at 00:37

2 Answers2

2

Use a key length of exactly the same length specified, in the case given AES256 make the key exactly 32-bytes in length. Otherwise an implementation can do whatever it wants from null padding, the garbage bytes past the end of the key or throw an error.

In the code there is a hexadecimal key of 32-bytes but then it is converted to a binary key of 16-bytes by the call: hex_to_bin(hex_key).

In a similar manner the 16-byte hex iv is being reduced to 8-bytes by the call: hex_to_bin(hex_iv).

You really need to supply longer hex keys. Just eliminating the conversion calls will result in 128-bits of key material.

zaph
  • 111,848
  • 21
  • 189
  • 228
1

Your intuition is correct - the problem is the call to hex_to_bin on key and iv. Here is a working decrypt routine which emits the string 'testing' when plugged into your sample code:

def decrypt(data, hex_key, hex_iv)
  decipher = OpenSSL::Cipher::AES256.new(:CBC)
  decipher.decrypt
  decipher.key = hex_key
  decipher.iv = hex_iv
  (decipher.update(hex_to_bin(data)) + decipher.final)
end
T Carey
  • 57
  • 6
  • 1
    Eliminating the hex to binary call on the key will produce a key with an equivalent key length of 128-bits since each character has only 4-bits of information. In a similar manner the iv will be weakened. – zaph Jun 23 '16 at 15:11