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