Python 如何使用PyKCS11库验证签名数据

Python 如何使用PyKCS11库验证签名数据,python,c++,smartcard,pkcs#11,Python,C++,Smartcard,Pkcs#11,我编写了一个简单的Python脚本,它使用我的智能卡(Rutoken ECP SC)、PKCS#11库(由我的供应商实现)和Python的PyKCS11包装器生成数字签名。 我已经使用该卡生成了私钥/公钥对,并使用pkcs11创建了签名,但我不知道如何验证该签名数据。 问题是我的pkcs11库(用c++实现)有验证方法,但PyKCS11包装器没有。现在我不知道如何解决这个问题。如果有人能告诉我如何解决这个问题,我将不胜感激 这就是我的剧本: import PyKCS11 import getop

我编写了一个简单的Python脚本,它使用我的智能卡(Rutoken ECP SC)、PKCS#11库(由我的供应商实现)和Python的PyKCS11包装器生成数字签名。 我已经使用该卡生成了私钥/公钥对,并使用pkcs11创建了签名,但我不知道如何验证该签名数据。 问题是我的pkcs11库(用c++实现)有验证方法,但PyKCS11包装器没有。现在我不知道如何解决这个问题。如果有人能告诉我如何解决这个问题,我将不胜感激

这就是我的剧本:

import PyKCS11
import getopt
import sys
import platform

red = blue = magenta = normal = ""
if sys.stdout.isatty() and platform.system().lower() != 'windows':
    red = "\x1b[01;31m"
    blue = "\x1b[34m"
    magenta = "\x1b[35m"
    normal = "\x1b[0m"

format_long = magenta + "  %s:" + blue + " %s (%s)" + normal
format_binary = magenta + "  %s:" + blue + " %d bytes" + normal
format_normal = magenta + "  %s:" + blue + " %s" + normal

pkcs11 = PyKCS11.PyKCS11Lib()
lib_path = "/usr/lib/pkcs11-arm/rtpkcs11ecp/librtpkcs11ecp.so"
pkcs11.load(lib_path)
info = pkcs11.getInfo()
print "Library manufacturerID: " + info.manufacturerID

slots = pkcs11.getSlotList()
print "Available Slots:", len(slots)

# As I understand we need only first slot
if len(slots) > 0:
    slot = slots[0]
    slotInfo = pkcs11.getSlotInfo(slot)
    tokenInfo = pkcs11.getTokenInfo(slot)

    flags = PyKCS11.CKF_RW_SESSION
    session = pkcs11.openSession(slot, flags)
    print "Opened session 0x%08X" % session.session.value()
    pin = "12345678"
    session.login(pin)
    objects = session.findObjects()                
    all_attributes = PyKCS11.CKA.keys()             # all keys supported by SC

    print "Defining KEY_GENERATION mechanism"
    mech = PyKCS11.Mechanism(PyKCS11.CKM_RSA_PKCS_KEY_PAIR_GEN, None)


    print "Generating key"
    public_template = [
        (PyKCS11.CKA_CLASS, PyKCS11.CKO_PUBLIC_KEY),
        (PyKCS11.CKA_PRIVATE, PyKCS11.CK_FALSE),
        (PyKCS11.CKA_TOKEN, PyKCS11.CK_TRUE),
        (PyKCS11.CKA_ENCRYPT, PyKCS11.CK_TRUE),
        (PyKCS11.CKA_VERIFY, PyKCS11.CK_TRUE),
        (PyKCS11.CKA_WRAP, PyKCS11.CK_TRUE),
        (PyKCS11.CKA_KEY_TYPE, PyKCS11.CKK_RSA),
        (PyKCS11.CKA_VERIFY_RECOVER, PyKCS11.CK_TRUE),
        (PyKCS11.CKA_MODULUS_BITS, 2048),
    ]

    private_template = [
        (PyKCS11.CKA_CLASS, PyKCS11.CKO_PRIVATE_KEY),
        (PyKCS11.CKA_PRIVATE, PyKCS11.CK_TRUE),
        (PyKCS11.CKA_TOKEN, PyKCS11.CK_TRUE),
        (PyKCS11.CKA_DECRYPT, PyKCS11.CK_TRUE),
        (PyKCS11.CKA_SIGN, PyKCS11.CK_TRUE),
        (PyKCS11.CKA_UNWRAP, PyKCS11.CK_TRUE)
        ]

    (pub, priv) = session.generateKeyPair(public_template, private_template, mech)

    # ==================================================
    # Signing data
    sourceText = "Hello World"
    binaryData = ' '.join(format(ord(x), 'b') for x in sourceText)

    signMechanism = PyKCS11.Mechanism(PyKCS11.CKM_RSA_PKCS, None)
    signedData = session.sign(priv, binaryData, signMechanism)
    print signedData


    #====================================================
    # now we have to verify signedData using the private key



    session.logout()
    session.closeSession()
    print "Close session 0x%08X" % session.session.value()
