< 返回版块

ppluck 发表于 2024-09-09 09:22

Tags:AES,Ring,Rust,Cripto,Aead

已解决

背景

各位大拿,我是Rust自学小白,我将一些java项目翻译成Rust进行学习,发现用到了AES加密、解密算法。Rust的加解密算法发展很快,目前还未找到Rust实现方法。比如Ring库或者Cripto库,我都没看到具体的AES128 加解密方案,网上的样例都是老版本的,最新版本都没找大。Ring v0.17.8有哪位大拿帮我看看这个。

非常感谢。

Java采用的算法是AES128 SHA1PRNG

评论区

写评论
作者 ppluck 2024-09-12 09:28

解决了

昨晚上折腾到9点,调通了,今天又重新重构了一下。为了方便理解,合并了几个方法。 各位大神一眼就看出来代码的问题,给你们点赞!多谢引导我这个小白进一步前进。这个AES折腾几天了。哈哈哈哈,Rust ring的这个封装的真实没那么方便。以下是通过版本


use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine as _};
use ring::aead::{self, Aad, BoundKey, Nonce, OpeningKey, SealingKey, UnboundKey, AES_128_GCM};

use base64;

use crate::err::biz_err::BizErr;

use super::constants::AES_KEY;


pub(crate) fn aes_encrypt(raw: &str, key: &str) -> Result<String, BizErr> {
    let mut secret = vec![0u8; AES_128_GCM.key_len()];
    secret[..key.len()].copy_from_slice(key.as_bytes());

    let n: Nonce = match Nonce::try_assume_unique_for_key(NONCE) {
        Ok(n) => n,
        Err(e) => {
            return Err(BizErr::InvalidNonceErr { val: e.to_string() });
        }
    };

    let ukey = UnboundKey::new(&AES_128_GCM, &secret)
        .map_err(|e| BizErr::InvalidNonceErr { val: e.to_string() })
        .unwrap();
    let nonce_sequence = OneNonceSequence::new(n);

    let mut s_key: SealingKey<OneNonceSequence> = SealingKey::new(ukey, nonce_sequence);

    let aes_key = &AES_KEY.as_bytes();
    let aad = Aad::from(aes_key);

    let mut in_out = raw.as_bytes().to_owned();

    let ret = s_key.seal_in_place_append_tag(aad, &mut in_out);

    match ret {
        Ok(_v) => Ok(STANDARD_NO_PAD.encode(in_out)),
        Err(e) => {
            return Err(BizErr::EncryptErr { val: e.to_string() });
        }
    }
}

pub(crate) fn aes_decrypt(data: &str, key: &str) -> Result<String, BizErr> {
    println!("aes_decrypt data: {data}, key: {key}");

    let mut in_out = match STANDARD_NO_PAD.decode(data) {
        Ok(r) => r,
        Err(e) => {
            return Err(BizErr::Base64DecodeErr { val: e.to_string() });
        }
    };

    let mut secret = vec![0u8; AES_128_GCM.key_len()];
    secret[..key.len()].copy_from_slice(key.as_bytes());

    let n = match Nonce::try_assume_unique_for_key(NONCE) {
        Ok(n) => n,
        Err(e) => {
            return Err(BizErr::InvalidNonceErr { val: e.to_string() });
        }
    };

    let ukey = UnboundKey::new(&AES_128_GCM, &secret)
        .map_err(|e| BizErr::InvalidNonceErr { val: e.to_string() })
        .unwrap();
    let nonce_sequence = OneNonceSequence::new(n);

    let mut o_key: OpeningKey<OneNonceSequence> = OpeningKey::new(ukey, nonce_sequence);

    let aes_key = &AES_KEY.as_bytes();
    let aad = Aad::from(aes_key);

    let ciphertext_and_tag = std::ops::RangeFrom { start: 0 };
    let ret = o_key.open_within(aad, &mut in_out, ciphertext_and_tag);
    // let ret = o_key.open_in_place(aad, &mut in_out);

    let text = match ret {
        Ok(v) => String::from_utf8_lossy(v).to_string(),
        Err(e) => {
            return Err(BizErr::DecryptErr { val: e.to_string() });
        }
    };

    Ok(text)
}

struct OneNonceSequence(Option<aead::Nonce>);

