1 /** 2 * PBKDF 3 * 4 * Copyright: 5 * (C) 1999-2007,2012 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.pbkdf.pbkdf; 12 13 import botan.constants; 14 import botan.algo_base.symkey; 15 import std.datetime; 16 import std.exception; 17 import botan.utils.types; 18 19 /** 20 * Base class for PBKDF (password based key derivation function) 21 * implementations. Converts a password into a key using a salt 22 * and iterated hashing to make brute force attacks harder. 23 */ 24 interface PBKDF 25 { 26 public: 27 /** 28 * Returns: new instance of this same algorithm 29 */ 30 PBKDF clone() const; 31 32 @property string name() const; 33 34 /** 35 * Derive a key from a passphrase 36 * Params: 37 * output_len = the desired length of the key to produce 38 * passphrase = the password to derive the key from 39 * salt = a randomly chosen salt 40 * salt_len = length of salt in bytes 41 * iterations = the number of iterations to use (use 10K or more) 42 */ 43 final OctetString deriveKey(size_t output_len, 44 in string passphrase, 45 const(ubyte)* salt, size_t salt_len, 46 size_t iterations) const 47 { 48 if (iterations == 0) 49 throw new InvalidArgument(name ~ ": Invalid iteration count"); 50 51 auto derived = keyDerivation(output_len, passphrase, 52 salt, salt_len, iterations, 53 Duration.zero); 54 55 assert(derived.first == iterations, 56 "PBKDF used the correct number of iterations"); 57 58 return derived.second; 59 } 60 61 /** 62 * Derive a key from a passphrase 63 * Params: 64 * output_len = the desired length of the key to produce 65 * passphrase = the password to derive the key from 66 * salt = a randomly chosen salt 67 * iterations = the number of iterations to use (use 10K or more) 68 */ 69 final OctetString deriveKey(Alloc)(size_t output_len, 70 in string passphrase, 71 const ref Vector!( ubyte, Alloc ) salt, 72 size_t iterations) const 73 { 74 return deriveKey(output_len, passphrase, salt.ptr, salt.length, iterations); 75 } 76 77 /** 78 * Derive a key from a passphrase 79 * Params: 80 * output_len = the desired length of the key to produce 81 * passphrase = the password to derive the key from 82 * salt = a randomly chosen salt 83 * salt_len = length of salt in bytes 84 * loop_for = is how long to run the PBKDF 85 * iterations = is set to the number of iterations used 86 */ 87 final OctetString deriveKey(size_t output_len, 88 in string passphrase, 89 const(ubyte)* salt, size_t salt_len, 90 Duration loop_for, 91 ref size_t iterations) const 92 { 93 auto derived = keyDerivation(output_len, passphrase, salt, salt_len, 0, loop_for); 94 95 iterations = derived.first; 96 97 return derived.second; 98 } 99 100 /** 101 * Derive a key from a passphrase using a certain amount of time 102 * Params: 103 * output_len = the desired length of the key to produce 104 * passphrase = the password to derive the key from 105 * salt = a randomly chosen salt 106 * loop_for = is how long to run the PBKDF 107 * iterations = is set to the number of iterations used 108 */ 109 final OctetString deriveKey(Alloc)(size_t output_len, 110 in string passphrase, 111 const ref Vector!( ubyte, Alloc ) salt, 112 Duration loop_for, 113 ref size_t iterations) const 114 { 115 return deriveKey(output_len, passphrase, salt.ptr, salt.length, loop_for, iterations); 116 } 117 118 /** 119 * Derive a key from a passphrase for a number of iterations 120 * specified by either iterations or if iterations == 0 then 121 * running until seconds time has elapsed. 122 * 123 * Params: 124 * output_len = the desired length of the key to produce 125 * passphrase = the password to derive the key from 126 * salt = a randomly chosen salt 127 * salt_len = length of salt in bytes 128 * iterations = the number of iterations to use (use 10K or more) 129 * loop_for = if iterations is zero, then instead the PBKDF is 130 * run until duration has passed. 131 * Returns: the number of iterations performed and the derived key 132 */ 133 Pair!(size_t, OctetString) 134 keyDerivation(size_t output_len, 135 in string passphrase, 136 const(ubyte)* salt, size_t salt_len, 137 size_t iterations, 138 Duration loop_for) const; 139 } 140 141 static if (BOTAN_HAS_TESTS && !SKIP_PBKDF_TEST) unittest { 142 logDebug("Testing pbkdf.d ..."); 143 import botan.test; 144 import botan.codec.hex; 145 import memutils.hashmap; 146 int total_tests; 147 auto test = delegate(string input) { 148 return runTests(input, "PBKDF", "Output", true, 149 (ref HashMap!(string, string) vec) { 150 total_tests += 1; 151 Unique!PBKDF pbkdf = getPbkdf(vec["PBKDF"]); 152 153 const size_t iterations = to!size_t(vec["Iterations"]); 154 const size_t outlen = to!size_t(vec["OutputLen"]); 155 const auto salt = hexDecode(vec["Salt"]); 156 const string pass = vec["Passphrase"]; 157 158 const auto key = pbkdf.deriveKey(outlen, pass, salt.ptr, salt.length, iterations).bitsOf(); 159 return hexEncode(key); 160 }); 161 }; 162 163 size_t fails = runTestsInDir("../test_data/pbkdf", test); 164 165 testReport("pbkdf", total_tests, fails); 166 }