Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第二十八 密钥

密钥

** 现代密码学的一个基本原则是“一切秘密寓于密钥之中”。** 密钥分为两种:对称密钥与非对称密钥

对称密码算法使用相同的密钥; 公钥密码使用不同的密钥来对消息进行加密解密; MAC消息认证码使用相同的密钥; 数字签名使用不同的密钥来对消息进行签名和验证。

密钥的管理

  • 如何生成公私钥对?
  • 如何根据编码后的公私钥对得到 PrivateKey, PublicKey ?
  • 如何保护私钥的安全?
  • 如何传输交换密钥?
  • 秘密共享 (Secret Sharing)

如何生成公私钥对?

RSA生成公私钥对

#![allow(unused)]
fn main() {
    use rand_core::CryptoRngCore;
    use rsa::pkcs8::{self, DecodePublicKey, EncodePrivateKey, EncodePublicKey, LineEnding};
    use rsa::{Pkcs1v15Encrypt, PublicKey, RsaPrivateKey, RsaPublicKey};

    let mut rng = random::thread_rng();
    let bits = 2048;
    //1. 生成RSA公私钥
    let priv_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
    let pub_key = RsaPublicKey::from(&priv_key);

    //2. 序列化公私钥
    if let Ok(priv_pem) = RsaPrivateKey::to_pkcs8_pem(&priv_key, pkcs8::LineEnding::default()){
        std::fs::write("private_rsa_key.pem",priv_pem);
    }

    if let Ok(pub_pem) = RsaPublicKey::to_public_key_pem(&pub_key, pkcs8::LineEnding::default()){
        std::fs::write("public_rsa_key.pem",pub_pem);
    }
}

ECC生成公私钥对

#![allow(unused)]
fn main() {
#[test]
fn ecc() {
    use base64ct::LineEnding;
    use elliptic_curve::SecretKey;
    use p256::NistP256;
    use rand_core::OsRng; // requires 'getrandom' feature

    // 1. 生成私钥
    let key: SecretKey<NistP256> = SecretKey::random(&mut OsRng);
    let pem_str = key.to_sec1_pem(LineEnding::LF);
    println!("{:?}", pem_str);
    // 根据私钥生成公钥
    println!("{:?}", key.public_key());

    //2. 根据PEM格式字符串恢复私钥
    let private_key : Result<SecretKey<NistP256>, elliptic_curve::Error> = elliptic_curve::SecretKey::from_sec1_pem("-----BEGIN EC PRIVATE KEY-----\nMGsCAQEEIKUhSRir8XkO1BcqcgdgFxtapjz0UFyzwQQpcCJ6IZhcoUQDQgAEWsVX\ns/5B/A4rWT4hRk6EBP/tzRzQjJKZIoh9WQbV4eots1mPwiio6XYhcYD+zauInLNq\nK1i6dCgXjJ0GB1FEhA==\n-----END EC PRIVATE KEY-----");

    //3. 根据私钥生成公钥
    let public_key = private_key.unwrap().public_key();
    println!("{:?}", public_key);
}

}

SM2生成公私钥对

#![allow(unused)]
fn main() {
use libsm::sm2::signature::{SigCtx, Signature};

    let ctx = SigCtx::new();
    let (pk, sk) = ctx.new_keypair().unwrap();
}

如何根据编码后的公私钥对得到 PrivateKey, PublicKey ?

#![allow(unused)]
fn main() {
    let private_key_pem = std::fs::read_to_string("private_key.pem").unwrap();
    let public_key_pem = std::fs::read_to_string("public_key.pem").unwrap();

    let priv_key = RsaPrivateKey::from_pkcs8_pem(&private_key_pem).unwrap();
    let pub_key = RsaPublicKey::from_public_key_pem(&public_key_pem).unwrap();
}

SM2

(1)获得openssl支持椭圆曲线算法列表
        命令:openssl ecparam -list_curves
(2)生成SM2私钥文件
          命令:openssl ecparam -outform pem -out sm2PrivateKey.pem -name SM2 -genkey
(3)查看私钥文件
          命令:openssl ec -in sm2PrivateKey.pem -text
(4)生成SM2 公钥文件
          命令:openssl ec -in sm2PrivateKey.pem -pubout -out sm2PublicKey.pem

密钥交换

#![allow(unused)]
fn main() {
use k256::{EncodedPoint, PublicKey, ecdh::EphemeralSecret};
use rand_core::OsRng; // requires 'getrandom' feature

// Alice
let alice_secret = EphemeralSecret::random(&mut OsRng);
let alice_pk_bytes = EncodedPoint::from(alice_secret.public_key());

// Bob
let bob_secret = EphemeralSecret::random(&mut OsRng);
let bob_pk_bytes = EncodedPoint::from(bob_secret.public_key());

// Alice decodes Bob's serialized public key and computes a shared secret from it
let bob_public = PublicKey::from_sec1_bytes(bob_pk_bytes.as_ref())
    .expect("bob's public key is invalid!"); // In real usage, don't panic, handle this!

let alice_shared = alice_secret.diffie_hellman(&bob_public);

// Bob decodes Alice's serialized public key and computes the same shared secret
let alice_public = PublicKey::from_sec1_bytes(alice_pk_bytes.as_ref())
    .expect("alice's public key is invalid!"); // In real usage, don't panic, handle this!

let bob_shared = bob_secret.diffie_hellman(&alice_public);

// Both participants arrive on the same shared secret
assert_eq!(alice_shared.raw_secret_bytes(), bob_shared.raw_secret_bytes());
}

