1 /** 2 * Hash Function Base Class 3 * 4 * Copyright: 5 * (C) 1999-2008 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.hash.hash; 12 13 import botan.constants; 14 import botan.algo_base.buf_comp; 15 16 /** 17 * This class represents hash function (message digest) objects 18 */ 19 interface HashFunction : BufferedComputation 20 { 21 public: 22 /** 23 * Returns: new object representing the same algorithm as this 24 */ 25 HashFunction clone() const; 26 27 void clear(); 28 29 @property string name() const; 30 31 /** 32 * Returns: hash block size as defined for this algorithm 33 */ 34 @property size_t hashBlockSize() const; 35 } 36 37 static if (BOTAN_TEST): 38 import botan.test; 39 40 import botan.libstate.libstate; 41 import botan.codec.hex; 42 import core.atomic; 43 import memutils.hashmap; 44 45 private shared size_t total_tests; 46 47 size_t hashTest(string algo, string in_hex, string out_hex) 48 { 49 AlgorithmFactory af = globalState().algorithmFactory(); 50 51 const auto providers = af.providersOf(algo); 52 size_t fails = 0; 53 atomicOp!"+="(total_tests, cast(size_t)1); 54 if (providers.empty) 55 { 56 logTrace("Unknown algo " ~ algo); 57 ++fails; 58 } 59 60 foreach (provider; providers[]) 61 { 62 auto proto = af.prototypeHashFunction(algo, provider); 63 64 atomicOp!"+="(total_tests, 1); 65 66 if (!proto) 67 { 68 logError("Unable to get " ~ algo ~ " from " ~ provider); 69 ++fails; 70 continue; 71 } 72 73 Unique!HashFunction hash = proto.clone(); 74 auto decoded = hexDecode(in_hex); 75 hash.update(decoded); 76 77 auto h = hash.finished(); 78 79 atomicOp!"+="(total_tests, 1); 80 81 if (h != hexDecodeLocked(out_hex)) 82 { 83 logError(algo ~ " " ~ provider ~ " got " ~ hexEncode(h) ~ " != " ~ out_hex); 84 ++fails; 85 } 86 87 // Test to make sure clear() resets what we need it to 88 hash.update("some discarded input"); 89 hash.clear(); 90 91 hash.update(hexDecode(in_hex)); 92 93 h = hash.finished(); 94 95 atomicOp!"+="(total_tests, 1); 96 97 if (h != hexDecodeLocked(out_hex)) 98 { 99 logError(algo ~ " " ~ provider ~ " got " ~ hexEncode(h) ~ " != " ~ out_hex); 100 ++fails; 101 } 102 } 103 104 return fails; 105 } 106 107 static if (BOTAN_HAS_TESTS && !SKIP_HASH_TEST) unittest 108 { 109 logDebug("Testing hash.d ..."); 110 import botan.libstate.libstate : globalState; 111 globalState(); 112 auto test = delegate(string input) 113 { 114 File vec = File(input, "r"); 115 116 return runTestsBb(vec, "Hash", "Out", true, 117 (ref HashMap!(string, string) m) { 118 return hashTest(m["Hash"], m["In"], m["Out"]); 119 }); 120 }; 121 122 size_t fails = runTestsInDir("../test_data/hash", test); 123 124 testReport("hash", total_tests, fails); 125 }