python (3.x) 实现RSA 加签 验签 以及key的序列化

首先 安装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 的长度.

    原文作者:EthanSun
    原文地址: https://segmentfault.com/a/1190000012892570
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