Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
608 changes: 608 additions & 0 deletions aws-lc-rs/src/cmac.rs

Large diffs are not rendered by default.

40 changes: 40 additions & 0 deletions aws-lc-rs/src/cmac/tests/fips.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC

#![cfg(debug_assertions)]

use crate::cmac::{sign, verify, Key, AES_128, AES_192, AES_256, TDES_FOR_LEGACY_USE_ONLY};
use crate::fips::{assert_fips_status_indicator, FipsServiceStatus};
use crate::rand::{self, SystemRandom};

const TEST_MESSAGE: &str = "test message";

macro_rules! cmac_api {
($name:ident, $alg:expr, $key_len:expr, $expect:path) => {
#[test]
fn $name() {
let rng = SystemRandom::new();

let key_value: [u8; $key_len] = rand::generate(&rng).unwrap().expose();

let s_key = Key::new($alg, key_value.as_ref());

let tag = assert_fips_status_indicator!(
sign(&s_key, TEST_MESSAGE.as_bytes()),
$expect
);

let v_key = Key::new($alg, key_value.as_ref());

assert_fips_status_indicator!(
verify(&v_key, TEST_MESSAGE.as_bytes(), tag.as_ref()),
$expect
).unwrap();
}
};
}

cmac_api!(aes_128, AES_128, 16, FipsServiceStatus::Approved);
cmac_api!(aes_192, AES_192, 24, FipsServiceStatus::NonApproved);
cmac_api!(aes_256, AES_256, 32, FipsServiceStatus::Approved);
cmac_api!(tdes, TDES_FOR_LEGACY_USE_ONLY, 24, FipsServiceStatus::NonApproved);
1 change: 1 addition & 0 deletions aws-lc-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ extern crate aws_lc_sys as aws_lc;

pub mod aead;
pub mod agreement;
pub mod cmac;
pub mod constant_time;
pub mod digest;
pub mod error;
Expand Down
5 changes: 3 additions & 2 deletions aws-lc-rs/src/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// SPDX-License-Identifier: Apache-2.0 OR ISC

use crate::aws_lc::{
BN_free, ECDSA_SIG_free, EC_GROUP_free, EC_KEY_free, EC_POINT_free, EVP_AEAD_CTX_free,
BN_free, CMAC_CTX_free, ECDSA_SIG_free, EC_GROUP_free, EC_KEY_free, EC_POINT_free, EVP_AEAD_CTX_free,
EVP_CIPHER_CTX_free, EVP_PKEY_CTX_free, EVP_PKEY_free, OPENSSL_free, RSA_free, BIGNUM,
ECDSA_SIG, EC_GROUP, EC_KEY, EC_POINT, EVP_AEAD_CTX, EVP_CIPHER_CTX, EVP_PKEY, EVP_PKEY_CTX,
CMAC_CTX, ECDSA_SIG, EC_GROUP, EC_KEY, EC_POINT, EVP_AEAD_CTX, EVP_CIPHER_CTX, EVP_PKEY, EVP_PKEY_CTX,
RSA,
};
use core::ops::Deref;
Expand Down Expand Up @@ -271,6 +271,7 @@ create_pointer!(EVP_PKEY_CTX, EVP_PKEY_CTX_free);
create_pointer!(RSA, RSA_free);
create_pointer!(EVP_AEAD_CTX, EVP_AEAD_CTX_free);
create_pointer!(EVP_CIPHER_CTX, EVP_CIPHER_CTX_free);
create_pointer!(CMAC_CTX, CMAC_CTX_free);

