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