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