SagePay V3 Form Integration using CFML - AES Encryption - encryption

I've got through the entire FORM integration successfully except for the encryption.
Version 3 requires AES encryption and I don't understand how to implement this stage.
Previously, the CFML script constructed the crypt field at the end using this:
//** call to include file to encrypt
crypt = base64Encode (SimpleXor(stuff,EncryptionPassword));
This called the functions file which did the actual work.
The help I need is in creating a new script in the function.cfm file and also what the call should be.
Can anyone help, please?
Cheers
Here's a snippet of the code:
<cfscript>
ThisVendorTxCode = "#sfo_id#";
ThisVendorName = "pivotell";
stuff = "VendorTxCode=" & ThisVendorTxCode & "&";
stuff = stuff & "VendorName=" & ThisVendorName & "&";
</cfscript>
<cfset encryptionKey = generateSecretKey( "AES" ) />
//** call to include file to encrypt
<cfset crypt = encrypt(stuff,encryptionKey,"AES","hex") />
<cfoutput>
<form action="https://test.sagepay.com/gateway/service/vspform-register.vsp" method="post" id="form1" name="form1">
<input type="hidden" name="VPSProtocol" value="3.00">
<input type="hidden" name="TxType" value="PAYMENT">
<input type="hidden" name="Crypt" value="#crypt#">
</form>
</cfoutput>
I've truncated the full thing for simplicity.

It took me 3 days and 3 nights to figure this out.
Please read page 37 of the Sage Pay Form Integration and Protocol Guidelines 3.00.
A1.1 The Crypt Field
The Crypt field should contain all the other transaction information in plain text as Name=Value fields separated by ‘&’
characters. Ensure that all mandatory fields are present and that
there are no spaces after the ‘&’ character.
This string should then be encrypted using AES (block size 128-bit) in CBC mode with PKCS#5 padding using the provided password as both
the key and initialisation vector and encode the result in hex
(making sure the letters are in upper case).
Prepend the ‘#’ sign to the beginning of the encoded result.
Together with the last answer on this post. It should sort it.
... Since your password string is not base64 encoded, the resulting key
length is too small, ie (12) instead of (16) bytes. ...The solution is
to base64 encode it first... Also, the iv parameter should be binary
<cfset keyIVBytes = charsetDecode(yourKeyString, "utf-8")>
<cfset base64Key = binaryEncode(keyIVBytes, "base64")>
<cfset result = encrypt(plainString, base64Key,"AES/CBC/PKCS5Padding", "hex", keyIVBytes)>

Related

ColdFusion decrypt encodings are not the same

