webrtc_dtls/crypto/
crypto_ccm.rs1use std::io::Cursor;
12
13use aes::Aes128;
14use ccm::aead::generic_array::GenericArray;
15use ccm::aead::AeadInPlace;
16use ccm::consts::{U12, U16, U8};
17use ccm::Ccm;
18use ccm::KeyInit;
19use rand::Rng;
20
21use super::*;
22use crate::content::*;
23use crate::error::*;
24use crate::record_layer::record_layer_header::*;
25
26const CRYPTO_CCM_8_TAG_LENGTH: usize = 8;
27const CRYPTO_CCM_TAG_LENGTH: usize = 16;
28const CRYPTO_CCM_NONCE_LENGTH: usize = 12;
29
30type AesCcm8 = Ccm<Aes128, U8, U12>;
31type AesCcm = Ccm<Aes128, U16, U12>;
32
33#[derive(Clone)]
34pub enum CryptoCcmTagLen {
35 CryptoCcm8TagLength,
36 CryptoCcmTagLength,
37}
38
39enum CryptoCcmType {
40 CryptoCcm8(AesCcm8),
41 CryptoCcm(AesCcm),
42}
43
44pub struct CryptoCcm {
46 local_ccm: CryptoCcmType,
47 remote_ccm: CryptoCcmType,
48 local_write_iv: Vec<u8>,
49 remote_write_iv: Vec<u8>,
50 local_write_key: Vec<u8>,
52 remote_write_key: Vec<u8>,
53}
54
55impl Clone for CryptoCcm {
56 fn clone(&self) -> Self {
57 match self.local_ccm {
58 CryptoCcmType::CryptoCcm(_) => Self::new(
59 &CryptoCcmTagLen::CryptoCcmTagLength,
60 &self.local_write_key,
61 &self.local_write_iv,
62 &self.remote_write_key,
63 &self.remote_write_iv,
64 ),
65 CryptoCcmType::CryptoCcm8(_) => Self::new(
66 &CryptoCcmTagLen::CryptoCcm8TagLength,
67 &self.local_write_key,
68 &self.local_write_iv,
69 &self.remote_write_key,
70 &self.remote_write_iv,
71 ),
72 }
73 }
74}
75
76impl CryptoCcm {
77 pub fn new(
78 tag_len: &CryptoCcmTagLen,
79 local_key: &[u8],
80 local_write_iv: &[u8],
81 remote_key: &[u8],
82 remote_write_iv: &[u8],
83 ) -> Self {
84 let key = GenericArray::from_slice(local_key);
85 let local_ccm = match tag_len {
86 CryptoCcmTagLen::CryptoCcmTagLength => CryptoCcmType::CryptoCcm(AesCcm::new(key)),
87 CryptoCcmTagLen::CryptoCcm8TagLength => CryptoCcmType::CryptoCcm8(AesCcm8::new(key)),
88 };
89
90 let key = GenericArray::from_slice(remote_key);
91 let remote_ccm = match tag_len {
92 CryptoCcmTagLen::CryptoCcmTagLength => CryptoCcmType::CryptoCcm(AesCcm::new(key)),
93 CryptoCcmTagLen::CryptoCcm8TagLength => CryptoCcmType::CryptoCcm8(AesCcm8::new(key)),
94 };
95
96 CryptoCcm {
97 local_ccm,
98 local_write_key: local_key.to_vec(),
99 local_write_iv: local_write_iv.to_vec(),
100 remote_ccm,
101 remote_write_key: remote_key.to_vec(),
102 remote_write_iv: remote_write_iv.to_vec(),
103 }
104 }
105
106 pub fn encrypt(&self, pkt_rlh: &RecordLayerHeader, raw: &[u8]) -> Result<Vec<u8>> {
107 let payload = &raw[RECORD_LAYER_HEADER_SIZE..];
108 let raw = &raw[..RECORD_LAYER_HEADER_SIZE];
109
110 let mut nonce = vec![0u8; CRYPTO_CCM_NONCE_LENGTH];
111 nonce[..4].copy_from_slice(&self.local_write_iv[..4]);
112 rand::thread_rng().fill(&mut nonce[4..]);
113 let nonce = GenericArray::from_slice(&nonce);
114
115 let additional_data = generate_aead_additional_data(pkt_rlh, payload.len());
116
117 let mut buffer: Vec<u8> = Vec::new();
118 buffer.extend_from_slice(payload);
119
120 match &self.local_ccm {
121 CryptoCcmType::CryptoCcm(ccm) => {
122 ccm.encrypt_in_place(nonce, &additional_data, &mut buffer)
123 .map_err(|e| Error::Other(e.to_string()))?;
124 }
125 CryptoCcmType::CryptoCcm8(ccm8) => {
126 ccm8.encrypt_in_place(nonce, &additional_data, &mut buffer)
127 .map_err(|e| Error::Other(e.to_string()))?;
128 }
129 }
130
131 let mut r = Vec::with_capacity(raw.len() + nonce.len() + buffer.len());
132
133 r.extend_from_slice(raw);
134 r.extend_from_slice(&nonce[4..]);
135 r.extend_from_slice(&buffer);
136
137 let r_len = (r.len() - RECORD_LAYER_HEADER_SIZE) as u16;
139 r[RECORD_LAYER_HEADER_SIZE - 2..RECORD_LAYER_HEADER_SIZE]
140 .copy_from_slice(&r_len.to_be_bytes());
141
142 Ok(r)
143 }
144
145 pub fn decrypt(&self, r: &[u8]) -> Result<Vec<u8>> {
146 let mut reader = Cursor::new(r);
147 let h = RecordLayerHeader::unmarshal(&mut reader)?;
148 if h.content_type == ContentType::ChangeCipherSpec {
149 return Ok(r.to_vec());
151 }
152
153 if r.len() <= (RECORD_LAYER_HEADER_SIZE + 8) {
154 return Err(Error::ErrNotEnoughRoomForNonce);
155 }
156
157 let mut nonce = vec![];
158 nonce.extend_from_slice(&self.remote_write_iv[..4]);
159 nonce.extend_from_slice(&r[RECORD_LAYER_HEADER_SIZE..RECORD_LAYER_HEADER_SIZE + 8]);
160 let nonce = GenericArray::from_slice(&nonce);
161
162 let out = &r[RECORD_LAYER_HEADER_SIZE + 8..];
163
164 let mut buffer: Vec<u8> = Vec::new();
165 buffer.extend_from_slice(out);
166
167 match &self.remote_ccm {
168 CryptoCcmType::CryptoCcm(ccm) => {
169 let additional_data =
170 generate_aead_additional_data(&h, out.len() - CRYPTO_CCM_TAG_LENGTH);
171 ccm.decrypt_in_place(nonce, &additional_data, &mut buffer)
172 .map_err(|e| Error::Other(e.to_string()))?;
173 }
174 CryptoCcmType::CryptoCcm8(ccm8) => {
175 let additional_data =
176 generate_aead_additional_data(&h, out.len() - CRYPTO_CCM_8_TAG_LENGTH);
177 ccm8.decrypt_in_place(nonce, &additional_data, &mut buffer)
178 .map_err(|e| Error::Other(e.to_string()))?;
179 }
180 }
181
182 let mut d = Vec::with_capacity(RECORD_LAYER_HEADER_SIZE + buffer.len());
183 d.extend_from_slice(&r[..RECORD_LAYER_HEADER_SIZE]);
184 d.extend_from_slice(&buffer);
185
186 Ok(d)
187 }
188}