这是sign方法的输出:

[83L, 29L, 52L, 93L, 228L, 220L, 13L, 187L, 224L, 212L, 112L, 204L, 198L, 91L, 207L, 6L, 215L, 38L, 233L, 194L, 252L, 140L, 106L, 62L, 69L, 94L, 252L, 89L, 194L, 18L, 58L, 240L, 174L, 2L, 26L, 212L, 152L, 134L, 40L, 67L, 163L, 53L, 226L, 74L, 15L, 47L, 200L, 131L, 58L, 199L, 22L, 103L, 145L, 235L, 196L, 117L, 196L, 78L, 160L, 223L, 118L, 0L, 147L, 91L, 9L, 146L, 218L, 142L, 1L, 47L, 192L, 20L, 96L, 230L, 77L, 242L, 124L, 232L, 77L, 130L, 207L, 226L, 165L, 108L, 241L, 198L, 33L, 9L, 79L, 238L, 35L, 53L, 127L, 31L, 118L, 167L, 4L, 84L, 158L, 98L, 171L, 37L, 221L, 208L, 80L, 17L, 142L, 61L, 207L, 204L, 17L, 94L, 38L, 136L, 44L, 161L, 191L, 131L, 237L, 213L, 108L, 175L, 14L, 31L, 61L, 2L, 85L, 6L, 104L, 226L, 201L, 71L, 141L, 243L, 72L, 2L, 142L, 83L, 87L, 140L, 1L, 83L, 26L, 93L, 96L, 96L, 207L, 217L, 222L, 168L, 78L, 221L, 158L, 199L, 213L, 82L, 212L, 45L, 62L, 14L, 22L, 128L, 68L, 76L, 205L, 247L, 124L, 23L, 69L, 123L, 68L, 116L, 239L, 49L, 130L, 207L, 43L, 194L, 9L, 4L, 55L, 35L, 51L, 21L, 233L, 198L, 121L, 212L, 61L, 244L, 117L, 98L, 174L, 173L, 209L, 252L, 218L, 51L, 63L, 217L, 160L, 18L, 45L, 167L, 161L, 79L, 10L, 130L, 80L, 63L, 234L, 48L, 155L, 66L, 84L, 116L, 186L, 42L, 119L, 250L, 177L, 206L, 90L, 117L, 159L, 98L, 165L, 70L, 141L, 39L, 108L, 212L, 33L, 20L, 163L, 181L, 113L, 177L, 201L, 129L, 108L, 182L, 94L, 14L, 200L, 213L, 22L, 29L, 182L, 45L, 16L, 242L, 227L, 242L, 192L, 42L]
这段代码适合我(注意,公共指数假定为3字节长):

我不喜欢python,所以请将其作为概念证明,而不是解决方案。对于有趣的部分:

  • 由于PKCS#11驱动程序不支持带有散列的RSA签名,因此需要计算散列并手动构建散列(结果在
    binaryData2
    变量中)

  • 由于
    RSA.new\u pub\u key()
    接受openssl格式的元组(内部使用),因此需要在模数前面加上一个额外的
    \x00
    ,以确保它被解释为正数(
    '\x00\x00\x01\x01\x00'
    部分)

  • 给定函数
    verify()
    使用openssl,该函数将签名数据的摘要(而不是数据本身)作为参数,它需要遵守并为其提供摘要(该摘要从签名生成部分重复使用,如果您计划使用单独的verify函数,则必须生成一个新的摘要)


注意:对于例如SHA256,您需要使用适当的digestInfo magic ASN.1字符串前缀(有关可用值,请参阅)+来自hashlib的适当摘要对象+正确的第三个验证调用参数


祝你好运

