cryptocol 0.19.10

A cryptographic library that includes big number arithmetic operations, hash algorithms, symmetric-key encryption/decryption algorithms, asymmetric-key (public-key) encryption/decryption algorithms, pseudo random number generators, etc. Hash algorithms includes MD4, MD5, SHA224, SHA256, SHA384, SHA512, SHA3, etc. Symmetric key encryption algorithms include DES, AES, etc. Public key encryption algorithms include RSA, ECC, etc.
Documentation
// Copyright 2025, 2026 PARK Youngho.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
// This file may not be copied, modified, or distributed
// except according to those terms.


#![allow(missing_docs)]
#![allow(unused_must_use)]
#![allow(dead_code)]
#![allow(unused_variables)]
// #![warn(rustdoc::missing_doc_code_examples)]


use crate::number::SmallUInt;
use crate::asymmetric::{ PRNG, Hash };

/// This trait OAEP is based on PKCS #1 ver. 2.1. The RSA OAEP (Optimal
/// Asymmetric Encryption Padding) format is a Feistel network-based padding
/// scheme designed to provide "plaintext awareness," preventing an attacker
/// from modifying the ciphertext without being detected.
///
/// Unlike the simpler PKCS #1 v1.5, OAEP utilizes a Mask Generation Function
/// (MGF) and cryptographic hash functions to inject high entropy and
/// mathematically ensure that the encryption is IND-CCA2 secure (secure
/// against chosen-ciphertext attacks).
///
/// # PKCS #1 v2.1 (RSAES-OAEP) Encryption Block Structure
/// The OAEP encoding process produces an Encoded Message (EM) of length k,
/// which is structured as follows:
///
/// | Offset          | Field Name  | Value        | Description                                                   |
/// |-----------------|-------------|--------------|---------------------------------------------------------------|
/// | 0               | Leading 00  | 0x00         | Ensures the numeric value of EM is less than the modulus n.   |
/// | 1 to hLen       | Masked Seed | Masked Bytes | seed XORed with dbMask. Provides randomness for the encoding. |
/// | hLen + 1 to k-1 | Masked DB   | Masked Bytes | DB XORed with seedMask. Contains the actual data and padding. |
///
/// ## Data Block (DB) Structure (Internal to Masked DB)
/// The Data Block (DB) before masking is composed of:
///
/// | Field Name   | Length            | Value          | Description                                                           |
/// |--------------|-------------------|----------------|-----------------------------------------------------------------------|
/// | lHash        | hLen              | Hash(L)        | Hash of the optional label L (empty string by default).               |
/// | PS (Padding) | k - m - 2hLen - 2 | 0x00...00      | Zero-byte padding string. Can be empty.                               |
/// | Separator    | 1                 | 0x01           | Single byte (0x01) indicating the end of padding and start of message.|
/// | Message (M)  | m                 | Actual Message | The raw data to be encrypted.                                         |
///
/// - k: The length of the RSA modulus n in bytes (e.g., 256 for a 2048-bit key).
/// - hLen: The output length of the chosen Hash function (e.g., 20 for SHA-1,
///   32 for SHA-256).
/// - m: The length of the message M in bytes.
/// - Max Message Length: k - 2 * hLen - 2
///   (e.g., 190 bytes for RSA-2048 with SHA-256).
///
/// # Key Field Details
/// ## 1. Leading 0x00 (1 byte)
/// Similar to PKCS #1 v1.5, this byte ensures that the integer represented by
/// the encoded block (EM) is numerically smaller than the RSA modulus n.
///
/// ## 2. Masked Seed (hLen bytes) (Masking using G function)
/// This field is generated by XORing a random seed with the output of a
/// Mask Generation Function (MGF) applied to the Masked DB.
/// - Purpose: It provides the entropy needed for probabilistic encryption,
///   ensuring the same message results in different ciphertexts.
///
/// ## 3. Masked Data Block (Masked DB) (k - hLen - 1 bytes) (Masking using H function)
/// This is the XOR sum of the raw Data Block (DB) and the output of the
/// MGF applied to the seed.
/// - Integrity: Because the seed and DB are cross-masked, any alteration
///   to the ciphertext will propagate errors through the MGF,
///   making the padding invalid upon decryption.
///
/// ## 4. lHash (Inside DB, hLen bytes)
/// The hash of an optional label L. By default, this is the hash of an
/// empty string.
/// - Role: It binds the ciphertext to a specific context or label,
///   providing an extra layer of verification.
///
/// ## 5. Padding String (PS) and Separator (0x01)
/// Unlike v1.5 which uses a simple 0x00 separator, OAEP uses a string of
/// 0x00 bytes (PS) followed by a mandatory 0x01 byte.
/// - Reason: This clear structure allows the decrypter to unambiguously
///   locate the start of the actual message M after unmasking the DB.
///
/// # Security Strength: IND-CCA2 Compliance
/// RSA-OAEP was specifically designed to overcome the weaknesses of
/// PKCS #1 v1.5.
/// - Resistance to Padding Oracle Attacks: OAEP is mathematically
///   proven to be secure against adaptive chosen-ciphertext attacks (IND-CCA2).
///   It is much harder for an attacker to gain information by observing
///   decryption errors (like Bleichenbacher's attack).
/// - All-or-Nothing Property: Due to the Feistel-like network of XORs
///   and MGFs, a candidate ciphertext is either decrypted perfectly or
///   fails the padding check entirely, leaking no partial information.
///
/// Therefore, RSA-OAEP is the current industry standard and the
/// recommended choice for all modern RSA encryption implementations to
/// ensure cryptographic robustness.
pub trait OAEP
{
    const BT: u8 = 2;

