首先 安装cryptography
sudo pip3 install cryptography
确认安装的是2.1.x版本 (1.x版本的api是不一样的).
生成公私钥对:
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization, hashes
from base64 import b64encode, b64decode
# 生成私钥 (同时包含公钥), 此处为RSA 2048
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
序列化公钥 私钥, 并写入文件存储.
# 序列化私钥
pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
# 无密码
encryption_algorithm=serialization.NoEncryption()
# 也可以加入密码保护私钥:
# encryption_algorithm=serialization.BestAvailableEncryption(b'mypassword')
)
# 将私钥写入文件
with open('private.pem', 'wb') as f:
f.write(pem)
public_key = private_key.public_key()
pub_pem = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
# 将公钥写入文件
with open('public.pem', 'wb') as f:
f.write(pub_pem)
也可以采用其他序列化方法, 比如对公钥, 生成OpenSSH格式的序列化字符串:
public_key.public_bytes(
encoding=serialization.Encoding.OpenSSH,
format=serialization.PublicFormat.OpenSSH
)
输出类似于:
b'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCbySUldhJYrDmf8+yyQXMB5HsIMwownZq3ft7k1nei/kVC/720np/1xyk7U8yNc2jL9Yb/pctD/0WAnI7vrkIVQniYfRwiEohDlZHGIvlUpXS4dtKvbOFRDQod9nn4Q9VwfrMq4yuBbKSaCqwcu8rkApWyj36
XhTV5/mT7Zs4H4m3OAyCVD2kkAoZYYbxA+pBNDLDcU4VlUuiC1FaWLTdU5dV6A0IGRGlOuFw4qaJZaFLu6mANaRdX836LA5DOmKpcwerb0ae3eGHZNSLQO6JkIT7oe/I+417jz5JmUI3V35BjKUrd7VjBgbE0jvpkxrzMFCaoOWP0BzTDn+C64fSR'
此后可以从文件读出公钥(私钥)
# 从文件读出并创建公钥
with open("public.pem", "rb") as pub_key_file:
# 读入私钥为 load_pem_private_key
public_key = serialization.load_pem_public_key(
pub_key_file.read(),
# 读入私钥此处还有: password=b'xxxx',
backend=default_backend()
)
对于openSSH格式, 应采用load_ssh_public_key
给指定消息加签, 获得签名
# 需要加签的消息
message = b"A message I want to sign"
# 对消息加签, 获得签名, 为bytes
signature = private_key.sign(
message,
padding.PSS(
mgf=padding.MGF1(hashes.SHA1()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA1()
)
# 需要传输, 展示, 存储时, 可以将签名转为base64格式的bytes,
# 也可以继续转为str: str(enc_sig, 'utf-8')
enc_sig = b64encode(signature)
验证签名:
# 通过signature, 公钥 给 消息message 验签, 验证是由私钥持有者发出的这条消息.
# 如果验签通过, 则正常通过, 否则, 抛出 cryptography.exceptions.InvalidSignature 异常
public_key.verify(
signature,
message,
padding.PSS(
mgf=padding.MGF1(hashes.SHA1()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA1()
)
这样生成的签名base64encode之后, 会有344byte 的长度.