如何用PyCryptodome重现PowerShell的PasswordDeriveBytes并获一致结果
搞定PyCryptodome和PowerShell PasswordDeriveBytes结果不一致的问题
我刚踩过这个坑!问题出在PowerShell的PasswordDeriveBytes默认用的是PBKDF1(基于SHA-1),而你大概率误用了PyCryptodome里的PBKDF2——这俩算法完全不一样,结果自然对不上。下面给你掰清楚细节,直接上可运行的代码:
先把PowerShell的行为摸透
你的代码片段里用了ASCIIEncoding,所以密码和盐都会被转成ASCII字节;PasswordDeriveBytes默认哈希算法是SHA-1,迭代次数是你指定的2次,要生成16字节的密钥(SHA-1输出是20字节,16比20小,所以直接取前16字节就行)。
先补全你的PowerShell代码,方便对比结果:
$AsciiEncoder = New-Object System.Text.ASCIIEncoding $passwordBytes = $AsciiEncoder.GetBytes('1234567890') $saltBytes = $AsciiEncoder.GetBytes('0987654321') $DerivedPass = New-Object System.Security.Cryptography.PasswordDeriveBytes($passwordBytes, $saltBytes, "SHA1", 2) $derivedKey = $DerivedPass.GetBytes(16) # 输出十六进制格式,方便和Python对比 [BitConverter]::ToString($derivedKey) -replace '-', ''
PyCryptodome的实现方法
PyCryptodome没有直接封装PBKDF1,但我们可以手动模拟它的逻辑,用SHA1哈希来实现,完全贴合PowerShell的行为:
from Crypto.Hash import SHA1 def ps_password_derive_bytes(password: str, salt: str, iterations: int, dk_len: int) -> bytes: # 统一用ASCII编码,和PowerShell保持一致 pass_bytes = password.encode('ascii') salt_bytes = salt.encode('ascii') # PBKDF1第一步:密码+盐拼接后哈希 current_hash = SHA1.new(pass_bytes + salt_bytes).digest() # 迭代剩下的次数(因为第一次已经算过了,所以减1) for _ in range(iterations - 1): current_hash = SHA1.new(current_hash).digest() # 取指定长度的前N字节 return current_hash[:dk_len] # 代入你的参数测试 password = '1234567890' salt = '0987654321' iterations = 2 dk_len = 16 result = ps_password_derive_bytes(password, salt, iterations, dk_len) # 输出大写十六进制,和PowerShell的结果对齐 print(result.hex().upper())
为什么之前会错?
要是你之前用了PyCryptodome的PBKDF2函数(比如from Crypto.Protocol.KDF import PBKDF2),那肯定对不上——PBKDF2是PBKDF1的升级版,推导逻辑完全不同。PowerShell的PasswordDeriveBytes只有显式指定KeyDerivationAlgorithm为PBKDF2时才会用它,默认是PBKDF1,这是最容易踩的坑!
运行上面的代码,你会发现和PowerShell的结果完全一致。
内容的提问来源于stack exchange,提问作者gakar06
相关产品推荐
相关产品推荐

