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?

5
  • 1
    Whatever you're doing, don't save passwords like that. Use proper password hashing functions like Argon2. Commented Apr 14, 2020 at 15:22
  • This was the first 3 stages of 5 to hash a password for a 3rd party API AuthenticationRequest Commented Apr 14, 2020 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...] Commented Apr 14, 2020 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. Commented Apr 14, 2020 at 20:56
  • 1
    Why don't you just convert the hex data to a string of bytes before calculating the hash? Commented Apr 14, 2020 at 21:00

1 Answer 1

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
Sign up to request clarification or add additional context in comments.

2 Comments

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.