Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/security/lockstore/lockstore_rs/src/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 8 kB image not shown  

Quelle  crypto.rs

  Sprache: Rust
 

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


use crate::LockstoreError;
use kvstore::{Database, GetOptions, Key, Store};
use nss_rs::aead::{Aead, AeadAlgorithms, Mode};
use nss_rs::p11;
use nss_rs::SymKey;
use serde::{Deserialize, Serialize};

pub const DEFAULT_CIPHER_SUITE: CipherSuite = CipherSuite::Aes256Gcm;

#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum CipherSuite {
    #[default]
    #[serde(rename = "aes256gcm")]
    Aes256Gcm,
    #[serde(rename = "chacha20poly1305")]
    ChaCha20Poly1305,
}

impl CipherSuite {
    pub const fn key_size(&self) -> usize {
        match self {
            CipherSuite::Aes256Gcm => 32,
            CipherSuite::ChaCha20Poly1305 => 32,
        }
    }

    pub const fn nonce_size(&self) -> usize {
        match self {
            CipherSuite::Aes256Gcm => 12,
            CipherSuite::ChaCha20Poly1305 => 12,
        }
    }

    pub const fn tag_size(&self) -> usize {
        match self {
            CipherSuite::Aes256Gcm => 16,
            CipherSuite::ChaCha20Poly1305 => 16,
        }
    }

