Python 3.8.3 hashlib中是否有一个哈希算法,可以用于算法; Base64(SHA1(NONCE + TIMESTAMP + SHA1(PASSWORD)))?

3

首先向大家道歉,作为新手我开始了我的Python之旅,并且迄今为止非常喜欢它,除了我现在遇到的这个小问题...

我一直在尝试使用Python的hashlib和base64库找到双散列(SHA1)和Base64编码一些值的方法,用于密码摘要,但我卡住了。

我需要使用以下算法填充SOAP XML web服务头,以使用摘要密码; Base64(SHA1(NONCE + TIMESTAMP + SHA1(PASSWORD)))

下面是文档的摘录,显示了正确的结果和一些常见错误:

引言 输入参数:

纯文本密码: AMADEUS

原始Nonce(可能无法打印):secretnonce10111

Base64编码的Nonce: c2VjcmV0bm9uY2UxMDExMQ==

时间戳/创建时间: 2015-09-30T14:12:15Z

  1. 正确的结果: 密码摘要:+LzcaRc+ndGAcZIXmq/N7xGes+k= 公式:Base64(SHA1($NONCE + $TIMESTAMP + SHA1($CLEARPASSWORD)))

  2. 所有参数正确,除了$NONCE与Nonce XML元素中相同的(Base64)格式外: 密码摘要:AiRk9oAVpkYDX2MXh+diClQ0Lds= 公式:Base64(SHA1(Base64($NONCE) + $TIMESTAMP + SHA1($CLEARPASSWORD)))

  3. 初始明文密码加密和连接字符串使用十六进制编码的SHA1,而不是原始SHA1: 密码摘要:NWE1MGRhM2ZmNjFhMDA2ODUyNmIxMGM4MTczODQ0NjE2MWQyM2IxZQ== 公式:Base64(HEX(SHA1($NONCE) + $TIMESTAMP + HEX(SHA1($CLEARPASSWORD))))

  4. 连接字符串使用十六进制编码的SHA1,密码没有使用SHA1进行加密: 密码摘要:NzU0ZjJlMTc2ZjkxZmM2OTg4N2E0ZDlkMWY2MWE0YWJkOGI0MzYxZA== 公式:Base64(HEX(SHA1($NONCE + $TIMESTAMP + $CLEARPASSWORD)))

  5. 几乎所有东西都是错误的:连接字符串使用十六进制编码的SHA1,密码没有使用SHA1进行加密,$NONCE与Nonce XML元素中相同的(Base64)格式: 密码摘要:NGIzYmNiY2I3Njc2ZjZiNzdmNDMwMGVlMTIwODdhZDE1ZmZlOTEwMA== 公式:Base64(HEX(SHA1(Base64($NONCE) + $TIMESTAMP + $CLEARPASSWORD))) UNQUOTE

这是我目前的翻译,按照文档建议使用变量以便检查结果。

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)

结果

<class 'str'> NWE1MGRhM2ZmNjFhMDA2ODUyNmIxMGM4MTczODQ0NjE2MWQyM2IxZQ==

注意:我已经使用了编码方式为utf-8和ascii的以及空白的代码,还写了一个更简洁的版本但是并没有成功...
PWDIGEST = base64.b64encode(hashlib.sha1((NONCE + TIMESTAMP + str(hashlib.sha1(PASSWORD.encode('ascii')).hexdigest())).encode('ascii')).hexdigest().encode('ascii')).decode('ascii')

如你所见,根据文档,它无法工作的原因是“初始纯文本密码加密和连接字符串的哈希使用十六进制编码的SHA1而不是原始SHA1”。

我意识到我在上面的代码中使用了hexdigest(),它将哈希渲染为十六进制,但这是我能得到的最接近的结果。

遵循Python hashlib文档,我也尝试过使用.digest()和update(),但是结果完全不同于文档中的内容,如下所示:

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)

结果

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

我也尝试过直接将字节值输入到base64.b64encode中,但没有成功...

我有很多问题,但我想最重要的问题是:我错过了什么?是否有一种优雅的方式可以完成这项任务?是否可能将“原始SHA1”或“类似字节对象”的值与字符串连接起来?


欢迎来到 Stack Overflow!请参观[tour]并阅读[ask]。这里有一些格式帮助,以提高您的问题的可读性——添加代码框架可以通过使代码与文本区分得非常清楚来大大提高可读性。 - Pranav Hosangadi
2个回答

1
我不明白指令要求你做什么,但你使用hexdigest()而不是digest()几乎肯定是一个错误。当你处理加密时,你几乎总是在处理字节而不是字符串。所有非字节字符串(文本、随机数和时间戳)都应该转换为字节字符串。所有计算和连接都应该使用这个字节串进行。然后,在必要时,你可以将其转换回字符串作为最后一步。

非常感谢,这确实帮助我找到了正确的方向!在哈希之前,我将NONCE和TIMESTAMP的值更改为字节字符串,从而获得了所需的结果。 - Steve Lawrence

1
感谢Frank Yellin的指引,我通过将算法中的所有值转换为字节来解决了这个问题,如下所示:

TIMESTAMPB = TIMESTAMP.encode('utf8')

NONCEB = NONCE.encode('utf8')

CONCAT = NONCEB + TIMESTAMPB + PWSHA1

CSHA = hashlib.sha1()

CSHA.update(CONCAT)

PWDIGEST = base64.b64encode(CSHA.digest())

print(type(PWDIGEST), PWDIGEST) <class 'bytes'> b'+LzcaRc+ndGAcZIXmq/N7xGes+k='

哦!


我很高兴我的信息是你所寻找的。 - Frank Yellin
@Steve,感谢您发布这段代码。我已经在这上面浪费了两天时间。最终通过查看您的问题和答案解决了它。我也正在处理Amadeus的SOAP Web服务。很高兴能与您联系。 - Noor Ahmed
1
@Noor 当然可以,如果你访问我的网站 https://artoro.co.uk 并使用联系表格发送信息,我会把我的联系方式发给你。 - Steve Lawrence

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接