一、格式

PEM(Privacy Enhanced Mail)是一种用于存储和传输加密对象的文件格式。

外观特征

1
2
3
-----BEGIN <LABEL>-----
Base64 编码的数据(每行 64 字符)
-----END <LABEL>-----

常见类型

  • -----BEGIN PUBLIC KEY-----:公钥

包含:n、e

  • -----BEGIN RSA PUBLIC KEY-----:RSA 公钥(较老格式,较少见)

包含:n、e

  • -----BEGIN PRIVATE KEY-----:PKCS#8 通用 私钥
  • -----BEGIN (RSA) PRIVATE KEY-----:PKCS#1 RSA 私钥
  • -----BEGIN CERTIFICATE-----:X.509 证书(其中包含公钥

生成公私钥:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from Crypto.PublicKey import RSA
from Crypto.Util.number import *
p,q=getPrime(512),getPrime(512)
n=p*q
e=0x10001
pub=RSA.construct((n,e))
with open('out.pem','wb') as f:
f.write(pub.exportKey('PEM'))
with open('out.pem','rb') as f:
print(f.read().decode())
from Crypto.PublicKey import RSA
from Crypto.Util.number import *
p,q = getPrime(512),getPrime(512)
n = p * q
e = 0x10001
d = inverse(e,(p - 1) * (q - 1))
pub = RSA.construct((n,e,d,p,q))
with open('out.pem','wb') as f:
f.write(pub.exportKey('PEM'))
with open('out.pem','rb') as f:
print(f.read().decode())

在python中利用公私钥文件,通过PKCS1_OAEP算法填充实现加解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Util.number import *
flag = b'This_is_a_message_qwer'

key = RSA.generate(1024)
pub = key.publickey().exportKey()
public_key = RSA.importKey(pub)
pk = PKCS1_OAEP.new(public_key)
enc = pk.encrypt(flag)
print(enc)

priv = key.exportKey()
priv_key = RSA.importKey(priv)
sk = PKCS1_OAEP.new(priv_key)
msg = sk.decrypt(enc)
print(msg)

二、OpenSSL

公钥文件

由私钥生成公钥:

1
2
openssl rsa -in private.pem -pubout -out public.pem
openssl rsa -in private.pem -RSAPublicKey_out -out public_rsa.pem

解析公钥文件:

1
openssl rsa -pubin -in public.pem -text -noout

只提取n:

1
openssl rsa -pubin -in public.pem -modulus -noout

转换为十进制:

1
print(int('ABCD',16))

私钥文件

生成传统的 PKCS#1 RSA 私钥文件:

1
2
openssl genrsa -out private.pem 2048
openssl genrsa -aes256 -out private_enc.pem 2048

生成 PKCS#8 通用 私钥文件:

1
openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen_bits:2048

解析私钥文件:

1
openssl rsa -in private.pem -text -noout
  • modulus (n)
  • publicExponent (e)
  • privateExponent (d)
  • prime1 (p)
  • prime2 (q)
  • exponent1 (d mod (p-1))
  • exponent2 (d mod (q-1))
  • coefficient (q^{-1} mod p)

给私钥文件加密:

1
openssl rsa -aes256 -in private.pem -out encrypted_private.pem

执行后提示输入两次密码,生成的 encrypted_private.pem 文件头部会多出Proc-Type: 4,ENCRYPTED 和加密参数

证书

1
openssl x509 -in cert.pem -text -noout

内容:

  • 版本号、序列号
  • 签名算法
  • 颁发者 (Issuer)
  • 有效期 (Validity)
  • 主体 (Subject) —— 这就是证书持有者
  • 公钥信息 (Subject Public Key Info) ——RSA中的n和e

提取公钥:

1
openssl x509 -in cert.pem -pubkey -noout > public.pem

格式转换

1
2
3
openssl pkcs8 -topk8 -inform PEM -in private_pkcs1.pem -outform PEM -out private_pkcs8.pem -nocrypt
openssl rsa -in private_pkcs8.pem -out private_pkcs1.pem
openssl rsa -pubin -in public_pkcs8.pem -RSAPublicKey_out -out public_pkcs1.pem

加密与解密

1
2
openssl pkeyutl -encrypt -pubin -inkey public.pem -in plain.txt -out cipher.bin
openssl pkeyutl -decrypt -inkey private.pem -in cipher.bin -out plain.txt

签名与验证

1
2
openssl dgst -sha256 -sign private.pem -out signature.bin data.txt
openssl dgst -sha256 -verify public.pem -signature signature.bin data.txt

常见问题

  • “Can’t open file”:检查路径,避免中文或空格,可用双引号包裹。

  • “RSA operation error”:可能填充方式不匹配,或私钥/公钥不对应,或密文损坏。

  • “Expecting: RSA PRIVATE KEY”:私钥格式不兼容,可使用 openssl rsa -in key.pem -check 查看,必要时转换格式


三、损坏的pem文件

标记错误

当报错时:

1
unable to load Public Key

判断正确格式:

1
openssl asn1parse -inform PEM -in public.pem

观察 ASN.1 结构

  • PKCS#1 公钥:一个 SEQUENCE,包含两个 INTEGER(n, e)。
  • PKCS#8 公钥:SEQUENCE 包含算法 OID 和 BIT STRING,BIT STRING 内部是 PKCS#1 公钥。
  • PKCS#1 私钥:包含 version, n, e, d, p, q 等。
  • PKCS#8 私钥:包含 version, algorithm, 私钥数据(OCTET STRING 内嵌 PKCS#1 私钥)。

如果报错,可以先去掉头尾,只保留 Base64 部分,然后用 openssl asn1parse -inform DER -in data.bin 查看

Base64编码错误

包含多余空格、不规则换行、非法字符

1
2
# 去除所有空白字符(包括换行、空格、制表符),但保留字母数字+/=
tr -d ' \t\n\r' < broken.pem > cleaned.b64

私钥加密

文件头有Proc-Type: 4,ENCRYPTEDDEK-Info: AES-256-CBC,<IV>

如果密码比较弱(简单单子数字),字典爆破:

1
openssl rsa -in encrypted.pem -passin pass:password -out decrypted.pem

部分参数泄露

手动提取

常见ASN.1类型标签

十六进制 类型 含义
02 INTEGER 整数
03 BIT SRING 位串(公钥嵌套公钥)
04 OCTET STRING 字节串(私钥中包裹私钥数据)
30 SEQUENCE 序列(容器,组合多个字段)
31 SET 集合

INTEGER字段:标签+长度+值

  • 标签:02
  • 长度:
  1. 短格式:长度小于128:用一个字节表示,该字节最高位为0
  2. 长格式:长度大于等于128:第一个字节的最高位设为1,低7位表示后续用于表示长度的字节数,后接长度值(大端序)

eg.02 81 81:129 02 82 0100:256


四、例题

未完待续


参考

https://www.cnblogs.com/JustGo12/p/17725443.html

感谢