1 /** 2 * Base class for message authentiction codes 3 * 4 * Copyright: 5 * (C) 1999-2007 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.mac.mac; 12 13 import botan.constants; 14 public import botan.algo_base.sym_algo; 15 public import botan.algo_base.buf_comp; 16 import botan.utils.mem_ops; 17 18 /** 19 * This class represents Message Authentication Code (MAC) objects. 20 */ 21 interface MessageAuthenticationCode : BufferedComputation, SymmetricAlgorithm 22 { 23 public: 24 /** 25 * Verify a MAC. 26 * 27 * Params: 28 * mac = the MAC to verify as a ubyte array 29 * length = the length of param in 30 * Returns: true if the MAC is valid, false otherwise 31 */ 32 final bool verifyMac(const(ubyte)* mac, size_t length) 33 { 34 SecureVector!ubyte our_mac = finished(); 35 36 if (our_mac.length != length) 37 return false; 38 39 return sameMem(our_mac.ptr, mac, length); 40 } 41 42 /** 43 * Get a new object representing the same algorithm as this 44 */ 45 abstract MessageAuthenticationCode clone() const; 46 47 /** 48 * Get the name of this algorithm. 49 * Returns: name of this algorithm 50 */ 51 abstract @property string name() const; 52 } 53 54 static if (BOTAN_TEST): 55 56 import botan.test; 57 import botan.libstate.libstate; 58 import botan.codec.hex; 59 import memutils.hashmap; 60 import core.atomic; 61 62 private shared size_t total_tests; 63 64 size_t macTest(string algo, string key_hex, string in_hex, string out_hex) 65 { 66 AlgorithmFactory af = globalState().algorithmFactory(); 67 68 const auto providers = af.providersOf(algo); 69 size_t fails = 0; 70 71 atomicOp!"+="(total_tests, 1); 72 if (providers.empty) 73 { 74 logError("Unknown algo " ~ algo); 75 ++fails; 76 } 77 78 foreach (provider; providers[]) 79 { 80 atomicOp!"+="(total_tests, 1); 81 auto proto = af.prototypeMac(algo, provider); 82 83 if (!proto) 84 { 85 logError("Unable to get " ~ algo ~ " from " ~ provider); 86 ++fails; 87 continue; 88 } 89 90 Unique!MessageAuthenticationCode mac = proto.clone(); 91 92 mac.setKey(hexDecode(key_hex)); 93 mac.update(hexDecode(in_hex)); 94 95 auto h = mac.finished(); 96 97 atomicOp!"+="(total_tests, 1); 98 if (h != hexDecodeLocked(out_hex)) 99 { 100 logError(algo ~ " " ~ provider ~ " got " ~ hexEncode(h) ~ " != " ~ out_hex); 101 ++fails; 102 } 103 } 104 105 return fails; 106 } 107 108 static if (BOTAN_HAS_TESTS && !SKIP_MAC_TEST) unittest { 109 logDebug("Testing mac.d ..."); 110 auto test = delegate(string input) { 111 File vec = File(input, "r"); 112 113 return runTestsBb(vec, "Mac", "Out", true, 114 (ref HashMap!(string, string) m) { 115 return macTest(m["Mac"], m["Key"], m["In"], m["Out"]); 116 }); 117 }; 118 119 size_t fails = runTestsInDir("../test_data/mac", test); 120 121 testReport("mac", total_tests, fails); 122 }