I am trying to decrypt a string using ColdFusion's Decrypt() function, but am getting an "encodings are not the same..." error.
These are the steps I was instructed to take from the string's source:
Create an MD5 hash of the shared key
Using TripeDES with the cipher of ECB, decrypt the encrypted string with the MD5 hash of the shared key
Code:
<cfset qKey = hash('shared_key','MD5') />
<cfset dc = Decrypt('string_to_decrypt', qkey, 'DESEDE/ECB/PKCS5Padding', 'Base64') />
<cfdump var="#dc#">
Error:
An error occurred while trying to encrypt or decrypt your input string: The input and output encodings are not same.
Update:
Also tried the following, but it throws the same error:
<cfset finalText = "WVJrOdkntkQ%3d">
<cfset theKey = "S3C016" />
<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#">
These are the steps I was instructed to take
Honestly, I always find it a little disturbing when I come across a recommendation for using TripleDES these days. As Zach pointed out it is no longer considered secure and was replaced by stronger algorithms like AES. Also, you can clearly see from wiki article images an illustration of why ECB mode is discouraged: "it does not hide data patterns well". (Side note, in the area of hashing MD5 was also surpassed by stronger algorithms a while ago). Bottom line, I strongly suggest discussing the chosen algorithms with whomever gave you the instructions, because they are not very secure.
However, to answer your question, there are a couple of issues:
Your code says the encrypted value is base64 encoded. However, it includes a percent % symbol which is not a valid character for base64. I am guessing that value was url encoded and must be decoded first:
<cfset encryptedText = urlDecode("WVJrOdkntkQ%3d")>
Hash() returns a hexadecimal string. The encrypt() function requires that keys be base64 encoded.
An MD5 hash returns sixteen (16) bytes. While that is a valid key size for TripleDES, the CF/Java implementation only supports 24 byte keys. You need to pad the key with the first eight (8) bytes to make it the proper size.
<cfset originalKey = hash("S3C016","MD5")>
<cfset padChars = left(originalKey, 16)>
<cfset keyBytes = binaryDecode(originalKey & padChars, "hex")>
<cfset newKeyString = binaryEncode(keyBytes, "base64")>
Making the changes above will resolve the error and allow you to decrypt the string successfully. The result should be "20".
<cfset dc = Decrypt(encryptedText, newKeyString, "DESEDE/ECB/PKCS5Padding", "Base64") />
<cfdump var="#dc#">
3DES uses a 24-byte key, MD5 produces a 16-bytes. Many times the first 8-bytes are also used for the final 8-bytes. Some implementations do tis automatically, others zero pad, others---who knows.
Try creating a 24-byte key by duplication the first 8-bytes to the 16-bytes produced by MD5.
Encoding the 16-bytes produced by MD5 really does not make sense in a cryptographic sense eventhough it will prodice 24-bytes.

Coldfusion Encrypt and Decrypt

