如何使用PyKCS11库验证签名数据 [英] How to verify signed data with PyKCS11 Library

查看:187
本文介绍了如何使用PyKCS11库验证签名数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



这是我的脚本:

  import PyKCS11 
import getopt
import sys
import platform

red = blue = magenta = normal =
如果sys.stdout.isatty()和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字节+正常
format_normal =洋红+%s:+蓝色+ + normal

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

slots = pkcs11.getSlotList()
print可用插槽: ,len(slots)

#根据我的理解,我们只需要第一个槽
如果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已打开的会话0x%08X%session.session.value()
pin =12345678
session.login pin
objects = session.findObjects()
all_attributes = PyKCS11.CKA.keys()#SC $ b支持的所有键
$ b print定义KEY_GENERATION机制
mech = PyKCS11.Mechanism(PyKCS11.CKM_RSA_PKCS_KEY_PAIR_GEN,None)


printGenerating 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 ,PybCS.C.CK_TRUE),
(PyKCS11.CKA_WRAP,PyKCS11.CK_TRUE),
(PyKCS11.CKA_KEY_TYPE,PyKCS11.CKK_RSA),
(PyKCS11.CKA_VERIFY_RECOVER,PyKCS11.CK_TRUE) $ b(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)

# =============================
#签名数据
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)
打印signedData


# ============================
#现在我们必须使用私钥来验证signedData



session.logout()
session.closeSession()
printClose 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, 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, 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] 
/ pre>

解决方案

这段代码适用于我(注意,公共指数假设为3个字节长):

  import PyKCS11 
import getopt
import sys
import platform
import hashlib
从M2Crypto导入RSA

pkcs11 = PyKCS11.PyKCS11Lib()
lib_path =/opt/safenet/protecttoolkit5/ptk/lib/libcryptoki.so
pkcs11.load lib_path)
info = pkcs11.getInfo()
slots = pkcs11.getSlotList()
如果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 ,Py bCSK.CK_TRUE),
(PyKCS11.CKA_DECRYPT,PyKCS11.CK_TRUE),
(PyKCS11.CKA_TOKEN,PyKCS11.CK_TRUE),
$ b(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)
#=================== ===============================
#签名数据
binaryData =Hello world
#生成SHA1
sha1 = hashlib.sha1()
sha1.update(str(bytearray(binaryData)))
digest = sha1.digest()
#指示使用SHA1
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')
printVERIFY:+ str(result)


$ b b

我不是python,所以请把它作为概念的证明,而不是一个解决方案。对于有趣的部分:




  • 因为您的PKCS#11驱动程序不支持带有散列的RSA签名,哈希并手动构建 DigestInfo ASN.1部分(结果是 binaryData2 变量)


  • RSA.new_pub_key c $ c>接受 BN_mpi2bn (opens it's format)的元组在内部使用),需要在模块前面添加一个 \x00 ,以确保它被解释为正数('\给定函数


  • \\ x00 \x00 \x01 \x01\x00' verify()使用openssl的 RSA_verify 作为参数的签名数据(而不是数据本身)的摘要,它需要服从,并给它的摘要(从签名生成部分重复使用,你将不得不生成一个新的,如果你计划有单独的验证功能)







SHA256,您需要使用适当的digestInfo magic ASN.1字符串前缀(参见此处可用值)+正确的第三个验证调用参数的适当摘要对象。



运气!


I wrote a simple Python script which makes a digital signature using my smart card (Rutoken ECP SC), PKCS#11 library (implemented by my vendor) and PyKCS11 wrapper for Python. I already generated the private/public key pair using this card and created a signature using pkcs11 but I don't know how to verify this signed data. The problem is that my pkcs11 library (implemented in c++) has verification methods but PyKCS11 wrapper don't. And now I don't know how to solve this problem. I will be appreciated if anybody could tell me how to fix this problem.

That's my script:

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()

This is the output of the sign method:

[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]

解决方案

This code works for me (beware, the public exponent is assumed to be 3 bytes long):

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)

I am not into python, so please take it as a proof of concept and not as a solution. For the interesting parts:

  • as your PKCS#11 driver does not support RSA signature with a hash it is needed to calculate the hash and build the DigestInfo ASN.1 part manually (the result is in the binaryData2 variable)

  • as RSA.new_pub_key() accepts a tuple in openssl's format for BN_mpi2bn (which it uses internally), it was needed to prefix the modulus with one additional \x00 to ensure it is interpreted as a positive number (the '\x00\x00\x01\x01\x00' part)

  • given the function verify() uses openssl's RSA_verify which takes as an argument a digest of signed data (and not the data itself) it was needed to obey and give it the digest (which is re-used from the signature generation part and you would have to generate a fresh one if you plan to have a separate verify function)


Note: For e.g. SHA256, you would need to use the appropriate digestInfo magic ASN.1 string prefix (see here for usable values) + appropriate digest object from the hashlib + correct 3rd verify call argument.

Good luck!

这篇关于如何使用PyKCS11库验证签名数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