Win32 portability fixes
[asdcplib.git] / src / AS_DCP_AES.cpp
1 /*
2 Copyright (c) 2004-2007, 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    AS_DCP_AES.h
28     \version $Id$       
29     \brief   AS-DCP library, AES wrapper
30 */
31
32
33 #include <assert.h>
34 #include <AS_DCP.h>
35 #include <KM_log.h>
36 #include <KM_prng.h>
37 using Kumu::DefaultLogSink;
38
39 using namespace ASDCP;
40 const int KEY_SIZE_BITS = 128;
41
42 #include <openssl/aes.h>
43 #include <openssl/sha.h>
44 #include <openssl/bn.h>
45 #include <openssl/err.h>
46
47
48 void
49 print_ssl_error()
50 {
51   char err_buf[256];
52   unsigned long errval = ERR_get_error();
53   DefaultLogSink().Error("OpenSSL: %s\n", ERR_error_string(errval, err_buf));
54 }
55
56 //------------------------------------------------------------------------------------------
57
58 class ASDCP::AESEncContext::h__AESContext : public AES_KEY
59 {
60 public:
61   byte_t m_IVec[CBC_BLOCK_SIZE];
62 };
63
64
65 ASDCP::AESEncContext::AESEncContext()  {}
66 ASDCP::AESEncContext::~AESEncContext() {}
67
68 // Initializes Rijndael CBC encryption context.
69 // Returns error if the key argument is NULL.
70 ASDCP::Result_t
71 ASDCP::AESEncContext::InitKey(const byte_t* key)
72 {
73   KM_TEST_NULL_L(key);
74
75   if ( m_Context )
76     return RESULT_INIT;
77
78   m_Context = new h__AESContext;
79
80   if ( AES_set_encrypt_key(key, KEY_SIZE_BITS, m_Context) )
81     {
82       print_ssl_error();
83       return RESULT_CRYPT_INIT;
84     }
85
86   return RESULT_OK;
87 }
88
89
90 // Set the value of the 16 byte CBC Initialization Vector. This operation may be performed
91 // any number of times for a given key.
92 // Returns error if the i_vec argument is NULL.
93 ASDCP::Result_t
94 ASDCP::AESEncContext::SetIVec(const byte_t* i_vec)
95 {
96   KM_TEST_NULL_L(i_vec);
97
98   if ( ! m_Context )
99     return  RESULT_INIT;
100
101   memcpy(m_Context->m_IVec, i_vec, CBC_BLOCK_SIZE);
102   return RESULT_OK;
103 }
104
105
106 // Retrieve the value of the  16 byte CBC Initialization Vector.
107 // Returns error if the i_vec argument is NULL.
108 ASDCP::Result_t
109 ASDCP::AESEncContext::GetIVec(byte_t* i_vec) const
110 {
111   KM_TEST_NULL_L(i_vec);
112
113   if ( ! m_Context )
114     return  RESULT_INIT;
115
116   memcpy(i_vec, m_Context->m_IVec, CBC_BLOCK_SIZE);
117   return RESULT_OK;
118 }
119
120
121 // Encrypt a 16 byte block of data.
122 // Returns error if either argument is NULL.
123 ASDCP::Result_t
124 ASDCP::AESEncContext::EncryptBlock(const byte_t* pt_buf, byte_t* ct_buf, ui32_t block_size)
125 {
126   KM_TEST_NULL_L(pt_buf);
127   KM_TEST_NULL_L(ct_buf);
128   assert(block_size > 0);
129   assert( block_size % CBC_BLOCK_SIZE == 0 );
130
131   if ( m_Context.empty() )
132     return  RESULT_INIT;
133
134   h__AESContext* Ctx = m_Context;
135   byte_t tmp_buf[CBC_BLOCK_SIZE];
136   const byte_t* in_p = pt_buf;
137   byte_t* out_p = ct_buf;
138
139   while ( block_size )
140     {
141       // xor with the previous block
142       for ( ui32_t i = 0; i < CBC_BLOCK_SIZE; i++ )
143         tmp_buf[i] = in_p[i] ^ Ctx->m_IVec[i]; 
144           
145       AES_encrypt(tmp_buf, Ctx->m_IVec, Ctx);
146       memcpy(out_p, Ctx->m_IVec, CBC_BLOCK_SIZE);
147
148       in_p += CBC_BLOCK_SIZE;
149       out_p += CBC_BLOCK_SIZE;
150       block_size -= CBC_BLOCK_SIZE;
151     }
152
153   return RESULT_OK;
154 }
155
156
157 //------------------------------------------------------------------------------------------
158
159 class ASDCP::AESDecContext::h__AESContext : public AES_KEY
160 {
161 public:
162   byte_t m_IVec[CBC_BLOCK_SIZE];
163 };
164
165 ASDCP::AESDecContext::AESDecContext()  {}
166 ASDCP::AESDecContext::~AESDecContext() {}
167
168
169 // Initializes Rijndael CBC decryption context.
170 // Returns error if the key argument is NULL.
171 ASDCP::Result_t
172 ASDCP::AESDecContext::InitKey(const byte_t* key)
173 {
174   KM_TEST_NULL_L(key);
175
176   if ( m_Context )
177     return  RESULT_INIT;
178
179   m_Context = new h__AESContext;
180
181   if ( AES_set_decrypt_key(key, KEY_SIZE_BITS, m_Context) )
182     {
183       print_ssl_error();
184       return RESULT_CRYPT_INIT;
185     }
186
187   return RESULT_OK;
188 }
189
190 // Initializes 16 byte CBC Initialization Vector. This operation may be performed
191 // any number of times for a given key.
192 // Returns error if the i_vec argument is NULL.
193 ASDCP::Result_t
194 ASDCP::AESDecContext::SetIVec(const byte_t* i_vec)
195 {
196   KM_TEST_NULL_L(i_vec);
197
198   if ( ! m_Context )
199     return  RESULT_INIT;
200
201   memcpy(m_Context->m_IVec, i_vec, CBC_BLOCK_SIZE);
202   return RESULT_OK;
203 }
204
205 // Decrypt a 16 byte block of data.
206 // Returns error if either argument is NULL.
207 ASDCP::Result_t
208 ASDCP::AESDecContext::DecryptBlock(const byte_t* ct_buf, byte_t* pt_buf, ui32_t block_size)
209 {
210   KM_TEST_NULL_L(ct_buf);
211   KM_TEST_NULL_L(pt_buf);
212   assert(block_size > 0);
213   assert( block_size % CBC_BLOCK_SIZE == 0 );
214
215   if ( m_Context.empty() )
216     return  RESULT_INIT;
217
218   register h__AESContext* Ctx = m_Context;
219
220   const byte_t* in_p = ct_buf;
221   byte_t* out_p = pt_buf;
222
223   while ( block_size )
224     {
225       AES_decrypt(in_p, out_p, Ctx);  
226
227       for ( ui32_t i = 0; i < CBC_BLOCK_SIZE; i++ )
228         out_p[i] ^= Ctx->m_IVec[i];
229
230       memcpy(Ctx->m_IVec, in_p, CBC_BLOCK_SIZE);
231
232       in_p += CBC_BLOCK_SIZE;
233       out_p += CBC_BLOCK_SIZE;
234       block_size -= CBC_BLOCK_SIZE;
235     }
236
237   return RESULT_OK;
238 }
239
240 //------------------------------------------------------------------------------------------
241
242 static const ui32_t B_len = 64; // rfc 2104, Sec. 2
243
244 static byte_t ipad[KeyLen] = { 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
245                                0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 };
246
247 static byte_t opad[KeyLen] = { 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
248                                0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c };
249
250 class HMACContext::h__HMACContext
251 {
252   SHA_CTX m_SHA;
253   byte_t  m_key[KeyLen];
254   ASDCP_NO_COPY_CONSTRUCT(h__HMACContext);
255
256 public:
257   byte_t     m_SHAValue[HMAC_SIZE];
258   LabelSet_t m_SetType;
259   bool       m_Final;
260
261   h__HMACContext() : m_Final(false) {}
262   ~h__HMACContext() {}
263
264   // SMPTE 429.6 MIC key generation
265   void SetKey(const byte_t* key)
266   {
267     byte_t rng_buf[SHA_DIGEST_LENGTH*2];
268     Kumu::Gen_FIPS_186_Value(key, KeyLen, rng_buf, SHA_DIGEST_LENGTH*2);
269     memcpy(m_key, rng_buf+SHA_DIGEST_LENGTH, KeyLen);
270     m_SetType = LS_MXF_SMPTE;
271     Reset();
272   }
273
274   // MXF Interop MIC key generation
275   void SetInteropKey(const byte_t* key)
276   {
277     static byte_t key_nonce[KeyLen] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 
278                                         0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
279     byte_t sha_buf[SHA_DIGEST_LENGTH];
280
281     // 7.10: MICKey = trunc( SHA1 ( key, key_nonce ) )
282     SHA_CTX SHA;
283     SHA1_Init(&SHA);
284     SHA1_Update(&SHA, key, KeyLen);
285     SHA1_Update(&SHA, key_nonce, KeyLen);
286     SHA1_Final(sha_buf, &SHA);
287     memcpy(m_key, sha_buf, KeyLen);
288     m_SetType = LS_MXF_INTEROP;
289     Reset();
290   }
291
292   //
293   void
294   Reset()
295   {
296     byte_t xor_buf[B_len];
297     memset(m_SHAValue, 0, HMAC_SIZE);
298     m_Final = false;
299     SHA1_Init(&m_SHA);
300
301     // H(K XOR opad, H(K XOR ipad, text))
302     //                 ^^^^^^^^^^
303     ui32_t i = 0;
304
305     for ( ; i < KeyLen; i++ )
306       xor_buf[i] = m_key[i] ^ ipad[i];
307
308     if ( m_SetType == LS_MXF_SMPTE )
309       {
310         for ( ; i < B_len; i++ )
311           xor_buf[i] = 0 ^ ipad[0];
312
313         SHA1_Update(&m_SHA, xor_buf, B_len);
314       }
315     else
316       {
317         SHA1_Update(&m_SHA, xor_buf, KeyLen);
318       }
319   }
320
321   //
322   void
323   Update(const byte_t* buf, ui32_t buf_len)
324   {
325     // H(K XOR opad, H(K XOR ipad, text))
326     //                             ^^^^
327     SHA1_Update(&m_SHA, buf, buf_len);
328   }
329
330   //
331   void
332   Finalize()
333   {
334     // H(K XOR opad, H(K XOR ipad, text))
335     // ^^^^^^^^^^^^^^^
336     SHA1_Final(m_SHAValue, &m_SHA);
337
338     SHA_CTX SHA;
339     SHA1_Init(&SHA);
340
341     byte_t xor_buf[KeyLen];
342     ui32_t i = 0;
343
344     for ( ; i < KeyLen; i++ )
345       xor_buf[i] = m_key[i] ^ opad[i];
346     
347     if ( m_SetType == LS_MXF_SMPTE )
348       {
349         for ( ; i < B_len; i++ )
350           xor_buf[i] = 0 ^ opad[0];
351         
352         SHA1_Update(&m_SHA, xor_buf, B_len);
353       }
354     else
355       {
356         SHA1_Update(&m_SHA, xor_buf, KeyLen);
357       }
358
359     SHA1_Update(&SHA, xor_buf, KeyLen);
360     SHA1_Update(&SHA, m_SHAValue, HMAC_SIZE);
361
362     SHA1_Final(m_SHAValue, &SHA);
363     m_Final = true;
364   }
365 };
366
367
368 HMACContext::HMACContext()
369 {
370 }
371
372 HMACContext::~HMACContext()
373 {
374 }
375
376
377 //
378 Result_t
379 HMACContext::InitKey(const byte_t* key, LabelSet_t SetType)
380 {
381   KM_TEST_NULL_L(key);
382
383   m_Context = new h__HMACContext;
384
385   switch ( SetType )
386     {
387     case LS_MXF_INTEROP: m_Context->SetInteropKey(key); break;
388     case LS_MXF_SMPTE:   m_Context->SetKey(key); break;
389     default:
390       m_Context = 0;
391       return RESULT_INIT;
392     }
393
394   return RESULT_OK;
395 }
396
397
398 //
399 void
400 HMACContext::Reset()
401 {
402   if ( ! m_Context.empty() )
403     m_Context->Reset();
404 }
405
406
407 //
408 Result_t
409 HMACContext::Update(const byte_t* buf, ui32_t buf_len)
410 {
411   KM_TEST_NULL_L(buf);
412
413   if ( m_Context.empty() || m_Context->m_Final )
414     return RESULT_INIT;
415
416   m_Context->Update(buf, buf_len);
417   return RESULT_OK;
418 }
419
420
421 //
422 Result_t
423 HMACContext::Finalize()
424 {
425   if ( m_Context.empty() || m_Context->m_Final )
426     return RESULT_INIT;
427   
428   m_Context->Finalize();
429   return RESULT_OK;
430 }
431
432
433 //
434 Result_t
435 HMACContext::GetHMACValue(byte_t* buf) const
436 {
437   KM_TEST_NULL_L(buf);
438
439   if ( m_Context.empty() || ! m_Context->m_Final )
440     return RESULT_INIT;
441
442   memcpy(buf, m_Context->m_SHAValue, HMAC_SIZE);
443   return RESULT_OK;
444 }
445
446
447 //
448 Result_t
449 HMACContext::TestHMACValue(const byte_t* buf) const
450 {
451   KM_TEST_NULL_L(buf);
452
453   if ( m_Context.empty() || ! m_Context->m_Final )
454     return RESULT_INIT;
455   
456   return ( memcmp(buf, m_Context->m_SHAValue, HMAC_SIZE) == 0 ) ? RESULT_OK : RESULT_HMACFAIL;
457 }
458
459
460
461 //
462 // end AS_DCP_AES.cpp
463 //