I am having issues using the cf9 encrypt and decrypt function. Specifically,the code I use needs to be able to encrypt with AES/ECB/PKCS5Padding 256. I am trying to post data to a third party bank with the following code:
<cfparam name="theKey" default="someStaticKey">
<cfset strName = leaddetail.leadlast&','&leaddetail.leadfirst />
<cfset stFields = {requesttype = "eftaddonetimecompletetransaction"
,clientid = "XXXXXX"
,urltoredirect = "#RedirectURl#"
,customerid = "#leaddetail.leadid#"
,isdebitcardonly = "No"
,customername = "#strName#"
,customeraddress1 = "#form.billingaddress#"
,customercity = "#form.billingcity#"
,customerstate = "#form.billingstate#"
,customerzip = "#form.billingzip#"
,cardbillingaddr1 = "#form.billingaddress#"
,cardbillingcity = "#form.billingcity#"
,cardbillingstate = "#form.billingstate#"
,cardbillingzip = "#form.billingzip#"
,accounttype = "CC"
,name_on_card = "#form.leadname#"
,accountnumber = "#form.ccacctnum#"
,expmonth = "#Left(form.ccexpdate,2)#"
,expyear = "#Right(form.ccexpdate,2)#"
,cvvcode = "#form.ccv2#"
,amount = "#NumberFormat(esigninfo.esignpayamt,'9999.99')#"
,startdate = "#DateFormat(Now(),'YYYY-MM-DD')#"
,transactiontypecode = "WEB"}/>
<cfset theEncryptedStr = ToBase64(encrypt(serializeJson(stFields),theKey))>
<!--- shake hands and login to api --->
<cfhttp url="https://www.somebank.com/cgi-bin/wsnvptest.vps" method="post" charset="ISO-8859-1" throwonerror="yes" result="httpResponse">
<!--- login Variables --->
<cfhttpparam type="Header" name="User-Agent" value="Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.41">
<cfhttpparam type="header" name="Content-Type" value="application/x-www-form-urlencoded" >
<cfhttpparam type="header" name="Accept" value="application/json" >
<!--- Login Credentials --->
<cfhttpparam type="formfield"name="nvpvar"value="''"/>
<cfhttpparam type="formfield"name="requesttype"value="login"/>
<cfhttpparam type="formfield"name="userid"value="Dauserid"/>
<cfhttpparam type="formfield"name="password"value="password"/>
<cfhttpparam type="formfield"name="requestid"value="#uniquerequestid#"/>
<cfhttpparam type="formfield"name="PostData" value="#theEncryptedStr#"/>
<cfif isDefined('CheckSession.sessionID') AND CheckSession.sessionID NEQ ''>
<cfhttpparam type="formfield"name="sessionid" value="#checkSession.sessionID#"/>
</cfif>
</cfhttp>
for some reason I can encrypt but cant decrypt the response. Is there anyone out there that has more experience with this that can put on a path to success?
(Update from rejected edit)
I am using the following script to decrypt my cfhttp response string:
<cfset content = httpResponse.filecontent>
<cfset authdata = structNew()>
<cfloop index="line" list="#content#">
<cfset dtype = listFirst(line, "=")/>
<cfset EncodedString = listRest(line, "=")/>
<cfset authdata[dtype] = EncodedString />
</cfloop>
<cfscript>
keyInBase64 = "Some64baseKey;
// Now decrypt the base64 encoded encryption string
decryptedValue = decrypt(EncodedString , keyInBase64 , "AES/ECB/PKCS5Padding" , "base64" );
WriteDump(variables);
</cfscript>
The string I am trying to decrypt looks similar to the following:
nvpvar=fKsJGJ-Fe-2zoqUROAeE8N8a87USuQpE7dVd5IvRa67cHsVkPwx9taKLuXKwsCKFC_-NW3j6IOQAvCnRNc4cRNfq2fqyRHBUrFbFDCCmwpk=
encrypt(serializeJson(stFields),theKey)
First, that is NOT AES encryption. You omitted the algorithm parameter, so encrypt() defaults to the legacy CFMX_COMPAT algorithm (weakest). CFMX_COMPAT it is not a "real" encryption algorithm at all, so do not use it - for anything!
Second, with AES you are limited to 128 bit keys out of the box. In order to use 256 bit keys you must first install the (JCE) Unlimited
Strength Jurisdiction Policy Files.
Copy them into your /lib/security/ directory. Then restart the CF server to apply the changes.
Note: If you have multiple JVM's installed,
be sure to update the correct one. ie The one listed in
the CF Administrator).
After restarting, you will be able to encrypt with a 256 bit key. With ECB mode, the syntax is: encrypt(string, key, algorithm, encoding)
string - plain text to encrypt
key - a 256 bit key, must be base64 encoded
algorithm - single string representing the desired: algorithm, mode and padding scheme. Note: "AES" is actually a shorthand for the longer "AES/ECB/PKCS5Padding"
encoding - "The binary encoding in which to represent the data as a string"
Putting it all together:
<cfscript>
// some sample data to encrypt
stFields = { clientid = "AA-BB-CC-123"
, customername = "ABC Incorporated"
};
// some 256 bit key, must be base64 encoded
// hard coded for demo purposes only
keyInBase64 = "9NJU2L3FZ8Rr0WKZUFC3lyE/yRrQ7sIZmQRk3kx9MLE=";
// AES encrypt the value, and base64 encode the result
encryptedValue = encrypt( serializeJson(stFields)
, keyInBase64
, "AES/ECB/PKCS5Padding"
, "base64"
);
// Now decrypt the base64 encoded encryption string
decryptedValue = decrypt( encryptedValue
, keyInBase64
, "AES/ECB/PKCS5Padding"
, "base64"
);
// display results
WriteDump( variables );
</cfscript>
Update based on comments:
I notice you are manipulating the raw http response string. Without seeing the API, I would guess that either a) You need to decrypt the whole string first, then extract the parts -OR- b) the code is not extracting the values correctly and that is why you cannot decrypt it. The cfloop treats the response as a comma separated list. Based on the variable names, I am guessing it is actually separated by new lines instead, ie:
param1=xxxxx -- new line
param2=yyyyy -- new line
param3=zzzzz
Those are just guesses though. Check your API. What is the actual format of the returned response? Also, can you please edit your question to include the full error message?

