是的你可以。此示例使用openssl smime具有 40 位密钥的默认 RC2 CBC。较新的cms子命令的行为略有不同,默认使用 3-DES。您可能不应该使用其中任何一种算法来加密重要数据;-)
有两个小警告:首先,我还将使用其他一些工具(尽管所有繁重的工作都使用OpenSSL),其次,我将对电子邮件的加密方式做出一些假设。
加密/解密与大多数使用 RSA 的方法一致:使用(缓慢、昂贵的)RSA 加密/解密对称密钥,使用快速对称密钥加密/解密真实数据。(有关更多背景信息,请参阅此问题或此问题)。
获取您的电子邮件,提取 P7M 部分,然后对其进行解码。如果你有一个.p7mbase64 编码的部分,你可以很容易地做到这一点metamail:
$ metamail -wy enc_mail.eml
保存 P7M 文件。这是一个ASN.1 DER 编码的CMS (PKCS#7) 文件,所以我们可以窥视一下:
$ dumpasn1 -tilda smime.p7m
0 1946: SEQUENCE {
4 9: . OBJECT IDENTIFIER envelopedData (1 2 840 113549 1 7 3)
: . . (PKCS #7)
15 1931: . [0] {
[ .. certificate details and whatnot omitted ...]
188 13: . . . . . SEQUENCE {
190 9: . . . . . . OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
: . . . . . . . (PKCS #1)
201 0: . . . . . . NULL
: . . . . . . }
203 256: . . . . . OCTET STRING
: . . . . . . A0 DA EA FB EA 1A 0F 81 ........
: . . . . . . F4 30 9F 78 5C 9B A7 27 .0.x\..'
[ ... blob snipped ...]
463 1483: . . . SEQUENCE {
467 9: . . . . OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
: . . . . . (PKCS #7)
478 26: . . . . SEQUENCE {
480 8: . . . . . OBJECT IDENTIFIER rc2CBC (1 2 840 113549 3 2)
: . . . . . . (RSADSI encryptionAlgorithm)
490 14: . . . . . SEQUENCE {
492 2: . . . . . . INTEGER 160
496 8: . . . . . . OCTET STRING 3E EA 0E 12 37 A8 56 70
: . . . . . . }
: . . . . . }
506 1440: . . . . [0]
: . . . . . A5 FF A1 70 2C AD 82 6A ...p,..j
: . . . . . C7 F0 84 E8 9E 93 8F 53 .......S
[... blob snipped ...]
我使用它是dumpasn1因为openssl asn1parse不愿意显示或转储我们感兴趣的各种 blob。当然,您的电子邮件结构会与上述不同。第 1 列和第 2 列是每个(可能是嵌套的)子结构的偏移量和大小。
有趣的部分在偏移处:
- 188 RSA 加密细节,在偏移量203之后是加密数据
- 463 S/MIME 加密细节和参数 (RC2 CBC)
- 506加密的 blob
在偏移量 188 处,我们可以看到使用了 RSA,然后是 256 字节的数据,因此提取该数据块(偏移量 203)并将其转换为二进制:
$ dumpasn1 -a -203 smime.p7m | tail -qn +2 | xxd -r -p > rsa.bin
(注意起始偏移-203和使用tail跳过输出的第一行。这有点令人费解,但不幸的是,当您尝试对对象进行切片和切块时,两者都dumpasn1保持openssl asn1parse类型长度前缀不变。)
使用 RSA 解密此数据:
$ openssl rsautl -inkey recip_priv.pem -in rsa.bin -decrypt -out rc2key.bin
$ xxd -u -p rc2key.bin
92F6EB53B1
在这种情况下,我们得到 5 个字节(40 位)的输出,即我们需要的对称密钥。由于各种原因,输入是PKCS#1 v1.5填充(参见第 8.1 节),因此存在大小差异。
主要有效负载(电子邮件)位于偏移量 506 的 blob 中,将其提取到文件中:
$ dumpasn1 -a -506 smime.p7m | tail -qn +2 | xxd -r -p > email.bin
现在这里有点棘手,对于 RC2,请参阅RFC 2268的第 6 节:
rc2CBC OBJECT IDENTIFIER
::= {iso(1) member-body(2) US(840) rsadsi(113549)
encryptionAlgorithm(3) 2}
RC2-CBCParameter ::= CHOICE {
iv IV,
params SEQUENCE {
version RC2Version,
iv IV
}
}
RC2Version ::= INTEGER -- 1-1024
IV ::= OCTET STRING -- 8 octets
这解释了偏移量 490 处的数据结构:
480 8: . . . . . OBJECT IDENTIFIER rc2CBC (1 2 840 113549 3 2)
: . . . . . . (RSADSI encryptionAlgorithm)
490 14: . . . . . SEQUENCE {
492 2: . . . . . . INTEGER 160
496 8: . . . . . . OCTET STRING 3E EA 0E 12 37 A8 56 70
: . . . . . . }
(您可以确认 RC2Version 160 (0xa0) 与 EKB 表中的密钥大小 40 位 (0x28) 匹配。)
因此,将它们放在一起:S/MIME 加密算法(RC2 40 位 CBC,偏移量 480)、RC2 密钥(从偏移量 203 处的 blob 解密)、RC2 IV(未加密,偏移量 496)和加密的有效负载(偏移量 506):
$ openssl enc -d -rc2-40-cbc -in email.bin -out email.txt -K 92F6EB53B1 -iv 3EEA0E1237A85670
email.txt应该是你要找的。
尖端:
- 确保不要使用旧版本的
xxd,它可能会破坏输入的十六进制数据
- 结构、大小和偏移量当然会因消息、密钥和算法而异
- 我发现
openssl enc -kfile ...不行,坚持-K
openssl smime 可能在加密之前修改了您的消息(CRLF要求)
berdump是一个方便的工具,因为它的输出更适合进一步处理。由于 DER 是 BER 的子集,您可以将其直接指向 PKCS#7 DER 文件