【问题标题】:Encrypting a data with a public key using pkcs11 module fails使用 pkcs11 模块使用公钥加密数据失败
【发布时间】:2020-02-23 07:39:43
【问题描述】:

我正在使用 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 函数而不会抱怨它不受支持。

我还要提一件事。我检查了我的证书,在 Extension -> Certificate Key Usage 下看到,它说:

Critical
Signing
Key Encipherment

我阅读了 key enciphermentdata encipherment 之间的区别,并了解到 key encipherment 用于加密秘密(对称)密钥而不是数据。这可能是我无法在此令牌会话中使用 encrypt 功能的原因吗?

任何反馈将不胜感激!

【问题讨论】:

  • 令牌中的每个对象都具有某些属性,这些属性定义了对象的用途。您应该查看的属性是EncryptDecrypt。是否为您尝试加密操作的公钥启用了这些功能?
  • @always_a_rookie_to_learn:我检查了 ''public[Attribute.ENCRYPT]'' 并且它返回 True,所以我猜它在这个对象中启用了。

标签: python smartcard public-key-encryption pkcs#11 opensc


【解决方案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-tool 和 openssl 功能来进行数据加密。我还没有弄清楚这种流程的所有复杂性,但我在想this sort

  1. (pkcs11-tool) 从所需的 PIV 插槽导出证书
  2. (openssl) 创建对称(例如 AES)密钥
  3. (openssl) 使用此密钥加密数据
  4. (openssl) 使用步骤 1 中的证书加密密钥
  5. 将 [对称] 加密数据和 [非对称] 加密密钥发送给收件人
  6. (pkcs11-tool) 解密安全令牌上的密钥
  7. (openssl) 使用解密后的密钥解密实际数据

看起来我应该能够在 Linux shell 中使用 pkcs11-toolopenssl 实用程序或在 Python 中使用 pkcs11 em> 和 OpenSSL 库。如果我决定稍后通过 GUI 执行此操作,后者似乎更可取。这一切似乎都很低级,所以我想知道是否有更简单的方法来加密/解密数据。我知道 PGP 将加密数据和打包的密钥融合到一个文件中,因此最终用户只需在他们的一端执行一个命令。

【讨论】:

  • 在为 X.509 相关密钥管理 (PKIX) 选择容器格式时,我们通常使用加密消息语法。 PGP 主要使用它自己的数据结构并使用完全不同的 PKI 结构。
  • @Maarten,我读到了 CMS,似乎 Python 有一些库可以让我创建或读取 CMS/PKCS#7 数据。当我在等式中添加智能卡时,它有点复杂,我希望有一个简单的例子让我开始做这件事。现在,我可以在 shell 中使用 openssl cms / engine 实用程序来完成。
【解决方案2】:

对不起,我认为这只是 API 的一个缺点。由于使用公钥加密不需要任何安全性,因此在 Yubikey 上实现它是没有意义的。导出公钥值并在主机上执行加密要快得多。

公平地说,Yubikey 本来可以很好地在 Ubikey PKCS#11 库中的软件中实现该功能。如果你真的想要,那么你可以创建一个新的 PKCS#11“包装器”库,确实包含软件中缺少的功能; Yubikey 执行 实现的所有其他命令都可以转发到原始的 Yubikey PKCS#11 库。

【讨论】:

  • @Maarten_Bodewes,是的,你完全正确。自从我的原始帖子以来,我进行了大量研究,现在我确信这确实是 OpenSC API 的缺点。似乎这些缺点不在于任何特定的硬件令牌(例如 Yubikey、Nitrokey、Gemalto 等),而是不完整的 API 本身。感谢您的反馈!
  • @ProtoUkr 请注意,OpenSC 在构建时考虑了智能卡。那些更不可能实现加密功能;公钥通常隐藏在某些证书中,智能卡不知道。这些东西大多不支持X.509解析......
猜你喜欢
  • 1970-01-01
  • 2011-01-28
  • 2018-02-26
  • 2022-10-23
  • 1970-01-01
  • 2015-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多