1use crate::{ ChachaPolyError, ChaCha20Ietf, Poly1305 };
2use crypto_api::{
3 cipher::{ CipherInfo, Cipher, AeadCipher },
4 rng::{ SecureRng, SecKeyGen }
5};
6use std::error::Error;
7
8
9#[cfg(target_pointer_width = "64")]
11pub const CHACHAPOLY_MAX: usize = (4_294_967_296 - 1) * 64; #[cfg(target_pointer_width = "32")]
14pub const CHACHAPOLY_MAX: usize = usize::max_value() - 16; pub const CHACHAPOLY_KEY: usize = 32;
18pub const CHACHAPOLY_NONCE: usize = 12;
20pub const CHACHAPOLY_TAG: usize = 16;
22
23
24pub fn chachapoly_seal(data: &mut[u8], tag: &mut[u8], ad: &[u8], key: &[u8], nonce: &[u8]) {
26 ChaCha20Ietf::xor(key, nonce, 1, data);
28
29 let mut foot = Vec::with_capacity(16);
31 foot.extend_from_slice(&(ad.len() as u64).to_le_bytes());
32 foot.extend_from_slice(&(data.len() as u64).to_le_bytes());
33
34 let mut pkey = vec![0; 32];
36 ChaCha20Ietf::xor(key, nonce, 0, &mut pkey);
37 Poly1305::chachapoly_auth(tag, ad, data, &foot, &pkey);
38}
39pub fn chachapoly_open(data: &mut[u8], tag: &[u8], ad: &[u8], key: &[u8], nonce: &[u8])
41 -> Result<(), Box<dyn Error + 'static>>
42{
43 let mut foot = Vec::with_capacity(16);
45 foot.extend_from_slice(&(ad.len() as u64).to_le_bytes());
46 foot.extend_from_slice(&(data.len() as u64).to_le_bytes());
47
48 let (mut pkey, mut vfy_tag) = (vec![0; 32], vec![0; 16]);
50 ChaCha20Ietf::xor(key, nonce, 0, &mut pkey);
51 Poly1305::chachapoly_auth(&mut vfy_tag, ad, data, &foot, &pkey);
52
53 Ok(match eq_ct!(&tag, &vfy_tag) {
55 true => ChaCha20Ietf::xor(key, nonce, 1, data),
56 false => Err(ChachaPolyError::InvalidData)?
57 })
58}
59
60
61pub struct ChachaPolyIetf;
64impl ChachaPolyIetf {
65 pub fn cipher() -> Box<dyn Cipher> {
67 Box::new(Self)
68 }
69 pub fn aead_cipher() -> Box<dyn AeadCipher> {
71 Box::new(Self)
72 }
73}
74impl SecKeyGen for ChachaPolyIetf {
75 fn new_sec_key(&self, buf: &mut[u8], rng: &mut dyn SecureRng) -> Result<usize, Box<dyn Error + 'static>> {
76 vfy_keygen!(CHACHAPOLY_KEY => buf);
78
79 rng.random(&mut buf[..CHACHAPOLY_KEY])?;
81 Ok(CHACHAPOLY_KEY)
82 }
83}
84impl Cipher for ChachaPolyIetf {
85 fn info(&self) -> CipherInfo {
86 CipherInfo {
87 name: "ChachaPolyIetf", is_otc: true,
88 key_len_r: CHACHAPOLY_KEY..(CHACHAPOLY_KEY + 1),
89 nonce_len_r: CHACHAPOLY_NONCE..(CHACHAPOLY_NONCE + 1),
90 aead_tag_len_r: CHACHAPOLY_TAG..(CHACHAPOLY_TAG + 1)
91 }
92 }
93
94 fn encrypted_len_max(&self, plaintext_len: usize) -> usize {
95 plaintext_len + 16
96 }
97
98 fn encrypt(&self, buf: &mut[u8], plaintext_len: usize, key: &[u8], nonce: &[u8])
99 -> Result<usize, Box<dyn Error + 'static>>
100 {
101 self.seal(buf, plaintext_len, &[], key, nonce)
102 }
103 fn encrypt_to(&self, buf: &mut[u8], plaintext: &[u8], key: &[u8], nonce: &[u8])
104 -> Result<usize, Box<dyn Error + 'static>>
105 {
106 self.seal_to(buf, plaintext, &[], key, nonce)
107 }
108
109 fn decrypt(&self, buf: &mut[u8], ciphertext_len: usize, key: &[u8], nonce: &[u8])
110 -> Result<usize, Box<dyn Error + 'static>>
111 {
112 self.open(buf, ciphertext_len, &[], key, nonce)
113 }
114 fn decrypt_to(&self, buf: &mut[u8], ciphertext: &[u8], key: &[u8], nonce: &[u8])
115 -> Result<usize, Box<dyn Error + 'static>>
116 {
117 self.open_to(buf, ciphertext, &[], key, nonce)
118 }
119}
120impl AeadCipher for ChachaPolyIetf {
121 fn seal(&self, buf: &mut[u8], plaintext_len: usize, ad: &[u8], key: &[u8], nonce: &[u8])
122 -> Result<usize, Box<dyn Error + 'static>>
123 {
124 vfy_seal!(
126 key => [CHACHAPOLY_KEY], nonce => [CHACHAPOLY_NONCE],
127 plaintext_len => [buf, CHACHAPOLY_MAX]
128 );
129
130 let (data, tag) = buf.split_at_mut(plaintext_len);
132 chachapoly_seal(data, &mut tag[..CHACHAPOLY_TAG], ad, key, nonce);
133 Ok(plaintext_len + CHACHAPOLY_TAG)
134 }
135 fn seal_to(&self, buf: &mut[u8], plaintext: &[u8], ad: &[u8], key: &[u8], nonce: &[u8])
136 -> Result<usize, Box<dyn Error + 'static>>
137 {
138 vfy_seal!(
140 key => [CHACHAPOLY_KEY], nonce => [CHACHAPOLY_NONCE],
141 plaintext => [buf, CHACHAPOLY_MAX]
142 );
143
144 let (data, tag) = buf.split_at_mut(plaintext.len());
146 data.copy_from_slice(plaintext);
147 chachapoly_seal(data, &mut tag[..CHACHAPOLY_TAG], ad, key, nonce);
148 Ok(plaintext.len() + CHACHAPOLY_TAG)
149 }
150
151 fn open(&self, buf: &mut[u8], ciphertext_len: usize, ad: &[u8], key: &[u8], nonce: &[u8])
152 -> Result<usize, Box<dyn Error + 'static>>
153 {
154 vfy_open!(
156 key => [CHACHAPOLY_KEY], nonce => [CHACHAPOLY_NONCE],
157 ciphertext_len => [buf, CHACHAPOLY_TAG, CHACHAPOLY_MAX]
158 );
159
160 let (data, tag) = buf.split_at_mut(ciphertext_len - CHACHAPOLY_TAG);
162 chachapoly_open(data, &tag[..CHACHAPOLY_TAG], ad, key, nonce)?;
163 Ok(ciphertext_len - CHACHAPOLY_TAG)
164 }
165 fn open_to(&self, buf: &mut[u8], ciphertext: &[u8], ad: &[u8], key: &[u8], nonce: &[u8])
166 -> Result<usize, Box<dyn Error + 'static>>
167 {
168 vfy_open!(
170 key => [CHACHAPOLY_KEY], nonce => [CHACHAPOLY_NONCE],
171 ciphertext => [buf, CHACHAPOLY_TAG, CHACHAPOLY_MAX]
172 );
173
174 let (data, tag) = ciphertext.split_at(ciphertext.len() - CHACHAPOLY_TAG);
176 buf[..data.len()].copy_from_slice(data);
177 chachapoly_open(&mut buf[..data.len()], &tag[..CHACHAPOLY_TAG], ad, key, nonce)?;
178 Ok(ciphertext.len() - CHACHAPOLY_TAG)
179 }
180}