1mod bit_hash;
5mod dh;
6pub use dh::RustCryptoDhKey;
7
8use crate::xmldsig::{DigestAlgorithm, SignatureAlgorithm};
9use p256::elliptic_curve::sec1::ToSec1Point;
10
11use super::{
12 KdfContext, KdfParameters, KeyAgreementKey, KeyAgreementParameters, ProviderError,
13 ProviderInputError, ProviderOperation,
14};
15
16pub(super) const X25519_URI: &str = "http://www.w3.org/2021/04/xmldsig-more#x25519";
17pub(super) const ECDH_URI: &str = "http://www.w3.org/2009/xmlenc11#ECDH-ES";
18pub(super) const DH_ES_URI: &str = "http://www.w3.org/2009/xmlenc11#dh-es";
19pub(super) const DH_URI: &str = "http://www.w3.org/2001/04/xmlenc#dh";
20const HKDF_URI: &str = "http://www.w3.org/2021/04/xmldsig-more#hkdf";
21const PBKDF2_URI: &str = "http://www.w3.org/2009/xmlenc11#pbkdf2";
22const CONCAT_KDF_URI: &str = "http://www.w3.org/2009/xmlenc11#ConcatKDF";
23const LEGACY_DH_URI: &str = "http://www.w3.org/2001/04/xmlenc#dh";
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum EcdhCurve {
28 P256,
30 P384,
32 P521,
34}
35
36enum EcdhSecret {
37 P256(p256::SecretKey),
38 P384(p384::SecretKey),
39 P521(p521::SecretKey),
40}
41
42pub struct RustCryptoEcdhKey(EcdhSecret);
44
45impl core::fmt::Debug for RustCryptoEcdhKey {
46 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
47 formatter
48 .debug_struct("RustCryptoEcdhKey")
49 .finish_non_exhaustive()
50 }
51}
52
53impl RustCryptoEcdhKey {
54 pub fn from_scalar(curve: EcdhCurve, bytes: &[u8]) -> Result<Self, ProviderError> {
57 let width = match curve {
58 EcdhCurve::P256 => 32,
59 EcdhCurve::P384 => 48,
60 EcdhCurve::P521 => 66,
61 };
62 if bytes.len() != width {
63 return Err(ProviderError::InvalidKeySize {
64 expected: width,
65 actual: bytes.len(),
66 });
67 }
68 let invalid = |_| ProviderError::InvalidInput(ProviderInputError::EcdhKey);
69 Ok(Self(match curve {
70 EcdhCurve::P256 => {
71 EcdhSecret::P256(p256::SecretKey::from_slice(bytes).map_err(invalid)?)
72 }
73 EcdhCurve::P384 => {
74 EcdhSecret::P384(p384::SecretKey::from_slice(bytes).map_err(invalid)?)
75 }
76 EcdhCurve::P521 => {
77 EcdhSecret::P521(p521::SecretKey::from_slice(bytes).map_err(invalid)?)
78 }
79 }))
80 }
81
82 pub fn public_key(&self) -> Vec<u8> {
84 match &self.0 {
85 EcdhSecret::P256(key) => key.public_key().to_sec1_point(false).as_bytes().to_vec(),
86 EcdhSecret::P384(key) => key.public_key().to_sec1_point(false).as_bytes().to_vec(),
87 EcdhSecret::P521(key) => key.public_key().to_sec1_point(false).as_bytes().to_vec(),
88 }
89 }
90}
91
92impl KeyAgreementKey for RustCryptoEcdhKey {
93 fn agree(&self, parameters: &KeyAgreementParameters<'_>) -> Result<Vec<u8>, ProviderError> {
94 if parameters.algorithm != ECDH_URI {
95 return Err(ProviderError::Unsupported {
96 operation: ProviderOperation::KeyAgreement,
97 algorithm: Some(parameters.algorithm.to_owned()),
98 });
99 }
100 macro_rules! agree {
101 ($key:expr, $public:ty) => {{
102 let peer = <$public>::from_sec1_bytes(parameters.peer_public_key)
107 .map_err(|_| ProviderError::InvalidInput(ProviderInputError::EcdhKey))?;
108 let shared = $key.diffie_hellman(&peer);
109 Ok(shared.raw_secret_bytes().to_vec())
110 }};
111 }
112 match &self.0 {
113 EcdhSecret::P256(key) => agree!(key, p256::PublicKey),
114 EcdhSecret::P384(key) => agree!(key, p384::PublicKey),
115 EcdhSecret::P521(key) => agree!(key, p521::PublicKey),
116 }
117 }
118}
119
120pub struct RustCryptoX25519Key(x25519_dalek::StaticSecret);
123
124impl core::fmt::Debug for RustCryptoX25519Key {
125 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
126 formatter
127 .debug_struct("RustCryptoX25519Key")
128 .finish_non_exhaustive()
129 }
130}
131
132impl RustCryptoX25519Key {
133 pub fn from_bytes(bytes: [u8; 32]) -> Self {
135 Self(x25519_dalek::StaticSecret::from(bytes))
136 }
137
138 pub fn public_key(&self) -> [u8; 32] {
140 x25519_dalek::PublicKey::from(&self.0).to_bytes()
141 }
142}
143
144impl KeyAgreementKey for RustCryptoX25519Key {
145 fn agree(&self, parameters: &KeyAgreementParameters<'_>) -> Result<Vec<u8>, ProviderError> {
146 if parameters.algorithm != X25519_URI {
147 return Err(ProviderError::Unsupported {
148 operation: ProviderOperation::KeyAgreement,
149 algorithm: Some(parameters.algorithm.to_owned()),
150 });
151 }
152 let bytes: [u8; 32] =
153 parameters
154 .peer_public_key
155 .try_into()
156 .map_err(|_| ProviderError::InvalidKeySize {
157 expected: 32,
158 actual: parameters.peer_public_key.len(),
159 })?;
160 let peer = x25519_dalek::PublicKey::from(bytes);
161 let secret = self.0.diffie_hellman(&peer);
162 if !secret.was_contributory() {
167 return Err(ProviderError::AuthenticationFailed);
168 }
169 Ok(secret.as_bytes().to_vec())
170 }
171}
172
173pub(super) fn supports_kdf(parameters: &KdfParameters<'_>) -> bool {
174 match parameters.algorithm {
175 HKDF_URI | PBKDF2_URI => hmac_prf(parameters).is_some(),
176 CONCAT_KDF_URI | LEGACY_DH_URI => concat_digest(parameters).is_some(),
177 _ => false,
178 }
179}
180
181fn hmac_prf(parameters: &KdfParameters<'_>) -> Option<SignatureAlgorithm> {
182 let algorithm = SignatureAlgorithm::from_uri(parameters.digest?)?;
183 match algorithm {
184 SignatureAlgorithm::HmacSha1
185 | SignatureAlgorithm::HmacSha224
186 | SignatureAlgorithm::HmacSha256
187 | SignatureAlgorithm::HmacSha384
188 | SignatureAlgorithm::HmacSha512 => Some(algorithm),
189 _ => None,
190 }
191}
192
193pub(super) fn derive_key(
194 parameters: &KdfParameters<'_>,
195 secret: &[u8],
196) -> Result<Vec<u8>, ProviderError> {
197 if parameters.algorithm == LEGACY_DH_URI {
198 return derive_legacy_dh(parameters, secret);
199 }
200 if parameters.algorithm == CONCAT_KDF_URI {
201 return derive_concat(parameters, secret);
202 }
203 if parameters.algorithm == PBKDF2_URI {
204 return derive_pbkdf2(parameters, secret);
205 }
206 if parameters.algorithm != HKDF_URI {
207 return Err(ProviderError::Unsupported {
208 operation: ProviderOperation::Kdf,
209 algorithm: Some(parameters.algorithm.to_owned()),
210 });
211 }
212 if parameters.iterations != 0 {
213 return Err(ProviderError::InvalidInput(
214 ProviderInputError::HkdfParameters,
215 ));
216 }
217 let info = context_octets(parameters.info).ok_or(ProviderError::InvalidInput(
218 ProviderInputError::HkdfParameters,
219 ))?;
220 macro_rules! derive {
221 ($digest:ty, $width:expr) => {{
222 if parameters.output_len > 255 * $width {
226 return Err(ProviderError::InvalidInput(
227 ProviderInputError::HkdfParameters,
228 ));
229 }
230 let kdf = hkdf::Hkdf::<$digest>::new(Some(parameters.salt), secret);
231 let mut output = zeroize::Zeroizing::new(vec![0; parameters.output_len]);
232 kdf.expand(info, &mut output)
233 .map_err(|_| ProviderError::InvalidInput(ProviderInputError::HkdfParameters))?;
234 Ok(core::mem::take(&mut *output))
235 }};
236 }
237 match hmac_prf(parameters) {
238 Some(SignatureAlgorithm::HmacSha1) => derive!(sha1::Sha1, 20),
239 Some(SignatureAlgorithm::HmacSha224) => derive!(sha2::Sha224, 28),
240 Some(SignatureAlgorithm::HmacSha256) => derive!(sha2::Sha256, 32),
241 Some(SignatureAlgorithm::HmacSha384) => derive!(sha2::Sha384, 48),
242 Some(SignatureAlgorithm::HmacSha512) => derive!(sha2::Sha512, 64),
243 _ => Err(ProviderError::Unsupported {
244 operation: ProviderOperation::Kdf,
245 algorithm: Some(parameters.algorithm.to_owned()),
246 }),
247 }
248}
249
250fn derive_pbkdf2(parameters: &KdfParameters<'_>, secret: &[u8]) -> Result<Vec<u8>, ProviderError> {
251 use hmac::Mac;
252 use zeroize::Zeroize;
253
254 if parameters.iterations == 0
255 || parameters.output_len == 0
256 || context_octets(parameters.info) != Some(&[][..])
257 {
258 return Err(ProviderError::InvalidInput(
259 ProviderInputError::Pbkdf2Parameters,
260 ));
261 }
262 macro_rules! derive {
263 ($digest:ty, $width:expr) => {{
264 let blocks = parameters.output_len.div_ceil($width);
268 if u32::try_from(blocks).is_err() {
269 return Err(ProviderError::InvalidInput(
270 ProviderInputError::Pbkdf2Parameters,
271 ));
272 }
273 let prf = <hmac::Hmac<$digest> as hmac::KeyInit>::new_from_slice(secret)
274 .map_err(|_| ProviderError::InvalidInput(ProviderInputError::Pbkdf2Parameters))?;
275 let mut salted = prf.clone();
276 salted.update(parameters.salt);
277 let mut output = zeroize::Zeroizing::new(vec![0; parameters.output_len]);
278 for (index, chunk) in output.chunks_mut($width).enumerate() {
282 let counter = u32::try_from(index + 1).map_err(|_| {
283 ProviderError::InvalidInput(ProviderInputError::Pbkdf2Parameters)
284 })?;
285 let mut first = salted.clone();
286 first.update(&counter.to_be_bytes());
287 let mut previous = first.finalize().into_bytes();
288 chunk.copy_from_slice(&previous[..chunk.len()]);
289 for _ in 1..parameters.iterations {
290 let mut next = prf.clone();
291 next.update(&previous);
292 previous.zeroize();
293 previous = next.finalize().into_bytes();
294 for (byte, value) in chunk.iter_mut().zip(previous.iter()) {
295 *byte ^= value;
296 }
297 }
298 previous.zeroize();
299 }
300 Ok(core::mem::take(&mut *output))
301 }};
302 }
303 match hmac_prf(parameters) {
304 Some(SignatureAlgorithm::HmacSha1) => derive!(sha1::Sha1, 20),
305 Some(SignatureAlgorithm::HmacSha224) => derive!(sha2::Sha224, 28),
306 Some(SignatureAlgorithm::HmacSha256) => derive!(sha2::Sha256, 32),
307 Some(SignatureAlgorithm::HmacSha384) => derive!(sha2::Sha384, 48),
308 Some(SignatureAlgorithm::HmacSha512) => derive!(sha2::Sha512, 64),
309 _ => Err(ProviderError::Unsupported {
310 operation: ProviderOperation::Kdf,
311 algorithm: Some(parameters.algorithm.to_owned()),
312 }),
313 }
314}
315
316fn context_octets(context: KdfContext<'_>) -> Option<&[u8]> {
317 match context {
318 KdfContext::Octets(bytes) => Some(bytes),
319 KdfContext::Bits { bytes, bit_len }
320 if bit_len.is_multiple_of(8) && bit_len / 8 == bytes.len() =>
321 {
322 Some(bytes)
323 }
324 KdfContext::Bits { .. } | KdfContext::LegacyDh { .. } => None,
325 }
326}
327
328fn concat_digest(parameters: &KdfParameters<'_>) -> Option<DigestAlgorithm> {
329 match DigestAlgorithm::from_uri(parameters.digest?)? {
330 algorithm @ (DigestAlgorithm::Sha1
331 | DigestAlgorithm::Sha224
332 | DigestAlgorithm::Sha256
333 | DigestAlgorithm::Sha384
334 | DigestAlgorithm::Sha512) => Some(algorithm),
335 _ => None,
336 }
337}
338
339fn derive_concat(parameters: &KdfParameters<'_>, secret: &[u8]) -> Result<Vec<u8>, ProviderError> {
340 let invalid = || ProviderError::InvalidInput(ProviderInputError::ConcatKdfParameters);
341 if parameters.iterations != 0 || !parameters.salt.is_empty() || parameters.output_len == 0 {
342 return Err(invalid());
343 }
344 let (info, bit_len) = match parameters.info {
345 KdfContext::Octets(bytes) => (bytes, bytes.len().checked_mul(8).ok_or_else(invalid)?),
346 KdfContext::Bits { bytes, bit_len } => (bytes, bit_len),
347 KdfContext::LegacyDh { .. } => return Err(invalid()),
348 };
349 if bit_len.div_ceil(8) != info.len() {
350 return Err(invalid());
351 }
352 let used_bits = bit_len % 8;
353 if used_bits != 0 && info[info.len() - 1] & (0xff >> used_bits) != 0 {
354 return Err(invalid());
355 }
356 let algorithm = concat_digest(parameters).ok_or_else(|| ProviderError::Unsupported {
357 operation: ProviderOperation::Kdf,
358 algorithm: Some(parameters.algorithm.to_owned()),
359 })?;
360 let width = algorithm.output_len();
361 if u32::try_from(parameters.output_len.div_ceil(width)).is_err() {
362 return Err(invalid());
363 }
364 let total_bits = 32 + secret.len() as u128 * 8 + bit_len as u128;
365 if width <= 32 && total_bits > u64::MAX as u128 {
366 return Err(invalid());
367 }
368 let mut output = zeroize::Zeroizing::new(vec![0; parameters.output_len]);
373 for (index, chunk) in output.chunks_mut(width).enumerate() {
374 let counter = u32::try_from(index + 1)
375 .map_err(|_| invalid())?
376 .to_be_bytes();
377 let block = bit_hash::hash(algorithm, &[&counter, secret], info, bit_len)?;
378 chunk.copy_from_slice(&block[..chunk.len()]);
379 }
380 Ok(core::mem::take(&mut *output))
381}
382
383fn derive_legacy_dh(
384 parameters: &KdfParameters<'_>,
385 secret: &[u8],
386) -> Result<Vec<u8>, ProviderError> {
387 let invalid = || ProviderError::InvalidInput(ProviderInputError::LegacyDhKdfParameters);
388 let KdfContext::LegacyDh {
389 encryption_algorithm,
390 nonce,
391 } = parameters.info
392 else {
393 return Err(invalid());
394 };
395 if parameters.iterations != 0 || !parameters.salt.is_empty() || parameters.output_len == 0 {
396 return Err(invalid());
397 }
398 let algorithm = concat_digest(parameters).ok_or_else(|| ProviderError::Unsupported {
399 operation: ProviderOperation::Kdf,
400 algorithm: Some(parameters.algorithm.to_owned()),
401 })?;
402 let width = algorithm.output_len();
403 if parameters.output_len.div_ceil(width) > u8::MAX as usize {
404 return Err(invalid());
405 }
406 let mut key_bits = parameters.output_len.checked_mul(8).ok_or_else(invalid)?;
407 let mut decimal = [0u8; 40];
410 let mut start = decimal.len();
411 while key_bits != 0 {
412 start -= 1;
413 decimal[start] = b'0' + (key_bits % 10) as u8;
414 key_bits /= 10;
415 }
416 let total_bytes = secret.len() as u128
417 + 2
418 + encryption_algorithm.len() as u128
419 + nonce.len() as u128
420 + (decimal.len() - start) as u128;
421 if width <= 32 && total_bytes * 8 > u64::MAX as u128 {
422 return Err(invalid());
423 }
424 const HEX: &[u8; 16] = b"0123456789ABCDEF";
429 let mut output = zeroize::Zeroizing::new(vec![0; parameters.output_len]);
430 for (index, chunk) in output.chunks_mut(width).enumerate() {
431 let counter = index + 1;
432 let ascii = [HEX[counter >> 4], HEX[counter & 15]];
433 let hash = bit_hash::hash(
434 algorithm,
435 &[
436 secret,
437 &ascii,
438 encryption_algorithm.as_bytes(),
439 nonce,
440 &decimal[start..],
441 ],
442 &[],
443 0,
444 )?;
445 chunk.copy_from_slice(&hash[..chunk.len()]);
446 }
447 Ok(core::mem::take(&mut *output))
448}