(理论上)由于公钥不敏感,您可以在不使用令牌的情况下验证签名(参见示例)。您需要首先提取公钥(通过<代码> CGGETAtQuestValue<代码> > <代码> CKAAYMAME> 和<代码> CKAYPuffyPosivs<代码>。另外,请考虑使用一些RSA签名变体与摘要(例如:代码> CKMYSH256YRSAYPKCS < /代码>或任何其他代码> CKM**YRSAYPKCS < /代码>一)。并确保您的签名/验证算法变体匹配。谢谢您的回复,@vlp。我会尝试测试这个idea@Tequila如果这是可行的,让vlp发布一个答案(没有理由不这样做)。如果愿意,您可以随时在以后添加代码。您可能还想阅读PKCS#11中签名算法的更多信息。要获取(一些)公钥:
RSA.new#u pub#key(“\x00\x00\x01\x00\xc4\x61\xb0\xb8\x39\xe1\xc0\x99.”跳过…\xdc\xfa\x85',“\x00\x00\x00\x03\x01\x00\x01”)
,这对我有效(请参阅和)。对于代码,我不太喜欢Python…抱歉PS:请考虑使用<代码> CKMySa1O-RSAYPKCs<代码>,而不是<代码> CKMYRSAYPKCS,作为M2CHICOTE的<代码> RSA。ValIFy()<代码>似乎需要一个摘要(Sa1是默认的)…祝你们好运!PS2:你得到的公钥参数看起来不错。哇,它工作了!你是怎么做到的?)今天是个好消息!非常感谢你!我几乎在C++上写了这个签名机制,但是在你的帮助下,现在不必了)你能推荐一些关于这些东西的书或资源吗?如果这些文献有俄语翻译(如果我不是你说俄语的话),那就太好了。非常感谢@龙舌兰酒我很高兴它管用!关于资源…谷歌?祝你的项目好运!
import PyKCS11
import getopt
import sys
import platform
import hashlib
from M2Crypto import RSA

pkcs11 = PyKCS11.PyKCS11Lib()
lib_path = "/opt/safenet/protecttoolkit5/ptk/lib/libcryptoki.so"
pkcs11.load(lib_path)
info = pkcs11.getInfo()
slots = pkcs11.getSlotList()
if len(slots) > 0:
    session = pkcs11.openSession(slots[0], PyKCS11.CKF_RW_SESSION)
    session.login("12345678")
    mech = PyKCS11.Mechanism(PyKCS11.CKM_RSA_PKCS_KEY_PAIR_GEN, None)
    public_template = [
        (PyKCS11.CKA_CLASS, PyKCS11.CKO_PUBLIC_KEY),
        (PyKCS11.CKA_PRIVATE, PyKCS11.CK_FALSE),
        (PyKCS11.CKA_TOKEN, PyKCS11.CK_TRUE),
        (PyKCS11.CKA_ENCRYPT, PyKCS11.CK_TRUE),
        (PyKCS11.CKA_VERIFY, PyKCS11.CK_TRUE),
        (PyKCS11.CKA_WRAP, PyKCS11.CK_TRUE),
        (PyKCS11.CKA_KEY_TYPE, PyKCS11.CKK_RSA),
        (PyKCS11.CKA_VERIFY_RECOVER, PyKCS11.CK_TRUE),
        (PyKCS11.CKA_MODULUS_BITS, 2048),
    ]
    private_template = [
        (PyKCS11.CKA_CLASS, PyKCS11.CKO_PRIVATE_KEY),
        (PyKCS11.CKA_PRIVATE, PyKCS11.CK_TRUE),
        (PyKCS11.CKA_TOKEN, PyKCS11.CK_TRUE),
        (PyKCS11.CKA_DECRYPT, PyKCS11.CK_TRUE),
        (PyKCS11.CKA_SIGN, PyKCS11.CK_TRUE),
        (PyKCS11.CKA_UNWRAP, PyKCS11.CK_TRUE)
        ]
    (pub, priv) = session.generateKeyPair(public_template, private_template, mech)
    (pubExp,pubModulus) = session.getAttributeValue(pub,[PyKCS11.CKA_PUBLIC_EXPONENT,PyKCS11.CKA_MODULUS], True)
    # ==================================================
    # Signing data
    binaryData = "Hello world"
    # Generate SHA1
    sha1 = hashlib.sha1()
    sha1.update(str(bytearray(binaryData)))
    digest=sha1.digest()
    # Indicate SHA1 is used
    binaryData2='\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14'+digest
    signMechanism = PyKCS11.Mechanism(PyKCS11.CKM_RSA_PKCS, None)
    signedData = session.sign(priv, binaryData2, signMechanism)
    session.logout()
    session.closeSession()
    # ==================================================
    # Verify
    pubkey = RSA.new_pub_key(('\x00\x00\x00\x03' + str(bytearray(pubExp)), '\x00\x00\x01\x01\x00'+str(bytearray(pubModulus))))
    result=pubkey.verify(str(bytearray(digest)), str(bytearray(signedData)), 'sha1')
    print "VERIFY:" + str(result)