views:

109

answers:

3

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.

+1  A: 

Not sure why the decrypting isnt working but You should really be one way hashing your passwords - otherwise you may as well be storing them in plaintext...

Aidan Kane
@Aidan - why do you say that if it is strong encrypted from the app to the DB?
JS
Because if the system is compromised the passwords can be read. Even if it's just someone internal to your organisation - they have access to passwords that they probably shouldn't. Having said that I'm trying to replicate your issue at the moment to try to figure it out because your code looks fine.
Aidan Kane
Thanks for the help man. I know about the NIST recommendation and that the hash can be improved with a salt (which gets you closer to encrypt with a key). Just wanted to be sure that I wasn't missing something from your comment about plaintext.
JS
I agree with Aidan. The user password should be one-way hashed. In particular with at least Hash(password,'SHA-256'). You check the password using a technique called Encrypt and Compare. That is, when the user attempts to log in, you run the password they entered through the hash, and compare that result with the hash you have stored. If they forget the password, you can have them reset it, rather than sending them their old password.
Mark
+2  A: 

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...

Aidan Kane
The main thing to check really is that when you cfdump the key and encrypted strings on the two different pages they are all the same. So the encrypted string before storing in the db should be the same as the one pulled from the db later. And the key you use each time needs to be the same.
Aidan Kane
Apologies - your answer is starting to make sense and I believe that I am using different keys. So dumb question for you; using generateSecretKey() for AES, how do I ensure that I am using the same key across restarts etc...?
JS
Personally I actually generate a single unique key for the application. That key is then hardcoded in the application (stored in a config file - just a cfm that holds a whole lot of constants). It means that you have to have a copy of the key somewhere on the server - but there's not much you can do about that.
Aidan Kane
Thanks again for your help. I created a variable from generateSecretKey, cfoutput it to see what the value was, and then used that for the key and am referencing the variable from a config file in my application.cfc.
JS
A: 

Disable jsafe. Add -Dcoldfusion.disablejsafe=true to your jvm config.

David Collie