密钥交换流程图

sequenceDiagram
    participant A as Alice
    participant B as Bob

    Note over A,B: 1. 各自生成临时密钥对
    A->>A: 生成 EphemeralSecret (alice_secret)
    A->>A: 从 secret 派生公钥并编码为 EncodedPoint (alice_pk_bytes)
    
    B->>B: 生成 EphemeralSecret (bob_secret)
    B->>B: 从 secret 派生公钥并编码为 EncodedPoint (bob_pk_bytes)

    Note over A,B: 2. 交换公钥 (通过不安全的信道)
    A-->>B: 发送 alice_pk_bytes
    B-->>A: 发送 bob_pk_bytes

    Note over A,B: 3. 解码对方公钥并计算共享密钥
    A->>A: 解码 bob_pk_bytes → bob_public
    A->>A: alice_secret.diffie_hellman(&bob_public) → alice_shared

    B->>B: 解码 alice_pk_bytes → alice_public
    B->>B: bob_secret.diffie_hellman(&alice_public) → bob_shared

    Note over A,B: 4. 验证共享密钥一致
    A->>A: alice_shared.raw_secret_bytes()
    B->>B: bob_shared.raw_secret_bytes()
    
    Note over A,B: ✅ assert_eq! 两者相等

ECDH 算法概述(CNG 示例)

Elliptic Curve Diffie-Hellman (ECDH) function

密钥交换算法

图解 ECDHE 密钥交换算法
离散对数,DH算法, curve25519

x25519-dalek X25519 elliptic curve Diffie-Hellman key exchange in pure-Rust, using curve25519-dalek.

秘密共享 (Secret Sharing)

秘密共享算法

Shamir 秘密共享方案的核心原理(用数学的“穿针引线”来理解)

拉格朗日插值法 (Lagrange Interpolation)

密钥管理系统(Key Management Service,KMS)

HashiCorp Vault官网 HashiCorp Vault Github RustyVault

HashiCorp Vault

#![allow(unused)]
fn main() {
async fn vault() {
    use vaultrs::client::{Client, VaultClient, VaultClientSettingsBuilder};

    use rand_core::CryptoRngCore;
    use rand_core::OsRng;
    use rsa::pkcs8::{
        self, DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey, LineEnding,
    };
    use rsa::{Pkcs1v15Encrypt, PublicKey, RsaPrivateKey, RsaPublicKey};
    use serde::{Deserialize, Serialize};
    use vaultrs::kv2;
    // let mut rng = random::thread_rng();

    // Create and read secrets
    #[derive(Debug, Deserialize, Serialize)]
    struct MySecret {
        key: String,
        password: String,
    }

    #[derive(Debug, Deserialize, Serialize)]
    struct RSAKey {
        public_key: String,
        private_key: String,
    }

    // Create a client
    let mut client = VaultClient::new(
        VaultClientSettingsBuilder::default()
            .address("http://127.0.0.1:8200")
            .token("hvs.80mEiiPnonTChoSTH5pkAeLg")
            .build()
            .unwrap(),
    )
    .unwrap();

    let secret = MySecret {
        key: "super".to_string(),
        password: "secret".to_string(),
    };
    kv2::set(&client, "secret", "mysecret", &secret).await;

    // let secret: MySecret = ;
    let result: Result<MySecret, vaultrs::error::ClientError> =
        kv2::read(&client, "secret", "mysecret").await;
    if (result.is_ok()) {
        println!("{}", result.unwrap().password) // "secret"
    } else {
        println!("{:?}", result.err()) // "secret"
    }

    let mut public_key = String::new();
    let mut private_key = String::new();

    let bits = 2048;
    let mut rng = rand::thread_rng();
    //1. 生成RSA公私钥
    let priv_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
    let pub_key = RsaPublicKey::from(&priv_key);

    //2. 序列化公私钥
    if let Ok(priv_pem) = RsaPrivateKey::to_pkcs8_pem(&priv_key, pkcs8::LineEnding::default()) {
        private_key = priv_pem.to_string();
    }

    if let Ok(pub_pem) = RsaPublicKey::to_public_key_pem(&pub_key, pkcs8::LineEnding::default()) {
        public_key = pub_pem.to_string();
    }

    let secret1 = RSAKey {
        public_key,
        private_key,
    };

    // let mut rng = rand_core::OsRng;
    let key = String::from("RSA:666666666666");

    kv2::set(&client, "secret", &key, &secret1).await;

    let result: Result<RSAKey, vaultrs::error::ClientError> =
        kv2::read(&client, "secret", &key).await;
    if (result.is_ok()) {
        println!("{}", result.unwrap().public_key)
    } else {
        println!("{:?}", result.err())
    }
}


}