DotNetNuke user authentication in ColdFusion

Is there a way to authenticate users from other web applications using DNN logins?

We have a main site that uses DNN, and user logins are stored in the asp net membership table. From what I read, passwords are encrypted with a machine key and then salted. I see where this information is, but cannot correctly encrypt passwords using this method.

I am trying to use the Coldfusion web application on the same server where our DNN site is located, but it does not want to work. You might think this would be a breakthrough with the ColdFusion encryption feature:

Encrypt(passwordstring, key [, algorithm, encoding, IVorSalt, iterations]) 

No matter what I try, I never get the corresponding value.

Any help, insight or pointing me in the right direction would be greatly appreciated!

+3
coldfusion dotnetnuke single-sign-on
source share
3 answers

(Edit: the original answer did not work in all cases. Substantially changed ...)

From what I read, DNN uses "SHA1" by default. The @barnyr stream shows that it simply hashes the concatenated salt and password, but with a few twists.

  • DNN uses UTF-16LE to retrieve password bytes, not the typical UTF-8 CF.
  • It also extracts separately the salt and password bytes, which can give different results than just decode everything as one line , which hash() does. (See Demo below).

Given that the CF9 Hash function does not accept a binary file (supported in CF11), I do not think that you can duplicate the results with your own CF functions only. Instead, I suggest decoding strings into binary files and then using java directly:

The code:

 <cfscript> thePassword = " DT!@12 "; base64Salt = "+muo6gAmjvvyy5doTdjyaA=="; // extract bytes of the salt and password saltBytes = binaryDecode(base64Salt, "base64"); passBytes = charsetDecode(thePassword, "UTF-16LE" ); // next combine the bytes. note, the returned arrays are immutable, // so we cannot use the standard CF tricks to merge them ArrayUtils = createObject("java", "org.apache.commons.lang.ArrayUtils"); dataBytes = ArrayUtils.addAll( saltBytes, passBytes ); // hash binary using java MessageDigest = createObject("java", "java.security.MessageDigest").getInstance("SHA-1"); MessageDigest.update(dataBytes); theBase64Hash = binaryEncode(MessageDigest.digest(), "base64"); WriteOutput("theBase64Hash= "& theBase64Hash &"<br/>"); </cfscript> 


Demonstration of differences:

 <cfscript> theEncoding = "UTF-16LE"; thePassword = " DT!@12 "; base64Salt = "+muo6gAmjvvyy5doTdjyaA=="; // extract the bytes SEPARATELY saltBytes = binaryDecode(base64Salt, "base64"); passBytes = charsetDecode(thePassword, theEncoding ); ArrayUtils = createObject("java", "org.apache.commons.lang.ArrayUtils"); separateBytes = ArrayUtils.addAll( saltBytes, passBytes ); // concatenate first, THEN extract the bytes theSalt = charsetEncode( binaryDecode(base64Salt, "base64"), theEncoding ); concatenatedBytes = charsetDecode( theSalt & thePassword, theEncoding ); // these are the raw bytes BEFORE hashing WriteOutput("separateBytes= "& arrayToList(separateBytes, "|") &"<br>"); WriteOutput("concatenatedBytes"& arrayToList(concatenatedBytes, "|") ); </cfscript> 


Results:

 separateBytes = -6|107|-88|-22|0|38|-114|-5|-14|-53|-105|104|77|-40|-14|104|68|0|84|0|33|0|64|0|49|0|50|0 concatenatedBytes = -6|107|-88|-22|0|38|-114|-5|-14|-53|-105|104|-3|-1|68|0|84|0|33|0|64|0|49|0|50|0 


+3
source share

Most likely, the password is not encrypted, it is hashed. Hashing is different from encryption because it is not reversible.

You would not use the ColdFusion encrypt () function for this, you would use the hash () function.

Thus, the questions you need to answer to figure out how to hash passwords in CF in order to be able to authenticate DNN users are as follows:

  • What algorithm uses DNN for password hashing?
  • How is salt with password used before hashing?
  • Deploying a DNN through a hash X a number of times for increased security?

All these questions must be answered in order to determine how CF should use the hash () function in combination with the salt and user passwords.

I will make some assumptions to give an answer.

If we assume that noiteration is done and that the salt is simply added to the password before using SHA1 to hash the password, then you can reproduce the hash digest as follows:

 <cfset hashDigest = hash(FORM.usersubmittedPassword & saltFromDB, "SHA1") /> 
+2
source share

(Post a new answer so that the "encrypted" process is separated from the "hash")

For "encrypted" keys, the DNN side uses standard algorithms, such as DES, 3DES or AES, depending on the machineKey settings. But with some differences, you need to match your CF code. Not knowing your actual settings, I assume that you are using the default 3DES at the moment.

Data for encryption

The encrypted value is a combination of salt and password. But as with hashing, DNN uses UTF-16LE . Unfortunately, the ColdFusion Encrypt() function always assumes UTF-8, which will lead to a completely different result. Therefore, you need to use the EncryptBinary function.

  // sample valus plainPassword = "password12345"; base64Salt = "x7le6CBSEvsFeqklvLbMUw=="; hexDecryptKey = "303132333435363738393031323334353637383930313233"; // first extract the bytes of the salt and password saltBytes = binaryDecode(base64Salt, "base64"); passBytes = charsetDecode(plainPassword, "UTF-16LE" ); // next combine the bytes. note, the returned arrays are immutable, // so we cannot use the standard CF tricks to merge them ArrayUtils = createObject("java", "org.apache.commons.lang.ArrayUtils"); dataBytes = ArrayUtils.addAll( saltBytes, passBytes ); 


Encryption algorithm

With ColdFusion block ciphers, the default is ECB mode . (See Strong Encryption in ColdFusion .) While .NET uses CBC mode by default, which requires an additional IV value. Therefore, you must adjust your CF code.

  // convert DNN hex key to base64 for ColdFusion base64Key = binaryEncode(binaryDecode( hexDecryptKey, "hex"), "base64"); // create an IV and intialize it with all zeroes // block size: 16 => AES, 8=> DES or TripleDES blockSize = 8; iv = javacast("byte[]", listToArray(repeatString("0,", blocksize))); // encrypt using CBC mode bytes = encryptBinary(dataBytes, base64Key, "DESede/CBC/PKCS5Padding", iv); // result: WBAnoV+7cLVI95LwVQhtysHb5/pjqVG35nP5Zdu7T/Cn94Sd8v1Vk9zpjQSFGSkv WriteOutput("encrypted password="& binaryEncode( bytes, "base64" )); 
+1
source share

All Articles