How to generate MD5 using VBScript in classic ASP?

I need to generate an MD5 in my application.
I've tried google but only find PHP code for MD5. I need to connect to a client system that validates using MD5 hash but their code is in PHP, mine is in Classic ASP using VBScript.
My server is .Net supported so I cannot use the PHP script. Is there any such MD5 code for VBScript in Classic ASP?
Update 2017-02-21 - Now with added HMACSHA256 for JWTs
Update 2016-07-05 - Now with added SHA1 and SHA256
Right, for all of you who have been struggling with this (like myself) and want to know, it is possible!
The following code is split up into several functions so that you can either MD5/sha1/sha256 a string, or a file.
I borrowed the functions GetBytes and BytesToBase64 from another stackexchange, and the code within stringToUTFBytes is based on another stackexchange.
function md5hashBytes(aBytes)
Dim MD5
set MD5 = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider")
MD5.Initialize()
'Note you MUST use computehash_2 to get the correct version of this method, and the bytes MUST be double wrapped in brackets to ensure they get passed in correctly.
md5hashBytes = MD5.ComputeHash_2( (aBytes) )
end function
function sha1hashBytes(aBytes)
Dim sha1
set sha1 = CreateObject("System.Security.Cryptography.SHA1Managed")
sha1.Initialize()
'Note you MUST use computehash_2 to get the correct version of this method, and the bytes MUST be double wrapped in brackets to ensure they get passed in correctly.
sha1hashBytes = sha1.ComputeHash_2( (aBytes) )
end function
function sha256hashBytes(aBytes)
Dim sha256
set sha256 = CreateObject("System.Security.Cryptography.SHA256Managed")
sha256.Initialize()
'Note you MUST use computehash_2 to get the correct version of this method, and the bytes MUST be double wrapped in brackets to ensure they get passed in correctly.
sha256hashBytes = sha256.ComputeHash_2( (aBytes) )
end function
function sha256HMACBytes(aBytes, aKey)
Dim sha256
set sha256 = CreateObject("System.Security.Cryptography.HMACSHA256")
sha256.Initialize()
sha256.key=aKey
'Note you MUST use computehash_2 to get the correct version of this method, and the bytes MUST be double wrapped in brackets to ensure they get passed in correctly.
sha256HMACBytes = sha256.ComputeHash_2( (aBytes) )
end function
function stringToUTFBytes(aString)
Dim UTF8
Set UTF8 = CreateObject("System.Text.UTF8Encoding")
stringToUTFBytes = UTF8.GetBytes_4(aString)
end function
function bytesToHex(aBytes)
dim hexStr, x
for x=1 to lenb(aBytes)
hexStr= hex(ascb(midb( (aBytes),x,1)))
if len(hexStr)=1 then hexStr="0" & hexStr
bytesToHex=bytesToHex & hexStr
next
end function
Function BytesToBase64(varBytes)
With CreateObject("MSXML2.DomDocument").CreateElement("b64")
.dataType = "bin.base64"
.nodeTypedValue = varBytes
BytesToBase64 = .Text
End With
End Function
'Special version that produces the URLEncoded variant of Base64 used in JWTs.
Function BytesToBase64UrlEncode(varBytes)
With CreateObject("MSXML2.DomDocument").CreateElement("b64")
.dataType = "bin.base64"
.nodeTypedValue = varBytes
BytesToBase64UrlEncode = replace(replace(replace(replace(replace(.Text,chr(13),""),chr(10),""),"+", "-"),"/", "_"),"=", "")
End With
End Function
Function GetBytes(sPath)
With CreateObject("Adodb.Stream")
.Type = 1 ' adTypeBinary
.Open
.LoadFromFile sPath
.Position = 0
GetBytes = .Read
.Close
End With
End Function
These can be used as follows:
BytesToBase64(md5hashBytes(stringToUTFBytes("Hello World")))
Produces: sQqNsWTgdUEFt6mb5y4/5Q==
bytesToHex(md5hashBytes(stringToUTFBytes("Hello World")))
Produces: B10A8DB164E0754105B7A99BE72E3FE5
For SHA1:
bytesToHex(sha1hashBytes(stringToUTFBytes("Hello World")))
Produces: 0A4D55A8D778E5022FAB701977C5D840BBC486D0
For SHA256:
bytesToHex(sha256hashBytes(stringToUTFBytes("Hello World")))
Produces: A591A6D40BF420404A011733CFB7B190D62C65BF0BCDA32B57B277D9AD9F146E
To get the MD5 of a file (useful for Amazon S3 MD5 checking):
BytesToBase64(md5hashBytes(GetBytes(sPath)))
Where sPath is the path to the local file.
And finally, to create a JWT:
'define the JWT header, needs to be converted to UTF bytes:
aHead=stringToUTFBytes("{""alg"":""HS256"",""typ"":""JWT""}")
'define the JWT payload, again needs to be converted to UTF Bytes.
aPayload=stringToUTFBytes("{""sub"":""1234567890"",""name"":""John Doe"",""admin"":true}")
'Your shared key.
theKey="mySuperSecret"
aSigSource=stringToUTFBytes(BytesToBase64UrlEncode(aHead) & "." & BytesToBase64UrlEncode(aPayload))
'The full JWT correctly Base 64 URL encoded.
aJWT=BytesToBase64UrlEncode(aHead) & "." & BytesToBase64UrlEncode(aPayload) & "." & BytesToBase64UrlEncode(sha256HMACBytes(aSigSource,stringToUTFBytes(theKey)))
Which will produce the following valid JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.7ofvtkn0z_pTl6WcqRTxw-4eSE3NqcEq9_3ax0YcuIQ
Here is a readable and downloadable version of MD5 as VBS script:
https://github.com/Wikinaut/md5.vbs
It's the code from http://chayoung.tistory.com/entry/VBScript-MD5 (thank you for this unique piece of code).
Thanks for all the links provided above, they were useful but this one I found really did the job if anybody ever needs it.
VBScript-MD5
I have no idea if this code even works, since I have no way of testing it. However, it seems to be what you are asking for.
http://www.bullzip.com/md5/vb/md5-vb-class.htm
Here is an interesting article by Jeff Attwood on hashes. He has some important things to say about MD5:
http://www.codinghorror.com/blog/2012/04/speed-hashing.html
First of all, thank you SgtWilko! :)
Based on your collected information, I've done one function for all (not for base64/Files).
Your code was very useful for me, but I was searching for a more PHP alike (simple) Function to deal with plain text and with a more explicit code.
Edited:
Based on the issue How to hash a UTF-8 string in Classic ASP, I come up with the ADODB.Stream solution. You can now use non-English characters.
Edited:
Parameter PlainText was changed to Target.
You can now use the HMAC versions.
Just use the Target parameter as an array.
Target(0) = PlainText
Target(1) = SharedKey
Thank you again SgtWilko ;)
Announcing the first SHA1 collision (Google Security Blog) February 23, 2017.
With this function you can hash the plain text into:
MD5, RIPEMD160, SHA1, SHA256, SHA384, SHA512, HMACMD5, HMACRIPEMD160, HMACSHA1, HMACSHA256, HMACSHA384 and HMACSHA512
If you need more you can find it in: System.Security.Cryptography Namespace
Function Hash(HashType, Target)
On Error Resume Next
Dim PlainText
If IsArray(Target) = True Then PlainText = Target(0) Else PlainText = Target End If
With CreateObject("ADODB.Stream")
.Open
.CharSet = "Windows-1252"
.WriteText PlainText
.Position = 0
.CharSet = "UTF-8"
PlainText = .ReadText
.Close
End With
Set UTF8Encoding = CreateObject("System.Text.UTF8Encoding")
Dim PlainTextToBytes, BytesToHashedBytes, HashedBytesToHex
PlainTextToBytes = UTF8Encoding.GetBytes_4(PlainText)
Select Case HashType
Case "md5": Set Cryptography = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider") '< 64 (collisions found)
Case "ripemd160": Set Cryptography = CreateObject("System.Security.Cryptography.RIPEMD160Managed")
Case "sha1": Set Cryptography = CreateObject("System.Security.Cryptography.SHA1Managed") '< 80 (collision found)
Case "sha256": Set Cryptography = CreateObject("System.Security.Cryptography.SHA256Managed")
Case "sha384": Set Cryptography = CreateObject("System.Security.Cryptography.SHA384Managed")
Case "sha512": Set Cryptography = CreateObject("System.Security.Cryptography.SHA512Managed")
Case "md5HMAC": Set Cryptography = CreateObject("System.Security.Cryptography.HMACMD5")
Case "ripemd160HMAC": Set Cryptography = CreateObject("System.Security.Cryptography.HMACRIPEMD160")
Case "sha1HMAC": Set Cryptography = CreateObject("System.Security.Cryptography.HMACSHA1")
Case "sha256HMAC": Set Cryptography = CreateObject("System.Security.Cryptography.HMACSHA256")
Case "sha384HMAC": Set Cryptography = CreateObject("System.Security.Cryptography.HMACSHA384")
Case "sha512HMAC": Set Cryptography = CreateObject("System.Security.Cryptography.HMACSHA512")
End Select
Cryptography.Initialize()
If IsArray(Target) = True Then Cryptography.Key = UTF8Encoding.GetBytes_4(Target(1))
BytesToHashedBytes = Cryptography.ComputeHash_2((PlainTextToBytes))
For x = 1 To LenB(BytesToHashedBytes)
HashedBytesToHex = HashedBytesToHex & Right("0" & Hex(AscB(MidB(BytesToHashedBytes, x, 1))), 2)
Next
If Err.Number <> 0 Then Response.Write(Err.Description) Else Hash = LCase(HashedBytesToHex)
On Error GoTo 0
End Function
These can be used as follows:
Hash("sha512", "Hello World")
Produces:
2c74fd17edafd80e8447b0d46741ee243b7eb74dd2149a0ab1b9246fb30382f27e853d8585719e0e67cbda0daa8f51671064615d645ae27acb15bfb1447f459b
Hash("sha256", "Hello World")
Produces:
a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e
Hash("md5", "muñeca")
Produces:
ea07bec1f37f4b56ebe368355d1c058f
Hash("sha512HMAC", Array("Hello World", "Shared Key"))
Produces:
28e72824c48da5a5f14b59246905d2839e7c50e271fc078b1c0a75c89b6a3998746bd8b2dc1764b19d312702cf5e15b38ce799156af28b98ce08b85e4df65b32
There is Javascript code that produces an MD5 checksum. One of them, derived from the Google closure library, is available here.
It's pretty easy to produce a Windows Script Component from the Javascript, then call that component from any COM-enabled language, including VB.
Here's a working example.

