7

I'm trying to create a password digest with this formula to get the following variables and my code is just not matching. Not sure what I'm doing wrong, but I'll admit when I need help. Hopefully someone is out there who can help.

  • Formula from documentation: Base64(SHA1(NONCE + TIMESTAMP + SHA1(PASSWORD)))

  • Correct Password Digest Answer: +LzcaRc+ndGAcZIXmq/N7xGes+k=

ColdFusion Code:

<cfSet PW = "AMADEUS">
<cfSet TS = "2015-09-30T14:12:15Z">
<cfSet NONCE = "secretnonce10111"> 
<cfDump var="#ToBase64(Hash(NONCE & TS & Hash(PW,'SHA-1'),'SHA-1'))#">

My code outputs:

Njk0MEY3MDc0NUYyOEE1MDMwRURGRkNGNTVGOTcyMUI4OUMxM0U0Qg==

I'm clearly doing something wrong, but for the life of me cannot figure out what. Anyone? Bueller?

Leigh
  • 28,765
  • 10
  • 55
  • 103
  • Can you post a link to the documentation? – Leigh May 19 '17 at 14:52
  • The documentation is not available in a public link :( – Jill Plotke May 19 '17 at 15:29
  • Bummer. Any "postable" examples or snippets - even in another language, like say java/c# or php? I see what is causing the problem, and have a solution for this specific case. However, there is a little ambiguity in their instructions, so I want to make sure the solution works in all cases. – Leigh May 19 '17 at 15:45
  • 1
    @Alex - Why do you say that? It decodes fine in CF. – Leigh May 19 '17 at 16:43
  • 1
    I don't know what sort of site you're protecting for or how secure you need this to be, but just for reference: https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet – Shawn May 19 '17 at 20:52

1 Answers1

6

The fun thing about hashing is that even if you start with the right string(s), the result can still be completely wrong, if those strings are combined/encoded/decoded incorrectly.

The biggest gotcha is that most of these functions actually work with the binary representation of the input strings. So how those strings are decoded makes a big difference. Notice the same string produces totally different binary when decoded as UTF-8 versus Hex? That means the results of Hash, ToBase64, etcetera will be totally different as well.

// Result: UTF-8: 65-65-68-69
writeOutput("<br>UTF-8: "& arrayToList(charsetDecode("AADE", "UTF-8"), "-"));

// Result:  HEX: -86--34
writeOutput("<br>HEX: "& arrayToList(binaryDecode("AADE", "HEX"), "-"));

Possible Solution:

The problem with the current code is that ToBase64 assumes the input string is encoded as UTF-8. Whereas Hash() actually returns a hexadecimal string. So ToBase64() decodes it incorrectly. Instead, use binaryDecode and binaryEncode to convert the hash from hex to base64:

resultAsHex = Hash( NONCE & TS & Hash(PW,"SHA-1"), "SHA-1");
resultAsBase64 = binaryEncode(binaryDecode(resultAsHex, "HEX"), "base64");
writeDump(resultAsBase64);

More Robust Solution:

Having said that, be very careful with string concatenation and hashing. As it does not always yield the expected results. Without knowing more about this specific API, I cannot be completely certain what it expects. However, it is usually safer to only work with the binary values. Unfortunately, CF's ArrayAppend() function lacks support for binary arrays, but you can easily use Apache's ArrayUtils class, which is bundled with CF.

ArrayUtils = createObject("java", "org.apache.commons.lang.ArrayUtils");

// Combine binary of NONCE + TS
nonceBytes = charsetDecode(NONCE, "UTF-8");
timeBytes = charsetDecode(TS, "UTF-8");
combinedBytes = ArrayUtils.addAll(nonceBytes, timeBytes);

// Combine with binary of SECRET 
secretBytes = binaryDecode( Hash(PW,"SHA-1"), "HEX");
combinedBytes = ArrayUtils.addAll(combinedBytes, secretBytes);

// Finally, HASH the binary and convert to base64
resultAsHex = hash(combinedBytes, "SHA-1");
resultAsBase64 = binaryEncode(binaryDecode(resultAsHex, "hex"), "base64");

writeDump(resultAsBase64);
Community
  • 1
  • 1
Leigh
  • 28,765
  • 10
  • 55
  • 103