用于 Yubico OpenPGP 智能卡的 PGP 数据加密
PGP data encryption for use with Yubico OpenPGP Smart Card
我正在尝试在 Java 应用程序中实现基于 Yubikey NEO OpenPGP 智能卡小程序的 PGP 加密。这似乎是一门黑暗的艺术,google 这些东西并不容易,但这是我到目前为止的进展:
卡已初始化,使用gpg工具生成密钥。它通常有效。我有 .asc
格式的 public 密钥,并设法将其加载到 org.bouncycastle.openpgp
使用 javax.smartcardio
API 连接到 USB 加密狗中的智能卡。
Select OpenPGP 小程序
val pgpAID = bytes(0xD2, 0x76, 0x00, 0x01, 0x24, 0x01)
val answer = cardChannel.transmit(CommandAPDU(0x00, 0xA4, 0x04, 0x00, pgpAID))
成功向卡输入正确的 PIN
val pin = "123456"
return bytes(0x00, 0x20, 0x00, 0x82, pin.length) + pin.toByteArray(Charsets.UTF_8)
发送准成功(见下文)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.
所以忽略它。
我正在尝试在 Java 应用程序中实现基于 Yubikey NEO OpenPGP 智能卡小程序的 PGP 加密。这似乎是一门黑暗的艺术,google 这些东西并不容易,但这是我到目前为止的进展:
卡已初始化,使用gpg工具生成密钥。它通常有效。我有
.asc
格式的 public 密钥,并设法将其加载到org.bouncycastle.openpgp
使用
javax.smartcardio
API 连接到 USB 加密狗中的智能卡。Select OpenPGP 小程序
val pgpAID = bytes(0xD2, 0x76, 0x00, 0x01, 0x24, 0x01) val answer = cardChannel.transmit(CommandAPDU(0x00, 0xA4, 0x04, 0x00, pgpAID))
成功向卡输入正确的 PIN
val pin = "123456" return bytes(0x00, 0x20, 0x00, 0x82, pin.length) + pin.toByteArray(Charsets.UTF_8)
发送准成功(见下文)
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.
所以忽略它。