    // fn set_prng(&mut self, prng: RNG)
    fn set_prng(&mut self, prng:  Box<dyn PRNG>);
    
    fn set_hash(&mut self, hash:  Box<dyn Hash>);
    
    fn encrypt(&mut self, message: *const u8, length_in_bytes: u64, cipher: *mut u8) -> u64;

    fn encrypt_into_vec<U>(&mut self, message: *const u8, length_in_bytes: u64, cipher: &mut Vec<U>) -> u64
    where U: SmallUInt;

    fn encrypt_into_array<U, const N: usize>(&mut self, message: *const u8, length_in_bytes: u64, cipher: &mut [U; N]) -> u64
    where U: SmallUInt;

    #[inline]
    fn encrypt_str(&mut self, message: &str, cipher: *mut u8) -> u64
    {
        self.encrypt(message.as_ptr(), message.len() as u64, cipher)
    }

    #[inline]
    fn encrypt_str_into_vec<U>(&mut self, message: &str, cipher: &mut Vec<U>) -> u64
    where U: SmallUInt
    {
        self.encrypt_into_vec(message.as_ptr(), message.len() as u64, cipher)
    }

    #[inline]
    fn encrypt_str_into_array<U, const N: usize>(&mut self, message: &str, cipher: &mut [U; N]) -> u64
    where U: SmallUInt
    {
        self.encrypt_into_array(message.as_ptr(), message.len() as u64, cipher)
    }

    #[inline]
    fn encrypt_string(&mut self, message: &String, cipher: *mut u8) -> u64
    {
        self.encrypt(message.as_ptr(), message.len() as u64, cipher)
    }

    #[inline]
    fn encrypt_string_into_vec<U>(&mut self, message: &String, cipher: &mut Vec<U>) -> u64
    where U: SmallUInt
    {
        self.encrypt_into_vec(message.as_ptr(), message.len() as u64, cipher)
    }

    #[inline]
    fn encrypt_string_into_array<U, const N: usize>(&mut self, message: &String, cipher: &mut [U; N]) -> u64
    where U: SmallUInt
    {
        self.encrypt_into_array(message.as_ptr(), message.len() as u64, cipher)
    }

    #[inline]
    fn encrypt_vec<U>(&mut self, message: &Vec<U>, cipher: *mut u8) -> u64
    where U: SmallUInt
    {
        self.encrypt(message.as_ptr() as *const u8, (message.len() as u32 * U::size_in_bytes()) as u64, cipher)
    }

    #[inline]
    fn encrypt_vec_into_vec<U, V>(&mut self, message: &Vec<U>, cipher: &mut Vec<V>) -> u64
    where U: SmallUInt, V: SmallUInt
    {
        self.encrypt_into_vec(message.as_ptr() as *const u8, (message.len() as u32 * U::size_in_bytes()) as u64, cipher)
    }

