// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use super::Hash256; use arrayref::array_ref; use subtle::ConstantTimeEq; const BLOCK_SIZE: usize = 64; const HASH_SIZE: usize = 32; const KEY_SIZE: usize = 32; pub fn verify_hmac_256(key: &[u8; KEY_SIZE], contents: &[u8], mac: &[u8; HASH_SIZE]) -> bool where H: Hash256, { let expected_mac = hmac_256::(key, contents); bool::from(expected_mac.ct_eq(mac)) } // FIDO2's PIN verification is just matching the first 16 bytes of the HMAC // against the pin ¯\_(ツ)_/¯ pub fn verify_hmac_256_first_128bits( key: &[u8; KEY_SIZE], contents: &[u8], pin: &[u8; 16], ) -> bool where H: Hash256, { let expected_mac = hmac_256::(key, contents); bool::from(array_ref![expected_mac, 0, 16].ct_eq(pin)) } pub fn hmac_256(key: &[u8; KEY_SIZE], contents: &[u8]) -> [u8; HASH_SIZE] where H: Hash256, { H::hmac(key, contents) } pub(crate) fn software_hmac_256(key: &[u8; KEY_SIZE], contents: &[u8]) -> [u8; HASH_SIZE] where H: Hash256, { let mut ipad: [u8; BLOCK_SIZE] = [0x36; BLOCK_SIZE]; let mut opad: [u8; BLOCK_SIZE] = [0x5c; BLOCK_SIZE]; if key.len() <= BLOCK_SIZE { xor_pads(&mut ipad, &mut opad, key); } else { xor_pads(&mut ipad, &mut opad, &H::hash(key)); } let mut ihasher = H::new(); ihasher.update(&ipad); ihasher.update(contents); let ihash = ihasher.finalize(); let mut ohasher = H::new(); ohasher.update(&opad); ohasher.update(&ihash); ohasher.finalize() } fn xor_pads(ipad: &mut [u8; BLOCK_SIZE], opad: &mut [u8; BLOCK_SIZE], key: &[u8; KEY_SIZE]) { for (i, k) in key.iter().enumerate() { ipad[i] ^= k; opad[i] ^= k; } } #[cfg(test)] mod test { use super::super::sha256::Sha256; use super::*; #[test] fn test_verify_hmac_valid() { // Test for various lengths of the contents. for len in 0..128 { let key = [0; KEY_SIZE]; let contents = vec![0; len]; let mac = hmac_256::(&key, &contents); assert!(verify_hmac_256::(&key, &contents, &mac)); } } #[test] fn test_verify_hmac_invalid() { // Test for various lengths of the contents. for len in 0..128 { let key = [0; KEY_SIZE]; let contents = vec![0; len]; let mac = hmac_256::(&key, &contents); // Check that invalid MACs don't verify, by changing any byte of the valid MAC. for i in 0..HASH_SIZE { let mut bad_mac = mac; bad_mac[i] ^= 0x01; assert!(!verify_hmac_256::(&key, &contents, &bad_mac)); } } } #[test] fn test_hmac_sha256_examples() { let key = [0; KEY_SIZE]; assert_eq!( hmac_256::(&key, &[]), hex::decode("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad") .unwrap() .as_slice() ); assert_eq!( hmac_256::(&key, b"The quick brown fox jumps over the lazy dog"), hex::decode("fb011e6154a19b9a4c767373c305275a5a69e8b68b0b4c9200c383dced19a416") .unwrap() .as_slice() ); } #[test] fn test_hash_sha256_for_various_lengths() { // This test makes sure that the key hashing and hash padding are implemented properly. // // Test vectors generated with the following Python script: // // import hashlib // import hmac // for n in range(128): // print('b"' + hmac.new(b'A' * 32, b'A' * n, hashlib.sha256).hexdigest() + '",') // let hashes: [&[u8; 64]; 128] = [ b"595a67cdd155b156011323818105d3d30cf8f6aad916685c0b2d1d7b7678b728", b"bfa8ad8ba9fe1e03dd80d3f3d782a9f5b66c387619e0dd836f4ea6187324ea66", b"7c5e78ab04692eec81140cdaebeb53f2caeda32815e34de8f92ea85c1a716b83", b"79f8fe074d9aa04e8e1aaaaa9170f8f990fa008db94d9a81e796904e4a4b69f3", b"6177f1d2208d33a3f255d569dc5e3388909376e291d574db4b2fe22dfc5b0027", b"57e164845ea82912bc162a99adf7c010d416a57cb619d79b1a916904c934b4c8", b"5a76f2ace99b5a61418f986e96c695179c4f02f44e00b0bba2a09daa7b53a4ab", b"ab392ef07ec6cdc33c86676cf58760087e136dad0ba6d3490c58e7797e313a88", b"018c06f8a2377d97ec955c6c2f06c937e66f97bec3101c40f039f8a1832fadc3", b"ef423b7ad8137e4e473252975570733cc6eb2780a4ca257cca7b592742548fe3", b"fed8c0e7daee2292841e2868a64e298a58f2438a9a14040999f0634cdb084c5f", b"4d645a6631328b2b09e7f50b4ee2e5630bec786e156ea6a2b827332d320e8f4b", b"b45d9d059b2b298b417bac0fa77ad66a8e771ada054b7131469c949550ded9be", b"47f6a1af667d49804b2f5917eb8b7de5cdb245670b6b9ad2ed9b2a21c2dbf0f7", b"dde1e7b53136a4bf72ed8640f4384805e923028da301b313f9aa475a6a1d38ca", b"fd53a20c62b18dccd079779f4fd2abefdf212838d68999140e0335d0500da3d9", b"1afdf50cc2c65a4eb6f643e8107dd4e06defde40d495b68783fa2d8b41f291d3", b"9d2b266b013dae3e0eb83be634fe0095eed403518d4bcff69e050cb59a20e0c9", b"d4ac6b4df53b7d0848a9d17984c555cf660482c3c1e86f5662279b108a0831f1", b"d1c3bc071da981b822b428771b7c21dc47d3cd868a5058a5e7d463c2fedc457e", b"dfe01e48ce8ae53b04c17b48287501b1e8e85f23c1d1a77e0000967dae16926c", b"ce31a2972842dc9d28c8c4e10963280bebb468fa14739d2d09d9063018521bb0", b"3390e5ea00fc447a1ba27784dfbc30cf62dc6fbd3af2347b85efa9ecf086db41", b"3f4f678e5b5d6b5ec5d8afe53da6904eb9e755e20a685eafcf163ea703043a7f", b"2fbd3730b3c5d0c647940f1405ee3761fdd9adb2ed10dd40524454bc1c5af019", b"fa675e4ea585f8c96c5ded7651d6d3a80c26161c28c73bf94cc2b93e43413658", b"0667a9ea56759ed908dd9e1ac46a8221abebb95f29b0749fd555707181a4af16", b"9dd330116d5750abfdfc7cee9f65db0360a94bf0d10fbe55d572e4f55c4c7cea", b"afd9c1e6ba141502a100311eb5a25f5078baa2bc9fbccb1fe3b0fc6daebfc6d3", b"bc2610c0e8c11dab2bf62ea2613265e9821d762e037bc6dd9ea4fd7955c88205", b"ab982b8c3395535f0835e0b212c20b67cc914db4e72c10f5b6214602d9a88a1d", b"8ebf970da05e08f54a39ecccf2d6afcf497c79c42c8a7c9c49d30f3316ff1581", b"e58aa85e83553b7fec841cbaf42cede943b6b7ded22661cd3b1867effe91b745", b"e4d991ec7a6e440b4ba447533f3154aaf4b98970aab17e51abbfc77ac6a9534e", b"c6c63e02951aa085d146efe270b4ebfc76bcd02a78086cbc236d04a08226c0a1", b"2891cc2b22d90da4dc2d7c4c8261d0419c39af278837b51b31a03d7433e9fefb", b"6a0c557d141cc6e2b3584d72dadeeae7ffdeb26661239715f414ea4d5bcbea61", b"ca82fea127dd876b595fd0ba90b2a38316946f65f05459091ddff1e9b7a5ee42", b"17c7b6db39bffa4600b0b4d3e14b2a664ae706a2ecfdaec5dbc2d3e07066ab6b", b"f65b1220142355c27df2a1e0f6f9755f7eb708646bad3b901b93d7fb32c8854f", b"2fe2e14d87053873cfa2f366320a62e1bdd3b3a56bec8939ac354b3ca2122719", b"909bbb93030313552e70abe519508bac3b5da2e04a7e87fa9bd74ca50bf3ff95", b"bc89b946a874fc3bdfcc70b01459e34eeaa1fe3ca50283be8678e06a98686ba8", b"de2468c21ca31e3e13e8a0cc685c7d52a73e22c90a6af72d572624277190e2ea", b"129379e4a0436dc85dab57fae14cb67cdbb808f911439a76de2ed987c7ed192a", b"d475c697a8792de00daa493eb24708ebc058686ace04e7406b7ff351dd4f2f01", b"728d210061d0e057d56bff712b9540f9d2c453f8766ad8990ae114f5527840b7", b"b0afbb7f1cc27233f08d74d06dbd1d85d3c68dd608dd4bcfea59c17a4cfa8002", b"077264c42786ba2803fa0d1b91eb45cd0cda3cfc28d3e12724050a7f0c236f43", b"727f3497843430636157f3d8b158a1a95318e9a85a98c50e549c1f17dc915d50", b"e17d3f5bfc328ab0ba2a0fc433f2bf46f8b28aa20d171f0de76f61c7741a1edd", b"80f61fc10cecc7a0ddb3e8e73f3c8900db0f1e9a45feba67e94e648353613cd3", b"6e84e742f4f0aa32da9034f404a609a490b6756e90deb3f6a6697e60698575e5", b"6ff3cdb270fe53f835d7be0320954d75125532f7774c5f3d515a5235f1e4cb77", b"b839681cadf03857f44d2b75d1ea702335b7fccd391ba48b6895b8859017eb40", b"404de6d3cdff8254b92a00a2b053ff4fd054e44447822c4865803a810301e1d4", b"759ce4ff23e6f79957fc53c9ea7b014dd8874e6daab3751b81c80ccf7208cce0", b"861c419860787f09021fdda2a66023662c9d27b00efb3c637f0dd2da709d5cfe", b"cac14f0cbe893fa214646e5b33d110318dcc9bf39789df7c7dbb86b7adf49d23", b"b2ed80ab57e54e7d68f40085adc346e01cc80d43d4c38efdbf99e646752a3e34", b"ea9e89716c7d62a0467db829f95e35171c414fc6a62e4ecb84086b137c0c87fe", b"a745acf53cb1efcfaae1d54a41a9b7109ce40e45b66899f43e84582a7d382652", b"96f4eff4f9a556509efc5a5fe6aa7e76abfd322a04096dee1013582a4f50e9c3", b"8d5cb04fe1685f1adca6db900744ce95496a69250d5e902526f113adde4230d7", b"787139d46676f1e9ba999008b747d6100d4d2d43c4a03da55b70c96e0e5a2b82", b"72e1658437cc6640b8a2107a0d0025ee2a9efeeec4ce0fa54f8aee27b500a90c", b"9715f4cd4c2612088a688a3c74c4743f567e1b10697a89832edee851167109a5", b"acf69295af3cbb198fab03ba0ceb0d6bd9f7592551d93ed025203f4b1125f5d2", b"79bab68ef25af25bd903fecc691ad03a3f5011b38876cc576f8bbac72648a675", b"078f2cd62dfc38eae5e5b4f31a6f226b53326a5e6e879190a5761375858e40b5", b"ad7b8a91191ca66df520104bf694f6300e02a3217f06524c5f5f2314259b688e", b"743810642997b9c59e254d9c26e0c419a94b9ede285c282e09a2544c24678c7c", b"731845f6bc49160f38bd15d50b5e8e9fabb015b6d47faafb701c68c39add3192", b"2f48b9d618f0ee7edb50b095e76dd1b69c2c12e77036ee76b1ac3fbf08f93bde", b"3c7a74c98330454f0c16b35697c81e33ac5c2c75404dde607f5ee9d43775201b", b"a36bd2c560abac0f80a261c30ac0e51ffb953daf616a2063fab57d140866a7f3", b"ba8fa68ef326ca68e30e55dfd10a706f8cb9dc159562e5e34529075215e78f3c", b"1a6e95178d9d86cdad770c5b17dbbe833bcd7c61701cec5938c6838dc77a988d", b"8a51d9eb445154c95c9274bc664f3db10b336fa3b1ea7f0a83e057444235db91", b"b89372d7f8f5595033a0758eb6442f136d0e66943b28717e9f851d72a69f60a3", b"165ed7cd7a3cf8304c861ccd5b5218a419d677bf5c54ae9ad41e0f8be76b83c7", b"9df5023a48caf3eead86b65b302ef412d2eeefdbbd1e764cd0e920086498cda8", b"0873f1f4f4c02e6a0edb9efa1129afb05660aaa83b24f99032553d8b9843a52c", b"5444a87785495cfe0d355c7a7f1836d4199b823d9d907c414b6be9b379638490", b"7a4c2867b2da2f2f24285f4ee2af2f553b0be7c82d67ab147513e66f185b0b6f", b"a21e41f5dbc69c6135def7f16694a6ac3a18d4063004084c52fee187501310e2", b"25e316dcedb6d826fd0c37d2376b8fbfbe95f20b3fcbd255985a0c3a63d05099", b"e2b71db388fdb675739b84791b432783f9bd4127d15692af80febec991c3ba90", b"f73cd2ba0a6cea09bc8c67fb39d4c66096bc26087ab2c8713944e61f167a4dff", b"2b3da7f3a41dd9a3d205278c0e5a5c2870f231129bdb249e0a4858996c446de2", b"ab0128c1519894e37dd0e69f5503149d17e94a1c0da830f988a206f02d7572ff", b"c3ca55ac522cdf4f92bdf57851f88ec257612e3a2b8639b06fb067fb7b1d6ec6", b"f7012c61df429af15f4f450d78c6d384345b1317a8a7befe1ec32bc31e169f0b", b"608679c2a6724c47a5341bb4775687492b5f17f3e6bbbf0f928d4f840ff487e3", b"1c55e5588e2f46291bf19b93c2f54f8e0f1ec1dc01c25dbb30102ce5d97048a8", b"90fccc4c44f678f30e8ea525ff1c63bac72e1ff237ef0e5a5e86be51c172d9cf", b"2a2f95fa5d73cd8f0fc9383c8a7d709099f0afbf710b26a96982e040927d79dc", b"479bdb6e248e3d9049a1eaaf8014c132c90b086b42d5d552e8fd03c6d0663420", b"ab7ccfcb8f819dae979872ce6f2592f3d8286940673367e127207fc4cc4a1f75", b"2f94d599f7ade79ca64fede6125f3fbf179a0da35fdfbed722a8771ff89b8f72", b"ab3b6c4946c6726cfed836d7675c63d015805727ae6c28deccd7fb42a44fddcd", b"d7e20cb59054732eb500d97417c24a08a67dbe5cbe3754cc2bd172b97c524986", b"710bc8668e43f019926f063a311d20e9bd50a17eb957098535115aded9a98b47", b"c08d6dccc3d600106fe28a2a4460c47b7c07e89ce6a1eb5d50835da1c38be9eb", b"01ce3c0fa8a4c5dc09301605e9e35fb33cbec95b05d28c9e49f0ec2606cfa89d", b"007dc1f7341d657df8cd8534b20d6ef5dd1692ccaf139e4b4efc63f832fca8ab", b"646a9a878f54c25af962493b1ad029995300d27343f682a2cee20273070dba27", b"73afb6201bb8c76183a43d0ed528fd2b150834def3a5b7ae4f225399b35ece3b", b"ba3a060e0e8b8b3052d18bba4db50ec8efb0b4d292d98c150bee71fdcf7d1998", b"c8c7db9ee462f60d656b32b7f61e95aa241f82333e8fc6a5b6444bf6650a3f30", b"5f50baf9b5454484eae8149100fdbd8442583a37ab2f0482c0ccff1fa37a33a1", b"4b784ddc1420627929f964e6dee12c1bbefb38c9cfaadf23bedf3a5ae0485ca5", b"5d415fb628585f178cdbdb055c37115094701466d0bbf5c7ecd180c51901d53c", b"82d3a99503290b09b3e592585e1e645a6adad45e5c6686a2614e498e2a10cecf", b"89eb30892cda11de7b05e43eac51aeae3f8f0df1f9c87be908a98ef50e1f9cb4", b"d7eebda26d41e3fe126aa37e430aef38f0a845029e83bc65a9b058a82d8d4977", b"5eaacda4a7f19c5a1098a3ed77ac4a7bf392e9e75b2e42f494466c31fbd3a0a9", b"ef660208fb6a737f66ad34d6265e15e85c757a82386927ec9b706efe157e1cb9", b"73c2b6e65017b32e45584adc1c4c6bdb0f7a0ca3d244519f0fc25c8f0a751e29", b"422eda482fe7068ff4127d2d5380a6a78901024284a78ea2a8d8ef32a9ee4771", b"b806ee79d7b4056f5e5b34d125c5b2af9048c353628fea3b6695bda1ec48ee9b", b"99028cba5d078e7189034725092f5a09f193fe2ab39f949e5c0d2ea19c635283", b"b58bb0c9281e7a07505ddc822d5c956f13bff612b6e18eef83c8833755bcd648", b"d48b15936aeab4dc79807591759a3c73143a22f1c0318b6d59b641522aeec5ef", b"96eadb7be9c75902be80616521e48ce906bb4c56586b9b8bb9736f4542f8ab4f", b"a72c6ab48bbd76d235c44984f77ad480c67cde8d4ab65fbf08f326e098855ec8", b"49664a5bc96cc6d02eb00f3d7a40872cd355860a11baa28b69383bbbcdbf8deb", b"cc912109318ac8e0a78a6c8d67805094f060cd410df843b7fe69f5b187439dbc", ]; let mut input = Vec::new(); let key = [b'A'; KEY_SIZE]; for i in 0..128 { assert_eq!( hmac_256::(&key, &input), hex::decode(hashes[i] as &[u8]).unwrap().as_slice() ); input.push(b'A'); } } // TODO: more tests }