Skip to content

Commit e3dcd05

Browse files
ElvrarinYiming Linjustsmthskmcgrail
authored
Adds CMAC (#903)
* Adds CMAC * change static to const * Use LcPtr * Removed SecureRandom parameter * Expose fallibility of Key::new, update, sign * Used AlgorithmId enum to provide EVP_CIPHER * Fix clippy warnings * Minor changes * Adding panic section for the docs * Fix formatting and Copyright messages * Update aws-lc-rs/src/cmac.rs * Update aws-lc-rs/src/cmac.rs --------- Co-authored-by: Yiming Lin <elyiming@amazon.com> Co-authored-by: Justin W Smith <103147162+justsmth@users.noreply.github.com> Co-authored-by: Sean McGrail <549813+skmcgrail@users.noreply.github.com>
1 parent 962dbb1 commit e3dcd05

9 files changed

Lines changed: 10042 additions & 4 deletions

File tree

aws-lc-rs/src/cmac.rs

Lines changed: 589 additions & 0 deletions
Large diffs are not rendered by default.

aws-lc-rs/src/cmac/tests/fips.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0 OR ISC
3+
4+
#![cfg(debug_assertions)]
5+
6+
use crate::cmac::{sign, verify, Key, AES_128, AES_192, AES_256, TDES_FOR_LEGACY_USE_ONLY};
7+
use crate::fips::{assert_fips_status_indicator, FipsServiceStatus};
8+
use crate::rand::{self, SystemRandom};
9+
10+
const TEST_MESSAGE: &str = "test message";
11+
12+
macro_rules! cmac_api {
13+
($name:ident, $alg:expr, $key_len:expr, $expect:path) => {
14+
#[test]
15+
fn $name() -> Result<(), Box<dyn std::error::Error>> {
16+
let rng = SystemRandom::new();
17+
18+
let key_value: [u8; $key_len] = rand::generate(&rng).unwrap().expose();
19+
20+
let s_key = Key::new($alg, key_value.as_ref()).unwrap();
21+
22+
let tag =
23+
assert_fips_status_indicator!(sign(&s_key, TEST_MESSAGE.as_bytes())?, $expect);
24+
25+
let v_key = Key::new($alg, key_value.as_ref()).unwrap();
26+
27+
assert_fips_status_indicator!(
28+
verify(&v_key, TEST_MESSAGE.as_bytes(), tag.as_ref())?,
29+
$expect
30+
);
31+
32+
Ok(())
33+
}
34+
};
35+
}
36+
37+
cmac_api!(aes_128, AES_128, 16, FipsServiceStatus::Approved);
38+
cmac_api!(aes_192, AES_192, 24, FipsServiceStatus::NonApproved);
39+
cmac_api!(aes_256, AES_256, 32, FipsServiceStatus::Approved);
40+
cmac_api!(
41+
tdes,
42+
TDES_FOR_LEGACY_USE_ONLY,
43+
24,
44+
FipsServiceStatus::NonApproved
45+
);

aws-lc-rs/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ extern crate aws_lc_sys as aws_lc;
163163

164164
pub mod aead;
165165
pub mod agreement;
166+
pub mod cmac;
166167
pub mod constant_time;
167168
pub mod digest;
168169
pub mod error;

aws-lc-rs/src/ptr.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
// SPDX-License-Identifier: Apache-2.0 OR ISC
33

44
use crate::aws_lc::{
5-
BN_free, ECDSA_SIG_free, EC_GROUP_free, EC_KEY_free, EC_POINT_free, EVP_AEAD_CTX_free,
6-
EVP_CIPHER_CTX_free, EVP_PKEY_CTX_free, EVP_PKEY_free, OPENSSL_free, RSA_free, BIGNUM,
7-
ECDSA_SIG, EC_GROUP, EC_KEY, EC_POINT, EVP_AEAD_CTX, EVP_CIPHER_CTX, EVP_PKEY, EVP_PKEY_CTX,
8-
RSA,
5+
BN_free, CMAC_CTX_free, ECDSA_SIG_free, EC_GROUP_free, EC_KEY_free, EC_POINT_free,
6+
EVP_AEAD_CTX_free, EVP_CIPHER_CTX_free, EVP_PKEY_CTX_free, EVP_PKEY_free, OPENSSL_free,
7+
RSA_free, BIGNUM, CMAC_CTX, ECDSA_SIG, EC_GROUP, EC_KEY, EC_POINT, EVP_AEAD_CTX,
8+
EVP_CIPHER_CTX, EVP_PKEY, EVP_PKEY_CTX, RSA,
99
};
1010
use core::ops::Deref;
1111
use std::marker::PhantomData;
@@ -271,6 +271,7 @@ create_pointer!(EVP_PKEY_CTX, EVP_PKEY_CTX_free);
271271
create_pointer!(RSA, RSA_free);
272272
create_pointer!(EVP_AEAD_CTX, EVP_AEAD_CTX_free);
273273
create_pointer!(EVP_CIPHER_CTX, EVP_CIPHER_CTX_free);
274+
create_pointer!(CMAC_CTX, CMAC_CTX_free);
274275

275276
#[cfg(test)]
276277
mod tests {

aws-lc-rs/tests/cmac_tests.rs

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0 OR ISC
3+
4+
use aws_lc_rs::{cmac, test, test_file};
5+
6+
#[test]
7+
fn cavp_cmac_aes128_tests() {
8+
test::run(
9+
test_file!("data/cavp_aes128_cmac_tests.txt"),
10+
|section, test_case| {
11+
assert_eq!(section, "");
12+
13+
let _count = test_case.consume_usize("Count");
14+
let _klen = test_case.consume_usize("Klen");
15+
let mlen = test_case.consume_usize("Mlen");
16+
let tlen = test_case.consume_usize("Tlen");
17+
let key = test_case.consume_bytes("Key");
18+
let msg = test_case.consume_bytes("Msg");
19+
let mac = test_case.consume_bytes("Mac");
20+
let result = test_case.consume_string("Result");
21+
22+
let input = if mlen == 0 { Vec::new() } else { msg };
23+
let should_pass = result.starts_with('P');
24+
25+
let cmac_key = cmac::Key::new(cmac::AES_128, &key).unwrap();
26+
let signature = cmac::sign(&cmac_key, &input).unwrap();
27+
28+
// Truncate to tlen
29+
let truncated_sig =
30+
&signature.as_ref()[..std::cmp::min(signature.as_ref().len(), tlen)];
31+
32+
if should_pass {
33+
assert_eq!(truncated_sig, &mac);
34+
} else {
35+
assert_ne!(truncated_sig, &mac);
36+
}
37+
38+
Ok(())
39+
},
40+
);
41+
}
42+
43+
#[test]
44+
fn cavp_cmac_aes192_tests() {
45+
test::run(
46+
test_file!("data/cavp_aes192_cmac_tests.txt"),
47+
|section, test_case| {
48+
assert_eq!(section, "");
49+
50+
let _count = test_case.consume_usize("Count");
51+
let _klen = test_case.consume_usize("Klen");
52+
let mlen = test_case.consume_usize("Mlen");
53+
let tlen = test_case.consume_usize("Tlen");
54+
let key = test_case.consume_bytes("Key");
55+
let msg = test_case.consume_bytes("Msg");
56+
let mac = test_case.consume_bytes("Mac");
57+
let result = test_case.consume_string("Result");
58+
59+
let input = if mlen == 0 { Vec::new() } else { msg };
60+
let should_pass = result.starts_with('P');
61+
62+
let cmac_key = cmac::Key::new(cmac::AES_192, &key).unwrap();
63+
let signature = cmac::sign(&cmac_key, &input).unwrap();
64+
65+
// Truncate to tlen
66+
let truncated_sig =
67+
&signature.as_ref()[..std::cmp::min(signature.as_ref().len(), tlen)];
68+
69+
if should_pass {
70+
assert_eq!(truncated_sig, &mac);
71+
} else {
72+
assert_ne!(truncated_sig, &mac);
73+
}
74+
75+
Ok(())
76+
},
77+
);
78+
}
79+
80+
#[test]
81+
fn cavp_cmac_aes256_tests() {
82+
test::run(
83+
test_file!("data/cavp_aes256_cmac_tests.txt"),
84+
|section, test_case| {
85+
assert_eq!(section, "");
86+
87+
let _count = test_case.consume_usize("Count");
88+
let _klen = test_case.consume_usize("Klen");
89+
let mlen = test_case.consume_usize("Mlen");
90+
let tlen = test_case.consume_usize("Tlen");
91+
let key = test_case.consume_bytes("Key");
92+
let msg = test_case.consume_bytes("Msg");
93+
let mac = test_case.consume_bytes("Mac");
94+
let result = test_case.consume_string("Result");
95+
96+
let input = if mlen == 0 { Vec::new() } else { msg };
97+
let should_pass = result.starts_with('P');
98+
99+
let cmac_key = cmac::Key::new(cmac::AES_256, &key).unwrap();
100+
let signature = cmac::sign(&cmac_key, &input).unwrap();
101+
102+
// Truncate to tlen
103+
let truncated_sig =
104+
&signature.as_ref()[..std::cmp::min(signature.as_ref().len(), tlen)];
105+
106+
if should_pass {
107+
assert_eq!(truncated_sig, &mac);
108+
} else {
109+
assert_ne!(truncated_sig, &mac);
110+
}
111+
112+
Ok(())
113+
},
114+
);
115+
}
116+
117+
#[test]
118+
fn cavp_cmac_3des_tests() {
119+
test::run(
120+
test_file!("data/cavp_3des_cmac_tests.txt"),
121+
|section, test_case| {
122+
assert_eq!(section, "");
123+
124+
let _count = test_case.consume_usize("Count");
125+
let _klen = test_case.consume_usize("Klen");
126+
let mlen = test_case.consume_usize("Mlen");
127+
let tlen = test_case.consume_usize("Tlen");
128+
let key1 = test_case.consume_bytes("Key1");
129+
let key2 = test_case.consume_bytes("Key2");
130+
let key3 = test_case.consume_bytes("Key3");
131+
let msg = test_case.consume_bytes("Msg");
132+
let mac = test_case.consume_bytes("Mac");
133+
let result = test_case.consume_string("Result");
134+
135+
// Combine 3DES keys
136+
let mut combined_key = key1;
137+
combined_key.extend(key2);
138+
combined_key.extend(key3);
139+
140+
let input = if mlen == 0 { Vec::new() } else { msg };
141+
let should_pass = result.starts_with('P');
142+
143+
let cmac_key = cmac::Key::new(cmac::TDES_FOR_LEGACY_USE_ONLY, &combined_key).unwrap();
144+
let signature = cmac::sign(&cmac_key, &input).unwrap();
145+
146+
// Truncate to tlen
147+
let truncated_sig =
148+
&signature.as_ref()[..std::cmp::min(signature.as_ref().len(), tlen)];
149+
150+
if should_pass {
151+
assert_eq!(truncated_sig, &mac);
152+
} else {
153+
assert_ne!(truncated_sig, &mac);
154+
}
155+
Ok(())
156+
},
157+
);
158+
}

0 commit comments

Comments
 (0)