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

PGP data encryption for use with Yubico OpenPGP Smart Card

我正在尝试在 Java 应用程序中实现基于 Yubikey NEO OpenPGP 智能卡小程序的 PGP 加密。这似乎是一门黑暗的艺术,google 这些东西并不容易,但这是我到目前为止的进展:

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

  2. 使用 javax.smartcardio API 连接到 USB 加密狗中的智能卡。

  3. Select 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)
    

    data = "xxxx".toByteArray()时,结果为SW=9000(=成功)但没有返回数据。这是一个天真的测试,因为第 52 页的 OpenPGP applet documentation 提到

    the command input (except padding indicator byte) shall be formatted according to PKCS#1 before encryption.

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

我也试过通读 Yubico OpenPGP card implementation tests but it only provides another "failing" example (line 196). I tried running that but the result is different: the test expects SW=0050 (indicating an exception?) and what I get is SW=6f00 (No precise diagnosis, according to this document)。

我用完整的代码创建了一个 GitHub repository。它是用 Kotlin 编写的,但应该很容易阅读。

你的问题有点混乱,但我很确定你想使用与智能卡上的 RSA 私钥相对应的 RSA 公钥创建 PGP 加密消息,然后使用智能卡上的 RSA 私钥来(帮助)解密它们。 PGP(几乎所有其他东西一样)使用混合加密,因此相关部分的 PGP 加密消息包括:

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

您不需要执行加密步骤,因为任何实现该标准的软件都可以这样做,包括 GnuPG 或 BouncyCastle 的 bcpg 库。如果您想自己做,也许对于使用伪造的 K 而没有真实消息的测试数据,您需要进行填充 and RSA 模幂运算;在 Java 中,至少 Oracle 或 openjdk Java 具有标准加密提供程序,您可以仅使用以通常方式通过 .getInstance("RSA/ECB/PKCS1Padding") 获得的 javax.crypto.Cipher

“PKCS1”加密填充(用于 RSA) 如该文档第 52 页底部和第 53 页顶部所述,其内容相同但格式不同到 current OpenPGP spec (and earlier), which refers to and is effectively identical to near-current PKCS#1 spec(及更早版本),所有这些都说它是:

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

注意段落开头

In case of the AES algorithm

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

By option (announced in Extended capabilities) the card supports the decryption of a plain text with an AES-key stored in a special DO (D5). This is useful if no certificate or public key exists and the external world has a common secret with the card.

所以忽略它。