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