anothertls/crypto/chacha20/
poly1305.rs1use crate::crypto::chacha20::ChaCha20;
9use crate::net::alert::TlsError;
10use crate::{crypto::Cipher, utils::bytes};
11use ibig::ibig;
12
13use super::cipher::ChaCha20Block;
14
15#[derive(Default)]
16pub struct Poly1305();
17
18impl Poly1305 {
19 pub fn key_gen(key: &[u8], iv: &[u8]) -> Vec<u8> {
20 let mut chacha20_block = ChaCha20Block::init(key, iv, 0).unwrap();
21 chacha20_block.get_block()[..32].to_vec()
22 }
23
24 pub fn mac(key: &[u8], msg: &[u8]) -> [u8; 16] {
25 let mut r = bytes::to_ibig_le(&key[..16]);
26 r &= ibig!(_0ffffffc0ffffffc0ffffffc0fffffff base 16);
27 let s = bytes::to_ibig_le(&key[16..32]);
28
29 let mut a = ibig!(0);
30 let p = ibig!(_3fffffffffffffffffffffffffffffffb base 16);
31
32 for i in 1..=(msg.len() as f32 / 16.0).ceil() as usize {
33 let n = if i * 16 > msg.len() {
34 let mut buf = vec![];
35 buf.extend_from_slice(&msg[(i - 1) * 16..]);
36 buf.push(0x01);
37 bytes::to_ibig_le(&buf)
38 } else {
39 let mut n = bytes::to_ibig_le(&msg[(i - 1) * 16..i * 16]);
40 n += ibig!(_100000000000000000000000000000000 base 16);
41 n
42 };
43 a += n;
44 a = (r.clone() * a) % p.clone();
45 }
46 a += s;
47 let mut ret = bytes::ibig_to_vec(a, bytes::ByteOrder::Little);
48 ret.resize(16, 0);
50 ret.try_into().unwrap()
51 }
52 pub fn pad16(input: &mut Vec<u8>, x: usize) {
53 if x % 16 != 0 {
54 input.resize(input.len() + (16 - (x % 16)), 0)
55 }
56 }
57 pub fn get_mac_data(ciphertext: &[u8], additional_data: &[u8]) -> Vec<u8> {
58 let mut mac_data = additional_data.to_vec();
59 Poly1305::pad16(&mut mac_data, additional_data.len());
60 mac_data.extend_from_slice(ciphertext);
61 Poly1305::pad16(&mut mac_data, ciphertext.len());
62
63 mac_data.extend_from_slice(&bytes::u64_to_bytes_le(additional_data.len() as u64));
64 mac_data.extend_from_slice(&bytes::u64_to_bytes_le(ciphertext.len() as u64));
65 mac_data
66 }
67}
68
69impl Cipher for Poly1305 {
70 fn encrypt(
71 &self,
72 key: &[u8],
73 iv: &[u8],
74 plaintext: &[u8],
75 additional_data: &[u8],
76 ) -> Result<(Vec<u8>, [u8; 16]), TlsError> {
77 let ciphertext = ChaCha20::encrypt(plaintext, key, iv, 1).unwrap();
78 let otk = Poly1305::key_gen(key, iv);
79 let tag = Poly1305::mac(&otk, &Poly1305::get_mac_data(&ciphertext, additional_data));
80 Ok((ciphertext, tag))
81 }
82
83 fn decrypt(
84 &self,
85 key: &[u8],
86 iv: &[u8],
87 ciphertext: &[u8],
88 additional_data: &[u8],
89 auth_tag: &[u8],
90 ) -> Result<Vec<u8>, TlsError> {
91 let otk = Poly1305::key_gen(key, iv);
92 let tag = Poly1305::mac(&otk, &Poly1305::get_mac_data(ciphertext, additional_data));
93 if tag == auth_tag {
94 if let Some(plaintext) = ChaCha20::decrypt(ciphertext, key, iv, 1) {
95 return Ok(plaintext);
96 }
97 }
98 Err(TlsError::BadRecordMac)
99 }
100
101 fn get_cipher_suite(&self) -> crate::crypto::CipherSuite {
102 crate::crypto::CipherSuite::TLS_CHACHA20_POLY1305_SHA256
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::Poly1305;
109 use crate::crypto::ciphersuite::Cipher;
110 use crate::utils::bytes;
111
112 #[test]
113 fn test_poly1305_mac() {
114 let key =
115 bytes::from_hex("85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b");
116 let msg =
117 bytes::from_hex("43727970746f6772617068696320466f72756d2052657365617263682047726f7570");
118
119 let expected = bytes::from_hex("a8061dc1305136c6c22b8baf0c0127a9");
120
121 assert_eq!(expected, Poly1305::mac(&key, &msg));
122 }
123
124 #[test]
125 fn test_poly1305_key_gen() {
126 let key =
127 bytes::from_hex("808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f");
128 let nonce = bytes::from_hex("000000000001020304050607");
129 let expected =
130 bytes::from_hex("8ad5a08b905f81cc815040274ab29471a833b637e3fd0da508dbb8e2fdd1a646");
131
132 assert_eq!(expected, Poly1305::key_gen(&key, &nonce));
133 }
134 #[test]
135 fn test_poly1305_aead_de_encrypt() {
136 let plaintext = bytes::from_hex("4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e");
137 let aad = bytes::from_hex("50515253c0c1c2c3c4c5c6c7");
138 let key =
139 bytes::from_hex("808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f");
140 let iv = bytes::from_hex("070000004041424344454647");
141 let ciphertext = bytes::from_hex("d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b6116");
142 let tag = bytes::from_hex("1ae10b594f09e26a7e902ecbd0600691");
143
144 let encrypted = Poly1305::default()
145 .encrypt(&key, &iv, &plaintext, &aad)
146 .unwrap();
147
148 assert_eq!(encrypted.0, ciphertext);
149 assert_eq!(&encrypted.1, &tag.as_slice());
150
151 let decrypted = Poly1305::default()
152 .decrypt(&key, &iv, &ciphertext, &aad, &tag)
153 .unwrap();
154
155 assert_eq!(decrypted, plaintext);
156 }
157
158 #[test]
159 fn test_poly1305_aead_decrypt() {
160 let ciphertext = bytes::from_hex("64a0861575861af460f062c79be643bd5e805cfd345cf389f108670ac76c8cb24c6cfc18755d43eea09ee94e382d26b0bdb7b73c321b0100d4f03b7f355894cf332f830e710b97ce98c8a84abd0b948114ad176e008d33bd60f982b1ff37c8559797a06ef4f0ef61c186324e2b3506383606907b6a7c02b0f9f6157b53c867e4b9166c767b804d46a59b5216cde7a4e99040c5a40433225ee282a1b0a06c523eaf4534d7f83fa1155b0047718cbc546a0d072b04b3564eea1b422273f548271a0bb2316053fa76991955ebd63159434ecebb4e466dae5a1073a6727627097a1049e617d91d361094fa68f0ff77987130305beaba2eda04df997b714d6c6f2c29a6ad5cb4022b02709b");
161
162 let key =
163 bytes::from_hex("1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0");
164 let aad = bytes::from_hex("f33388860000000000004e91");
165 let tag = bytes::from_hex("eead9d67890cbb22392336fea1851f38");
166 let iv = bytes::from_hex("000000000102030405060708");
167 let plaintext = bytes::from_hex("496e7465726e65742d4472616674732061726520647261667420646f63756d656e74732076616c696420666f722061206d6178696d756d206f6620736978206d6f6e74687320616e64206d617920626520757064617465642c207265706c616365642c206f72206f62736f6c65746564206279206f7468657220646f63756d656e747320617420616e792074696d652e20497420697320696e617070726f70726961746520746f2075736520496e7465726e65742d447261667473206173207265666572656e6365206d6174657269616c206f7220746f2063697465207468656d206f74686572207468616e206173202fe2809c776f726b20696e2070726f67726573732e2fe2809d");
168
169 let decrypted = Poly1305::default()
170 .decrypt(&key, &iv, &ciphertext, &aad, &tag)
171 .unwrap();
172
173 assert_eq!(decrypted, plaintext);
174 }
175}