1 /** 2 * Key Derivation Function interfaces 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.kdf.kdf; 12 13 import botan.constants; 14 static if (BOTAN_HAS_TLS || BOTAN_HAS_PUBLIC_KEY_CRYPTO): 15 16 import memutils.vector; 17 import botan.utils.types; 18 19 import botan.libstate.libstate; 20 import botan.algo_base.scan_token; 21 import botan.constants; 22 static if (BOTAN_HAS_KDF1) import botan.kdf.kdf1; 23 static if (BOTAN_HAS_KDF2) import botan.kdf.kdf2; 24 static if (BOTAN_HAS_X942_PRF) import botan.kdf.prf_x942; 25 static if (BOTAN_HAS_SSL_V3_PRF) import botan.kdf.prf_ssl3; 26 static if (BOTAN_HAS_TLS_V10_PRF) import botan.kdf.prf_tls; 27 28 /** 29 * Key Derivation Function 30 */ 31 class KDF 32 { 33 public: 34 ~this() {} 35 36 abstract @property string name() const; 37 38 /** 39 * Derive a key 40 * Params: 41 * key_len = the desired output length in bytes 42 * secret = the secret input 43 * salt = a diversifier 44 */ 45 SecureVector!ubyte deriveKey()(size_t key_len, 46 auto const ref SecureVector!ubyte secret, 47 in string salt = "") const 48 { 49 return deriveKey(key_len, secret.ptr, secret.length, 50 cast(const(ubyte)*)(salt.ptr), 51 salt.length); 52 } 53 54 /** 55 * Derive a key 56 * Params: 57 * key_len = the desired output length in bytes 58 * secret = the secret input 59 * salt = a diversifier 60 */ 61 62 SecureVector!ubyte deriveKey(Alloc)(size_t key_len, 63 auto const ref SecureVector!ubyte secret, 64 auto const ref Vector!( ubyte, Alloc ) salt) const 65 { 66 return deriveKey(key_len, secret.ptr, secret.length, salt.ptr, salt.length); 67 } 68 69 /** 70 * Derive a key 71 * Params: 72 * key_len = the desired output length in bytes 73 * secret = the secret input 74 * salt = a diversifier 75 * salt_len = size of salt in bytes 76 */ 77 SecureVector!ubyte deriveKey()(size_t key_len, 78 auto const ref SecureVector!ubyte secret, 79 const(ubyte)* salt, 80 size_t salt_len) const 81 { 82 return deriveKey(key_len, 83 secret.ptr, secret.length, 84 salt, salt_len); 85 } 86 87 /** 88 * Derive a key 89 * Params: 90 * key_len = the desired output length in bytes 91 * secret = the secret input 92 * secret_len = size of secret in bytes 93 * salt = a diversifier 94 */ 95 SecureVector!ubyte deriveKey(size_t key_len, 96 const(ubyte)* secret, 97 size_t secret_len, 98 in string salt = "") const 99 { 100 return deriveKey(key_len, secret, secret_len, 101 cast(const(ubyte)*)(salt.ptr), 102 salt.length); 103 } 104 105 /** 106 * Derive a key 107 * Params: 108 * key_len = the desired output length in bytes 109 * secret = the secret input 110 * secret_len = size of secret in bytes 111 * salt = a diversifier 112 * salt_len = size of salt in bytes 113 */ 114 SecureVector!ubyte deriveKey(size_t key_len, 115 const(ubyte)* secret, 116 size_t secret_len, 117 const(ubyte)* salt, 118 size_t salt_len) const 119 { 120 return derive(key_len, secret, secret_len, salt, salt_len); 121 } 122 123 abstract KDF clone() const; 124 125 protected: 126 abstract SecureVector!ubyte 127 derive(size_t key_len, 128 const(ubyte)* secret, size_t secret_len, 129 const(ubyte)* salt, size_t salt_len) const; 130 } 131 132 /** 133 * Factory method for KDF (key derivation function) 134 * Params: 135 * algo_spec = the name of the KDF to create 136 * Returns: pointer to newly allocated object of that type 137 */ 138 KDF getKdf(in string algo_spec) 139 { 140 SCANToken request = SCANToken(algo_spec); 141 142 AlgorithmFactory af = globalState().algorithmFactory(); 143 144 if (request.algoName == "Raw") 145 return null; // No KDF 146 147 static if (BOTAN_HAS_KDF1) { 148 if (request.algoName == "KDF1" && request.argCount() == 1) 149 return new KDF1(af.makeHashFunction(request.arg(0))); 150 } 151 152 static if (BOTAN_HAS_KDF2) { 153 if (request.algoName == "KDF2" && request.argCount() == 1) 154 return new KDF2(af.makeHashFunction(request.arg(0))); 155 } 156 157 static if (BOTAN_HAS_X942_PRF) { 158 if (request.algoName == "X9.42-PRF" && request.argCount() == 1) 159 return new X942PRF(request.arg(0)); // OID 160 } 161 162 static if (BOTAN_HAS_SSL_V3_PRF) { 163 if (request.algoName == "SSL3-PRF" && request.argCount() == 0) 164 return new SSL3PRF; 165 } 166 167 static if (BOTAN_HAS_TLS_V10_PRF) { 168 if (request.algoName == "TLS-PRF" && request.argCount() == 0) 169 return new TLSPRF; 170 } 171 172 static if (BOTAN_HAS_TLS_V12_PRF) { 173 if (request.algoName == "TLS-12-PRF" && request.argCount() == 1) 174 return new TLS12PRF(af.makeMac("HMAC(" ~ request.arg(0) ~ ")")); 175 } 176 177 throw new AlgorithmNotFound(algo_spec); 178 } 179 180 static if (BOTAN_TEST): 181 182 import botan.libstate.lookup; 183 import botan.codec.hex; 184 import botan.test; 185 import memutils.hashmap; 186 import core.atomic; 187 shared(int) g_total_tests; 188 static if (BOTAN_HAS_TESTS && !SKIP_KDF_TEST) unittest 189 { 190 logDebug("Testing kdf.d ..."); 191 auto test = delegate(string input) { 192 return runTests(input, "KDF", "Output", true, 193 (ref HashMap!(string, string) vec) 194 { 195 atomicOp!"+="(g_total_tests, 1); 196 Unique!KDF kdf = getKdf(vec["KDF"]); 197 198 const size_t outlen = to!uint(vec["OutputLen"]); 199 const auto salt = hexDecode(vec["Salt"]); 200 const auto secret = hexDecodeLocked(vec["Secret"]); 201 202 const auto key = kdf.deriveKey(outlen, secret, salt); 203 auto encoded = hexEncode(key); 204 return encoded; 205 }); 206 }; 207 208 size_t fails = runTestsInDir("test_data/kdf", test); 209 210 testReport("kdf", g_total_tests, fails); 211 }