灵符lingfu

ling-lang

↓ 0 downloads

Ling - The Omniglot Systems Language

Keywords systems, polyglot, ai, crypto, game
lingfu install ling-lang
LicenseApache-2.0 OR MIT
AuthorsLing Lin, Sanny Lin
READMECode / FilesVersionsDependency GraphDependentsSecurityBuildsSettings

Code / Files (995)

crates/ling-crypto/src/symmetric.rs
//! Authenticated encryption: AES-256-GCM and XChaCha20-Poly1305.

use aes_gcm::{
    aead::{Aead, KeyInit},
    Aes256Gcm, Key, Nonce,
};
use alloc::vec::Vec;
use chacha20poly1305::{XChaCha20Poly1305, XNonce};
use zeroize::Zeroizing;

use crate::rng;

pub struct AesGcm256 {
    key: Zeroizing<[u8; 32]>,
}

impl AesGcm256 {
    pub fn new(key: [u8; 32]) -> Self {
        Self { key: Zeroizing::new(key) }
    }

    pub fn generate_key() -> [u8; 32] {
        rng::random_bytes::<32>()
    }

    /// Returns nonce (12 bytes) + ciphertext + tag.
    pub fn encrypt(&self, plaintext: &[u8]) -> Result<Vec<u8>, &'static str> {
        let cipher = Aes256Gcm::new(Key::<Aes256Gcm>::from_slice(&*self.key));
        let nonce_bytes = rng::random_bytes::<12>();
        let nonce = Nonce::from_slice(&nonce_bytes);
        let ct = cipher
            .encrypt(nonce, plaintext)
            .map_err(|_| "encryption failed")?;
        let mut out = nonce_bytes.to_vec();
        out.extend_from_slice(&ct);
        Ok(out)
    }

    /// Input: nonce (12 bytes) + ciphertext + tag.
    pub fn decrypt(&self, nonce_and_ct: &[u8]) -> Result<Vec<u8>, &'static str> {
        if nonce_and_ct.len() < 12 {
            return Err("too short");
        }
        let (nonce_bytes, ct) = nonce_and_ct.split_at(12);
        let cipher = Aes256Gcm::new(Key::<Aes256Gcm>::from_slice(&*self.key));
        let nonce = Nonce::from_slice(nonce_bytes);
        cipher
            .decrypt(nonce, ct)
            .map_err(|_| "decryption/auth failed")
    }
}

pub struct XChaCha20 {
    key: Zeroizing<[u8; 32]>,
}

impl XChaCha20 {
    pub fn new(key: [u8; 32]) -> Self {
        Self { key: Zeroizing::new(key) }
    }

    pub fn generate_key() -> [u8; 32] {
        rng::random_bytes::<32>()
    }

    /// Returns nonce (24 bytes) + ciphertext + tag.
    pub fn encrypt(&self, plaintext: &[u8]) -> Result<Vec<u8>, &'static str> {
        let cipher = XChaCha20Poly1305::new(chacha20poly1305::Key::from_slice(&*self.key));
        let nonce_bytes = rng::random_bytes::<24>();
        let nonce = XNonce::from_slice(&nonce_bytes);
        let ct = cipher
            .encrypt(nonce, plaintext)
            .map_err(|_| "encryption failed")?;
        let mut out = nonce_bytes.to_vec();
        out.extend_from_slice(&ct);
        Ok(out)
    }

    /// Input: nonce (24 bytes) + ciphertext + tag.
    pub fn decrypt(&self, nonce_and_ct: &[u8]) -> Result<Vec<u8>, &'static str> {
        if nonce_and_ct.len() < 24 {
            return Err("too short");
        }
        let (nonce_bytes, ct) = nonce_and_ct.split_at(24);
        let cipher = XChaCha20Poly1305::new(chacha20poly1305::Key::from_slice(&*self.key));
        let nonce = XNonce::from_slice(nonce_bytes);
        cipher
            .decrypt(nonce, ct)
            .map_err(|_| "decryption/auth failed")
    }
}

← Back to index