FIPS 186-2 fixes
[asdcplib.git] / src / KM_util.h
1 /*
2 Copyright (c) 2005-2009, John Hurst
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 1. Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11    notice, this list of conditions and the following disclaimer in the
12    documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14    derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27   /*! \file    KM_util.h
28     \version $Id$
29     \brief   Utility functions
30   */
31
32 #ifndef _KM_UTIL_H_
33 #define _KM_UTIL_H_
34
35 #include <KM_memio.h>
36 #include <KM_error.h>
37 #include <string.h>
38 #include <string>
39 #include <list>
40
41 namespace Kumu
42 {
43   // The version number declaration and explanation are in ../configure.ac
44   const char* Version();
45
46   // a class that represents the string form of a value
47   template <class T, int SIZE = 16>
48     class IntPrinter : public std::string
49   {
50     KM_NO_COPY_CONSTRUCT(IntPrinter);
51     IntPrinter();
52
53     protected:
54     const char* m_format;
55     char m_strbuf[SIZE];
56     
57     public:
58     IntPrinter(const char* format, T value) {
59       assert(format);
60       m_format = format;
61       snprintf(m_strbuf, SIZE, m_format, value);
62     }
63
64     inline operator const char*() { return m_strbuf; }
65     inline const char* c_str() { return m_strbuf; }
66     inline const char* set_value(T value) {
67       snprintf(m_strbuf, SIZE, m_format, value);
68       return m_strbuf;
69     }
70   };
71
72   struct i8Printer : public IntPrinter<i8_t> {
73     i8Printer(i8_t value) : IntPrinter<i8_t>("%hd", value) {}
74   };
75
76   struct ui8Printer : public IntPrinter<ui8_t> {
77     ui8Printer(ui8_t value) : IntPrinter<ui8_t>("%hu", value) {}
78   };
79
80   struct i16Printer : public IntPrinter<i16_t> {
81     i16Printer(i16_t value) : IntPrinter<i16_t>("%hd", value) {}
82   };
83
84   struct ui16Printer : public IntPrinter<ui16_t> {
85     ui16Printer(ui16_t value) : IntPrinter<ui16_t>("%hu", value) {}
86   };
87
88   struct i32Printer : public IntPrinter<i32_t> {
89     i32Printer(i32_t value) : IntPrinter<i32_t>("%d", value) {}
90   };
91
92   struct ui32Printer : public IntPrinter<ui32_t> {
93     ui32Printer(ui32_t value) : IntPrinter<ui32_t>("%u", value) {}
94   };
95
96 #ifdef KM_WIN32
97   struct i64Printer : public IntPrinter<i64_t, 32> {
98     i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%I64d", value) {}
99   };
100
101   struct ui64Printer : public IntPrinter<ui64_t, 32> {
102     ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%I64u", value) {}
103   };
104 #else
105   struct i64Printer : public IntPrinter<i64_t, 32> {
106     i64Printer(i64_t value) : IntPrinter<i64_t, 32>("%qd", value) {}
107   };
108
109   struct ui64Printer : public IntPrinter<ui64_t, 32> {
110     ui64Printer(ui64_t value) : IntPrinter<ui64_t, 32>("%qu", value) {}
111   };
112 #endif
113
114   // Convert NULL-terminated UTF-8 hexadecimal string to binary, returns 0 if
115   // the binary buffer was large enough to hold the result. The output parameter
116   // 'char_count' will contain the length of the converted string. If the output
117   // buffer is too small or any of the pointer arguments are NULL, the subroutine
118   // will return -1 and set 'char_count' to the required buffer size. No data will
119   // be written to 'buf' if the subroutine fails.
120   i32_t       hex2bin(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count);
121
122   // Convert a binary string to NULL-terminated UTF-8 hexadecimal, returns the buffer
123   // if the output buffer was large enough to hold the result. If the output buffer
124   // is too small or any of the pointer arguments are NULL, the subroutine will
125   // return 0.
126   //
127   const char* bin2hex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
128
129   const char* bin2UUIDhex(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
130
131   // same as above for base64 text
132   i32_t       base64decode(const char* str, byte_t* buf, ui32_t buf_len, ui32_t* char_count);
133   const char* base64encode(const byte_t* bin_buf, ui32_t bin_len, char* str_buf, ui32_t str_len);
134
135   // returns the length of a Base64 encoding of a buffer of the given length
136   inline ui32_t base64_encode_length(ui32_t length) {
137     while ( ( length % 3 ) != 0 )
138       length++;
139
140     return ( length / 3 ) * 4;
141   }
142
143   // print buffer contents to a stream as hexadecimal values in numbered
144   // rows of 16-bytes each.
145   //
146   void hexdump(const byte_t* buf, ui32_t dump_len, FILE* stream = 0);
147
148   // Return the length in bytes of a BER encoded value
149   inline ui32_t BER_length(const byte_t* buf)
150     {
151       if ( buf == 0 || (*buf & 0xf0) != 0x80 )
152         return 0;
153
154       return (*buf & 0x0f) + 1;
155     }
156
157   // read a BER value
158   bool read_BER(const byte_t* buf, ui64_t* val);
159
160   // decode a ber value and compare it to a test value
161   bool read_test_BER(byte_t **buf, ui64_t test_value);
162
163   // create BER encoding of integer value
164   bool write_BER(byte_t* buf, ui64_t val, ui32_t ber_len = 0);
165
166   //----------------------------------------------------------------
167   //
168
169   // an abstract base class that objects implement to serialize state
170   // to and from a binary stream.
171   class IArchive
172     {
173     public:
174       virtual ~IArchive(){}
175       virtual bool   HasValue() const = 0;
176       virtual ui32_t ArchiveLength() const = 0;
177       virtual bool   Archive(MemIOWriter* Writer) const = 0;
178       virtual bool   Unarchive(MemIOReader* Reader) = 0;
179     };
180
181   //
182   template <class T>
183   class ArchivableList : public std::list<T>, public IArchive
184     {
185     public:
186       ArchivableList() {}
187       virtual ~ArchivableList() {}
188
189       bool HasValue() const { return ! this->empty(); }
190
191       ui32_t ArchiveLength() const
192       {
193         ui32_t arch_size = sizeof(ui32_t);
194
195         typename ArchivableList<T>::const_iterator i = this->begin();
196         for ( ; i != this->end(); i++ )
197           arch_size += i->ArchiveLength();
198
199         return arch_size;
200       }
201
202       bool Unarchive(Kumu::MemIOReader* Reader)
203         {
204           if ( Reader == 0 ) return false;
205           ui32_t read_size = 0;
206           if ( ! Reader->ReadUi32BE(&read_size) ) return false;
207           for ( ui32_t i = 0; i < read_size; i++ )
208             {
209               T TmpTP;
210               if ( ! TmpTP.Unarchive(Reader) ) return false;
211               this->push_back(TmpTP);
212             }
213
214           return true;
215         }
216
217       bool Archive(Kumu::MemIOWriter* Writer) const
218         {
219           if ( Writer == 0 ) return false;
220           if ( ! Writer->WriteUi32BE(this->size()) ) return false;
221           typename ArchivableList<T>::const_iterator i = this->begin();
222           for ( ; i != this->end(); i++ )
223             if ( ! i->Archive(Writer) ) return false;
224
225           return true;
226         }
227     };
228
229   //
230   // the base of all identifier classes, Identifier is not usually used directly
231   // see UUID and SymmetricKey below for more detail.
232   //
233   template <ui32_t SIZE>
234     class Identifier : public IArchive
235     {
236     protected:
237       bool   m_HasValue;
238       byte_t m_Value[SIZE];
239
240     public:
241       Identifier() : m_HasValue(false) { memset(m_Value, 0, SIZE); }
242       Identifier(const byte_t* value) : m_HasValue(true) { memcpy(m_Value, value, SIZE); }
243       Identifier(const Identifier& rhs) : IArchive() {
244         m_HasValue = rhs.m_HasValue;
245         memcpy(m_Value, rhs.m_Value, SIZE);
246       }
247
248       virtual ~Identifier() {}
249
250       const Identifier& operator=(const Identifier& rhs) {
251         m_HasValue = rhs.m_HasValue;
252         memcpy(m_Value, rhs.m_Value, SIZE);
253         return *this;
254       }
255
256       inline void Set(const byte_t* value) { m_HasValue = true; memcpy(m_Value, value, SIZE); }
257       inline void Reset() { m_HasValue = false; memset(m_Value, 0, SIZE); }
258       inline const byte_t* Value() const { return m_Value; }
259       inline ui32_t Size() const { return SIZE; }
260
261       inline bool operator<(const Identifier& rhs) const {
262         ui32_t test_size = xmin(rhs.Size(), SIZE);
263
264         for ( ui32_t i = 0; i < test_size; i++ )
265           {
266             if ( m_Value[i] != rhs.m_Value[i] )
267               return m_Value[i] < rhs.m_Value[i];
268           }
269         
270         return false;
271       }
272
273       inline bool operator==(const Identifier& rhs) const {
274         if ( rhs.Size() != SIZE ) return false;
275         return ( memcmp(m_Value, rhs.m_Value, SIZE) == 0 );
276       }
277
278       inline bool operator!=(const Identifier& rhs) const {
279         if ( rhs.Size() != SIZE ) return true;
280         return ( memcmp(m_Value, rhs.m_Value, SIZE) != 0 );
281       }
282
283       inline bool DecodeHex(const char* str) {
284         ui32_t char_count;
285         m_HasValue = ( hex2bin(str, m_Value, SIZE, &char_count) == 0 );
286         if ( m_HasValue && char_count != SIZE )
287           m_HasValue = false;
288         return m_HasValue;
289       }
290
291       inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
292         return bin2hex(m_Value, SIZE, buf, buf_len);
293       }
294
295       inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
296         return EncodeHex(str_buf, buf_len);
297       }
298
299       inline bool DecodeBase64(const char* str) {
300         ui32_t char_count;
301         m_HasValue = ( base64decode(str, m_Value, SIZE, &char_count) == 0 );
302         if ( m_HasValue && char_count != SIZE )
303           m_HasValue = false;
304         return m_HasValue;
305       }
306
307       inline const char* EncodeBase64(char* buf, ui32_t buf_len) const {
308         return base64encode(m_Value, SIZE, buf, buf_len);
309       }
310
311       inline bool HasValue() const { return m_HasValue; }
312
313       inline ui32_t ArchiveLength() const { return SIZE; }
314
315       inline bool Unarchive(Kumu::MemIOReader* Reader) {
316         m_HasValue = Reader->ReadRaw(m_Value, SIZE);
317         return m_HasValue;
318       }
319
320       inline bool Archive(Kumu::MemIOWriter* Writer) const {
321         return Writer->WriteRaw(m_Value, SIZE);
322       }
323     };
324
325
326   // UUID
327   //
328   const ui32_t UUID_Length = 16;
329   class UUID : public Identifier<UUID_Length>
330     {
331     public:
332       UUID() {}
333       UUID(const byte_t* value) : Identifier<UUID_Length>(value) {}
334       UUID(const UUID& rhs) : Identifier<UUID_Length>(rhs) {}
335       virtual ~UUID() {}
336
337       inline const char* EncodeString(char* buf, ui32_t buf_len) const {
338         return bin2UUIDhex(m_Value, Size(), buf, buf_len);
339       }
340
341       inline const char* EncodeHex(char* buf, ui32_t buf_len) const {
342         return bin2UUIDhex(m_Value, Size(), buf, buf_len);
343       }
344     };
345   
346   void GenRandomUUID(byte_t* buf); // buf must be UUID_Length or longer
347   void GenRandomValue(UUID&);
348   
349   typedef ArchivableList<UUID> UUIDList;
350
351   // a self-wiping key container
352   //
353   const ui32_t SymmetricKey_Length = 16;
354   const byte_t NilKey[SymmetricKey_Length] = {
355     0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce,
356     0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce, 0xfa, 0xce
357   };
358
359   class SymmetricKey : public Identifier<SymmetricKey_Length>
360     {
361     public:
362       SymmetricKey() {}
363       SymmetricKey(const byte_t* value) : Identifier<SymmetricKey_Length>(value) {}
364       SymmetricKey(const UUID& rhs) : Identifier<SymmetricKey_Length>(rhs) {}
365       virtual ~SymmetricKey() { memcpy(m_Value, NilKey, 16); m_HasValue = false; }
366     };
367
368   void GenRandomValue(SymmetricKey&);
369
370   //
371   // 2004-05-01T13:20:00+00:00
372   const ui32_t DateTimeLen = 25; //  the number of chars in the xs:dateTime format (sans milliseconds)
373
374   // UTC time+date representation
375   class Timestamp : public IArchive
376     {
377     public:
378       ui16_t Year;
379       ui8_t  Month;
380       ui8_t  Day;
381       ui8_t  Hour;
382       ui8_t  Minute;
383       ui8_t  Second;
384
385       Timestamp();
386       Timestamp(const Timestamp& rhs);
387       Timestamp(const char* datestr);
388       virtual ~Timestamp();
389
390       const Timestamp& operator=(const Timestamp& rhs);
391       bool operator<(const Timestamp& rhs) const;
392       bool operator>(const Timestamp& rhs) const;
393       bool operator==(const Timestamp& rhs) const;
394       bool operator!=(const Timestamp& rhs) const;
395
396       // Write the timestamp value to the given buffer in the form 2004-05-01T13:20:00+00:00
397       // returns 0 if the buffer is smaller than DateTimeLen
398       const char* EncodeString(char* str_buf, ui32_t buf_len) const;
399       const char* EncodeStringWithOffset(char* str_buf, ui32_t buf_len,
400                                          i32_t offset_minutes = 0) const;
401
402       // decode and set value from string formatted by EncodeString
403       bool        DecodeString(const char* datestr);
404
405       // Add the given number of days, hours, minutes, or seconds to the timestamp value.
406       // Values less than zero will cause the timestamp to decrease
407       void AddDays(i32_t);
408       void AddHours(i32_t);
409       void AddMinutes(i32_t);
410       void AddSeconds(i32_t);
411
412       // Read and write the timestamp value as a byte string having
413       // the following format:
414       // | 16 bits int, big-endian |    8 bits   |   8 bits  |   8 bits   |    8 bits    |    8 bits    |
415       // |        Year A.D         | Month(1-12) | Day(1-31) | Hour(0-23) | Minute(0-59) | Second(0-59) |
416       //
417       virtual bool   HasValue() const;
418       virtual ui32_t ArchiveLength() const { return 8L; }
419       virtual bool   Archive(MemIOWriter* Writer) const;
420       virtual bool   Unarchive(MemIOReader* Reader);
421
422       // Get the number of seconds since the Unix epoch (1970-01-01T00:00:00+00:00)
423       long GetSecondsSinceEpoch(void) const;
424     };
425
426   //
427   class ByteString : public IArchive
428     {
429       KM_NO_COPY_CONSTRUCT(ByteString);
430         
431     protected:
432       byte_t* m_Data;          // pointer to memory area containing frame data
433       ui32_t  m_Capacity;      // size of memory area pointed to by m_Data
434       ui32_t  m_Length;        // length of byte string in memory area pointed to by m_Data
435         
436     public:
437       ByteString();
438       ByteString(ui32_t cap);
439       virtual ~ByteString();
440
441       // Sets or resets the size of the internally allocated buffer.
442       Result_t Capacity(ui32_t cap);
443
444       Result_t Append(const ByteString&);
445       Result_t Append(const byte_t* buf, ui32_t buf_len);
446         
447       // returns the size of the buffer
448       inline ui32_t  Capacity() const { return m_Capacity; }
449
450       // returns a const pointer to the essence data
451       inline const byte_t* RoData() const { assert(m_Data); return m_Data; }
452         
453       // returns a non-const pointer to the essence data
454       inline byte_t* Data() { assert(m_Data); return m_Data; }
455         
456       // set the length of the buffer's contents
457       inline ui32_t  Length(ui32_t l) { return m_Length = l; }
458         
459       // returns the length of the buffer's contents
460       inline ui32_t  Length() const { return m_Length; }
461
462       // copy the given data into the ByteString, set Length value.
463       // Returns error if the ByteString is too small.
464       Result_t Set(const byte_t* buf, ui32_t buf_len);
465       Result_t Set(const ByteString& Buf);
466
467       inline virtual bool HasValue() const { return m_Length > 0; }
468
469       inline virtual ui32_t ArchiveLength() const { return m_Length; }
470
471       inline virtual bool Archive(MemIOWriter* Writer) const {
472         assert(Writer);
473         if ( ! Writer->WriteUi32BE(m_Length) ) return false;
474         if ( ! Writer->WriteRaw(m_Data, m_Length) ) return false;
475         return true;
476       }
477
478       inline virtual bool Unarchive(MemIOReader* Reader) {
479         assert(Reader);
480         ui32_t tmp_len;
481         if ( ! Reader->ReadUi32BE(&tmp_len) ) return false;
482         if ( KM_FAILURE(Capacity(tmp_len)) ) return false;
483         if ( ! Reader->ReadRaw(m_Data, tmp_len) ) return false;
484         m_Length = tmp_len;
485         return true;
486       }
487     };
488
489 } // namespace Kumu
490
491
492 #endif // _KM_UTIL_H_
493
494 //
495 // end KM_util.h
496 //