Ruby 加密很难:AES加密到十六进制
所以,我有一个应用程序正在使用ColdFusion对字符串进行加密。ColdFusion的bulit in encryption helpers使它变得非常简单:Ruby 加密很难:AES加密到十六进制,ruby,encryption,encoding,coldfusion,Ruby,Encryption,Encoding,Coldfusion,所以,我有一个应用程序正在使用ColdFusion对字符串进行加密。ColdFusion的bulit in encryption helpers使它变得非常简单: encrypt('string_to_encrypt','key','AES','HEX') 我尝试使用Ruby创建与这个ColdFusion脚本创建的相同的加密字符串。不幸的是,加密是人类已知的最令人困惑的计算机科学学科 我找到了几个使用openssl库的助手方法,并为您提供了一个非常简单的加密/解密方法。下面是结果字符串: "\
encrypt('string_to_encrypt','key','AES','HEX')
我尝试使用Ruby创建与这个ColdFusion脚本创建的相同的加密字符串。不幸的是,加密是人类已知的最令人困惑的计算机科学学科
我找到了几个使用openssl库的助手方法,并为您提供了一个非常简单的加密/解密方法。下面是结果字符串:
"\370\354D\020\357A\227\377\261G\333\314\204\361\277\250"
我觉得这很奇怪。我尝试了几个库将其转换为十六进制,但它们都说它包含无效字符。尝试将其解压缩会导致以下结果:
string = "\370\354D\020\357A\227\377\261G\333\314\204\361\277\250"
string.unpack('U')
ArgumentError: malformed UTF-8 character
from (irb):19:in `unpack'
from (irb):19
一天结束时,它应该是这样的(ColdFusion加密方法的输出):
当然,这是假设所有的填充、初始化向量、盐类、密码类型和其他一百万种可能的差异都是一致的
下面是我用来加密/解密的简单脚本:
def aes(m,k,t)
(aes = OpenSSL::Cipher::Cipher.new('aes-256-cbc').send(m)).key = Digest::SHA256.digest(k)
aes.update(t) << aes.final
end
def encrypt(key, text)
aes(:encrypt, key, text)
end
def decrypt(key, text)
aes(:decrypt, key, text)
end
def aes(m,k,t)
(aes=OpenSSL::Cipher::Cipher.new('aes-256-cbc').send(m)).key=Digest::SHA256.Digest(k)
aes.update(t)要将结果字符串转换为类似于ColdFusion输出的格式,只需使用:
raw = "\370\354D\020\357A\227\377\261G\333\314\204\361\277\250"
raw.unpack('H*').to_s.upcase
=> "F8EC4410EF4197FFB147DBCC84F1BFA8"
我今天也遇到了类似的问题。我的有点棘手,b/c我没有访问CF代码-只有文本要加密,密钥和加密结果的SHA256
说:
键:字符串。用于加密字符串的密钥或种子
- 对于CFMX_COMPAT算法,任何字符数的任意组合;用作种子,用于生成32位加密密钥
- 对于所有其他算法,使用算法所用格式的密钥。对于这些算法,请使用生成密钥功能
生成密钥
在我的例子中,我得到了一个32个字符长的MD5字符串,这是我必须使用的一个键
由于我们不能直接使用AES ancryption的own键,因此我必须将其转换为GenerateCretKey
所具有的相同格式
经过一番挖掘,似乎generateScretKey
创建了随机的16字节长的二进制字符串,并将其编码为Base64。但是——这很重要——在加密过程中对其进行内部解码
这就是有效的解决方案:
CF代码:
plain_key = "REPLACE_ME_WITH_32_HEX_UPPERCASED_CHARS"; // this can be MD5 of some secret string
encoded_key = ToBase64(BinaryDecode(plain_key, "Hex"));
base64EncodedResult = Encrypt("PLAIN TEXT", key, "AES", "Base64");
plain_key = "REPLACE_ME_WITH_32_HEX_UPPERCASED_CHARS"
encoded_key = plain_key.unpack('a2' * 16).map(&:hex).pack('c' * 16) # same as in CF except encoding to Base64
aes_encrypted = Aes.encrypt('PLAIN TEXT', encoded_key)
base64_encoded_result = ActiveSupport::Base64.encode64s(aes_encrypted)
# Two changes comparing to author's code:
# 1) AES-128-ECB instead of AES-256-CBC
# 2) No key conversion to SHA256
module Aes
def self.aes(m,k,t)
(aes = OpenSSL::Cipher::Cipher.new('aes-128-ecb').send(m)).key = k
aes.update(t) << aes.final
end
def self.encrypt(text, key)
aes(:encrypt, key, text)
end
def self.decrypt(text, key)
aes(:decrypt, key, text)
end
end
Ruby代码:
plain_key = "REPLACE_ME_WITH_32_HEX_UPPERCASED_CHARS"; // this can be MD5 of some secret string
encoded_key = ToBase64(BinaryDecode(plain_key, "Hex"));
base64EncodedResult = Encrypt("PLAIN TEXT", key, "AES", "Base64");
plain_key = "REPLACE_ME_WITH_32_HEX_UPPERCASED_CHARS"
encoded_key = plain_key.unpack('a2' * 16).map(&:hex).pack('c' * 16) # same as in CF except encoding to Base64
aes_encrypted = Aes.encrypt('PLAIN TEXT', encoded_key)
base64_encoded_result = ActiveSupport::Base64.encode64s(aes_encrypted)
# Two changes comparing to author's code:
# 1) AES-128-ECB instead of AES-256-CBC
# 2) No key conversion to SHA256
module Aes
def self.aes(m,k,t)
(aes = OpenSSL::Cipher::Cipher.new('aes-128-ecb').send(m)).key = k
aes.update(t) << aes.final
end
def self.encrypt(text, key)
aes(:encrypt, key, text)
end
def self.decrypt(text, key)
aes(:decrypt, key, text)
end
end
Aes模块代码:
plain_key = "REPLACE_ME_WITH_32_HEX_UPPERCASED_CHARS"; // this can be MD5 of some secret string
encoded_key = ToBase64(BinaryDecode(plain_key, "Hex"));
base64EncodedResult = Encrypt("PLAIN TEXT", key, "AES", "Base64");
plain_key = "REPLACE_ME_WITH_32_HEX_UPPERCASED_CHARS"
encoded_key = plain_key.unpack('a2' * 16).map(&:hex).pack('c' * 16) # same as in CF except encoding to Base64
aes_encrypted = Aes.encrypt('PLAIN TEXT', encoded_key)
base64_encoded_result = ActiveSupport::Base64.encode64s(aes_encrypted)
# Two changes comparing to author's code:
# 1) AES-128-ECB instead of AES-256-CBC
# 2) No key conversion to SHA256
module Aes
def self.aes(m,k,t)
(aes = OpenSSL::Cipher::Cipher.new('aes-128-ecb').send(m)).key = k
aes.update(t) << aes.final
end
def self.encrypt(text, key)
aes(:encrypt, key, text)
end
def self.decrypt(text, key)
aes(:decrypt, key, text)
end
end
#与作者代码相比,有两处变化:
#1)AES-128-ECB代替AES-256-CBC
#2)没有到SHA256的密钥转换
模块Aes
定义自身aes(m、k、t)
(aes=OpenSSL::Cipher::Cipher.new('aes-128-ecb').send(m)).key=k
更新(t)您的字符串不是Unicode。它只是一堆字节。您只需要将每个字节转换为十六进制数字形式。第一个是八进制的370
,是十六进制的F8
。我不能帮助您完成加密部分,但要将字节序列(在Ruby中通常表示为普通字符串)显示为十六进制数字符串,您可以使用s.each_byte.map{b|b.to_s(16)}。join
。我不认为Unicode在这里有任何关系。