用于Yubico OpenPGP智能卡的PGP数据加密

2022-09-04 22:53:44

我正在尝试在Java应用程序中实现基于Yubikey NEO OpenPGP智能卡小程序的PGP加密。这似乎是一种黑暗艺术,在谷歌上搜索这些东西并不容易,但这是我到目前为止得到的地方:

  1. 卡已初始化,密钥使用gpg工具生成。它通常有效。我有我的公钥格式,并设法将其加载到.ascorg.bouncycastle.openpgp

  2. 使用 API 连接到 USB 硬件保护装置中的智能卡。javax.smartcardio

  3. 选择 OpenPGP 小程序

    val pgpAID = bytes(0xD2, 0x76, 0x00, 0x01, 0x24, 0x01)
    val answer = cardChannel.transmit(CommandAPDU(0x00, 0xA4, 0x04, 0x00, pgpAID))
    
  4. 成功向卡出示正确的 PIN 码

    val pin = "123456"
    return bytes(0x00, 0x20, 0x00, 0x82, pin.length) + pin.toByteArray(Charsets.UTF_8)
    
  5. 发送准成功(见下文)命令decipher

    bytes(0x00, 0x2a, 0x80, 0x86, data.size) + data + bytes(0x00)
    

    当 时,结果为 (= 成功),但不返回任何数据。这是一个幼稚的测试,因为第52页上的OpenPGP小程序文档提到data = "xxxx".toByteArray()SW=9000

    命令输入(填充指示符字节除外)应在加密前根据 PKCS#1 进行格式化。

我不知道如何加密数据并将其转换为PKCS#1格式。

我还尝试阅读Yubico OpenPGP卡实现测试,但它只提供了另一个“失败”的例子(第196行)。我尝试运行它,但结果是不同的:测试期望(指示异常?)并且我得到的是(根据本文档,没有精确的诊断)。SW=0050SW=6f00

我用整个代码创建了一个GitHub存储库。它是用 Kotlin 编写的,但应该易于阅读。


答案 1

您的问题有些混乱,但我非常确定您希望使用与智能卡上的RSA私钥相对应的RSA公钥创建PGP加密消息,然后使用智能卡上的RSA私钥(帮助)解密它们。PGP(与其他所有内容一样)使用混合加密,因此相关部分中的PGP加密消息包括:

  • 使用随机生成的工作密钥使用适当的对称算法(如TDES或AES)加密的实际消息,称为K
  • 工作密钥K加上RSA使用收件人的公钥加密的一些元数据和原始PKCS#1标准定义的填充,现在正式称为RSAES-PKCS1-v1_5但仍然被广泛称为PKCS1。

你不需要做加密步骤,因为任何实现该标准的软件都可以这样做,包括GnuPG或BouncyCastle的库。如果你想自己做,也许对于使用伪造的K并且没有真实消息的测试数据,你需要做填充RSA模块化幂;在Java中,至少Oracle或openjdk Java与标准加密提供程序,你可以用通常的方式使用一个获取的。bcpgjavax.crypto.Cipher.getInstance("RSA/ECB/PKCS1Padding")

“PKCS1”加密填充(用于RSA)如该文档的第52页底部和第53页的顶部所述,其内容与当前的OpenPGP规范(及更早版本)不同,但格式相同,它引用并有效地与接近当前的PKCS#1规范(及更早版本)相同,所有这些都说它是:

  • 1 字节 00
  • 一个字节 02
  • 足够的非零随机字节,以使结果具有正确的长度并且是安全的
  • 1 字节 00
  • “明文”,对于PGP加密,它实际上是PGP规范中指定的格式化的工作对称密钥K。

请注意段落开头

在 AES 算法的情况下

似乎用于不同的选项,而不是PGP AFAICS,在上一页中描述为

通过选项(在扩展功能中宣布),该卡支持使用存储在特殊DO(D5)中的AES密钥解密纯文本。如果不存在证书或公钥,并且外部世界与卡具有共同的机密,则这很有用。

所以忽略它。


答案 2

推荐