How to verify signed data with PyKCS11 Library

一笑奈何 提交于 2019-12-04 17:12:20

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!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!