[英]Rails Encryption using AES, overcomplicated
我在加密我正在使用的第三方供应商的价值时遇到了问题。
他们的指示如下:
1) Convert the encryption password to a byte array.
2) Convert the value to be encrypted to a byte array.
3) The entire length of the array is inserted as the first four bytes onto the front
of the first block of the resultant byte array before encryption.
4) Encrypt the value using AES with:
1. 256-bit key size,
2. 256-bit block size,
3. Encryption Mode ECB, and
4. an EMPTY initialization vector.
5) After encryption, you should now have a byte array that holds the encrypted value.
6) Convert each byte to a HEX format and string all the HEX values together.
7) The final result is a string of HEX values. This is the final encrypted value to be passed.
The length of the final value will always be an even number.
EXAMPLE:
Given the following input values:
plainText: 2017/02/07 22:46
secretKey: ABCD1234FGHI5678
The following string will be produced:
D6281D5BE6CD6E79BB41C039F4DD020FBEC9D290AD631B2598A6DFF55C68AD04
到目前为止我尝试过的...
plain_text = "2017/02/07 22:46"
secret_key = "ABCD1234FGHI5678"
plain_text_byte_array = plain_text.bytes
plain_text_byte_array.unshift(0).unshift(0).unshift(0).unshift(16) # I found a Java example in their documentation and this is what they do. They prepend their byte array with 16, 0, 0, 0
secret_byte_array = secret_key.bytes
secret_byte_array = secret_byte_array.concat([0, 0, 0,...]) # also from their java example, they append the secret_byte array with 16 0's in order to get its length to 32
cipher = OpenSSL::Cipher::AES256.new(:ECB)
cipher.key = secret_byte_array.pack("C*")
encrypted = cipher.update(plain_text_byte_array.pack("C*")) + cipher.final
p encrypted.unpack("H*").first.to_s.upcase
# Result is:
# "84A0E5DCA7D704C41332F86E707DDAC244A1A87C38A906145DE4060D2BC5C8F4"
正如您所看到的,我的结果与实际结果不符,应该是“D6281D5BE6CD6E79BB41C039F4DD020FBEC9D290AD631B2598A6DFF55C68AD04”
有谁知道我错过了什么或做了一些奇怪的事情。 他们的指示很难让我解析,所以也许我错过了一些东西。 感谢您提供任何帮助! (我在上面看到的内容上尝试了很多不同的变化)。 我只是需要一些指导,或者至少有人告诉我,我不会因为不理解他们的指示而疯狂。
我设法重现了他们的结果 - 他们使用的过程非常令人费解,并且尽可能地优雅。 我附加了一个更为描述性的解释,说明了实现结果所需的步骤,以及我过去使用的C#源代码。
将密码转换为字节数组。 字节数组的长度必须为32个字节,如果密码不够长,则应使用0字节右键填充。 因此,他们的密码(十六进制编码)变为4142434431323334464748493536373800000000000000000000000000000000
。
将要加密的值转换为字节数组。 这个很简单,只需用UTF-8编码。
在加密之前,数组的整个长度作为前四个字节插入到结果字节数组的第一个块的前面。 这是愚蠢的,没有用处,但是将步骤2中的字节数组的长度作为无符号的32位整数并转换为小端字节数组。 将此前缀添加到步骤2中的数组。
使用AES加密值 。 嗯。 不,不要那样做。 使用Rijndael加密值,使用256位块大小,256位密钥大小,ECB模式和零填充。
其余的很简单,只需将加密结果转换为十六进制即可。
我用来实现这个结果的代码如下所示,在C#中。 我不太了解Ruby,对不起。
// 1. Convert the encryption password to a byte array.
byte[] passwordBytesOriginal = Encoding.UTF8.GetBytes("ABCD1234FGHI5678");
byte[] passwordBytes = new byte[32];
Array.Copy(passwordBytesOriginal, 0, passwordBytes, 0, passwordBytesOriginal.Length);
// 2. Convert the value to be encrypted to a byte array.
byte[] valueBytes = Encoding.UTF8.GetBytes("2017/02/07 22:46");
// 3. The entire length of the array is inserted as the first four bytes onto the front
// of the first block of the resultant byte array before encryption.
byte[] valueLengthAsBytes = BitConverter.GetBytes((uint)valueBytes.Length);
byte[] finalPlaintext = new byte[valueBytes.Length + valueLengthAsBytes.Length];
Array.Copy(valueLengthAsBytes, 0, finalPlaintext, 0, valueLengthAsBytes.Length);
Array.Copy(valueBytes, 0, finalPlaintext, valueLengthAsBytes.Length, valueBytes.Length);
// 4. Encrypt the value using AES...
byte[] ciphertext;
using (RijndaelManaged rijn = new RijndaelManaged())
{
rijn.BlockSize = 256;
rijn.KeySize = 256;
rijn.Key = passwordBytes;
rijn.Mode = CipherMode.ECB;
rijn.Padding = PaddingMode.Zeros;
var encryptor = rijn.CreateEncryptor();
ciphertext = encryptor.TransformFinalBlock(finalPlaintext, 0, finalPlaintext.Length);
}
// 5., 6., 7...
string result = BitConverter.ToString(ciphertext).Replace("-", "").ToUpper();
Console.WriteLine(result); // D6281D5BE6CD6E79BB41C039F4DD020FBEC9D290AD631B2598A6DFF55C68AD04
基于Luke的优秀答案是Ruby版本。 我不得不使用ruby-mcrypt gem并使用brew install libmcrypt
在本地安装mcrypt库。
正如卢克的答案所指出的那样,秘密密钥应该用0填充。 这是我的代码:
plain_text = "2017/02/07 22:46"
secret_text = "ABCD1234FGHI5678"
answer = "D6281D5BE6CD6E79BB41C039F4DD020FBEC9D290AD631B2598A6DFF55C68AD04"
def format_byte_arrays(plain, secret)
zero_byte_array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
length_array = [16, 0, 0, 0]
plain_bytes = length_array.concat(plain.bytes)
secret_bytes = secret.bytes.concat(zero_byte_array)
[plain_bytes, secret_bytes]
end
plain_bytes, secret_bytes = format_byte_arrays(plain_text, secret_text)
final_plain, final_secret = [plain_bytes.pack("C*"), secret_bytes.pack("C*")]
cipher = Mcrypt.new("rijndael-256", :ecb, final_secret, nil, :zeros)
encrypted = cipher.encrypt(final_plain)
result = encrypted.unpack("H*").first.to_s.upcase
结果将是正确的答案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.