static NONCE: &[u8] = &[0; 12];

impl OneNonceSequence {
    fn new(nonce: aead::Nonce) -> Self {
        Self(Some(nonce))
    }
}

impl aead::NonceSequence for OneNonceSequence {
    fn advance(&mut self) -> Result<aead::Nonce, ring::error::Unspecified> {
        self.0.take().ok_or(ring::error::Unspecified)
    }
}

mod test {
    use crate::utils::{
        crypto::{aes_decrypt, aes_encrypt, md5_hex},
        time_tools,
    };

    #[test]
    fn test_encrypt_and_decrypt() {
        let raw = "abc";
        let key = "def";

        let mut val = "".to_string();
        match aes_encrypt(&raw, &key) {
            Ok(v) => {
                println!("encrypt_text: {}", v);
                match aes_decrypt(&v, &key) {
                    Ok(text) => {
                        println!("decrypt_text: {}", text);
                        val = text;
                    }
                    Err(e) => println!("decrypt_err: {e}"),
                }
            }
            Err(e) => {
                println!("encrypt_err: {e}");
            }
        }

        assert_eq!(val, raw);
    }

}


ting723 2024-09-11 23:06

aes-gcm 算法的,直接用这个库吧 https://docs.rs/aes-gcm/latest/aes_gcm/