    pub(cratefn to_nss_algorithm(self) -> AeadAlgorithms {
        match self {
            CipherSuite::Aes256Gcm => AeadAlgorithms::Aes256Gcm,
            CipherSuite::ChaCha20Poly1305 => AeadAlgorithms::ChaCha20Poly1305,
        }
    }

    pub fn as_str(&self) -> &str {
        match self {
            CipherSuite::Aes256Gcm => "aes256gcm",
            CipherSuite::ChaCha20Poly1305 => "chacha20poly1305",
        }
    }

    pub fn parse(s: &str) -> Option<Self> {
        match s {
            "aes256gcm" => Some(CipherSuite::Aes256Gcm),
            "chacha20poly1305" => Some(CipherSuite::ChaCha20Poly1305),
            _ => None,
        }
    }
}

fn cipher_suite_id(cs: CipherSuite) -> u8 {
    match cs {
        CipherSuite::Aes256Gcm => 0,
        CipherSuite::ChaCha20Poly1305 => 1,
    }
}

fn cipher_suite_from_id(id: u8) -> Option<CipherSuite> {
    match id {
        0 => Some(CipherSuite::Aes256Gcm),
        1 => Some(CipherSuite::ChaCha20Poly1305),
        _ => None,
    }
}

/// Parse the cipher-suite id from the leading byte of a self-describing
/// ciphertext blob produced by `encrypt_with_symkey` /
/// `encrypt_with_key`. Returns `Decryption` on an empty blob or an
/// unknown id.
pub(cratefn cipher_suite_of_blob(blob: &[u8]) -> Result<CipherSuite, LockstoreError> {
    if blob.is_empty() {
        return Err(LockstoreError::Decryption(
            "Ciphertext is empty".to_string(),
        ));
    }
    cipher_suite_from_id(blob[0])
        .ok_or_else(|| LockstoreError::Decryption(format!("Unknown cipher suite id: {}", blob[0])))
}

fn random_bytes(size: usize) -> Vec<u8> {
    let mut buf = vec![0u8; size];
    p11::randomize(&mut buf);
    buf
}

pub fn generate_random_key(cipher_suite: CipherSuite) -> Vec<u8> {
    random_bytes(cipher_suite.key_size())
}

pub fn generate_random_nonce(cipher_suite: CipherSuite) -> Vec<u8> {
    random_bytes(cipher_suite.nonce_size())
}

/// `len` random bytes from NSS's PRNG. Use for salts and any other
/// random byte string whose size is not derived from a `CipherSuite`.
/// For nonces tied to a cipher suite, use `generate_random_nonce`; for
/// symmetric keys, use `generate_random_key`.
pub fn generate_random_bytes(len: usize) -> Vec<u8> {
    random_bytes(len)
}

/// Encrypts data using AEAD with a SymKey handle.
/// The returned blob is self-describing: [cipher_suite_id(1)] || [nonce] || [ciphertext+tag].
pub fn encrypt_with_symkey(
    plaintext: &[u8],
    key: &SymKey,
    cipher_suite: CipherSuite,
) -> Result<Vec<u8>, LockstoreError> {
    let nonce = generate_random_nonce(cipher_suite);
    let mut nonce_bytes = [0u8; 12];
    nonce_bytes[..nonce.len()].copy_from_slice(&nonce);

    let alg = cipher_suite.to_nss_algorithm();
    let mut aead = Aead::new(Mode::Encrypt, alg, key, nonce_bytes)
        .map_err(|e| LockstoreError::Encryption(format!("Failed to create AEAD: {}", e)))?;

    // The cipher-suite id is prepended to the blob as its first byte;
    // pass that same byte as AAD so the AEAD tag authenticates it
    // directly. Tampering with the prefix is then caught by tag
    // verification, not just by our own prefix consistency check.
    let aad = [cipher_suite_id(cipher_suite)];
    let ciphertext = aead
        .encrypt(&aad, plaintext)
        .map_err(|e| LockstoreError::Encryption(format!("Encryption failed: {}", e)))?;

    let mut result = Vec::with_capacity(1 + nonce.len() + ciphertext.len());
    result.push(aad[0]);
    result.extend_from_slice(&nonce);
    result.extend_from_slice(&ciphertext);

    Ok(result)
}

/// Decrypts data produced by `encrypt_with_symkey` or `encrypt_with_key`.
/// The cipher suite is inferred from the blob's leading byte.
pub fn decrypt_with_symkey(ciphertext: &[u8], key: &SymKey) -> Result<Vec<u8>, LockstoreError> {
    if ciphertext.is_empty() {
        return Err(LockstoreError::Decryption(
            "Ciphertext is empty".to_string(),
        ));
    }

    let suite_byte = ciphertext[0];
    let cipher_suite = cipher_suite_from_id(suite_byte).ok_or_else(|| {
        LockstoreError::Decryption(format!("Unknown cipher suite id: {}", suite_byte))
    })?;
    let ciphertext = &ciphertext[1..];
    let nonce_size = cipher_suite.nonce_size();

    if ciphertext.len() < nonce_size {
        return Err(LockstoreError::Decryption(
            "Ciphertext too short to contain nonce".to_string(),
        ));
    }

    let mut nonce_bytes = [0u8; 12];
    nonce_bytes[..nonce_size].copy_from_slice(&ciphertext[..nonce_size]);
    let actual_ciphertext = &ciphertext[nonce_size..];

    let alg = cipher_suite.to_nss_algorithm();
    let mut aead = Aead::new(Mode::Decrypt, alg, key, nonce_bytes)
        .map_err(|e| LockstoreError::Decryption(format!("Failed to create AEAD: {}", e)))?;

    // AAD = the suite-id prefix byte (see `encrypt_with_symkey`); tag
    // verification fails if the prefix has been tampered with.
    let aad = [suite_byte];
    let plaintext = aead
        .decrypt(&aad, 0, actual_ciphertext)
        .map_err(|e| LockstoreError::Decryption(format!("Decryption failed: {}", e)))?;

    Ok(plaintext)
}

/// Encrypts data using AEAD with raw key bytes.
/// The returned blob is self-describing: [cipher_suite_id(1)] || [nonce] || [ciphertext+tag].
pub fn encrypt_with_key(
    plaintext: &[u8],
    key: &[u8],
    cipher_suite: CipherSuite,
) -> Result<Vec<u8>, LockstoreError> {
    if key.len() != cipher_suite.key_size() {
        return Err(LockstoreError::Encryption(format!(
            "Invalid key size: expected {}, got {}",
            cipher_suite.key_size(),
            key.len()
        )));
    }
    let alg = cipher_suite.to_nss_algorithm();
    let nss_key = Aead::import_key(alg, key)
        .map_err(|e| LockstoreError::Encryption(format!("Failed to import key: {}", e)))?;
    encrypt_with_symkey(plaintext, &nss_key, cipher_suite)
}

/// Decrypts data produced by `encrypt_with_key`.
/// The cipher suite is inferred from the blob's leading byte.
pub fn decrypt_with_key(ciphertext: &[u8], key: &[u8]) -> Result<Vec<u8>, LockstoreError> {
    if ciphertext.is_empty() {
        return Err(LockstoreError::Decryption(
            "Ciphertext is empty".to_string(),
        ));
    }
    let cipher_suite = cipher_suite_from_id(ciphertext[0]).ok_or_else(|| {
        LockstoreError::Decryption(format!("Unknown cipher suite id: {}", ciphertext[0]))
    })?;
    if key.len() != cipher_suite.key_size() {
        return Err(LockstoreError::Decryption(format!(
            "Invalid key size: expected {}, got {}",
            cipher_suite.key_size(),
            key.len()
        )));
    }
    let alg = cipher_suite.to_nss_algorithm();
    let nss_key = Aead::import_key(alg, key)
        .map_err(|e| LockstoreError::Decryption(format!("Failed to import key: {}", e)))?;
    decrypt_with_symkey(ciphertext, &nss_key)
}

/// Overwrites a stored value with zeros of the same size (does not delete).
///
/// Note: this is best-effort in-memory sanitization only. SQLite's WAL/journal
/// mode means the original bytes may persist on disk until the relevant WAL
/// pages are checkpointed and overwritten.
pub fn zeroize(store: &Store, db_name: &str, key_name: &str) -> Result<(), LockstoreError> {
    let db = Database::new(store, db_name);
    let key = Key::from(key_name);
    if let Some(value) = db.get(&key, &GetOptions::default())? {
        let bytes = crate::utils::value_to_bytes(&value)?;
        let zeros = vec![0u8; bytes.len()];
        let zero_value = crate::utils::bytes_to_value(&zeros)?;
        db.put(&[(key, Some(zero_value))])?;
    }
    Ok(())
}

/// Overwrites a stored value with zeros, then deletes the entry.
pub fn secure_delete(store: &Store, db_name: &str, key_name: &str) -> Result<(), LockstoreError> {
    zeroize(store, db_name, key_name)?;
    let db = Database::new(store, db_name);
    let key = Key::from(key_name);
    db.delete(&key)?;
    Ok(())
}

Messung V0.5 in Prozent
C=89 H=100 G=94

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.