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
use {aead, chacha, error, poly1305, polyfill};
pub static CHACHA20_POLY1305: aead::Algorithm = aead::Algorithm {
key_len: chacha::KEY_LEN_IN_BYTES,
init: chacha20_poly1305_init,
seal: chacha20_poly1305_seal,
open: chacha20_poly1305_open,
};
pub fn chacha20_poly1305_init(ctx_buf: &mut [u8], key: &[u8])
-> Result<(), error::Unspecified> {
ctx_buf[..key.len()].copy_from_slice(key);
Ok(())
}
fn chacha20_poly1305_seal(ctx: &[u64; aead::KEY_CTX_BUF_ELEMS],
nonce: &[u8; aead::NONCE_LEN], ad: &[u8],
in_out: &mut [u8], tag_out: &mut [u8; aead::TAG_LEN])
-> Result<(), error::Unspecified> {
let chacha20_key = ctx_as_key(ctx)?;
let mut counter = chacha::make_counter(nonce, 1);
chacha::chacha20_xor_in_place(&chacha20_key, &counter, in_out);
counter[0] = 0;
aead_poly1305(tag_out, chacha20_key, &counter, ad, in_out);
Ok(())
}
fn chacha20_poly1305_open(ctx: &[u64; aead::KEY_CTX_BUF_ELEMS],
nonce: &[u8; aead::NONCE_LEN], ad: &[u8],
in_prefix_len: usize, in_out: &mut [u8],
tag_out: &mut [u8; aead::TAG_LEN])
-> Result<(), error::Unspecified> {
let chacha20_key = ctx_as_key(ctx)?;
let mut counter = chacha::make_counter(nonce, 0);
{
let ciphertext = &in_out[in_prefix_len..];
aead_poly1305(tag_out, chacha20_key, &counter, ad, ciphertext);
}
counter[0] = 1;
chacha::chacha20_xor_overlapping(&chacha20_key, &counter, in_out,
in_prefix_len);
Ok(())
}
fn ctx_as_key(ctx: &[u64; aead::KEY_CTX_BUF_ELEMS])
-> Result<&chacha::Key, error::Unspecified> {
slice_as_array_ref!(
&polyfill::slice::u64_as_u32(ctx)[..(chacha::KEY_LEN_IN_BYTES / 4)],
chacha::KEY_LEN_IN_BYTES / 4)
}
fn aead_poly1305(tag_out: &mut [u8; aead::TAG_LEN], chacha20_key: &chacha::Key,
counter: &chacha::Counter, ad: &[u8], ciphertext: &[u8]) {
debug_assert_eq!(counter[0], 0);
let key = poly1305::Key::derive_using_chacha(chacha20_key, counter);
let mut ctx = poly1305::SigningContext::from_key(key);
poly1305_update_padded_16(&mut ctx, ad);
poly1305_update_padded_16(&mut ctx, ciphertext);
let lengths =
[polyfill::u64_from_usize(ad.len()).to_le(),
polyfill::u64_from_usize(ciphertext.len()).to_le()];
ctx.update(polyfill::slice::u64_as_u8(&lengths));
ctx.sign(tag_out);
}
#[inline]
fn poly1305_update_padded_16(ctx: &mut poly1305::SigningContext, data: &[u8]) {
ctx.update(data);
if data.len() % 16 != 0 {
static PADDING: [u8; 16] = [0u8; 16];
ctx.update(&PADDING[..PADDING.len() - (data.len() % 16)])
}
}