我正在使用Python的pkcs11包来访问存储在Yubikey 5中的X.509证书。使用pkcs11对象访问证书,公用密钥和专用密钥与签名和签名验证一样工作正常。但是,对于我的一生,我无法弄清楚为什么使用公钥加密无法正常工作。这是我的代码:
import pkcs11
from pkcs11 import Attribute, ObjectClass, KeyType, util
lib = pkcs11.lib('/usr/lib/x86_64-linux-gnu/pkcs11/onepin-opensc-pkcs11.so')
token = lib.get_token(token_label='PIV Card Holder pin (PIV_II)'
session = token.open(user_pin=pin)
# Getting a private and a public key as pkcs11 Object
private = next(session.get_objects({
Attribute.CLASS: ObjectClass.PRIVATE_KEY,
}))
public = next(session.get_objects({
Attribute.CLASS: ObjectClass.PUBLIC_KEY,
}))
data = 'Hello, world!'
sig = private.sign(data) # Works!
sig_verif = public.verify(data, sig) # Works!
print("Signature is valid? "+str(sig_verif)) # True
# So far, everything above worked fine.
# ----------
# Now, this is the part that does not work
encrypt_data = public.encrypt(data) # Fails!
上面的最后一行失败,并出现 pkcs11.exceptions.FunctionNotSupported 错误。我做了一些研究,发现的解释似乎暗示我使用的openSC库文件(* .so)不支持此功能(加密)。但是,我很难相信考虑到签名功能就可以了。
为了确保可以在会话上下文之外使用此特定的公钥,我使用Crypto软件包尝试了以下代码:
from Crypto.Cipher import PKCS1_OAEP
public_key = RSA.importKey(public[Attribute.VALUE]) # The content of pkcs11 public key as DER
cipher = PKCS1_OAEP.new(public_key)
encr_data = cipher.encrypt(data) # This works!
因此,似乎使用我的独立公共密钥可以加密数据。但是,为什么不能在pkcs11令牌会话的上下文中执行此操作?
然后,我尝试使用pkcs11对象解密功能来尝试解密使用上述Crypto模块生成的数据:
decrypted = private.decrypt(encr_data) # It fails!
以上操作失败,并出现 pkcs11.exceptions.MechanismInvalid 错误。我尝试使用不同的机制,但所有机制均导致相同的错误。有趣的是-似乎pkcs11对象使我至少可以调用 decrypt 函数,而不必抱怨它不受支持。
我还要提一件事。我检查了证书,发现在扩展名->证书密钥用法下显示为:
Critical
Signing
Key Encipherment
我阅读了密钥加密和数据加密的区别,并了解到密钥加密用于加密秘密(对称)密钥而不是数据。这可能是我无法在此令牌会话中使用 encrypt 函数的原因吗?
任何反馈将不胜感激!
答案 0 :(得分:2)
很抱歉,但这只是API的一个缺点。由于使用公钥加密不需要任何安全性,因此在Yubikey上实现它没有任何意义。导出公钥值并在主机上执行加密要快得多。
说句公道话,Yubikey可能很好,并且可以在Ubikey PKCS#11库中的软件中实现该功能。如果确实需要,则可以创建一个新的PKCS#11“包装程序”库,其中确实包含软件中缺少的功能; Yubikey 执行执行的所有其他命令都可以转发到原始的Yubikey PKCS#11库。
答案 1 :(得分:1)
在进行了广泛的研究并考虑了该线程的答复后,我发现加密在此令牌会话中不起作用是由于OpenSC API的限制。实际上,在python-pkcs11页面上有一个compatibility table,以纯文本形式显示OpenSC不支持加密,对称密钥生成,密钥包装和其他功能。它完全支持签名/验证,部分支持解密。如果我做得更好,那将为我节省很多时间。
事实上,使用“ pkcs11-tool”进行硬令牌测试非常有用,因为它将显示每个PIV插槽支持的功能和机制。就我而言,我按如下方式调用它:
pkcs11-tool -p $pin -t
并收到以下报告:
Using slot 0 with a present token (0x0)
C_SeedRandom() and C_GenerateRandom():
seeding (C_SeedRandom) not supported
seems to be OK
Digests:
all 4 digest functions seem to work
MD5: OK
SHA-1: OK
RIPEMD160: OK
Signatures (currently only for RSA)
testing key 0 (PIV AUTH key)
all 4 signature functions seem to work
testing signature mechanisms:
RSA-X-509: OK
RSA-PKCS: OK
SHA1-RSA-PKCS: OK
MD5-RSA-PKCS: OK
RIPEMD160-RSA-PKCS: OK
SHA256-RSA-PKCS: OK
testing key 1 (2048 bits, label=SIGN key) with 1 signature mechanism
RSA-X-509: OK
testing key 2 (2048 bits, label=KEY MAN key) with 1 signature mechanism -- can't be used to sign/verify, skipping
Verify (currently only for RSA)
testing key 0 (PIV AUTH key)
RSA-X-509: OK
RSA-PKCS: OK
SHA1-RSA-PKCS: OK
MD5-RSA-PKCS: OK
RIPEMD160-RSA-PKCS: OK
testing key 1 (SIGN key) with 1 mechanism
RSA-X-509: OK
testing key 2 (KEY MAN key) with 1 mechanism -- can't be used to sign/verify, skipping
Unwrap: not implemented
Decryption (currently only for RSA)
testing key 0 (PIV AUTH key)
RSA-X-509: OK
RSA-PKCS: OK
testing key 1 (SIGN key)
RSA-X-509: OK
RSA-PKCS: OK
testing key 2 (KEY MAN key)
RSA-X-509: OK
RSA-PKCS: OK
No errors
从那里,我们可以看到所有三个占用的插槽都支持解密,但是仅使用RSA-X-509和RSA-PKCS机制(没有OAEP)。
现在,我正在考虑将pkcs11工具和openssl功能融合在一起以进行数据加密。我还没有弄清这种流程的所有复杂性,但是我在想this sort:
看来我应该能够在Linux shell中使用 pkcs11-tool 和 openssl 实用程序,或者在Python中使用 pkcs11 来实现这种解决方法。 em>和 OpenSSL 库。如果我决定以后再通过GUI进行操作,则后者似乎更可取。这一切似乎都还很低,所以我想知道是否有更简单的方法来加密/解密数据。我知道PGP将加密的数据和包装好的密钥融合到一个文件中,因此最终用户只需要在其末端执行一个命令即可。