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 final @disable KDF dup() const; 125 126 protected: 127 abstract SecureVector!ubyte 128 derive(size_t key_len, 129 const(ubyte)* secret, size_t secret_len, 130 const(ubyte)* salt, size_t salt_len) const; 131 } 132 133 /** 134 * Factory method for KDF (key derivation function) 135 * Params: 136 * algo_spec = the name of the KDF to create 137 * Returns: pointer to newly allocated object of that type 138 */ 139 KDF getKdf(in string algo_spec) 140 { 141 SCANToken request = SCANToken(algo_spec); 142 143 AlgorithmFactory af = globalState().algorithmFactory(); 144 145 if (request.algoName == "Raw") 146 return null; // No KDF 147 148 static if (BOTAN_HAS_KDF1) { 149 if (request.algoName == "KDF1" && request.argCount() == 1) 150 return new KDF1(af.makeHashFunction(request.arg(0))); 151 } 152 153 static if (BOTAN_HAS_KDF2) { 154 if (request.algoName == "KDF2" && request.argCount() == 1) 155 return new KDF2(af.makeHashFunction(request.arg(0))); 156 } 157 158 static if (BOTAN_HAS_X942_PRF) { 159 if (request.algoName == "X9.42-PRF" && request.argCount() == 1) 160 return new X942PRF(request.arg(0)); // OID 161 } 162 163 static if (BOTAN_HAS_SSL_V3_PRF) { 164 if (request.algoName == "SSL3-PRF" && request.argCount() == 0) 165 return new SSL3PRF; 166 } 167 168 static if (BOTAN_HAS_TLS_V10_PRF) { 169 if (request.algoName == "TLS-PRF" && request.argCount() == 0) 170 return new TLSPRF; 171 } 172 173 static if (BOTAN_HAS_TLS_V12_PRF) { 174 if (request.algoName == "TLS-12-PRF" && request.argCount() == 1) 175 return new TLS12PRF(af.makeMac("HMAC(" ~ request.arg(0) ~ ")")); 176 } 177 178 throw new AlgorithmNotFound(algo_spec); 179 } 180 181 static if (BOTAN_TEST): 182 183 import botan.libstate.lookup; 184 import botan.codec.hex; 185 import botan.test; 186 import memutils.hashmap; 187 import core.atomic; 188 shared(int) g_total_tests; 189 static if (BOTAN_HAS_TESTS && !SKIP_KDF_TEST) unittest 190 { 191 logDebug("Testing kdf.d ..."); 192 auto test = delegate(string input) { 193 return runTests(input, "KDF", "Output", true, 194 (ref HashMap!(string, string) vec) 195 { 196 atomicOp!"+="(g_total_tests, 1); 197 Unique!KDF kdf = getKdf(vec["KDF"]); 198 199 const size_t outlen = to!uint(vec["OutputLen"]); 200 const auto salt = hexDecode(vec["Salt"]); 201 const auto secret = hexDecodeLocked(vec["Secret"]); 202 203 const auto key = kdf.deriveKey(outlen, secret, salt); 204 auto encoded = hexEncode(key); 205 return encoded; 206 }); 207 }; 208 209 size_t fails = runTestsInDir("test_data/kdf", test); 210 211 testReport("kdf", g_total_tests, fails); 212 }