Coldfusion 9 Encryption Key from Java Byte Array

I am working on a project where we are passing encrypted data between C#, Java and ColdFusion applications. To generate the key and iv for 256 bit AES encryption. I have the following array which I need to convert in ColdFusion 9 to useable key
The Java Code for the Key
new byte[]{
(byte)172, (byte)181, (byte)241, (byte)21, (byte)129,
(byte)236, (byte)96, (byte)46, (byte)92, (byte)211,
(byte)187, (byte)106, (byte)90,(byte)69, (byte)29,
(byte)186, (byte)99, (byte)65, (byte)134, (byte)125,
(byte)218,(byte)117, (byte)9, (byte)223, (byte)13,
(byte)207, (byte)20, (byte)62, (byte)31,(byte)226, (byte)129, (byte)33
}
The ColdFusion Code to encrypt (Can't seem to get this to all show up here):
<cfset awsSecret = "[172,181,241,21,129,236,96,46,92,211,187,106,90,69,29,186,99,65,134,125,218,117,9,223,13,207,20,62,31,226,129,33]"
Using .getBytes() and base64 encoding - I also end up with a key that is 113 bytes. Any help would be fantastic!
One way is to convert the int values to a byte array, then to base64
<cfset ints = [172,181,241,21,129,236,96,46,92,211,187,106,90,69,29,186,99,65,134,125,218,117,9,223,13,207,20,62,31,226,129,33]>
<cfset bytes = []>
<cfloop array="#ints#" index="i">
<cfset arrayAppend(bytes, javacast("int", i).byteValue())>
</cfloop>
<cfset keyAsBase64 = BinaryEncode(javacast("byte[]", bytes), "base64")>

Error with Decrypt for "Could not perform unpadding: invalid pad byte.."

Using CF8 and MySQL 5.1, I am trying to encrypt() a password upon creation and then decrypt() at login. I can get the decrypt() to work fine on a test page but when I put it in a cfincluded page with cflogin I get the error "An error occurred while trying to encrypt or decrypt your input string: com.rsa.jsafe.crypto.dr: Could not perform unpadding: invalid pad byte.. ". It is the same code and DB from my test page to my app.
application.cfc:
<cfif NOT IsDefined("Request.PasswordKey")>
<cfset request.PasswordKey = generateSecretKey("AES")>
<cfset request.algorithm = "AES">
<cfset request.encoding = "hex">
</cfif>
test page which works fine:
FORM DATA: <br/>
form password:<cfoutput>#form.passwd#</cfoutput><br/>
<cfset encrypted = Encrypt(form.passwd,Request.PasswordKey,Request.algorithm,Request.encoding)>
Encrypted: <cfoutput>#encrypted#</cfoutput><br/>
Decrypted: <cfoutput>#Decrypt(variables.encrypted,Request.PasswordKey,Request.algorithm,Request.encoding)#</cfoutput><br/>
<br/>
QUERY DATA<br/>
<cfinvoke component="components.userQ" method="login" returnvariable="qLogin">
<cfinvokeargument name="formData" value="#form#">
</cfinvoke>
<cfoutput>qLogin password: #qlogin.encPasswd#</cfoutput><br/>
<cfoutput>Decrypted encPasswd from qLogin: #Decrypt(qlogin.encPasswd,Request.PasswordKey,Request.algorithm,Request.encoding)#</cfoutput>
Decrypt() in app page that is erroring:
<cfset unEnPasswd = #Decrypt(qlogin.encPasswd,Request.PasswordKey,Request.algorithm,Request.encoding)#>
I can get the default CFMX_COMPAT encrypt() and decrypt() to work fine in my app with the same code, just changing the key, algorithm, and encoding variables.
BTW, I am also storing the encrypted strings as varchar() in the DB so it doesn't mess up the padding (so I read). I tried BLOB but get a bytearray error.
Any help or thoughts are greatly appreciated.
You're creating a new secret key on every request,
Really your code should be more like:
<cffunction name="onApplicationStart" returnType="boolean" output="false">
<cfset application.PasswordKey = generateSecretKey("AES")>
</cffunction>
<cffunction name="onRequestStart" returnType="boolean" output="false">
<cfset request.PasswordKey = application.PasswordKey />
<cfset request.algorithm = "AES" />
<cfset request.encoding = "hex" />
</cffunction>
Though really you want to have the password key hardcoded in a config file otherwise if you restart your server you won't be able to access any of your passwords ever again...
Disable jsafe. Add -Dcoldfusion.disablejsafe=true to your jvm config.

Resources