Crypto++ 8.0 Free C++ class library of cryptographic schemes

pwdbased.h
Go to the documentation of this file.
1 // pwdbased.h - originally written and placed in the public domain by Wei Dai
2 // Cutover to KeyDerivationFunction interface by Uri Blumenthal
3 // Marcel Raad and Jeffrey Walton in March 2018.
4
5 /// \file pwdbased.h
6 /// \brief Password based key derivation functions
7
8 #ifndef CRYPTOPP_PWDBASED_H
9 #define CRYPTOPP_PWDBASED_H
10
11 #include "cryptlib.h"
12 #include "hrtimer.h"
13 #include "integer.h"
14 #include "argnames.h"
15 #include "algparam.h"
16 #include "hmac.h"
17
18 NAMESPACE_BEGIN(CryptoPP)
19
20 // ******************** PBKDF1 ********************
21
22 /// \brief PBKDF1 from PKCS #5
23 /// \tparam T a HashTransformation class
24 template <class T>
25 class PKCS5_PBKDF1 : public PasswordBasedKeyDerivationFunction
26 {
27 public:
28 virtual ~PKCS5_PBKDF1() {}
29
30 static std::string StaticAlgorithmName () {
31 const std::string name(std::string("PBKDF1(") +
32 std::string(T::StaticAlgorithmName()) + std::string(")"));
33 return name;
34 }
35
36 // KeyDerivationFunction interface
37 std::string AlgorithmName() const {
38 return StaticAlgorithmName();
39 }
40
41 // KeyDerivationFunction interface
42 size_t MaxDerivedKeyLength() const {
43 return static_cast<size_t>(T::DIGESTSIZE);
44 }
45
46 // KeyDerivationFunction interface
47 size_t GetValidDerivedLength(size_t keylength) const;
48
49 // KeyDerivationFunction interface
50 virtual size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen,
51 const NameValuePairs& params = g_nullNameValuePairs) const;
52
53 /// \brief Derive a key from a secret seed
54 /// \param derived the derived output buffer
55 /// \param derivedLen the size of the derived buffer, in bytes
56 /// \param purpose a purpose byte
57 /// \param secret the seed input buffer
58 /// \param secretLen the size of the secret buffer, in bytes
59 /// \param salt the salt input buffer
60 /// \param saltLen the size of the salt buffer, in bytes
61 /// \param iterations the number of iterations
62 /// \param timeInSeconds the in seconds
63 /// \returns the number of iterations performed
64 /// \throws InvalidDerivedLength if <tt>derivedLen</tt> is invalid for the scheme
65 /// \details DeriveKey() provides a standard interface to derive a key from
66 /// a seed and other parameters. Each class that derives from KeyDerivationFunction
67 /// provides an overload that accepts most parameters used by the derivation function.
68 /// \details If <tt>timeInSeconds</tt> is <tt>&gt; 0.0</tt> then DeriveKey will run for
69 /// the specified amount of time. If <tt>timeInSeconds</tt> is <tt>0.0</tt> then DeriveKey
70 /// will run for the specified number of iterations.
71 /// \details PKCS #5 says PBKDF1 should only take 8-byte salts. This implementation
72 /// allows salts of any length.
73 size_t DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const;
74
75 protected:
76 // KeyDerivationFunction interface
77 const Algorithm & GetAlgorithm() const {
78 return *this;
79 }
80 };
81
82 template <class T>
83 size_t PKCS5_PBKDF1<T>::GetValidDerivedLength(size_t keylength) const
84 {
85 if (keylength > MaxDerivedLength())
86 return MaxDerivedLength();
87 return keylength;
88 }
89
90 template <class T>
91 size_t PKCS5_PBKDF1<T>::DeriveKey(byte *derived, size_t derivedLen,
92 const byte *secret, size_t secretLen, const NameValuePairs& params) const
93 {
94 CRYPTOPP_ASSERT(secret /*&& secretLen*/);
95 CRYPTOPP_ASSERT(derived && derivedLen);
96 CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength());
97
98 byte purpose = (byte)params.GetIntValueWithDefault("Purpose", 0);
99 unsigned int iterations = (unsigned int)params.GetIntValueWithDefault("Iterations", 1);
100
101 double timeInSeconds = 0.0f;
102 (void)params.GetValue("TimeInSeconds", timeInSeconds);
103
104 ConstByteArrayParameter salt;
105 (void)params.GetValue(Name::Salt(), salt);
106
107 return DeriveKey(derived, derivedLen, purpose, secret, secretLen, salt.begin(), salt.size(), iterations, timeInSeconds);
108 }
109
110 template <class T>
111 size_t PKCS5_PBKDF1<T>::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const
112 {
113 CRYPTOPP_ASSERT(secret /*&& secretLen*/);
114 CRYPTOPP_ASSERT(derived && derivedLen);
115 CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength());
116 CRYPTOPP_ASSERT(iterations > 0 || timeInSeconds > 0);
117 CRYPTOPP_UNUSED(purpose);
118
119 ThrowIfInvalidDerivedLength(derivedLen);
120
121 // Business logic
122 if (!iterations) { iterations = 1; }
123
124 T hash;
125 hash.Update(secret, secretLen);
126 hash.Update(salt, saltLen);
127
128 SecByteBlock buffer(hash.DigestSize());
129 hash.Final(buffer);
130
131 unsigned int i;
132 ThreadUserTimer timer;
133
134 if (timeInSeconds)
135 timer.StartTimer();
136
137 for (i=1; i<iterations || (timeInSeconds && (i%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); i++)
138 hash.CalculateDigest(buffer, buffer, buffer.size());
139
140 memcpy(derived, buffer, derivedLen);
141 return i;
142 }
143
144 // ******************** PKCS5_PBKDF2_HMAC ********************
145
146 /// \brief PBKDF2 from PKCS #5
147 /// \tparam T a HashTransformation class
148 template <class T>
149 class PKCS5_PBKDF2_HMAC : public PasswordBasedKeyDerivationFunction
150 {
151 public:
152 virtual ~PKCS5_PBKDF2_HMAC() {}
153
154 static std::string StaticAlgorithmName () {
155 const std::string name(std::string("PBKDF2_HMAC(") +
156 std::string(T::StaticAlgorithmName()) + std::string(")"));
157 return name;
158 }
159
160 // KeyDerivationFunction interface
161 std::string AlgorithmName() const {
162 return StaticAlgorithmName();
163 }
164
165 // KeyDerivationFunction interface
166 // should multiply by T::DIGESTSIZE, but gets overflow that way
167 size_t MaxDerivedKeyLength() const {
168 return 0xffffffffU;
169 }
170
171 // KeyDerivationFunction interface
172 size_t GetValidDerivedLength(size_t keylength) const;
173
174 // KeyDerivationFunction interface
175 size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen,
176 const NameValuePairs& params = g_nullNameValuePairs) const;
177
178 /// \brief Derive a key from a secret seed
179 /// \param derived the derived output buffer
180 /// \param derivedLen the size of the derived buffer, in bytes
181 /// \param purpose a purpose byte
182 /// \param secret the seed input buffer
183 /// \param secretLen the size of the secret buffer, in bytes
184 /// \param salt the salt input buffer
185 /// \param saltLen the size of the salt buffer, in bytes
186 /// \param iterations the number of iterations
187 /// \param timeInSeconds the in seconds
188 /// \returns the number of iterations performed
189 /// \throws InvalidDerivedLength if <tt>derivedLen</tt> is invalid for the scheme
190 /// \details DeriveKey() provides a standard interface to derive a key from
191 /// a seed and other parameters. Each class that derives from KeyDerivationFunction
192 /// provides an overload that accepts most parameters used by the derivation function.
193 /// \details If <tt>timeInSeconds</tt> is <tt>&gt; 0.0</tt> then DeriveKey will run for
194 /// the specified amount of time. If <tt>timeInSeconds</tt> is <tt>0.0</tt> then DeriveKey
195 /// will run for the specified number of iterations.
196 size_t DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen,
197 const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const;
198
199 protected:
200 // KeyDerivationFunction interface
201 const Algorithm & GetAlgorithm() const {
202 return *this;
203 }
204 };
205
206 template <class T>
207 size_t PKCS5_PBKDF2_HMAC<T>::GetValidDerivedLength(size_t keylength) const
208 {
209 if (keylength > MaxDerivedLength())
210 return MaxDerivedLength();
211 return keylength;
212 }
213
214 template <class T>
215 size_t PKCS5_PBKDF2_HMAC<T>::DeriveKey(byte *derived, size_t derivedLen,
216 const byte *secret, size_t secretLen, const NameValuePairs& params) const
217 {
218 CRYPTOPP_ASSERT(secret /*&& secretLen*/);
219 CRYPTOPP_ASSERT(derived && derivedLen);
220 CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength());
221
222 byte purpose = (byte)params.GetIntValueWithDefault("Purpose", 0);
223 unsigned int iterations = (unsigned int)params.GetIntValueWithDefault("Iterations", 1);
224
225 double timeInSeconds = 0.0f;
226 (void)params.GetValue("TimeInSeconds", timeInSeconds);
227
228 ConstByteArrayParameter salt;
229 (void)params.GetValue(Name::Salt(), salt);
230
231 return DeriveKey(derived, derivedLen, purpose, secret, secretLen, salt.begin(), salt.size(), iterations, timeInSeconds);
232 }
233
234 template <class T>
235 size_t PKCS5_PBKDF2_HMAC<T>::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const
236 {
237 CRYPTOPP_ASSERT(secret /*&& secretLen*/);
238 CRYPTOPP_ASSERT(derived && derivedLen);
239 CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength());
240 CRYPTOPP_ASSERT(iterations > 0 || timeInSeconds > 0);
241 CRYPTOPP_UNUSED(purpose);
242
243 ThrowIfInvalidDerivedLength(derivedLen);
244
245 // Business logic
246 if (!iterations) { iterations = 1; }
247
248 HMAC<T> hmac(secret, secretLen);
249 SecByteBlock buffer(hmac.DigestSize());
250 ThreadUserTimer timer;
251
252 unsigned int i=1;
253 while (derivedLen > 0)
254 {
255 hmac.Update(salt, saltLen);
256 unsigned int j;
257 for (j=0; j<4; j++)
258 {
259 byte b = byte(i >> ((3-j)*8));
260 hmac.Update(&b, 1);
261 }
262 hmac.Final(buffer);
263
264 #if CRYPTOPP_MSC_VERSION
265 const size_t segmentLen = STDMIN(derivedLen, buffer.size());
266 memcpy_s(derived, segmentLen, buffer, segmentLen);
267 #else
268 const size_t segmentLen = STDMIN(derivedLen, buffer.size());
269 memcpy(derived, buffer, segmentLen);
270 #endif
271
272 if (timeInSeconds)
273 {
274 timeInSeconds = timeInSeconds / ((derivedLen + buffer.size() - 1) / buffer.size());
275 timer.StartTimer();
276 }
277
278 for (j=1; j<iterations || (timeInSeconds && (j%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); j++)
279 {
280 hmac.CalculateDigest(buffer, buffer, buffer.size());
281 xorbuf(derived, buffer, segmentLen);
282 }
283
284 if (timeInSeconds)
285 {
286 iterations = j;
287 timeInSeconds = 0;
288 }
289
290 derived += segmentLen;
291 derivedLen -= segmentLen;
292 i++;
293 }
294
295 return iterations;
296 }
297
298 // ******************** PKCS12_PBKDF ********************
299
300 /// \brief PBKDF from PKCS #12, appendix B
301 /// \tparam T a HashTransformation class
302 template <class T>
303 class PKCS12_PBKDF : public PasswordBasedKeyDerivationFunction
304 {
305 public:
306 virtual ~PKCS12_PBKDF() {}
307
308 static std::string StaticAlgorithmName () {
309 const std::string name(std::string("PBKDF_PKCS12(") +
310 std::string(T::StaticAlgorithmName()) + std::string(")"));
311 return name;
312 }
313
314 // KeyDerivationFunction interface
315 std::string AlgorithmName() const {
316 return StaticAlgorithmName();
317 }
318
319 // TODO - check this
320 size_t MaxDerivedKeyLength() const {
321 return static_cast<size_t>(-1);
322 }
323
324 // KeyDerivationFunction interface
325 size_t GetValidDerivedLength(size_t keylength) const;
326
327 // KeyDerivationFunction interface
328 size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen,
329 const NameValuePairs& params = g_nullNameValuePairs) const;
330
331 /// \brief Derive a key from a secret seed
332 /// \param derived the derived output buffer
333 /// \param derivedLen the size of the derived buffer, in bytes
334 /// \param purpose a purpose byte
335 /// \param secret the seed input buffer
336 /// \param secretLen the size of the secret buffer, in bytes
337 /// \param salt the salt input buffer
338 /// \param saltLen the size of the salt buffer, in bytes
339 /// \param iterations the number of iterations
340 /// \param timeInSeconds the in seconds
341 /// \returns the number of iterations performed
342 /// \throws InvalidDerivedLength if <tt>derivedLen</tt> is invalid for the scheme
343 /// \details DeriveKey() provides a standard interface to derive a key from
344 /// a seed and other parameters. Each class that derives from KeyDerivationFunction
345 /// provides an overload that accepts most parameters used by the derivation function.
346 /// \details If <tt>timeInSeconds</tt> is <tt>&gt; 0.0</tt> then DeriveKey will run for
347 /// the specified amount of time. If <tt>timeInSeconds</tt> is <tt>0.0</tt> then DeriveKey
348 /// will run for the specified number of iterations.
349 size_t DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen,
350 const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const;
351
352 protected:
353 // KeyDerivationFunction interface
354 const Algorithm & GetAlgorithm() const {
355 return *this;
356 }
357 };
358
359 template <class T>
360 size_t PKCS12_PBKDF<T>::GetValidDerivedLength(size_t keylength) const
361 {
362 if (keylength > MaxDerivedLength())
363 return MaxDerivedLength();
364 return keylength;
365 }
366
367 template <class T>
368 size_t PKCS12_PBKDF<T>::DeriveKey(byte *derived, size_t derivedLen,
369 const byte *secret, size_t secretLen, const NameValuePairs& params) const
370 {
371 CRYPTOPP_ASSERT(secret /*&& secretLen*/);
372 CRYPTOPP_ASSERT(derived && derivedLen);
373 CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength());
374
375 byte purpose = (byte)params.GetIntValueWithDefault("Purpose", 0);
376 unsigned int iterations = (unsigned int)params.GetIntValueWithDefault("Iterations", 1);
377
378 double timeInSeconds = 0.0f;
379 (void)params.GetValue("TimeInSeconds", timeInSeconds);
380
381 // NULL or 0 length salt OK
382 ConstByteArrayParameter salt;
383 (void)params.GetValue(Name::Salt(), salt);
384
385 return DeriveKey(derived, derivedLen, purpose, secret, secretLen, salt.begin(), salt.size(), iterations, timeInSeconds);
386 }
387
388 template <class T>
389 size_t PKCS12_PBKDF<T>::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const
390 {
391 CRYPTOPP_ASSERT(secret /*&& secretLen*/);
392 CRYPTOPP_ASSERT(derived && derivedLen);
393 CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength());
394 CRYPTOPP_ASSERT(iterations > 0 || timeInSeconds > 0);
395
396 ThrowIfInvalidDerivedLength(derivedLen);
397
398 // Business logic
399 if (!iterations) { iterations = 1; }
400
401 const size_t v = T::BLOCKSIZE; // v is in bytes rather than bits as in PKCS #12
402 const size_t DLen = v, SLen = RoundUpToMultipleOf(saltLen, v);
403 const size_t PLen = RoundUpToMultipleOf(secretLen, v), ILen = SLen + PLen;
404 SecByteBlock buffer(DLen + SLen + PLen);
405 byte *D = buffer, *S = buffer+DLen, *P = buffer+DLen+SLen, *I = S;
406
407 memset(D, purpose, DLen);
408 size_t i;
409 for (i=0; i<SLen; i++)
410 S[i] = salt[i % saltLen];
411 for (i=0; i<PLen; i++)
412 P[i] = secret[i % secretLen];
413
414 T hash;
415 SecByteBlock Ai(T::DIGESTSIZE), B(v);
416 ThreadUserTimer timer;
417
418 while (derivedLen > 0)
419 {
420 hash.CalculateDigest(Ai, buffer, buffer.size());
421
422 if (timeInSeconds)
423 {
424 timeInSeconds = timeInSeconds / ((derivedLen + Ai.size() - 1) / Ai.size());
425 timer.StartTimer();
426 }
427
428 for (i=1; i<iterations || (timeInSeconds && (i%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); i++)
429 hash.CalculateDigest(Ai, Ai, Ai.size());
430
431 if (timeInSeconds)
432 {
433 iterations = (unsigned int)i;
434 timeInSeconds = 0;
435 }
436
437 for (i=0; i<B.size(); i++)
438 B[i] = Ai[i % Ai.size()];
439
440 Integer B1(B, B.size());
441 ++B1;
442 for (i=0; i<ILen; i+=v)
443 (Integer(I+i, v) + B1).Encode(I+i, v);
444
445 #if CRYPTOPP_MSC_VERSION
446 const size_t segmentLen = STDMIN(derivedLen, Ai.size());
447 memcpy_s(derived, segmentLen, Ai, segmentLen);
448 #else
449 const size_t segmentLen = STDMIN(derivedLen, Ai.size());
450 std::memcpy(derived, Ai, segmentLen);
451 #endif
452
453 derived += segmentLen;
454 derivedLen -= segmentLen;
455 }
456
457 return iterations;
458 }
459
460 NAMESPACE_END
461
462 #endif
ConstByteArrayParameter
Used to pass byte array input as part of a NameValuePairs object.
Definition: algparam.h:20
NameValuePairs::GetIntValueWithDefault
int GetIntValueWithDefault(const char *name, int defaultValue) const
Get a named value with type int, with default.
Definition: cryptlib.h:395
argnames.h
Standard names for retrieving values by name when working with NameValuePairs.
algparam.h
Classes for working with NameValuePairs.
ConstByteArrayParameter::size
size_t size() const
Length of the memory block.
Definition: algparam.h:84
PKCS5_PBKDF2_HMAC::AlgorithmName
std::string AlgorithmName() const
Provides the name of this algorithm.
Definition: pwdbased.h:161
HMAC_Base::DigestSize
unsigned int DigestSize() const
Provides the digest size of the hash.
Definition: hmac.h:30
cryptlib.h
Abstract base classes that provide a uniform interface to this library.
memcpy_s
void memcpy_s(void *dest, size_t sizeInBytes, const void *src, size_t count)
Bounds checking replacement for memcpy()
Definition: misc.h:411
PKCS5_PBKDF2_HMAC::GetValidDerivedLength
size_t GetValidDerivedLength(size_t keylength) const
Returns a valid key length for the derivation function.
Definition: pwdbased.h:207
SecByteBlock
SecBlock<byte> typedef.
Definition: secblock.h:1058
PKCS5_PBKDF2_HMAC
PBKDF2 from PKCS #5.
Definition: pwdbased.h:149
PKCS5_PBKDF1::GetValidDerivedLength
size_t GetValidDerivedLength(size_t keylength) const
Returns a valid key length for the derivation function.
Definition: pwdbased.h:83
PKCS5_PBKDF2_HMAC::DeriveKey
size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, const NameValuePairs &params=g_nullNameValuePairs) const
Derive a key from a seed.
Definition: pwdbased.h:215
PKCS5_PBKDF1
PBKDF1 from PKCS #5.
Definition: pwdbased.h:25
hmac.h
Classes for HMAC message authentication codes.
PKCS12_PBKDF
PBKDF from PKCS #12, appendix B.
Definition: pwdbased.h:303
ConstByteArrayParameter::begin
const byte * begin() const
Pointer to the first byte in the memory block.
Definition: algparam.h:80
Name::Salt
const char * Salt()
ConstByteArrayParameter.
Definition: argnames.h:87
Integer
Multiple precision integer with arithmetic operations.
Definition: integer.h:49
HMAC_Base::Update
void Update(const byte *input, size_t length)
Updates a hash with additional input.
Definition: hmac.cpp:60
PKCS12_PBKDF::DeriveKey
size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, const NameValuePairs &params=g_nullNameValuePairs) const
Derive a key from a seed.
Definition: pwdbased.h:368
g_nullNameValuePairs
const NameValuePairs & g_nullNameValuePairs
An empty set of name-value pairs.
Definition: cryptlib.h:500
PKCS12_PBKDF::AlgorithmName
std::string AlgorithmName() const
Provides the name of this algorithm.
Definition: pwdbased.h:315
STDMIN
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition: misc.h:535
CRYPTOPP_ASSERT
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:69
Algorithm
Interface for all crypto algorithms.
Definition: cryptlib.h:570
HashTransformation::CalculateDigest
virtual void CalculateDigest(byte *digest, const byte *input, size_t length)
Updates the hash with additional input and computes the hash of the current message.
Definition: cryptlib.h:1160
PKCS5_PBKDF1::AlgorithmName
std::string AlgorithmName() const
Provides the name of this algorithm.
Definition: pwdbased.h:37
HMAC
HMAC.
Definition: hmac.h:52
xorbuf
void xorbuf(byte *buf, const byte *mask, size_t count)
Performs an XOR of a buffer with a mask.
Definition: misc.cpp:32
PasswordBasedKeyDerivationFunction
Interface for password based key derivation functions.
Definition: cryptlib.h:1533
integer.h
Multiple precision integer with arithmetic operations.
RoundUpToMultipleOf
T1 RoundUpToMultipleOf(const T1 &n, const T2 &m)
Rounds a value up to a multiple of a second value.
Definition: misc.h:1053
CryptoPP
Crypto++ library namespace.
NameValuePairs::GetValue
bool GetValue(const char *name, T &value) const
Get a named value.
Definition: cryptlib.h:350
ThreadUserTimer
Measure CPU time spent executing instructions of this thread (if supported by OS) ...
Definition: hrtimer.h:46
HashTransformation::Final
virtual void Final(byte *digest)
Computes the hash of the current message.
Definition: cryptlib.h:1114
PKCS5_PBKDF1::DeriveKey
virtual size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, const NameValuePairs &params=g_nullNameValuePairs) const
Derive a key from a seed.
Definition: pwdbased.h:91
PKCS12_PBKDF::GetValidDerivedLength
size_t GetValidDerivedLength(size_t keylength) const
Returns a valid key length for the derivation function.
Definition: pwdbased.h:360
SecBlock::size
size_type size() const
Provides the count of elements in the SecBlock.
Definition: secblock.h:797
NameValuePairs
Interface for retrieving values given their names.
Definition: cryptlib.h:293