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 }