2K.4K switching
[asdcplib.git] / src / AS_DCP_AES.cpp
1 /*
2 Copyright (c) 2004-2006, 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 using Kumu::DefaultLogSink;
37
38 using namespace ASDCP;
39 const int KEY_SIZE_BITS = 128;
40
41
42 #include <openssl/aes.h>
43 #include <openssl/sha.h>
44 #include <openssl/bn.h>
45 #include <openssl/err.h>
46
47 void
48 print_ssl_error()
49 {
50   char err_buf[256];
51   unsigned long errval = ERR_get_error();
52   DefaultLogSink().Error("OpenSSL: %s\n", ERR_error_string(errval, err_buf));
53 }
54
55 //------------------------------------------------------------------------------------------
56
57 class ASDCP::AESEncContext::h__AESContext : public AES_KEY
58 {
59 public:
60   byte_t m_IVec[CBC_BLOCK_SIZE];
61 };
62
63
64 ASDCP::AESEncContext::AESEncContext()  {}
65 ASDCP::AESEncContext::~AESEncContext() {}
66
67 // Initializes Rijndael CBC encryption context.
68 // Returns error if the key argument is NULL.
69 ASDCP::Result_t
70 ASDCP::AESEncContext::InitKey(const byte_t* key)
71 {
72   ASDCP_TEST_NULL(key);
73
74   if ( m_Context )
75     return RESULT_INIT;
76
77   m_Context = new h__AESContext;
78
79   if ( AES_set_encrypt_key(key, KEY_SIZE_BITS, m_Context) )
80     {
81       print_ssl_error();
82       return RESULT_CRYPT_INIT;
83     }
84
85   return RESULT_OK;
86 }
87
88
89 // Set the value of the 16 byte CBC Initialization Vector. This operation may be performed
90 // any number of times for a given key.
91 // Returns error if the i_vec argument is NULL.
92 ASDCP::Result_t
93 ASDCP::AESEncContext::SetIVec(const byte_t* i_vec)
94 {
95   ASDCP_TEST_NULL(i_vec);
96
97   if ( ! m_Context )
98     return  RESULT_INIT;
99
100   memcpy(m_Context->m_IVec, i_vec, CBC_BLOCK_SIZE);
101   return RESULT_OK;
102 }
103
104
105 // Retrieve the value of the  16 byte CBC Initialization Vector.
106 // Returns error if the i_vec argument is NULL.
107 ASDCP::Result_t
108 ASDCP::AESEncContext::GetIVec(byte_t* i_vec) const
109 {
110   ASDCP_TEST_NULL(i_vec);
111
112   if ( ! m_Context )
113     return  RESULT_INIT;
114
115   memcpy(i_vec, m_Context->m_IVec, CBC_BLOCK_SIZE);
116   return RESULT_OK;
117 }
118
119
120 // Encrypt a 16 byte block of data.
121 // Returns error if either argument is NULL.
122 ASDCP::Result_t
123 ASDCP::AESEncContext::EncryptBlock(const byte_t* pt_buf, byte_t* ct_buf, ui32_t block_size)
124 {
125   ASDCP_TEST_NULL(pt_buf);
126   ASDCP_TEST_NULL(ct_buf);
127   assert(block_size > 0);
128   assert( block_size % CBC_BLOCK_SIZE == 0 );
129
130   if ( m_Context.empty() )
131     return  RESULT_INIT;
132
133   h__AESContext* Ctx = m_Context;
134   byte_t tmp_buf[CBC_BLOCK_SIZE];
135   const byte_t* in_p = pt_buf;
136   byte_t* out_p = ct_buf;
137
138   while ( block_size )
139     {
140       // xor with the previous block
141       for ( ui32_t i = 0; i < CBC_BLOCK_SIZE; i++ )
142         tmp_buf[i] = in_p[i] ^ Ctx->m_IVec[i]; 
143           
144       AES_encrypt(tmp_buf, Ctx->m_IVec, Ctx);
145       memcpy(out_p, Ctx->m_IVec, CBC_BLOCK_SIZE);
146
147       in_p += CBC_BLOCK_SIZE;
148       out_p += CBC_BLOCK_SIZE;
149       block_size -= CBC_BLOCK_SIZE;
150     }
151
152   return RESULT_OK;
153 }
154
155
156 //------------------------------------------------------------------------------------------
157
158 class ASDCP::AESDecContext::h__AESContext : public AES_KEY
159 {
160 public:
161   byte_t m_IVec[CBC_BLOCK_SIZE];
162 };
163
164 ASDCP::AESDecContext::AESDecContext()  {}
165 ASDCP::AESDecContext::~AESDecContext() {}
166
167
168 // Initializes Rijndael CBC decryption context.
169 // Returns error if the key argument is NULL.
170 ASDCP::Result_t
171 ASDCP::AESDecContext::InitKey(const byte_t* key)
172 {
173   ASDCP_TEST_NULL(key);
174
175   if ( m_Context )
176     return  RESULT_INIT;
177
178   m_Context = new h__AESContext;
179
180   if ( AES_set_decrypt_key(key, KEY_SIZE_BITS, m_Context) )
181     {
182       print_ssl_error();
183       return RESULT_CRYPT_INIT;
184     }
185
186   return RESULT_OK;
187 }
188
189 // Initializes 16 byte CBC Initialization Vector. This operation may be performed
190 // any number of times for a given key.
191 // Returns error if the i_vec argument is NULL.
192 ASDCP::Result_t
193 ASDCP::AESDecContext::SetIVec(const byte_t* i_vec)
194 {
195   ASDCP_TEST_NULL(i_vec);
196
197   if ( ! m_Context )
198     return  RESULT_INIT;
199
200   memcpy(m_Context->m_IVec, i_vec, CBC_BLOCK_SIZE);
201   return RESULT_OK;
202 }
203
204 // Decrypt a 16 byte block of data.
205 // Returns error if either argument is NULL.
206 ASDCP::Result_t
207 ASDCP::AESDecContext::DecryptBlock(const byte_t* ct_buf, byte_t* pt_buf, ui32_t block_size)
208 {
209   ASDCP_TEST_NULL(ct_buf);
210   ASDCP_TEST_NULL(pt_buf);
211   assert(block_size > 0);
212   assert( block_size % CBC_BLOCK_SIZE == 0 );
213
214   if ( m_Context.empty() )
215     return  RESULT_INIT;
216
217   register h__AESContext* Ctx = m_Context;
218
219   const byte_t* in_p = ct_buf;
220   byte_t* out_p = pt_buf;
221
222   while ( block_size )
223     {
224       AES_decrypt(in_p, out_p, Ctx);  
225
226       for ( ui32_t i = 0; i < CBC_BLOCK_SIZE; i++ )
227         out_p[i] ^= Ctx->m_IVec[i];
228
229       memcpy(Ctx->m_IVec, in_p, CBC_BLOCK_SIZE);
230
231       in_p += CBC_BLOCK_SIZE;
232       out_p += CBC_BLOCK_SIZE;
233       block_size -= CBC_BLOCK_SIZE;
234     }
235
236   return RESULT_OK;
237 }
238
239 //------------------------------------------------------------------------------------------
240
241
242 static byte_t ipad[KeyLen] = { 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
243                                0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 };
244
245 static byte_t opad[KeyLen] = { 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
246                                0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c };
247
248 class HMACContext::h__HMACContext
249 {
250   SHA_CTX m_SHA;
251   byte_t m_key[KeyLen];
252   ASDCP_NO_COPY_CONSTRUCT(h__HMACContext);
253
254 public:
255   byte_t sha_value[HMAC_SIZE];
256   bool   m_Final;
257
258   h__HMACContext() : m_Final(false) {}
259   ~h__HMACContext() {}
260
261   // SMPTE 429.6 MIC key generation
262   void SetKey(const byte_t* key)
263   {
264     // FIPS 186-2 Sec. 3.1 as modified by Change 1, section entitled "General Purpose Random Number Generation"
265     //
266
267     static byte_t t[SHA_DIGEST_LENGTH] = {
268       0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x89,
269       0x98, 0xba, 0xdc, 0xfe, 0x10, 0x32, 0x54, 0x76,
270       0xc3, 0xd2, 0xe1, 0xf0
271     };
272
273     byte_t sha_buf0[SHA_DIGEST_LENGTH];
274     byte_t sha_buf1[SHA_DIGEST_LENGTH];
275     SHA_CTX SHA;
276     BN_CTX* ctx1 = BN_CTX_new(); // used by BN_* functions
277     assert(ctx1);
278
279     // create the 2^160 constant
280     BIGNUM c_2powb, c_2, c_160;
281     BN_init(&c_2powb);  BN_init(&c_2);  BN_init(&c_160);
282     BN_set_word(&c_2, 2);
283     BN_set_word(&c_160, 160);
284     BN_exp(&c_2powb, &c_2, &c_160, ctx1);
285
286     // ROUND 1
287     // step a -- SMPTE 429.6 sets XSEED = 0, so no need to do anything for this step
288     // step b -- (key mod 2^160) is moot because the input value is only 128 bits in length
289
290     // step c -- x = G(t,xkey)
291     SHA1_Init(&SHA);
292     SHA1_Update(&SHA, t, SHA_DIGEST_LENGTH);
293     SHA1_Update(&SHA, key, KeyLen);
294     SHA1_Final(sha_buf0, &SHA);
295
296     // step d ...
297     BIGNUM xkey1, xkey2, x0;
298     BN_init(&xkey1);  BN_init(&xkey2);    BN_init(&x0);
299
300     BN_bin2bn(key, KeyLen, &xkey1);
301     BN_bin2bn(sha_buf0, SHA_DIGEST_LENGTH, &x0);
302     BN_add_word(&xkey1, 1);            // xkey += 1
303     BN_add(&xkey2, &xkey1, &x0);       // xkey += x
304     BN_mod(&xkey1, &xkey2, &c_2powb, ctx1);  // xkey = xkey mod (2^160)
305
306     // ROUND 2
307     // step a -- SMPTE 429.6 sets XSEED = 0, so no need to do anything for this step
308     // step b -- (key mod 2^160) is moot because xkey1 is the result of the same operation
309
310     byte_t bin_buf[SHA_DIGEST_LENGTH+1]; // we need xkey1 in bin form for use by SHA1_Update
311     ui32_t bin_buf_len = BN_num_bytes(&xkey1);
312     assert(bin_buf_len < SHA_DIGEST_LENGTH+1);
313     BN_bn2bin(&xkey1, bin_buf);
314
315     // step c -- x = G(t,xkey)
316     SHA1_Init(&SHA);
317     SHA1_Update(&SHA, t, SHA_DIGEST_LENGTH);
318     SHA1_Update(&SHA, bin_buf, bin_buf_len);
319     SHA1_Final(sha_buf1, &SHA);
320
321     assert(memcmp(sha_buf1, sha_buf0, SHA_DIGEST_LENGTH) != 0); // are x0 and x1 different?
322
323     BN_CTX_free(ctx1);
324     memcpy(m_key, sha_buf1, KeyLen);
325     Reset();
326   }
327
328   // MXF Interop MIC key generation
329   void SetInteropKey(const byte_t* key)
330   {
331     static byte_t key_nonce[KeyLen] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 
332                                         0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
333     byte_t sha_buf[SHA_DIGEST_LENGTH];
334
335     // 7.10: MICKey = trunc( SHA1 ( key, key_nonce ) )
336     SHA_CTX SHA;
337     SHA1_Init(&SHA);
338     SHA1_Update(&SHA, key, KeyLen);
339     SHA1_Update(&SHA, key_nonce, KeyLen);
340     SHA1_Final(sha_buf, &SHA);
341     memcpy(m_key, sha_buf, KeyLen);
342
343     Reset();
344   }
345
346   void
347   Reset()
348   {
349     byte_t xor_buf[KeyLen];
350     memset(sha_value, 0, HMAC_SIZE);
351     m_Final = false;
352     SHA1_Init(&m_SHA);
353
354     // H(K XOR opad, H(K XOR ipad, text))
355     //                 ^^^^^^^^^^
356     for ( ui32_t i = 0; i < KeyLen; i++ )
357       xor_buf[i] = m_key[i] ^ ipad[i];
358
359     SHA1_Update(&m_SHA, xor_buf, KeyLen);
360   }
361
362   //
363   void
364   Update(const byte_t* buf, ui32_t buf_len)
365   {
366     // H(K XOR opad, H(K XOR ipad, text))
367     //                             ^^^^
368     SHA1_Update(&m_SHA, buf, buf_len);
369   }
370
371   //
372   void
373   Finalize()
374   {
375     // H(K XOR opad, H(K XOR ipad, text))
376     // ^^^^^^^^^^^^^^^
377     SHA1_Final(sha_value, &m_SHA);
378
379     SHA_CTX SHA;
380     SHA1_Init(&SHA);
381
382     byte_t xor_buf[KeyLen];
383
384     for ( ui32_t i = 0; i < KeyLen; i++ )
385       xor_buf[i] = m_key[i] ^ opad[i];
386     
387     SHA1_Update(&SHA, xor_buf, KeyLen);
388     SHA1_Update(&SHA, sha_value, HMAC_SIZE);
389
390     SHA1_Final(sha_value, &SHA);
391     m_Final = true;
392   }
393 };
394
395
396 HMACContext::HMACContext()
397 {
398 }
399
400 HMACContext::~HMACContext()
401 {
402 }
403
404
405 //
406 Result_t
407 HMACContext::InitKey(const byte_t* key, LabelSet_t SetType)
408 {
409   ASDCP_TEST_NULL(key);
410
411   m_Context = new h__HMACContext;
412
413   switch ( SetType )
414     {
415     case LS_MXF_INTEROP: m_Context->SetInteropKey(key); break;
416     case LS_MXF_SMPTE:   m_Context->SetKey(key); break;
417     default:
418       m_Context = 0;
419       return RESULT_INIT;
420     }
421
422   return RESULT_OK;
423 }
424
425
426 //
427 void
428 HMACContext::Reset()
429 {
430   if ( ! m_Context.empty() )
431     m_Context->Reset();
432 }
433
434
435 //
436 Result_t
437 HMACContext::Update(const byte_t* buf, ui32_t buf_len)
438 {
439   ASDCP_TEST_NULL(buf);
440
441   if ( m_Context.empty() || m_Context->m_Final )
442     return RESULT_INIT;
443
444   m_Context->Update(buf, buf_len);
445   return RESULT_OK;
446 }
447
448
449 //
450 Result_t
451 HMACContext::Finalize()
452 {
453   if ( m_Context.empty() || m_Context->m_Final )
454     return RESULT_INIT;
455   
456   m_Context->Finalize();
457   return RESULT_OK;
458 }
459
460
461 //
462 Result_t
463 HMACContext::GetHMACValue(byte_t* buf) const
464 {
465   ASDCP_TEST_NULL(buf);
466
467   if ( m_Context.empty() || ! m_Context->m_Final )
468     return RESULT_INIT;
469
470   memcpy(buf, m_Context->sha_value, HMAC_SIZE);
471   return RESULT_OK;
472 }
473
474
475 //
476 Result_t
477 HMACContext::TestHMACValue(const byte_t* buf) const
478 {
479   ASDCP_TEST_NULL(buf);
480
481   if ( m_Context.empty() || ! m_Context->m_Final )
482     return RESULT_INIT;
483   
484   return ( memcmp(buf, m_Context->sha_value, HMAC_SIZE) == 0 ) ? RESULT_OK : RESULT_HMACFAIL;
485 }
486
487
488
489 //
490 // end AS_DCP_AES.cpp
491 //