I've been trying for many days to try and solve this issue.
A 3rd Party webservice requires me to send encrypted data using 3DES with ECB
and PKCS7padding - They're using .NET
The encrypt function within railo CFML is limited to DESede without any further options (i.e. defaults are used for cipher mode and padding).
Has anyone had this issue in Railo and come up with a solution (java based perhaps)? - I'm seriously pulling my hair out here!
Based on Leigh's suggestions below I made some changes:
I've made a bit of progress, I think this key has some kind of MD5 hashing on it.
I fished around the web and modified your solution a bit - I don't think the padding is necessary but the resultant encrypted string at first appears to be what I should expect but then closer on inspection it's incorrect:
IvParameterSpec = createObject("java", "javax.crypto.spec.IvParameterSpec");
Cipher = createObject("java", "javax.crypto.Cipher");
SecretKeySpec = createObject("java", "javax.crypto.spec.SecretKeySpec");
BASE64Decoder = createObject("java", "sun.misc.BASE64Decoder");
Str = createObject("java", "java.lang.String");
MessageDigest = createObject("java", "java.security.MessageDigest");
input = "<xml><PanNumber>6280390027626871</PanNumber><Req_Currency_Code>826</Req_Currency_Code><Card_Pin>1234</Card_Pin><Till_Amount></Till_Amount><Auth_Code></Auth_Code></xml>";
key = "06098140901984F95E139F29B479D952CB6545C177D21456";
md = MessageDigest.getInstance("MD5");
md.update(key.getBytes("UTF-8"), 0, key.length());
keyBytes = md.digest();
newKey = tobase64(keyBytes);
keyBytes2 = binaryDecode(newKey, "base64");
keyBytes2 = arrayMerge(keyBytes, arraySlice(keyBytes, 1, 8));
allnewKey = binaryEncode(javacast("byte[]", keyBytes2), "base64");
encrypted = encrypt(input, allnewKey, "desede", "base64");
WriteDump("encrypted (CF): "& encrypted);`
The result is: 26sfwv2DHDj7EHYd5Qao8veDtPbKIcv8rDVhbLPDEaWHO27EUGRF6KrdbXe7NBUVADYMdGuagfO4Tev584dUcgKGJ2h6kWPZxooNUGMgL2xB7e00YOkLosA8wFD569sZUd1MGKuF9yCjY1zCsAE4SgohkcuK9YZ7BizQma99/W9yOsIjAfHtAqGiep4tMTQ+eFASYtPybccsgi8H4brIB/HAu0kaDSAw
The expected result is:
26sfwv2DHDj7EHYd5Qao8veDtPbKIcv8rDVhbLPDEaWHO27EUGRF6MxaAzUpJDqQBq8NGgdqmtn6q/wVQNHGWrOE8+aetKVC78nszS3ZO8AHjwoT1igv4lGl78n8jCHHU+KwnBT7KfXIYMTCuwO/MohIiFbGyhMXPsvv3/G4OY1C2nEkN0LweLh4mTgtU8syT1M9XdmvwhaltsmPoFtoE9FujvQpJCY3
The encrypt function within railo CFML is limited to DESede without
any further options (i.e. defaults are used for cipher mode and
padding).
Yes, I believe it uses java's defaults ie DESede/ECB/PKCS5Padding
which are compatible with TripleDES/ECB/PKCS7padding
in .NET. So it should work right out of the box as long as you are using a 24 byte key.
Without knowing more, I am guessing it might be a problem with your key size. .NET supports both 16 and 24 byte keys, but java only supports 24 byte keys. So if your key is only 16 bytes, you need to pad it with the first eight (8) bytes to make it acceptable to Java/Railo.
CF/Railo Code
<cfscript>
input = "DESede (3DES) Encryption in RAILO CFML";
key = "ru8femXhTm9jwdGdhb/4Sw==";
// pad the key with the first eight bytes. then convert back to base64
keyBytes = binaryDecode(key, "base64");
keyBytes = arrayMerge(keyBytes, arraySlice(keyBytes, 1, 8));
newKey = binaryEncode(javacast("byte[]", keyBytes), "base64");
encrypted = encrypt(input, newKey, "desede", "base64");
WriteDump("encrypted (CF): "& encrypted);
</cfscript>
C# Code
byte[] input = Encoding.UTF8.GetBytes("DESede (3DES) Encryption in RAILO CFML");
byte[] key = Convert.FromBase64String("ru8femXhTm9jwdGdhb/4Sw==");
TripleDESCryptoServiceProvider algorithm = new TripleDESCryptoServiceProvider();
algorithm.Mode = CipherMode.ECB;
algorithm.BlockSize = 64;
algorithm.KeySize = 128; // 16 byte key
algorithm.Key = key;
ICryptoTransform cipher = algorithm.CreateEncryptor();
byte[] encrypted = cipher.TransformFinalBlock(input, 0, input.Length);
Console.WriteLine("encrypted (.NET): {0}", Convert.ToBase64String(encrypted));
Results:
encrypted (CF): fMPlk0ZqHDwp2zzZs/Cng7Y6r8Acr55UPJYWJTruEesxkBApsEFo6w==
encrypted (.NET): fMPlk0ZqHDwp2zzZs/Cng7Y6r8Acr55UPJYWJTruEesxkBApsEFo6w==
Update: Weird. When I MD5 hash the key in .NET I get your first result rather than the "expected result"
String rawInput = "<xml><PanNumber>6280390027626871</PanNumber><Req_Currency_Code>826</Req_Currency_Code><Card_Pin>1234</Card_Pin><Till_Amount></Till_Amount><Auth_Code></Auth_Code></xml>";
String rawKey = "06098140901984F95E139F29B479D952CB6545C177D21456";
byte[] input = Encoding.UTF8.GetBytes(rawInput);
byte[] key = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(rawKey));
// ... rest of code
Result:
encrypted (.NET): 26sfwv2DHDj7EHYd5Qao8veDtPbKIcv8rDVhbLPDEaWHO27EUGRF6KrdbXe7NB
UVADYMdGuagfO4Tev584dUcgKGJ2h6kWPZxooNUGMgL2xB7e00YOkLosA8wFD569sZUd1MGKuF9yCjY1
zCsAE4SgohkcuK9YZ7BizQma99/W9yOsIjAfHtAqGiep4tMTQ+eFASYtPybccsgi8H4brIB/HAu0kaDS
Aw