#[cfg(test)]
mod tests {
Expand Down
139 changes: 139 additions & 0 deletions aws-lc-rs/tests/cmac_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
use aws_lc_rs::{cmac, test, test_file};

#[test]
fn cavp_cmac_aes128_tests() {
test::run(test_file!("data/cavp_aes128_cmac_tests.txt"), |section, test_case| {
assert_eq!(section, "");

let _count = test_case.consume_usize("Count");
let _klen = test_case.consume_usize("Klen");
let mlen = test_case.consume_usize("Mlen");
let tlen = test_case.consume_usize("Tlen");
let key = test_case.consume_bytes("Key");
let msg = test_case.consume_bytes("Msg");
let mac = test_case.consume_bytes("Mac");
let result = test_case.consume_string("Result");

let input = if mlen == 0 { Vec::new() } else { msg };
let should_pass = result.chars().next().unwrap() == 'P';

let cmac_key = cmac::Key::new(cmac::AES_128, &key);
let signature = cmac::sign(&cmac_key, &input);

// Truncate to tlen
let truncated_sig = &signature.as_ref()[..std::cmp::min(signature.as_ref().len(), tlen)];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The truncation used here and in the other functions is not needed -- it would actually hide a bug were we to produce too long of a signature.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied these tests data, and test functions from the aws-lc. The original tests also does a truncation. Without the truncation, the tests start to fail.
https://github.com/aws/aws-lc/blob/main/crypto/fipsmodule/cmac/cmac_test.cc#L226-L227

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, we should just trancate it to tlen then -- it should never be longer than the actual tag:

let truncated_sig = &signature.as_ref()[..tlen];


if should_pass {
assert_eq!(truncated_sig, &mac);
} else {
assert_ne!(truncated_sig, &mac);
}

Ok(())
});
}

#[test]
fn cavp_cmac_aes192_tests() {
test::run(test_file!("data/cavp_aes192_cmac_tests.txt"), |section, test_case| {
assert_eq!(section, "");

let _count = test_case.consume_usize("Count");
let _klen = test_case.consume_usize("Klen");
let mlen = test_case.consume_usize("Mlen");
let tlen = test_case.consume_usize("Tlen");
let key = test_case.consume_bytes("Key");
let msg = test_case.consume_bytes("Msg");
let mac = test_case.consume_bytes("Mac");
let result = test_case.consume_string("Result");

let input = if mlen == 0 { Vec::new() } else { msg };
let should_pass = result.chars().next().unwrap() == 'P';

let cmac_key = cmac::Key::new(cmac::AES_192, &key);
let signature = cmac::sign(&cmac_key, &input);

// Truncate to tlen
let truncated_sig = &signature.as_ref()[..std::cmp::min(signature.as_ref().len(), tlen)];

if should_pass {
assert_eq!(truncated_sig, &mac);
} else {
assert_ne!(truncated_sig, &mac);
}

Ok(())
});
}

#[test]
fn cavp_cmac_aes256_tests() {
test::run(test_file!("data/cavp_aes256_cmac_tests.txt"), |section, test_case| {
assert_eq!(section, "");

let _count = test_case.consume_usize("Count");
let _klen = test_case.consume_usize("Klen");
let mlen = test_case.consume_usize("Mlen");
let tlen = test_case.consume_usize("Tlen");
let key = test_case.consume_bytes("Key");
let msg = test_case.consume_bytes("Msg");
let mac = test_case.consume_bytes("Mac");
let result = test_case.consume_string("Result");

let input = if mlen == 0 { Vec::new() } else { msg };
let should_pass = result.chars().next().unwrap() == 'P';

let cmac_key = cmac::Key::new(cmac::AES_256, &key);
let signature = cmac::sign(&cmac_key, &input);

// Truncate to tlen
let truncated_sig = &signature.as_ref()[..std::cmp::min(signature.as_ref().len(), tlen)];

if should_pass {
assert_eq!(truncated_sig, &mac);
} else {
assert_ne!(truncated_sig, &mac);
}

Ok(())
});
}

#[test]
fn cavp_cmac_3des_tests() {
test::run(test_file!("data/cavp_3des_cmac_tests.txt"), |section, test_case| {
assert_eq!(section, "");

let _count = test_case.consume_usize("Count");
let _klen = test_case.consume_usize("Klen");
let mlen = test_case.consume_usize("Mlen");
let tlen = test_case.consume_usize("Tlen");
let key1 = test_case.consume_bytes("Key1");
let key2 = test_case.consume_bytes("Key2");
let key3 = test_case.consume_bytes("Key3");
let msg = test_case.consume_bytes("Msg");
let mac = test_case.consume_bytes("Mac");
let result = test_case.consume_string("Result");

// Combine 3DES keys
let mut combined_key = key1;
combined_key.extend(key2);
combined_key.extend(key3);

let input = if mlen == 0 { Vec::new() } else { msg };
let should_pass = result.chars().next().unwrap() == 'P';

let cmac_key = cmac::Key::new(cmac::TDES_FOR_LEGACY_USE_ONLY, &combined_key);
let signature = cmac::sign(&cmac_key, &input);

// Truncate to tlen
let truncated_sig = &signature.as_ref()[..std::cmp::min(signature.as_ref().len(), tlen)];

if should_pass {
assert_eq!(truncated_sig, &mac);
} else {
assert_ne!(truncated_sig, &mac);
}
Ok(())
});
}
Loading
Loading