免责声明:我对密码学非常担心,对RSA或密码验证我了解得很少。
我需要使用Python验证签名许可证。我使用了“带有SHA256摘要的RSA PKCS1 v1.5填充”。背景信息是我正在尝试使用https://keygen.sh分发软件。
基本上,二进制软件安装在服务器上,并验证存储在服务器上的许可证文件是正版的。为此,该软件可以访问我的RSA公钥。我有一段来自the official keygen documentation的Node.js代码,并且试图将其移植到Python,但没有成功。我选择使用cryptodome库,但是我可以接受其他选择。
这是Node.js中的工作代码片段:
const crypto = require('crypto')
const public_key = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtmwlw+mDo2ZVBlRXa7Em\ncj7cVrlwnwrIPC+Ij5KpltadJfwvRFvCr37USJvkc+FIND2dKk2mmbY32cvtxl3F\nYLpjRwwlFuajbP8ZEdJl1YJyJDnLlKHWEfTSvTzZhpT939yjuBKoZ9A+wiIQ9tzY\nF/ytb9zwPkOF7/XmPAaukah5xRgwsb3fo7E0CsBQuHZxFX83+nfdZ/60MWpSCWL6\nAjNWDEmoLFEHVRm69+lwXTW51wojfurZy/wUw42sciHLV5A8mz7gJJGO5y+sGzzD\nM5VxtmLz51Fl1Rl3fMzUAjPK77i9UDWo11EuNPrzMAgjmuuMLfpIDMlMR3n/ZsW7\nXwIDAQAB\n-----END PUBLIC KEY-----\n"
const key = 'somerandomkey'
const encodedSignature = "oMTrvIz3IX4kre5UTzvkzCn712wulPvl9knSYBduYcGsX2W703zWMC9ZVepDytxLdpUIiCUtx6wx5OzmLx3rTzgaKqptrbf2wYHrCIPBgrhcHdJ3fLJRh8ASC_NdLK6i1jC_bEAq84d7QNLlTPC20aCmNLdxEJFy-DValGG0iFdxx6n6-Vp5oL8jSyWubAvBSqEQ4ubptcYirxpbDdC4DRpNzBuA48DGxWg6Pxq5HdGZWKS05iohNlrFkW-K8NJYHuLKszT0FN5UWcghx1oklagCm72aDvXm3CzKL2id7yL78X_V69JYsExx3fjRsU0pUe-f5lzKLB_HLTAdc0e1gQ=="
const verifier = crypto.createVerify('sha256')
verifier.write(key)
verifier.end()
const ok = verifier.verify(public_key, encodedSignature, 'base64')
if (ok) {
console.log('License key is valid!')
} else {
console.log('License key is invalid!')
}
运行这段代码(nodejs verify.js
)将打印License key is valid!
。
这是Python中失败的代码:
import base64
# pip install cryptodome
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
import Crypto.Signature.pkcs1_15
import Crypto.Util.Padding
public_key = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtmwlw+mDo2ZVBlRXa7Em\ncj7cVrlwnwrIPC+Ij5KpltadJfwvRFvCr37USJvkc+FIND2dKk2mmbY32cvtxl3F\nYLpjRwwlFuajbP8ZEdJl1YJyJDnLlKHWEfTSvTzZhpT939yjuBKoZ9A+wiIQ9tzY\nF/ytb9zwPkOF7/XmPAaukah5xRgwsb3fo7E0CsBQuHZxFX83+nfdZ/60MWpSCWL6\nAjNWDEmoLFEHVRm69+lwXTW51wojfurZy/wUw42sciHLV5A8mz7gJJGO5y+sGzzD\nM5VxtmLz51Fl1Rl3fMzUAjPK77i9UDWo11EuNPrzMAgjmuuMLfpIDMlMR3n/ZsW7\nXwIDAQAB\n-----END PUBLIC KEY-----\n"
license_key = b'somerandomkey'
encoded_license_signature = """oMTrvIz3IX4kre5UTzvkzCn712wulPvl9knSYBduYcGsX2W703zWMC9ZVepDytxLdpUIiCUtx6wx5OzmLx3rTzgaKqptrbf2wYHrCIPBgrhcHdJ3fLJRh8ASC_NdLK6i1jC_bEAq84d7QNLlTPC20aCmNLdxEJFy-DValGG0iFdxx6n6-Vp5oL8jSyWubAvBSqEQ4ubptcYirxpbDdC4DRpNzBuA48DGxWg6Pxq5HdGZWKS05iohNlrFkW-K8NJYHuLKszT0FN5UWcghx1oklagCm72aDvXm3CzKL2id7yL78X_V69JYsExx3fjRsU0pUe-f5lzKLB_HLTAdc0e1gQ=="""
license_signature = base64.b64decode(encoded_license_signature)
# Padding: none of these solutions work
# license_signature = Crypto.Util.Padding.pad(license_signature, 8, style='pkcs7')
# license_signature = Crypto.Util.Padding.pad(license_signature, 8, style='iso7816')
# license_signature = Crypto.Util.Padding.pad(license_signature, 8, style='x923')
# Custom zero-padding (doesn't work either)
#license_signature = (8 - len(license_signature) % 8)*bytes([0]) + license_signature
#license_signature = license_signature + (8 - len(license_signature) % 8)*bytes([0])
rsa_public_key = RSA.import_key(public_key)
signature = Crypto.Signature.pkcs1_15.new(rsa_public_key)
license_hash = SHA256.new(data=license_key)
print(signature.verify(license_hash, license_signature))
运行这段代码(python3 verify.py
)会引发错误:
Traceback (most recent call last):
File "verify.py", line 30, in <module>
print(signature.verify(license_hash, license_signature))
File "/home/user/venvs/tutor/lib/python3.6/site-packages/Crypto/Signature/pkcs1_15.py", line 111, in verify
raise ValueError("Invalid signature")
ValueError: Invalid signature
# Step 1
if len(signature) != k:
raise ValueError("Invalid signature")
我认为这是由不正确的填充引起的,因此我对签名填充进行了不同的尝试,您可以在我的代码段中看到这些尝试,但均无济于事。但是至少,它们使我超越了签名验证的第一步。我现在陷入了fourth and final step:
Traceback (most recent call last):
File "verify.py", line 30, in <module>
print(signature.verify(license_hash, license_signature))
File "/home/user/venvs/tutor/lib/python3.6/site-packages/Crypto/Signature/pkcs1_15.py", line 137, in verify
raise ValueError("Invalid signature")
ValueError: Invalid signature
任何想法如何解决这个问题?如有必要,我准备使用不同于cryptodome的东西。
答案 0 :(得分:2)
您的签名位于base64url中,而不是标准base64中。我认为后者是罪魁祸首。因此,您需要将-
替换为+
,并将_
替换为/
。或当然使用base64url解码器。
答案 1 :(得分:1)
我是Keygen的创始人。我这方面缺少适当的文档,我将予以纠正。像Maarten mentioned一样,许可证密钥的签名内容(包含两部分:密钥有效载荷及其签名)是使用RFC 4648(base64的URL安全版本,大多数编程支持)对base64url进行编码的语言(但并非总是如此)。如Maarten的答案所述,这种base64url编码方案与常规base64编码略有不同。
大多数编程语言都具有单独的功能来解码URL base64编码的值,
但如果不是这样,就像Maarten在他的回答中概述的那样,您可以简单地将所有“ -
” base64字符替换为“ +
”,并将所有“ _
”字符替换为“ {{1}” }”。
这是使用PKCS1 v1.5填充验证用RSA-SHA256签名的许可证密钥的完整示例:
/
我已经更新了Keygen的文档,以澄清所有这些问题,并提供有关如何以密码方式验证许可证的更好的示例。