【问题标题】:problem converting php code to python generating password digest for soap requests将php代码转换为python为soap请求生成密码摘要的问题
【发布时间】:2022-01-13 18:39:15
【问题描述】:
<?php
$password = "SECRETPASSWORD";
$nonce = random_bytes(32); # requires PHP 7
date_default_timezone_set("UTC");
$timestamp = date(DATE_ATOM);
$encodedNonce = base64_encode($nonce);
$passSHA = base64_encode(sha1($nonce . $timestamp . sha1($password, true), true));
?>

它使用 28 个字符的密码摘要生成以下结果,我在肥皂请求中使用它,它工作正常

password_digest = '/pBYmwwc2cM87CUr8oB4Wkmyc0Q='
nonce = '���>�!��g��q�[�`�R��=J�o�'
nonce_base_64_encode = 'uqbkProhsR3JZxjC93HWW8BghQFSgqo9Sv9vGgUa4hs='
timestamp = '2022-01-13T18:28:52+00:00'

我需要在 python 中做同样的事情,但是 python 以某种方式生成更长的 password_digest,soap 请求失败。我不知道我是否没有在 python 中正确生成 random_bytes 或其他问题。下面是python代码:

import secrets
import hashlib
import datetime

clearPassword = 'MYSECRETPASSWORD'
created_at_timestamp_utc = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")


def getSha1String(string):
    stringInBytes = string.encode('ascii')
    hash_object = hashlib.sha1(stringInBytes)
    hex_dig = hash_object.hexdigest()
    return hex_dig

def getBase64NonceString(nonce):
    nonce_bytes = nonce.encode('ascii')
    base64_bytes = base64.b64encode(nonce_bytes)
    base64_nonce = base64_bytes.decode('ascii')
    return base64_nonce

def getBase64String(string):
    string_bytes = string.encode('ascii')
    base64_bytes = base64.b64encode(string_bytes)
    base64_string = base64_bytes.decode('ascii')
    return base64_string

nonce =  secrets.token_bytes(32)
base64_nonce = getBase64Nonce(nonce)
sha1_password = getSha1String(clearPassword)
password_digest = getBase64String(getSha1String(str(nonce) + created_at_timestamp_utc + sha1_password)) 

【问题讨论】:

    标签: python php password-encryption password-hash


    【解决方案1】:

    你的python代码有3个问题:

    1. 您在 PHP 中使用来自 sha1() 的二进制输出,但在 python 中使用十六进制输出。使用digest(),而不是hexdigest()。这就是为什么你的输出在 python 中更长的原因。

    2. 您的时间戳格式不正确。

      PHP 格式DATE_ATOM"Y-m-d\TH:i:sP",其中P+00:00 格式输出UTC 偏移量。不幸的是,Python 的 strftime() 似乎没有等价物,但无论如何它都是 UTC 格式的,而且您的 python 代码只是指定了静态字符串 Z。所以把它改成+00:00,否则你的令牌将不匹配。

      例如:timestamp = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S+00:00')

    3. 你在 PHP 中使用 SECRETPASSWORD,在 python 中使用 MYSECRETPASSWORD,我很尴尬我在没有注意到的情况下撞了那个头。

    简洁的工作代码:

    import hashlib, datetime, base64
    
    password = 'SECRETPASSWORD'
    timestamp = '2022-01-13T18:28:52+00:00'
    nonce = base64.b64decode('uqbkProhsR3JZxjC93HWW8BghQFSgqo9Sv9vGgUa4hs=')
    
    def quickSHA(input):
        return hashlib.sha1(input).digest()
    
    def makeToken(password, timestamp, nonce):
        return base64.b64encode(
            quickSHA( nonce + timestamp + quickSHA(password) )
        )
    
    print makeToken(password, timestamp, nonce)
    

    输出:/pBYmwwc2cM87CUr8oB4Wkmyc0Q=

    【讨论】:

    • 感谢您的回复。我在 python2 上测试了你的代码,它按预期工作。但在 python3 上它不起作用。并给出错误。我已跟踪错误并应用了可能的修复程序。但最后在 python3 中生成的哈希仍然很长。虽然 python2 给出了 28 个字符的哈希值,但无论输入有多长。 Python3 错误:TypeError: can't concat str to bytes (因为 nonce 是字节) TypeError: Unicode-objects must be encrypted before hashing (需要在散列之前将普通密码转换为字节)
    • 最终问题通过将所有参数转换为字节来解决,正如这个 stackoverflow 问题stackoverflow.com/questions/64234340/… 中所建议的那样
    猜你喜欢
    • 1970-01-01
    • 2020-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-25
    • 1970-01-01
    相关资源
    最近更新 更多