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 }