Search code examples
pythonbase64hexsha1hashlib

Is there a Hash algorithm in Python 3.8.3 hashlib for the algorithm; Base64(SHA1(NONCE + TIMESTAMP + SHA1(PASSWORD)))?


Apologies first, newbie here just setting off on my Pythonic journey and rather enjoying it so far, aside from this little issue I'm facing...

I've been trying to find a way to double hash (SHA1) and base64 encode some values, using Python's hashlib and base64 libraries, for a password digest but I'm stuck.

I need to populate a SOAP XML web service header with a digested password that uses the following algorithm; Base64(SHA1(NONCE + TIMESTAMP + SHA1(PASSWORD)))

An extract of the documentation, below, shows the correct result and some common errors:

QUOTE Input parameters:

Plain text password: AMADEUS

Raw Nonce (may be unprintable): secretnonce10111

Base64 encoded Nonce: c2VjcmV0bm9uY2UxMDExMQ==

Timestamp/Created: 2015-09-30T14:12:15Z

  1. Correct result: Password digest: +LzcaRc+ndGAcZIXmq/N7xGes+k= Formula: Base64(SHA1($NONCE + $TIMESTAMP + SHA1($CLEARPASSWORD)))

  2. All parameters correct, except $NONCE which has the same (Base64) format as in Nonce XML element: Password digest: AiRk9oAVpkYDX2MXh+diClQ0Lds= Formula: Base64(SHA1(Base64($NONCE) + $TIMESTAMP + SHA1($CLEARPASSWORD)))

  3. SHA1 in hexadecimal encoding instead of raw SHA1 for initial plain password encryption and for concatenated string: Password digest: NWE1MGRhM2ZmNjFhMDA2ODUyNmIxMGM4MTczODQ0NjE2MWQyM2IxZQ== Formula: Base64(HEX(SHA1($NONCE) + $TIMESTAMP + HEX(SHA1($CLEARPASSWORD))))

  4. SHA1 in hexadecimal encoding instead of raw SHA1 for concatenated string, password not encrypted with SHA1: Password digest: NzU0ZjJlMTc2ZjkxZmM2OTg4N2E0ZDlkMWY2MWE0YWJkOGI0MzYxZA== Formula: Base64(HEX(SHA1($NONCE + $TIMESTAMP + $CLEARPASSWORD)))

  5. Almost everything is incorrect: SHA1 in hexadecimal encoding instead of raw SHA1 for concatenated string, password not encrypted with SHA1, $NONCE has the same (Base64) format as in Nonce XML element: Password digest: NGIzYmNiY2I3Njc2ZjZiNzdmNDMwMGVlMTIwODdhZDE1ZmZlOTEwMA== Formula: Base64(HEX(SHA1(Base64($NONCE) + $TIMESTAMP + $CLEARPASSWORD))) UNQUOTE

Here is what I have so far, using the variables suggested in the documentation so that I can check the results:

import base64    
import hashlib

NONCE = "secretnonce10111"    
TIMESTAMP = "2015-09-30T14:12:15Z"    
PASSWORD = "AMADEUS"    
PWSHA1 = hashlib.sha1(PASSWORD.encode('ascii')).hexdigest()    
CONCAT = (NONCE + TIMESTAMP + str(PWSHA1)).encode('ascii')    
CONCATSHA1 = hashlib.sha1(CONCAT).hexdigest()    
PWDIGEST = base64.b64encode(CONCATSHA1.encode('ascii')).decode('ascii')    
print(type(PWDIGEST), PWDIGEST)

Result

<class 'str'> NWE1MGRhM2ZmNjFhMDA2ODUyNmIxMGM4MTczODQ0NjE2MWQyM2IxZQ==

Note: I've used encoding in ('utf-8') as well as ('ascii') and just (), and I've also written a more concise version of the code above but to no avail...

PWDIGEST = base64.b64encode(hashlib.sha1((NONCE + TIMESTAMP + str(hashlib.sha1(PASSWORD.encode('ascii')).hexdigest())).encode('ascii')).hexdigest().encode('ascii')).decode('ascii')

So as you can see, according to the documentation, it's not wokring because "SHA1 in hexadecimal encoding instead of raw SHA1 for initial plain password encryption and for concatenated string".

I realise that I'm using hexdigest() in the code above, which is rending the hash to hexadecimal, but it's the closest I can get.

Following the Python hashlib docs I have also tried using .digest() and update(), which gives a completely different result that's not in the docs, as shown below:

PWSHA = hashlib.sha1()    
PWSHA.update(PASSWORD.encode('utf-8'))    
PWSHA1 = PWSHA.digest()    
CONCAT = (NONCE + TIMESTAMP + str(PWSHA1))    
CSHA = hashlib.sha1()    
CSHA.update(CONCAT.encode("utf-8"))    
CSHA1 = CSHA.digest()    
PWDIGEST = base64.b64encode(CSHA1).decode('ascii')    
print(type(PWDIGEST), PWDIGEST)

Results in

<class 'str'> exB8TjilUE+w8b2SKs+PkOhRjfg=

I've also tried inputting the bytes values directly into base64.b64encode, but no joy...

I have loads of questions, but I guess the most important ones are; what am I missing? Is there an elegant way in which this can be done? Is it possible to concatenate "raw SHA1" or "bytes-like objects" values with strings?


Solution

  • I don't understand what the instructions are telling you to do, but your use of hexdigest() instead of digest() is almost certainly a mistake. When you work with crypto, you are almost always dealing with bytes, not strings. Everything that is not a byte string (the text, the nonce, the timestamp) should be converted into a byte string. All calculations and concatenations should be done with this bytestring. And then as the last step, if necessary, you convert it back to a string.