2

I have this Python script which produces the correct output:

import hashlib

username = "LoginUser"
password = "LoginPass"
nonce = "1234567890"

def LowerCase(s): return s.lower()
def Hex(s): return ''.join([hex(char)[2:] for char in s])

def SHA1(s): h = hashlib.sha1(); h.update(s); return h.digest()
def SHA1Raw(s): h = hashlib.sha1(); h.update(s); return h.hexdigest()

def SHA256(s): h = hashlib.sha256(); h.update(s); return h.digest()
def SHA256Raw(s): h = hashlib.sha256(); h.update(s); return h.hexdigest()

def UTF8Encode(s): return str.encode(s)



step1 = SHA256((UTF8Encode(username)))
step2 = SHA1((UTF8Encode(password)))

step3 = SHA256Raw(step1 + step2)

step1 = SHA256Raw((UTF8Encode(username)))
step2 = SHA1Raw((UTF8Encode(password)))


print("""
SHA256(username={username})                            =    {step1}
SHA1(password={password})                              =    {step2}
SHA256((username + password)={username}{password})     =    {step3}
""".format(
    username = username,
    password = password,
    step1 = step1,
    step2 = step2,
    step3 = step3
))

Output:

PS D:\project> python .\test.py
SHA256(username=LoginUser)                            =    7981673b2c73a6bdb665f347dc89e9d324f542b1fa1c4a700bc523d8a9a6f565  
SHA1(password=LoginPass)                              =    df703733447469593d39a125ca93462eade53cab
SHA256((username + password)=LoginUserLoginPass)     =    cf3066e157468d6a9d59f9ff0662e4f8f8432be4e07c68320a8b6a031d0c022b

Now in Javascript, I try to mirror the functions I have in Python. I cannot for the life of me. I tried quickly understanding Buffers and streams in this context but I believe I am just confusing myself further by not staying grounded to something.

Anyways here's the Javascript versiona and it's output:

const crypto = require('crypto')

const username = "LoginUser"
const password = "LoginPass"
const nonce = "1234567890"

const LowerCase = s => s.toLowerCase()
const Hex = s => Buffer.from(s, 'utf8').toString('hex')

const SHA1 = s => crypto.createHash('sha1').update(s, 'utf8').digest('hex')
const SHA1Raw = s => crypto.createHash('sha1').update(s, 'utf8').digest()

const SHA256 = s => crypto.createHash('sha256').update(s, 'utf8').digest('hex')
const SHA256Raw = s => crypto.createHash('sha256').update(s, 'utf8').digest()

const UTF8Encode = s => Buffer.from(s, 'utf8');


let step1 = SHA256(username)
let step2 = SHA1(password)
let step3 = SHA256Raw(step1.concat(step2))

console.log(`
SHA256(username=${username})                            =    ${step1}
SHA1(password=${password})                              =    ${step2}
SHA256((username + password)=${username+password})      =    ${step3.toString('hex')}
`)

Output:

PS D:\project> node .\test.js


SHA256(username=LoginUser)                            =    7981673b2c73a6bdb665f347dc89e9d324f542b1fa1c4a700bc523d8a9a6f565
SHA1(password=LoginPass)                              =    df703733447469593d39a125ca93462eade53cab
SHA256((username + password)=LoginUserLoginPass)      =    757101f0fd2628ce12dc039146f56da14a1e85a27fda5d68c2623f616c4fc3cc

Can anyone help?

Nulla
  • 62
  • 9
  • 1
    Whatever you're doing, don't save passwords like that. Use proper password hashing functions like Argon2. – oittaa Apr 14 '20 at 15:22
  • This was the first 3 stages of 5 to hash a password for a 3rd party API AuthenticationRequest – Nulla Apr 14 '20 at 15:23
  • 2
    You appear to be getting your raw and hex-encoded hashes in a muddle. `757101f0fd2628ce12dc039146f56da14a1e85a27fda5d68c2623f616c4fc3cc` is the sha256 hash of the hex string `7981673b2c73a6bdb665f347dc89e9d324f542b1fa1c4a700bc523d8a9a6f565` + `df703733447469593d39a125ca93462eade53cab`. Your Python code is calculating the hash of the corresponding byte array [0x79, 0x81, 0x67, 0x2c, 0x73, 0xa6, ...etc...] – r3mainer Apr 14 '20 at 16:31
  • @r3mainer how would I calculate the hash of a byte array in javascript? I tried creating a buffer and looping through it to update a hash but that has given me the same output. – Nulla Apr 14 '20 at 20:56
  • 1
    Why don't you just [convert the hex data to a string of bytes](https://stackoverflow.com/q/3745666/1679849) before calculating the hash? – r3mainer Apr 14 '20 at 21:00

1 Answers1

3

You only need a very small modification to make this work in Node.js.

I would suggest calculating the hashes as buffer objects, this makes the combined hash easier to calculate (since we don't need to parse from hex).

We do this by using Buffer.concat to concatenate the output of the previous hashes.

const crypto = require('crypto')

const username = "LoginUser"
const password = "LoginPass"
const nonce = "1234567890"

const LowerCase = s => s.toLowerCase()
const Hex = s => Buffer.from(s, 'utf8').toString('hex')

const SHA1 = s => crypto.createHash('sha1').update(s, 'utf8').digest('hex')
const SHA1Raw = s => crypto.createHash('sha1').update(s, 'utf8').digest()

const SHA256 = s => crypto.createHash('sha256').update(s, 'utf8').digest('hex')
const SHA256Raw = s => crypto.createHash('sha256').update(s, 'utf8').digest()

const UTF8Encode = s => Buffer.from(s, 'utf8');


let step1 = SHA256Raw(username) // Get the SHA256 as a buffer.
let step2 = SHA1Raw(password) // Get the SHA1 as a buffer.
let step3 = SHA256Raw(Buffer.concat([step1, step2])) // Get the SHA256 of the previous steps concatenated as a buffer.

console.log(`
SHA256(username=${username})                            =    ${step1.toString('hex')}
SHA1(password=${password})                              =    ${step2.toString('hex')}
SHA256((username + password)=${username+password})      =    ${step3.toString('hex')}
`)

This gives the correct result, e.g.

SHA256(username=LoginUser)                            =    7981673b2c73a6bdb665f347dc89e9d324f542b1fa1c4a700bc523d8a9a6f565
SHA1(password=LoginPass)                              =    df703733447469593d39a125ca93462eade53cab
SHA256((username + password)=LoginUserLoginPass)      =    cf3066e157468d6a9d59f9ff0662e4f8f8432be4e07c68320a8b6a031d0c022b
Terry Lennox
  • 29,471
  • 5
  • 28
  • 40
  • 1
    Thank you! Works flawlessly. I tried the aforementioned method of converting the step1+2 strings into byte arrays but I got malformed results. I suppose I didn't forsee the Buffer.concat() method being the solution here. Again, I give my biggest thanks. I'll read up on the Buffer type in Javascript and try to see what's happening here in more clear terms. Parsing from hex seems to be a redundant/unnecessary step, so I'll have to develop my understanding of why it is. – Nulla Apr 16 '20 at 18:27
  • Great to hear it, Python seems to handle concatenation a little bit more seamlessly. It's a real Node thing the Buffer.concat. In any case it's a small change, but yes it can be frustrating trying to find that last line of code! – Terry Lennox Apr 16 '20 at 18:59