4

We are having difficulty decrypting a string in ColdFusion that was previously encrypted with 3DES and C#. Here is the code we used to encrypt the string initially:

    public static string EncryptTripleDES(string plaintext, string key)
    {
    TripleDESCryptoServiceProvider DES = new TripleDESCryptoServiceProvider();
    MD5CryptoServiceProvider hashMD5 = new MD5CryptoServiceProvider();
    DES.Key = hashMD5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(key));
    DES.Mode = CipherMode.ECB;
    ICryptoTransform DESEncrypt = DES.CreateEncryptor();
    byte[] Buffer = ASCIIEncoding.ASCII.GetBytes(plaintext);

    string EncString = Convert.ToBase64String(DESEncrypt.TransformFinalBlock(Buffer, 0, Buffer.Length));
    EncString = EncString.Replace("+", "@@12");

    return EncString;
    }

We have tried using the suggestions here:

TripleDES Encryption - .NET and ColdFusion not playing nice

..with no luck. Here is our CF code and the error:

  <cfset variables.theKey = "blahblah" />
  <cfset variables.theAlgorithm = "DESede/CBC/PKCS5Padding">
  <cfset variables.theEncoding = "Base64">
  <cfset strTest = decrypt(#DB.PASSWORD#, variables.theKey, variables.theAlgorithm, variables.theEncoding)>

Error returned: An error occurred while trying to encrypt or decrypt your input string: '' Can not decode string "blahblah"

So, it looks like it's trying to decrypt the key and not the string, but that's not how the decrypt function is outlined in ColdFusion. Any ideas?

UPDATE: Attempted to use the following CF code, but the error returned is still "An error occurred while trying to encrypt or decrypt your input string: Given final block not properly padded."

<cfset dbPassword  = "Hx41SYUrmnFPa31QCH1ArCHN1YOF8IAL">
<cfset finalText   = replace(dbPassword, "@@12", "+", "all")>
<cfset theKey      = "abcdefgh">
<cfset theKeyInBase64 = toBase64(theKey)>
<cfset hashedKey   = hash( theKeyInBase64, "md5" )>
<cfset padBytes    = left( hashedKey, 16 )>
<cfset keyBytes    = binaryDecode( hashedKey & padBytes , "hex" )>
<cfset finalKey    = binaryEncode( keyBytes, "base64" )>
<cfset decrypted = decrypt( finalText, finalKey, "DESede/ECB/PKCS5Padding", "base64" )>
Decrypted String: <cfdump var="#decrypted#">

UPDATE:

The solution if you follow the comments was to change:

<cfset hashedKey   = hash( theKeyInBase64, "md5" )>

To:

<cfset hashedKey   = hash( theKey, "md5" )>

The final code is this:

<cfset dbPassword  = "Hx41SYUrmnFPa31QCH1ArCHN1YOF8IAL">
<cfset finalText   = replace(dbPassword, "@@12", "+", "all")>
<cfset theKey      = "abcdefgh">
<cfset hashedKey   = hash( theKey, "md5" )>
<cfset padBytes    = left( hashedKey, 16 )>
<cfset keyBytes    = binaryDecode( hashedKey & padBytes , "hex" )>
<cfset finalKey    = binaryEncode( keyBytes, "base64" )>
<cfset decrypted = decrypt( finalText, finalKey, "DESede/ECB/PKCS5Padding", "base64" )>
Decrypted String: <cfdump var="#decrypted#">
4

1 回答 1

6

看起来您的 c# 函数中需要处理一些额外的曲折以实现兼容性:

  1. .NET 函数修改加密字符串。您需要撤消这些更改,以便解密将其识别为有效的 base64:

    <!--- reverse replacements in encrypted text ie #DB.Password# --->
    <cfset dbPassword = "uAugP@@12aP4GGBOLCLRqxlNPL1PSHfTNEZ">
    <cfset finalText = replace(dbPassword, "@@12", "+", "all")>
    
  2. 该函数还使用创建 16 字节密钥的哈希。CF/java 需要该算法的24 字节密钥。因此,您必须首先散列密钥并将其填充到适当的长度。否则,decrypt() 会抱怨密钥太小。

    注意:CF 还期望最终密钥是 base64 编码的。错误无法解码字符串“blahblah”表明您的输入密钥不在 base64 中。

    <!--- hash and pad the key (ie "blahblah"), then convert to base64 for CF --->
    <cfset theKeyInBase64 = "rpaSPvIvVLlrcmtzPU9/c67Gkj7yL1S5">
    <cfset hashedKey   = hash( theKeyInBase64, "md5" )>
    <cfset padBytes    = left( hashedKey, 16 )>
    <cfset keyBytes    = binaryDecode( hashedKey & padBytes , "hex" )>
    <cfset finalKey    = binaryEncode( keyBytes, "base64" )>
    
  3. 最后,反馈模式必须匹配。由于 .NET 代码使用安全性较低的ECB模式,CF 代码也必须使用该模式。

    <!--- .net code uses the less secure ECB mode --->
    <cfset decrypted = decrypt( finalText, finalKey, "DESede/ECB/PKCS5Padding", "base64" )>
    Decrypted String: <cfdump var="#decrypted#">
    
  4. 另一个需要注意的问题是编码。在 CF 中,加密/解密始终将输入字符串解释为 UTF8,而 .NET 函数使用ASCII。为了完全兼容,双方应使用相同的编码,在本例中为 UTF8。


更新:

我用任意 8 个字符的密钥(而不是 base64 字符串)测试了上述内容,CF9 仍然正确解密了字符串。

// .NET Code
String text = "some text to encrypt";
String key = "abcdefgh";
String encrypted = EncryptTripleDES(text, key);
// result: encrypted=Hx41SYUrmnFPa31QCH1ArCHN1YOF8IAL
Console.WriteLine("encrypted={0}", encrypted);

<!--- same code, only the encrypted text and key changed ---> 
<cfset dbPassword  = "Hx41SYUrmnFPa31QCH1ArCHN1YOF8IAL">
<cfset finalText   = replace(dbPassword, "@@12", "+", "all")>
<cfset theKey      = "abcdefgh">
<cfset hashedKey   = hash( theKey, "md5" )>
.... 
于 2012-02-09T03:41:36.003 回答