2010-04-02 224 views
2

所以,我有一個應用程序在使用ColdFusion加密字符串。 ColdFusion的儲存卡的加密助手讓它非常簡單:加密很難:AES加密到十六進制

encrypt('string_to_encrypt','key','AES','HEX') 

我試圖做的是用Ruby創建,因爲這ColdFusion的腳本創建相同的加密字符串。不幸的是,加密是人類已知的最令人困惑的計算機科學主題。

我發現了一些使用openssl庫的輔助方法,並給你一個非常簡單的加密/解密方法。這是由此產生的字符串:

"\370\354D\020\357A\227\377\261G\333\314\204\361\277\250" 

這看起來unicode-ish對我來說。我已經嘗試了幾個庫將其轉換爲十六進制,但他們都說它包含無效字符。試圖解開它會導致這樣的:

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的加密方法的輸出):

F8E91A689565ED24541D2A0109F201EF 

當然這是假設所有填充,初始化向量,鹽類,密碼類型以及其他一百萬種其他可能的差異都會排列起來。

下面是我使用加密的簡單腳本/解密:

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 

任何幫助嗎?也許只是一個簡單的選項,我可以傳遞給OpenSSL :: Cipher :: Cipher,它會告訴它對最終字符串進行十六進制編碼?

+0

您的字符串不是Unicode。這只是一堆字節。你只需要以十六進制數字形式轉換每個字節。第一個八進制的「370」是十六進制的「F8」。 – Joey 2010-04-02 19:59:16

+1

我不能幫你加密部分,但要顯示一個字節序列(在Ruby中通常以普通字符串的形式表示)作爲一串十六進制數字,可以使用's.each_byte.map {| b | b.to_s(16)}。join'。無論如何,我不認爲Unicode是相關的。 – 2010-04-02 20:00:21

回答

2

我今天遇到了類似的問題。我的技術有點棘手,我沒有訪問CF代碼 - 只有文本加密,密鑰和加密結果的SHA256。

Official documentation for Encrypt function說:

關鍵:字符串。用於加密字符串的密鑰或種子。

  • 對於CFMX_COMPAT算法,任意數量字符的任意組合;用作用於生成32位加密密鑰的種子。

  • 對於所有其他算法,算法使用的格式中的密鑰。對於這些算法,使用GenerateSecretKey函數 來生成密鑰。

在我來說,我得到了一些字符串,它是一個關鍵,我不得不使用的32個字符長的MD5。

因爲我們不能直接使用AES ancryption 自己關鍵 - 我不得不將其轉換爲相同的格式GenerateSecretKey了。

經過一番挖掘,似乎GenerateSecretKey創建隨機的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"); 

Ruby代碼:

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) 

AES模塊代碼:

# 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

要將得到的字符串轉換成類似於ColdFusion的輸出格式,只需使用:

raw = "\370\354D\020\357A\227\377\261G\333\314\204\361\277\250" 
raw.unpack('H*').to_s.upcase 
=> "F8EC4410EF4197FFB147DBCC84F1BFA8"