Ruby 加密很难:AES加密到十六进制

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库的助手方法,并为您提供了一个非常简单的加密/解密方法。下面是结果字符串: "\

所以,我有一个应用程序正在使用ColdFusion对字符串进行加密。ColdFusion的bulit in encryption helpers使它变得非常简单:

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在这里有任何关系。