示例如下: use aes_gcm::{ aead::{Aead, AeadCore, KeyInit, OsRng}, Aes256Gcm, Nonce, Key // Or Aes128Gcm };

// The encryption key can be generated randomly: let key = Aes256Gcm::generate_key(OsRng);

// Transformed from a byte array: let key: &[u8; 32] = &[42; 32]; let key: &Key = key.into();

// Note that you can get byte array from slice using the TryInto trait: let key: &[u8] = &[42; 32]; let key: [u8; 32] = key.try_into()?;

// Alternatively, the key can be transformed directly from a byte slice // (panicks on length mismatch): let key = Key::::from_slice(key);

let cipher = Aes256Gcm::new(&key); let nonce = Aes256Gcm::generate_nonce(&mut OsRng); // 96-bits; unique per message let ciphertext = cipher.encrypt(&nonce, b"plaintext message".as_ref())?; let plaintext = cipher.decrypt(&nonce, ciphertext.as_ref())?; assert_eq!(&plaintext, b"plaintext message");

TinusgragLin 2024-09-11 20:46

看文档,open_in_placeopen_within 会返回不带 tag 的 plaintext,文档中给了例子:

let plaintext = key.open_within(aad, in_out, cipertext_and_tag)?;

方案二 encrypt_and_encode 的 key 完全没有给到 secret,相当于加密密钥一直都是全 0!这就是开变量未使用 warning 的好处了。

潜水的猫 2024-09-11 19:31

第一个乱码有补码,用库带的去掉补码

--
👇
ppluck: gpt和文新一言知识不够新,错误一大推,解决不了了。

我网上找到了两种方法,改了改,但是加密后,解密后半部分不对。

以下是多方寻找以及源码阅读,写的demo,并未严格做好错误处理。等调通了再做各种处理

方案1:



/// 生成一个随机的 96 位 nonce
static NONCE: OnceLock<[u8; 12]> = OnceLock::new();

fn init() {
    NONCE.get_or_init(|| {
        let rng = SystemRandom::new();
        let mut nonce_data = [0u8; NONCE_LEN]; // 96bit nonc
        rng.fill(&mut nonce_data)
            .expect("Failed to generate random nonce");

        nonce_data
        // Nonce::assume_unique_for_key(nonce_data)
        // Nonce::try_assume_unique_for_key(&nonce_data).unwrap()
    });
}

fn ed2() {
    init();

    let mac = "c8:16:bd:50:26:6a";
    let self_id = "1428";
    let aes_key = "abc";

    let time = time_tools::unixtime_now();
    let mac2 = mac.to_lowercase().replace(":", "");

    let key = format!("{}{}", aes_key, self_id);
    let input = format!("{}_{}_{}", time, self_id, mac2);

    let binding = NONCE.get().unwrap().to_vec().clone();

    let n = binding.as_slice();
    let n2 = binding.as_slice();

    let nonce = Nonce::try_assume_unique_for_key(n).unwrap();
    let nonce2 = Nonce::try_assume_unique_for_key(n2).unwrap();

    let mut secret = vec![0u8; AES_128_GCM.key_len()];
    secret[..key.len()].copy_from_slice(key.as_bytes());

    let key = LessSafeKey::new(UnboundKey::new(&AES_128_GCM, &secret).unwrap());
    let mut payload = Vec::from(String::from("Test"));
    let aad = Aad::from(AES_KEY);

    println!("{:?}", secret);
    println!("{:?}", aad);
    println!("{:?}", payload);
    println!("{}", String::from_utf8_lossy(&payload).to_string());

    key.seal_in_place_append_tag(nonce, aad, &mut payload)
        .unwrap();
    println!("{:?}", secret);
    println!("{:?}", aad);
    println!("{:?}", payload);
    println!("{}", STANDARD_NO_PAD.encode(&payload));

    // let key2 = LessSafeKey::new(UnboundKey::new(&AES_128_GCM, &secret).unwrap());
    key.open_in_place(nonce2, aad, &mut payload).unwrap(); //Panics here

    println!("{:?}", secret);
    println!("{:?}", aad);
    println!("{:?}", payload);
    println!("{}", String::from_utf8_lossy(&payload).to_string());
}


以上执行结果,解密最后面老是有一段乱码:

[97, 98, 99, 49, 52, 50, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Aad("i71")
[84, 101, 115, 116]
Test
[97, 98, 99, 49, 52, 50, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Aad("i71")
[120, 57, 78, 68, 78, 74, 201, 166, 74, 141, 75, 38, 6, 150, 161, 183, 82, 111, 162, 197]
eDlORE5KyaZKjUsmBpaht1JvosU
[97, 98, 99, 49, 52, 50, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Aad("i71")
[84, 101, 115, 116, 78, 74, 201, 166, 74, 141, 75, 38, 6, 150, 161, 183, 82, 111, 162, 197]
TestNJɦJ�K&���Ro��


方案2:


/// 生成一个随机的 96 位 nonce
static NONCE: OnceLock<[u8; 12]> = OnceLock::new();

fn init() {
    NONCE.get_or_init(|| {
        let rng = SystemRandom::new();
        let mut nonce_data = [0u8; NONCE_LEN]; // 96bit nonc
        rng.fill(&mut nonce_data)
            .expect("Failed to generate random nonce");

        nonce_data
        // Nonce::assume_unique_for_key(nonce_data)
        // Nonce::try_assume_unique_for_key(&nonce_data).unwrap()
    });
}



struct OneNonceSequence(Option<aead::Nonce>);

impl OneNonceSequence {
    /// Constructs the sequence allowing `advance()` to be called
    /// `allowed_invocations` times.
    fn new(nonce: aead::Nonce) -> Self {
        Self(Some(nonce))
    }
}

impl aead::NonceSequence for OneNonceSequence {
    fn advance(&mut self) -> Result<aead::Nonce, ring::error::Unspecified> {
        self.0.take().ok_or(ring::error::Unspecified)
    }
}

fn seal_with_key(
    algorithm: &'static aead::Algorithm,
    key: &[u8],
    nonce: aead::Nonce,
    aad: aead::Aad<&[u8]>,
    in_out: &mut Vec<u8>,
) -> Result<(), ring::error::Unspecified> {
    let key = aead::UnboundKey::new(algorithm, key).unwrap();
    let nonce_sequence = OneNonceSequence::new(nonce);
    let mut s_key: SealingKey<OneNonceSequence> = SealingKey::new(key, nonce_sequence);

    s_key.seal_in_place_append_tag(aad, in_out)
}

fn open_with_key<'a>(
    algorithm: &'static aead::Algorithm,
    key: &[u8],
    nonce: aead::Nonce,
    aad: aead::Aad<&[u8]>,
    in_out: &'a mut [u8],
    ciphertext_and_tag: std::ops::RangeFrom<usize>,
) -> Result<&'a mut [u8], ring::error::Unspecified> {
    let key = aead::UnboundKey::new(algorithm, key).unwrap();
    let nonce_sequence = OneNonceSequence::new(nonce);
    let mut o_key: OpeningKey<OneNonceSequence> = OpeningKey::new(key, nonce_sequence);

    o_key.open_within(aad, in_out, ciphertext_and_tag)
}

pub fn encrypt_and_encode(
    algorithm: &'static aead::Algorithm,
    input: String,
    key: &[u8],
    nonce: &Vec<u8>,
) -> Result<String, Unspecified> {
    // attempt to convert the nonce vector into an aead::Nonce
    let n = match aead::Nonce::try_assume_unique_for_key(nonce) {
        Ok(n) => n,
        Err(e) => {
            error!("Could not use nonce {}", e);
            return Err(e);
        }
    };

    let mut raw = input.as_bytes().to_owned();
    let secret = vec![0u8; AES_128_GCM.key_len()];

    match seal_with_key(
        algorithm,
        &secret,
        n,
        ring::aead::Aad::from(&AES_KEY.as_bytes()),
        &mut raw,
    ) {
        Ok(_v) => _v,
        Err(e) => {
            error!("Could not encrypt value {}", e);
            return Err(e);
        }
    }

    return Ok(STANDARD_NO_PAD.encode(raw));
}

pub fn decrypt_and_decode(
    algorithm: &'static aead::Algorithm,
    input: String,
    key: &[u8],
    nonce: &Vec<u8>,
) -> Result<String, BizErr> {
    let mut raw = match STANDARD_NO_PAD.decode(input) {
        Ok(r) => r,
        Err(e) => {
            error!("Could not decode msg {}", e);
            return Err(BizErr::Base64DecodeErr { val: e.to_string() });
        }
    };

    // attempt to convert the nonce vector into an aead::Nonce
    let n = match aead::Nonce::try_assume_unique_for_key(nonce) {
        Ok(n) => n,
        Err(e) => {
            error!("Could not use nonce {}", e);
            return Err(BizErr::InvalidNonceErr { val: e.to_string() });
        }
    };

    // decrypt the oauth values
    let res = match open_with_key(
        algorithm,
        &key,
        n,
        ring::aead::Aad::from(&AES_KEY.as_bytes()),
        &mut raw,
        std::ops::RangeFrom { start: 0 },
    ) {
        Ok(v) => v,
        Err(e) => {
            error!("Could not decrypt value {}", e);
            return Err(BizErr::DecryptErr { val: e.to_string() });
        }
    };

    let res = match String::from_utf8(res.to_vec()) {
        Ok(value) => value,
        Err(e) => {
            error!("Could not from utf8 for value {}", e);
            let msg = String::from_utf8_lossy(&res).to_string();
            return Err(BizErr::FromUtf8Err { val: msg });
        }
    };

    Ok(res)
}


    #[test]
    fn test_encrypt_and_decrypt() {
        let nonce = NONCE.get_or_init(|| {
            let rng = SystemRandom::new();
            let mut nonce_data = [0u8; NONCE_LEN]; // 96bit nonc
            rng.fill(&mut nonce_data)
                .expect("Failed to generate random nonce");
            nonce_data
        });

        let mac = "c8:16:bd:50:26:6a";
        let self_id = "1428";
        let aes_key = "abc";

        let time = time_tools::unixtime_now();
        let mac2 = mac.to_lowercase().replace(":", "");
        let key = format!("{}{}", aes_key, self_id);
        
        let mut secret = vec![0u8; AES_128_GCM.key_len()];
        secret[..key.len()].copy_from_slice(key.as_bytes());

        let input = format!("{}_{}_{}", time, self_id, mac2);

        let text = encrypt_and_encode(&AES_128_GCM, input.clone(), &secret, nonce.to_vec().as_ref())
            .unwrap_or_default();

        println!("sec: {text}");
        
        let src = decrypt_and_decode(&AES_128_GCM, text, &secret, nonce.to_vec().as_ref()).unwrap_or_default();
        println!("src: {src}");

        assert!(src == input);

    }


也不对,打印出来,解密报错了,待进一步一点一点分析: sec: COLIo8+YS1tui+oKOESv6bns6T28i4Fvc6Pr2GH0xHLZV/ONGrSLIkQuPxE src:

潜水的猫 2024-09-11 12:12

这个是基于对称加密的随机数生成,这个暂时可能需要自己写 prng 可以在ai上试下

c5soft 2024-09-10 17:17

求助AI

1 共 6 条评论, 1 页