1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#![doc = include_str!("../Readme.md")]
#![no_std]

extern crate alloc;
#[cfg(feature = "std")]
extern crate std;

use alloc::string::String;
use alloc::vec::Vec;

use error::Error;
use types::{AeadAlgorithm, KemAlgorithm};

pub mod error;
pub mod types;

// re-export trait
pub use rand_core::{CryptoRng, RngCore};

/// The [`HpkeCrypto`] trait defines the necessary cryptographic functions used
/// in the HPKE implementation.
pub trait HpkeCrypto: core::fmt::Debug + Send + Sync {
    /// The PRNG implementation returned in [`HpkeCrypto::prng()`].
    type HpkePrng: RngCore + CryptoRng + HpkeTestRng;

    /// The name of the implementation.
    fn name() -> String;

    /// Returns an error if the KDF algorithm is not supported by this crypto provider.
    fn supports_kdf(alg: types::KdfAlgorithm) -> Result<(), Error>;

    /// Returns an error if the KEM algorithm is not supported by this crypto provider.
    fn supports_kem(alg: types::KemAlgorithm) -> Result<(), Error>;

    /// Returns an error if the AEAD algorithm is not supported by this crypto provider.
    fn supports_aead(alg: types::AeadAlgorithm) -> Result<(), Error>;

    /// Get a stateful PRNG.
    /// Note that this will create a new PRNG state.
    fn prng() -> Self::HpkePrng;

    /// Get the length of the output digest.
    #[inline(always)]
    fn kdf_digest_length(alg: types::KdfAlgorithm) -> usize {
        match alg {
            types::KdfAlgorithm::HkdfSha256 => 32,
            types::KdfAlgorithm::HkdfSha384 => 48,
            types::KdfAlgorithm::HkdfSha512 => 64,
        }
    }

    /// KDF Extract
    fn kdf_extract(alg: types::KdfAlgorithm, salt: &[u8], ikm: &[u8]) -> Vec<u8>;

    /// KDF Expand
    fn kdf_expand(
        alg: types::KdfAlgorithm,
        prk: &[u8],
        info: &[u8],
        output_size: usize,
    ) -> Result<Vec<u8>, Error>;

    /// KEM Derive
    fn kem_derive(alg: KemAlgorithm, pk: &[u8], sk: &[u8]) -> Result<Vec<u8>, Error>;

    /// KEM Derive with base
    fn kem_derive_base(alg: KemAlgorithm, sk: &[u8]) -> Result<Vec<u8>, Error>;

    /// KEM Key generation
    fn kem_key_gen(alg: KemAlgorithm, prng: &mut Self::HpkePrng) -> Result<Vec<u8>, Error>;

    /// Validate a secret key for its correctness.
    fn kem_validate_sk(alg: KemAlgorithm, sk: &[u8]) -> Result<Vec<u8>, Error>;

    /// AEAD encrypt.
    fn aead_seal(
        alg: AeadAlgorithm,
        key: &[u8],
        nonce: &[u8],
        aad: &[u8],
        msg: &[u8],
    ) -> Result<Vec<u8>, Error>;

    /// AEAD decrypt.
    fn aead_open(
        alg: AeadAlgorithm,
        key: &[u8],
        nonce: &[u8],
        aad: &[u8],
        msg: &[u8],
    ) -> Result<Vec<u8>, Error>;

    /// Get key length for AEAD.
    ///
    /// Note that this function returns `0` for export only keys of unknown size.
    fn aead_key_length(alg: AeadAlgorithm) -> usize {
        match alg {
            AeadAlgorithm::Aes128Gcm => 16,
            AeadAlgorithm::Aes256Gcm => 32,
            AeadAlgorithm::ChaCha20Poly1305 => 32,
            AeadAlgorithm::HpkeExport => 0,
        }
    }

    /// Get key length for AEAD.
    ///
    /// Note that this function returns `0` for export only nonces of unknown size.
    fn aead_nonce_length(alg: AeadAlgorithm) -> usize {
        match alg {
            AeadAlgorithm::Aes128Gcm => 12,
            AeadAlgorithm::Aes256Gcm => 12,
            AeadAlgorithm::ChaCha20Poly1305 => 12,
            AeadAlgorithm::HpkeExport => 0,
        }
    }

    /// Get key length for AEAD.
    ///
    /// Note that this function returns `0` for export only tags of unknown size.
    fn aead_tag_length(alg: AeadAlgorithm) -> usize {
        match alg {
            AeadAlgorithm::Aes128Gcm => 16,
            AeadAlgorithm::Aes256Gcm => 16,
            AeadAlgorithm::ChaCha20Poly1305 => 16,
            AeadAlgorithm::HpkeExport => 0,
        }
    }
}

/// PRNG extension for testing that is supposed to return pre-configured bytes.
pub trait HpkeTestRng {
    /// Like [`RngCore::try_fill_bytes`] but the result is expected to be known.
    fn try_fill_test_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error>;

    /// Set the randomness state of this test PRNG.
    fn seed(&mut self, seed: &[u8]);
}