Add PCMParserList.h to list of extra exported headers.
[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[B_len] = {
245   0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
246   0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
247   0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
248   0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
249 };
250
251 static byte_t opad[B_len] = {
252   0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
253   0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
254   0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
255   0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c
256 };
257
258 class HMACContext::h__HMACContext
259 {
260   SHA_CTX m_SHA;
261   byte_t  m_key[KeyLen];
262   ASDCP_NO_COPY_CONSTRUCT(h__HMACContext);
263
264 public:
265   byte_t     m_SHAValue[HMAC_SIZE];
266   bool       m_Final;
267
268   h__HMACContext() : m_Final(false) {}
269   ~h__HMACContext() {}
270
271   // SMPTE 429.6 MIC key generation
272   void SetKey(const byte_t* key)
273   {
274     byte_t rng_buf[SHA_DIGEST_LENGTH*2];
275     Kumu::Gen_FIPS_186_Value(key, KeyLen, rng_buf, SHA_DIGEST_LENGTH*2);
276     memcpy(m_key, rng_buf+SHA_DIGEST_LENGTH, KeyLen);
277     Reset();
278   }
279
280   // MXF Interop MIC key generation
281   void SetInteropKey(const byte_t* key)
282   {
283     static byte_t key_nonce[KeyLen] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 
284                                         0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
285     byte_t sha_buf[SHA_DIGEST_LENGTH];
286
287     // 7.10: MICKey = trunc( SHA1 ( key, key_nonce ) )
288     SHA_CTX SHA;
289     SHA1_Init(&SHA);
290     SHA1_Update(&SHA, key, KeyLen);
291     SHA1_Update(&SHA, key_nonce, KeyLen);
292     SHA1_Final(sha_buf, &SHA);
293     memcpy(m_key, sha_buf, KeyLen);
294     Reset();
295   }
296
297   //
298   void
299   Reset()
300   {
301     byte_t xor_buf[B_len];
302     memset(xor_buf, 0, B_len);
303     memcpy(xor_buf, m_key, KeyLen);
304
305     memset(m_SHAValue, 0, HMAC_SIZE);
306     m_Final = false;
307     SHA1_Init(&m_SHA);
308
309     // H(K XOR opad, H(K XOR ipad, text))
310     //                 ^^^^^^^^^^
311     for ( ui32_t i = 0; i < B_len; i++ )
312       xor_buf[i] ^= ipad[i];
313
314     SHA1_Update(&m_SHA, xor_buf, B_len);
315   }
316
317   //
318   void
319   Update(const byte_t* buf, ui32_t buf_len)
320   {
321     // H(K XOR opad, H(K XOR ipad, text))
322     //                             ^^^^
323     SHA1_Update(&m_SHA, buf, buf_len);
324   }
325
326   //
327   void
328   Finalize()
329   {
330     SHA_CTX SHA;
331     SHA1_Init(&SHA);
332
333     byte_t xor_buf[B_len];
334     memset(xor_buf, 0, B_len);
335     memcpy(xor_buf, m_key, KeyLen);
336
337     SHA1_Init(&SHA);
338
339     // H(K XOR opad, H(K XOR ipad, text))
340     //   ^^^^^^^^^^
341     for ( ui32_t i = 0; i < B_len; i++ )
342       xor_buf[i] ^= opad[i];
343
344     SHA1_Update(&SHA, xor_buf, B_len);
345
346     // H(K XOR opad, H(K XOR ipad, text))
347     //               ^
348     SHA1_Final(m_SHAValue, &m_SHA);
349     SHA1_Update(&SHA, m_SHAValue, HMAC_SIZE);
350
351     // H(K XOR opad, H(K XOR ipad, text))
352     // ^
353     SHA1_Final(m_SHAValue, &SHA);
354     m_Final = true;
355   }
356 };
357
358
359 HMACContext::HMACContext()
360 {
361 }
362
363 HMACContext::~HMACContext()
364 {
365 }
366
367
368 //
369 Result_t
370 HMACContext::InitKey(const byte_t* key, LabelSet_t SetType)
371 {
372   KM_TEST_NULL_L(key);
373
374   m_Context = new h__HMACContext;
375
376   switch ( SetType )
377     {
378     case LS_MXF_INTEROP: m_Context->SetInteropKey(key); break;
379     case LS_MXF_SMPTE:   m_Context->SetKey(key); break;
380     default:
381       m_Context = 0;
382       return RESULT_INIT;
383     }
384
385   return RESULT_OK;
386 }
387
388
389 //
390 void
391 HMACContext::Reset()
392 {
393   if ( ! m_Context.empty() )
394     m_Context->Reset();
395 }
396
397
398 //
399 Result_t
400 HMACContext::Update(const byte_t* buf, ui32_t buf_len)
401 {
402   KM_TEST_NULL_L(buf);
403
404   if ( m_Context.empty() || m_Context->m_Final )
405     return RESULT_INIT;
406
407   m_Context->Update(buf, buf_len);
408   return RESULT_OK;
409 }
410
411
412 //
413 Result_t
414 HMACContext::Finalize()
415 {
416   if ( m_Context.empty() || m_Context->m_Final )
417     return RESULT_INIT;
418   
419   m_Context->Finalize();
420   return RESULT_OK;
421 }
422
423
424 //
425 Result_t
426 HMACContext::GetHMACValue(byte_t* buf) const
427 {
428   KM_TEST_NULL_L(buf);
429
430   if ( m_Context.empty() || ! m_Context->m_Final )
431     return RESULT_INIT;
432
433   memcpy(buf, m_Context->m_SHAValue, HMAC_SIZE);
434   return RESULT_OK;
435 }
436
437
438 //
439 Result_t
440 HMACContext::TestHMACValue(const byte_t* buf) const
441 {
442   KM_TEST_NULL_L(buf);
443
444   if ( m_Context.empty() || ! m_Context->m_Final )
445     return RESULT_INIT;
446   
447   return ( memcmp(buf, m_Context->m_SHAValue, HMAC_SIZE) == 0 ) ? RESULT_OK : RESULT_HMACFAIL;
448 }
449
450
451
452 //
453 // end AS_DCP_AES.cpp
454 //