Crypto++ 8.2
Free C&
asn.cpp
1// asn.cpp - originally written and placed in the public domain by Wei Dai
2// CryptoPP::Test namespace added by JW in February 2017
3
4#include "pch.h"
5#include "config.h"
6
7#ifndef CRYPTOPP_IMPORTS
8
9#include "asn.h"
10
11#include <iomanip>
12#include <time.h>
13
14NAMESPACE_BEGIN(CryptoPP)
15
16/// DER Length
17size_t DERLengthEncode(BufferedTransformation &bt, lword length)
18{
19 size_t i=0;
20 if (length <= 0x7f)
21 {
22 bt.Put(byte(length));
23 i++;
24 }
25 else
26 {
27 bt.Put(byte(BytePrecision(length) | 0x80));
28 i++;
29 for (int j=BytePrecision(length); j; --j)
30 {
31 bt.Put(byte(length >> (j-1)*8));
32 i++;
33 }
34 }
35 return i;
36}
37
38bool BERLengthDecode(BufferedTransformation &bt, lword &length, bool &definiteLength)
39{
40 byte b;
41
42 if (!bt.Get(b))
43 return false;
44
45 if (!(b & 0x80))
46 {
47 definiteLength = true;
48 length = b;
49 }
50 else
51 {
52 unsigned int lengthBytes = b & 0x7f;
53
54 if (lengthBytes == 0)
55 {
56 definiteLength = false;
57 return true;
58 }
59
60 definiteLength = true;
61 length = 0;
62 while (lengthBytes--)
63 {
64 if (length >> (8*(sizeof(length)-1)))
65 BERDecodeError(); // length about to overflow
66
67 if (!bt.Get(b))
68 return false;
69
70 length = (length << 8) | b;
71 }
72 }
73 return true;
74}
75
76bool BERLengthDecode(BufferedTransformation &bt, size_t &length)
77{
78 lword lw = 0;
79 bool definiteLength = false;
80 if (!BERLengthDecode(bt, lw, definiteLength))
82 if (!SafeConvert(lw, length))
84 return definiteLength;
85}
86
87void DEREncodeNull(BufferedTransformation &out)
88{
89 out.Put(TAG_NULL);
90 out.Put(0);
91}
92
93void BERDecodeNull(BufferedTransformation &in)
94{
95 byte b;
96 if (!in.Get(b) || b != TAG_NULL)
98 size_t length;
99 if (!BERLengthDecode(in, length) || length != 0)
101}
102
103/// ASN Strings
104size_t DEREncodeOctetString(BufferedTransformation &bt, const byte *str, size_t strLen)
105{
106 bt.Put(OCTET_STRING);
107 size_t lengthBytes = DERLengthEncode(bt, strLen);
108 bt.Put(str, strLen);
109 return 1+lengthBytes+strLen;
110}
111
112size_t DEREncodeOctetString(BufferedTransformation &bt, const SecByteBlock &str)
113{
114 return DEREncodeOctetString(bt, str.begin(), str.size());
115}
116
117size_t BERDecodeOctetString(BufferedTransformation &bt, SecByteBlock &str)
118{
119 byte b;
120 if (!bt.Get(b) || b != OCTET_STRING)
122
123 size_t bc;
124 if (!BERLengthDecode(bt, bc))
126 if (bc > bt.MaxRetrievable()) // Issue 346
128
129 str.New(bc);
130 if (bc != bt.Get(str, bc))
132 return bc;
133}
134
135size_t BERDecodeOctetString(BufferedTransformation &bt, BufferedTransformation &str)
136{
137 byte b;
138 if (!bt.Get(b) || b != OCTET_STRING)
140
141 size_t bc;
142 if (!BERLengthDecode(bt, bc))
144 if (bc > bt.MaxRetrievable()) // Issue 346
146
147 bt.TransferTo(str, bc);
148 return bc;
149}
150
151size_t DEREncodeTextString(BufferedTransformation &bt, const std::string &str, byte asnTag)
152{
153 bt.Put(asnTag);
154 size_t lengthBytes = DERLengthEncode(bt, str.size());
155 bt.Put((const byte *)str.data(), str.size());
156 return 1+lengthBytes+str.size();
157}
158
159size_t BERDecodeTextString(BufferedTransformation &bt, std::string &str, byte asnTag)
160{
161 byte b;
162 if (!bt.Get(b) || b != asnTag)
164
165 size_t bc;
166 if (!BERLengthDecode(bt, bc))
168 if (bc > bt.MaxRetrievable()) // Issue 346
170
171 SecByteBlock temp(bc);
172 if (bc != bt.Get(temp, bc))
174 if (bc)
175 str.assign((char *)temp.begin(), bc);
176 else
177 str.clear();
178 return bc;
179}
180
181/// ASN BitString
182size_t DEREncodeBitString(BufferedTransformation &bt, const byte *str, size_t strLen, unsigned int unusedBits)
183{
184 bt.Put(BIT_STRING);
185 size_t lengthBytes = DERLengthEncode(bt, strLen+1);
186 bt.Put((byte)unusedBits);
187 bt.Put(str, strLen);
188 return 2+lengthBytes+strLen;
189}
190
191size_t BERDecodeBitString(BufferedTransformation &bt, SecByteBlock &str, unsigned int &unusedBits)
192{
193 byte b;
194 if (!bt.Get(b) || b != BIT_STRING)
196
197 size_t bc;
198 if (!BERLengthDecode(bt, bc))
200 if (bc == 0)
202 if (bc > bt.MaxRetrievable()) // Issue 346
204
205 // X.690, 8.6.2.2: "The number [of unused bits] shall be in the range zero to seven"
206 byte unused;
207 if (!bt.Get(unused) || unused > 7)
209 unusedBits = unused;
210 str.resize(bc-1);
211 if ((bc-1) != bt.Get(str, bc-1))
213 return bc-1;
214}
215
216void DERReencode(BufferedTransformation &source, BufferedTransformation &dest)
217{
218 byte tag;
219 source.Peek(tag);
220 BERGeneralDecoder decoder(source, tag);
221 DERGeneralEncoder encoder(dest, tag);
222 if (decoder.IsDefiniteLength())
223 decoder.TransferTo(encoder, decoder.RemainingLength());
224 else
225 {
226 while (!decoder.EndReached())
227 DERReencode(decoder, encoder);
228 }
229 decoder.MessageEnd();
230 encoder.MessageEnd();
231}
232
233void OID::EncodeValue(BufferedTransformation &bt, word32 v)
234{
235 for (unsigned int i=RoundUpToMultipleOf(STDMAX(7U,BitPrecision(v)), 7U)-7; i != 0; i-=7)
236 bt.Put((byte)(0x80 | ((v >> i) & 0x7f)));
237 bt.Put((byte)(v & 0x7f));
238}
239
240size_t OID::DecodeValue(BufferedTransformation &bt, word32 &v)
241{
242 byte b;
243 size_t i=0;
244 v = 0;
245 while (true)
246 {
247 if (!bt.Get(b))
249 i++;
250 if (v >> (8*sizeof(v)-7)) // v about to overflow
252 v <<= 7;
253 v += b & 0x7f;
254 if (!(b & 0x80))
255 return i;
256 }
257}
258
260{
261 CRYPTOPP_ASSERT(m_values.size() >= 2);
262 ByteQueue temp;
263 temp.Put(byte(m_values[0] * 40 + m_values[1]));
264 for (size_t i=2; i<m_values.size(); i++)
265 EncodeValue(temp, m_values[i]);
266 bt.Put(OBJECT_IDENTIFIER);
267 DERLengthEncode(bt, temp.CurrentSize());
268 temp.TransferTo(bt);
269}
270
272{
273 byte b;
274 if (!bt.Get(b) || b != OBJECT_IDENTIFIER)
276
277 size_t length;
278 if (!BERLengthDecode(bt, length) || length < 1)
280
281 if (!bt.Get(b))
283
284 length--;
285 m_values.resize(2);
286 m_values[0] = b / 40;
287 m_values[1] = b % 40;
288
289 while (length > 0)
290 {
291 word32 v;
292 size_t valueLen = DecodeValue(bt, v);
293 if (valueLen > length)
295 m_values.push_back(v);
296 length -= valueLen;
297 }
298}
299
301{
302 OID oid(bt);
303 if (*this != oid)
305}
306
307inline BufferedTransformation & EncodedObjectFilter::CurrentTarget()
308{
309 if (m_flags & PUT_OBJECTS)
310 return *AttachedTransformation();
311 else
312 return TheBitBucket();
313}
314
315void EncodedObjectFilter::Put(const byte *inString, size_t length)
316{
317 if (m_nCurrentObject == m_nObjects)
318 {
319 AttachedTransformation()->Put(inString, length);
320 return;
321 }
322
323 LazyPutter lazyPutter(m_queue, inString, length);
324
325 while (m_queue.AnyRetrievable())
326 {
327 switch (m_state)
328 {
329 case IDENTIFIER:
330 if (!m_queue.Get(m_id))
331 return;
332 m_queue.TransferTo(CurrentTarget(), 1);
333 m_state = LENGTH;
334 // fall through
335 case LENGTH:
336 {
337 byte b;
338 if (m_level > 0 && m_id == 0 && m_queue.Peek(b) && b == 0)
339 {
340 m_queue.TransferTo(CurrentTarget(), 1);
341 m_level--;
342 m_state = IDENTIFIER;
343 break;
344 }
345 ByteQueue::Walker walker(m_queue);
346 bool definiteLength = false;
347 if (!BERLengthDecode(walker, m_lengthRemaining, definiteLength))
348 return;
349 m_queue.TransferTo(CurrentTarget(), walker.GetCurrentPosition());
350 if (!((m_id & CONSTRUCTED) || definiteLength))
352 if (!definiteLength)
353 {
354 if (!(m_id & CONSTRUCTED))
356 m_level++;
357 m_state = IDENTIFIER;
358 break;
359 }
360 m_state = BODY;
361 }
362 // fall through
363 case BODY:
364 m_lengthRemaining -= m_queue.TransferTo(CurrentTarget(), m_lengthRemaining);
365
366 if (m_lengthRemaining == 0)
367 m_state = IDENTIFIER;
368 // fall through
369 case TAIL:
370 case ALL_DONE:
371 default: ;;
372 }
373
374 if (m_state == IDENTIFIER && m_level == 0)
375 {
376 // just finished processing a level 0 object
377 ++m_nCurrentObject;
378
379 if (m_flags & PUT_MESSANGE_END_AFTER_EACH_OBJECT)
381
382 if (m_nCurrentObject == m_nObjects)
383 {
384 if (m_flags & PUT_MESSANGE_END_AFTER_ALL_OBJECTS)
386
387 if (m_flags & PUT_MESSANGE_SERIES_END_AFTER_ALL_OBJECTS)
389
391 return;
392 }
393 }
394 }
395}
396
397BERGeneralDecoder::BERGeneralDecoder(BufferedTransformation &inQueue, byte asnTag)
398 : m_inQueue(inQueue), m_finished(false)
399{
400 Init(asnTag);
401}
402
403BERGeneralDecoder::BERGeneralDecoder(BERGeneralDecoder &inQueue, byte asnTag)
404 : m_inQueue(inQueue), m_finished(false)
405{
406 Init(asnTag);
407}
408
409void BERGeneralDecoder::Init(byte asnTag)
410{
411 byte b;
412 if (!m_inQueue.Get(b) || b != asnTag)
414
415 if (!BERLengthDecode(m_inQueue, m_length, m_definiteLength))
417
418 if (!m_definiteLength && !(asnTag & CONSTRUCTED))
419 BERDecodeError(); // cannot be primitive and have indefinite length
420}
421
422BERGeneralDecoder::~BERGeneralDecoder()
423{
424 try // avoid throwing in destructor
425 {
426 if (!m_finished)
427 MessageEnd();
428 }
429 catch (const Exception&)
430 {
431 // CRYPTOPP_ASSERT(0);
432 }
433}
434
435bool BERGeneralDecoder::EndReached() const
436{
437 if (m_definiteLength)
438 return m_length == 0;
439 else
440 { // check end-of-content octets
441 word16 i;
442 return (m_inQueue.PeekWord16(i)==2 && i==0);
443 }
444}
445
446byte BERGeneralDecoder::PeekByte() const
447{
448 byte b;
449 if (!Peek(b))
451 return b;
452}
453
454void BERGeneralDecoder::CheckByte(byte check)
455{
456 byte b;
457 if (!Get(b) || b != check)
459}
460
461void BERGeneralDecoder::MessageEnd()
462{
463 m_finished = true;
464 if (m_definiteLength)
465 {
466 if (m_length != 0)
468 }
469 else
470 { // remove end-of-content octets
471 word16 i;
472 if (m_inQueue.GetWord16(i) != 2 || i != 0)
474 }
475}
476
477size_t BERGeneralDecoder::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking)
478{
479 if (m_definiteLength && transferBytes > m_length)
480 transferBytes = m_length;
481 size_t blockedBytes = m_inQueue.TransferTo2(target, transferBytes, channel, blocking);
482 ReduceLength(transferBytes);
483 return blockedBytes;
484}
485
486size_t BERGeneralDecoder::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const
487{
488 if (m_definiteLength)
489 end = STDMIN(m_length, end);
490 return m_inQueue.CopyRangeTo2(target, begin, end, channel, blocking);
491}
492
493lword BERGeneralDecoder::ReduceLength(lword delta)
494{
495 if (m_definiteLength)
496 {
497 if (m_length < delta)
499 m_length -= delta;
500 }
501 return delta;
502}
503
504DERGeneralEncoder::DERGeneralEncoder(BufferedTransformation &outQueue, byte asnTag)
505 : ByteQueue(), m_outQueue(outQueue), m_asnTag(asnTag), m_finished(false)
506{
507}
508
509DERGeneralEncoder::DERGeneralEncoder(DERGeneralEncoder &outQueue, byte asnTag)
510 : ByteQueue(), m_outQueue(outQueue), m_asnTag(asnTag), m_finished(false)
511{
512}
513
514DERGeneralEncoder::~DERGeneralEncoder()
515{
516 try // avoid throwing in constructor
517 {
518 if (!m_finished)
519 MessageEnd();
520 }
521 catch (const Exception&)
522 {
524 }
525}
526
527void DERGeneralEncoder::MessageEnd()
528{
529 m_finished = true;
530 lword length = CurrentSize();
531 m_outQueue.Put(m_asnTag);
532 DERLengthEncode(m_outQueue, length);
533 TransferTo(m_outQueue);
534}
535
536// *************************************************************
537
539{
540 BERSequenceDecoder subjectPublicKeyInfo(bt);
541 BERSequenceDecoder algorithm(subjectPublicKeyInfo);
543 bool parametersPresent = algorithm.EndReached() ? false : BERDecodeAlgorithmParameters(algorithm);
544 algorithm.MessageEnd();
545
546 BERGeneralDecoder subjectPublicKey(subjectPublicKeyInfo, BIT_STRING);
547 subjectPublicKey.CheckByte(0); // unused bits
548 BERDecodePublicKey(subjectPublicKey, parametersPresent, (size_t)subjectPublicKey.RemainingLength());
549 subjectPublicKey.MessageEnd();
550 subjectPublicKeyInfo.MessageEnd();
551}
552
554{
555 DERSequenceEncoder subjectPublicKeyInfo(bt);
556
557 DERSequenceEncoder algorithm(subjectPublicKeyInfo);
558 GetAlgorithmID().DEREncode(algorithm);
559 DEREncodeAlgorithmParameters(algorithm);
560 algorithm.MessageEnd();
561
562 DERGeneralEncoder subjectPublicKey(subjectPublicKeyInfo, BIT_STRING);
563 subjectPublicKey.Put(0); // unused bits
564 DEREncodePublicKey(subjectPublicKey);
565 subjectPublicKey.MessageEnd();
566
567 subjectPublicKeyInfo.MessageEnd();
568}
569
571{
572 BERSequenceDecoder privateKeyInfo(bt);
573 word32 version;
574 BERDecodeUnsigned<word32>(privateKeyInfo, version, INTEGER, 0, 0); // check version
575
576 BERSequenceDecoder algorithm(privateKeyInfo);
578 bool parametersPresent = algorithm.EndReached() ? false : BERDecodeAlgorithmParameters(algorithm);
579 algorithm.MessageEnd();
580
581 BERGeneralDecoder octetString(privateKeyInfo, OCTET_STRING);
582 BERDecodePrivateKey(octetString, parametersPresent, (size_t)privateKeyInfo.RemainingLength());
583 octetString.MessageEnd();
584
585 if (!privateKeyInfo.EndReached())
586 BERDecodeOptionalAttributes(privateKeyInfo);
587 privateKeyInfo.MessageEnd();
588}
589
591{
592 DERSequenceEncoder privateKeyInfo(bt);
593 DEREncodeUnsigned<word32>(privateKeyInfo, 0); // version
594
595 DERSequenceEncoder algorithm(privateKeyInfo);
596 GetAlgorithmID().DEREncode(algorithm);
597 DEREncodeAlgorithmParameters(algorithm);
598 algorithm.MessageEnd();
599
600 DERGeneralEncoder octetString(privateKeyInfo, OCTET_STRING);
601 DEREncodePrivateKey(octetString);
602 octetString.MessageEnd();
603
604 DEREncodeOptionalAttributes(privateKeyInfo);
605 privateKeyInfo.MessageEnd();
606}
607
609{
610 DERReencode(bt, m_optionalAttributes);
611}
612
614{
615 m_optionalAttributes.CopyTo(bt);
616}
617
618NAMESPACE_END
619
620#endif
Classes and functions for working with ANS.1 objects.
bool BERLengthDecode(BufferedTransformation &bt, size_t &length)
BER decode a length.
Definition: asn.cpp:76
size_t DERLengthEncode(BufferedTransformation &bt, lword length)
DER encode a length.
Definition: asn.cpp:17
void DERReencode(BufferedTransformation &bt, BufferedTransformation &dest)
BER decode and DER re-encode.
Definition: asn.cpp:216
void BERDecodeError()
Raises a BERDecodeErr.
Definition: asn.h:69
BER General Decoder.
Definition: asn.h:259
size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true)
Transfer bytes from this object to another BufferedTransformation.
Definition: asn.cpp:477
size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const
Copy bytes from this object to another BufferedTransformation.
Definition: asn.cpp:486
BER Sequence Decoder.
Definition: asn.h:310
Interface for buffered transformations.
Definition: cryptlib.h:1599
size_t GetWord16(word16 &value, ByteOrder order=BIG_ENDIAN_ORDER)
Retrieve a 16-bit word.
Definition: cryptlib.cpp:793
bool MessageEnd(int propagation=-1, bool blocking=true)
Signals the end of messages to the object.
Definition: cryptlib.h:1682
virtual size_t TransferTo2(BufferedTransformation &target, lword &byteCount, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true)=0
Transfer bytes from this object to another BufferedTransformation.
virtual lword MaxRetrievable() const
Provides the number of bytes ready for retrieval.
Definition: cryptlib.cpp:504
size_t PeekWord16(word16 &value, ByteOrder order=BIG_ENDIAN_ORDER) const
Peek a 16-bit word.
Definition: cryptlib.cpp:762
lword CopyTo(BufferedTransformation &target, lword copyMax=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL) const
copy copyMax bytes of the buffered output to target as input
Definition: cryptlib.h:1926
virtual size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const =0
Copy bytes from this object to another BufferedTransformation.
void TransferAllTo(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL)
Transfer all bytes from this object to another BufferedTransformation.
Definition: cryptlib.h:2005
virtual size_t Get(byte &outByte)
Retrieve a 8-bit byte.
Definition: cryptlib.cpp:527
virtual bool MessageSeriesEnd(int propagation=-1, bool blocking=true)
Marks the end of a series of messages, with signal propagation.
Definition: cryptlib.cpp:447
lword TransferTo(BufferedTransformation &target, lword transferMax=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL)
move transferMax bytes of the buffered output to target as input
Definition: cryptlib.h:1901
virtual size_t Peek(byte &outByte) const
Peek a 8-bit byte.
Definition: cryptlib.cpp:550
size_t Put(byte inByte, bool blocking=true)
Input a byte for processing.
Definition: cryptlib.h:1620
A ByteQueue iterator.
Definition: queue.h:77
Data structure used to store byte strings.
Definition: queue.h:19
size_t Get(byte &outByte)
Retrieve a 8-bit byte.
Definition: queue.cpp:301
size_t Peek(byte &outByte) const
Peek a 8-bit byte.
Definition: queue.cpp:325
bool AnyRetrievable() const
Determines whether bytes are ready for retrieval.
Definition: queue.h:35
DER General Encoder.
Definition: asn.h:292
DER Sequence Encoder.
Definition: asn.h:320
void Put(const byte *inString, size_t length)
Input a byte buffer for processing.
Definition: asn.cpp:315
Base class for all exceptions thrown by the library.
Definition: cryptlib.h:159
BufferedTransformation * AttachedTransformation()
Retrieve attached transformation.
Definition: filters.cpp:36
use this to make sure LazyPut is finalized in event of exception
Definition: queue.h:127
Object Identifier.
Definition: asn.h:167
void BERDecodeAndCheck(BufferedTransformation &bt) const
BER decode an OID.
Definition: asn.cpp:300
void DEREncode(BufferedTransformation &bt) const
DER encode this OID.
Definition: asn.cpp:259
void BERDecode(BufferedTransformation &bt)
BER decode an OID.
Definition: asn.cpp:271
virtual void DEREncodePrivateKey(BufferedTransformation &bt) const =0
encode privateKey part of privateKeyInfo, without the OCTET STRING header
virtual void BERDecodeOptionalAttributes(BufferedTransformation &bt)
decode optional attributes including context-specific tag
Definition: asn.cpp:608
void DEREncode(BufferedTransformation &bt) const
Encode this object into a BufferedTransformation.
Definition: asn.cpp:590
virtual OID GetAlgorithmID() const =0
Retrieves the OID of the algorithm.
void BERDecode(BufferedTransformation &bt)
Decode this object from a BufferedTransformation.
Definition: asn.cpp:570
virtual void DEREncodeOptionalAttributes(BufferedTransformation &bt) const
encode optional attributes including context-specific tag
Definition: asn.cpp:613
virtual void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size)=0
decode privateKey part of privateKeyInfo, without the OCTET STRING header
iterator begin()
Provides an iterator pointing to the first element in the memory block.
Definition: secblock.h:772
void New(size_type newSize)
Change size without preserving contents.
Definition: secblock.h:965
size_type size() const
Provides the count of elements in the SecBlock.
Definition: secblock.h:797
void resize(size_type newSize)
Change size and preserve contents.
Definition: secblock.h:1031
SecBlock<byte> typedef.
Definition: secblock.h:1058
virtual OID GetAlgorithmID() const =0
Retrieves the OID of the algorithm.
void DEREncode(BufferedTransformation &bt) const
Encode this object into a BufferedTransformation.
Definition: asn.cpp:553
virtual void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size)=0
decode subjectPublicKey part of subjectPublicKeyInfo, without the BIT STRING header
void BERDecode(BufferedTransformation &bt)
Decode this object from a BufferedTransformation.
Definition: asn.cpp:538
virtual void DEREncodePublicKey(BufferedTransformation &bt) const =0
encode subjectPublicKey part of subjectPublicKeyInfo, without the BIT STRING header
Library configuration file.
const T & STDMAX(const T &a, const T &b)
Replacement function for std::max.
Definition: misc.h:578
unsigned int BitPrecision(const T &value)
Returns the number of bits required for a value.
Definition: misc.h:754
unsigned int BytePrecision(const T &value)
Returns the number of 8-bit bytes or octets required for a value.
Definition: misc.h:731
T1 RoundUpToMultipleOf(const T1 &n, const T2 &m)
Rounds a value up to a multiple of a second value.
Definition: misc.h:1085
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition: misc.h:567
bool SafeConvert(T1 from, T2 &to)
Tests whether a conversion from -> to is safe to perform.
Definition: misc.h:622
Crypto++ library namespace.
Precompiled header file.
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:69