    #[inline]
    fn encrypt_vec_into_array<U, V, const N: usize>(&mut self, message: &Vec<U>, cipher: &mut [V; N]) -> u64
    where U: SmallUInt, V: SmallUInt
    {
        self.encrypt_into_array(message.as_ptr() as *const u8, (message.len() as u32 * U::size_in_bytes()) as u64, cipher)
    }

    #[inline]
    fn encrypt_array<U, const N: usize>(&mut self, message: &[U; N], cipher: *mut u8) -> u64
    where U: SmallUInt
    {
        self.encrypt(message.as_ptr() as *const u8, (N as u32 * U::size_in_bytes()) as u64, cipher)
    }

    #[inline]
    fn encrypt_array_into_vec<U, V, const N: usize>(&mut self, message: &[U; N], cipher: &mut Vec<V>) -> u64
    where U: SmallUInt, V: SmallUInt
    {
        self.encrypt_into_vec(message.as_ptr() as *const u8, (N as u32 * U::size_in_bytes()) as u64, cipher)
    }

    #[inline]
    fn encrypt_array_into_array<U, V, const N: usize, const M: usize>(&mut self, message: &[U; N], cipher: &mut [V; M]) -> u64
    where U: SmallUInt, V: SmallUInt
    {
        self.encrypt_into_array(message.as_ptr() as *const u8, (N as u32 * U::size_in_bytes()) as u64, cipher)
    }

    fn decrypt(&mut self, cipher: *const u8, message: *mut u8) -> u64;

    fn decrypt_into_vec<U>(&mut self, cipher: *const u8, message: &mut Vec<U>) -> u64
    where U: SmallUInt;

    fn decrypt_into_array<U, const N: usize>(&mut self, cipher: *const u8, message: &mut [U; N]) -> u64
    where U: SmallUInt;

    #[inline]
    fn decrypt_into_string(&mut self, cipher: *const u8, message: &mut String) -> u64
    {
        self.decrypt_into_vec(cipher, unsafe { message.as_mut_vec() })
    }

    #[inline]
    fn decrypt_vec<U>(&mut self, cipher: &Vec<U>, message: *mut u8) -> u64
    where U: SmallUInt
    {
        self.decrypt(cipher.as_ptr() as *const u8, message)
    }

    fn decrypt_vec_into_vec<U, V>(&mut self, cipher: &Vec<U>, message: &mut Vec<V>) -> u64
    where U: SmallUInt, V: SmallUInt;

    #[inline]
    fn decrypt_vec_into_array<U, V, const N: usize>(&mut self, cipher: &Vec<U>, message: &mut [V; N]) -> u64
    where U: SmallUInt, V: SmallUInt
    {
        self.decrypt_into_array(cipher.as_ptr() as *const u8, message)
    }

    #[inline]
    fn decrypt_vec_into_string<U>(&mut self, cipher: &Vec<U>, message: &mut String) -> u64
    where U: SmallUInt
    {
        self.decrypt_into_string(cipher.as_ptr() as *const u8, message)
    }

    #[inline]
    fn decrypt_array<U, const N: usize>(&mut self, cipher: &[U; N], message: *mut u8) -> u64
    where U: SmallUInt
    {
        self.decrypt(cipher.as_ptr() as *const u8, message)
    }

    #[inline]
    fn decrypt_array_into_vec<U, V, const N: usize>(&mut self, cipher: &[U; N], message: &mut Vec<V>) -> u64
    where U: SmallUInt, V: SmallUInt
    {
        self.decrypt_into_vec(cipher.as_ptr() as *const u8, message)
    }

    #[inline]
    fn decrypt_array_into_array<U, V, const N: usize, const M: usize>(&mut self, cipher: &[U; N], message: &mut [V; M]) -> u64
    where U: SmallUInt, V: SmallUInt
    {
        self.decrypt_into_array(cipher.as_ptr() as *const u8, message)
    }

    #[inline]
    fn decrypt_array_into_string<U, const N: usize>(&mut self, cipher: &[U; N], message: &mut String) -> u64
    where U: SmallUInt
    {
        self.decrypt_into_string(cipher.as_ptr() as *const u8, message)
    }
}