Rust实现AES、RSA加解密及签名验签

1,713 阅读3分钟

Rust中有不少加解密库,例如 ringrust-opensslRust Crypto。本文选用Rust Crypto系列中的库实现aes加解密,rsa加解密 签名验签。

  1. Rust Crypto纯Rust实现,方便交叉编译
  2. Rust Crypto各个算法独立实现,例如aes、cbc、pkcs7独立实现,cbc pkcs7也可以和国密算法sm4结合使用

1. AES 加解密

本文aes加密选择cbc工作模式、Pkcs7填充模式, 如需其他工作模式可参考block-modes,如需其他padding模式参考block-padding

加密结果如需使用base64,可使用base64对加密数据进行操作。

use aes::cipher::block_padding::Pkcs7;
use anyhow::anyhow;
use cbc::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit};

type Aes256CbcEnc = cbc::Encryptor<aes::Aes256>;
type Aes256CbcDec = cbc::Decryptor<aes::Aes256>;

const AES_KEY: [u8; 32] = *b"1d64dce239c4437d1d64dce239c4437d";
const AES_IV: [u8; 16] = *b"45154c1fc4541161";

/// aes cbc pkcs7 enc
pub fn enc(input: &[u8]) -> anyhow::Result<Vec<u8>> {
    let res =
        Aes256CbcEnc::new(&AES_KEY.into(), &AES_IV.into()).encrypt_padded_vec_mut::<Pkcs7>(input);
    Ok(res)
}

/// aes cbc pkcs7 dec
pub fn dec(cipher: &[u8]) -> anyhow::Result<Vec<u8>> {
    let res = Aes256CbcDec::new(&AES_KEY.into(), &AES_IV.into())
        .decrypt_padded_vec_mut::<Pkcs7>(&cipher)
        .map_err(|e| anyhow!(format!("dec err {:?}", e.to_string())))?;
    Ok(res)
}

2. Rsa 加解密及签名验签

Rsa一般用作公钥加密,私钥解密,私钥签名,公钥验签。密钥格式有两种,Pkcs1 Pkcs8。

Pkcs1 pem格式如下开头 -----BEGIN RSA PRIVATE KEY-----

Pkcs8 pem格式如下开头 -----BEGIN PRIVATE KEY-----

加解密、签名验签功能如下

use rand_chacha::rand_core::SeedableRng;
use rand_chacha::ChaCha8Rng;
use rsa::pkcs1v15::{Signature, SigningKey, VerifyingKey};
use rsa::signature::{Keypair, RandomizedSigner, SignatureEncoding, Verifier};
use rsa::{pkcs1, pkcs8, Pkcs1v15Encrypt, Pkcs1v15Sign, RsaPrivateKey, RsaPublicKey};
use sha2::Sha256;

pub enum RsaKey {
    Pkcs1 { key: String },
    Pkcs8 { key: String },
}

/// PKCS#1 v1.5 encryption
pub fn rsa_enc(data: &[u8], pub_key_type: RsaKey) -> anyhow::Result<Vec<u8>> {
    let public_key: RsaPublicKey;
    match pub_key_type {
        RsaKey::Pkcs1 { key } => {
            public_key = pkcs1::DecodeRsaPublicKey::from_pkcs1_pem(key.as_str())?;
        }
        RsaKey::Pkcs8 { key } => {
            public_key = pkcs8::DecodePublicKey::from_public_key_pem(key.as_str())?;
        }
    }
    let mut rng = ChaCha8Rng::from_seed([42; 32]);
    let enc_data = public_key.encrypt(&mut rng, Pkcs1v15Encrypt, data)?;
    Ok(enc_data)
}

/// PKCS#1 v1.5 decryption
pub fn rsa_dec(cipher_text: &[u8], private_key_str: RsaKey) -> anyhow::Result<Vec<u8>> {
    let private_key: RsaPrivateKey;
    match private_key_str {
        RsaKey::Pkcs1 { key } => {
            private_key = pkcs1::DecodeRsaPrivateKey::from_pkcs1_pem(key.as_str())?;
        }
        RsaKey::Pkcs8 { key } => {
            private_key = pkcs8::DecodePrivateKey::from_pkcs8_pem(key.as_str())?;
        }
    }
    let dec_data = private_key.decrypt(Pkcs1v15Encrypt, cipher_text)?;
    Ok(dec_data)
}

/// PKCS#1 v1.5 signatures
pub fn rsa_sign(data: &[u8], private_key_str: RsaKey) -> anyhow::Result<Vec<u8>> {
    let private_key: RsaPrivateKey;
    match private_key_str {
        RsaKey::Pkcs1 { key } => {
            private_key = pkcs1::DecodeRsaPrivateKey::from_pkcs1_pem(key.as_str())?;
        }
        RsaKey::Pkcs8 { key } => {
            private_key = pkcs8::DecodePrivateKey::from_pkcs8_pem(key.as_str())?;
        }
    };
    let signing_key = SigningKey::<Sha256>::new_unprefixed(private_key);

    let mut rng = ChaCha8Rng::from_seed([42; 32]);
    let signature = signing_key.sign_with_rng(&mut rng, data);
    Ok(signature.to_bytes().to_vec())
}

pub fn rsa_verify(data: &[u8], sign: &[u8], pub_key: RsaKey) -> anyhow::Result<()> {
    let public_key: RsaPublicKey;
    match pub_key {
        RsaKey::Pkcs1 { key } => {
            public_key = pkcs1::DecodeRsaPublicKey::from_pkcs1_pem(key.as_str())?;
        }
        RsaKey::Pkcs8 { key } => {
            public_key = pkcs8::DecodePublicKey::from_public_key_pem(key.as_str())?;
        }
    }
    let verifying_key: VerifyingKey<Sha256> = VerifyingKey::<Sha256>::new_unprefixed(public_key);
    let signature = Signature::try_from(sign)?;
    verifying_key.verify(data, &signature)?;
    Ok(())
}

以上代码详见rust_crypto_demo

Openssl 产生RSA公私钥对

openssl 产生Pkcs8公私钥对命令如下

产生Pkcs8私钥 openssl genpkey -algorithm RSA -out private_pkcs8.pem

产生Pkcs8公钥openssl rsa -pubout -in private_pkcs8.pem -out public_pkcs8.pem

Pkcs8公私钥对转换为Pkcs1命令如下

私钥转化openssl rsa -in private_pkcs8.pem -out private_pkcs1.pem -traditional

公钥转化openssl rsa -pubin -in public_pkcs8.pem -RSAPublicKey_out -out public_pkcs1.pem