Fix a type-punning warning.
[asdcplib-cth.git] / 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.14 2014/03/14 21:53:38 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   Kumu::SymmetricKey m_KeyBuf;
62   byte_t m_IVec[CBC_BLOCK_SIZE];
63 };
64
65
66 ASDCP::AESEncContext::AESEncContext()  {}
67 ASDCP::AESEncContext::~AESEncContext() {}
68
69 // Initializes Rijndael CBC encryption context.
70 // Returns error if the key argument is NULL.
71 ASDCP::Result_t
72 ASDCP::AESEncContext::InitKey(const byte_t* key)
73 {
74   KM_TEST_NULL_L(key);
75
76   if ( m_Context )
77     return RESULT_INIT;
78
79   m_Context = new h__AESContext;
80   m_Context->m_KeyBuf.Set(key);
81
82   if ( AES_set_encrypt_key(m_Context->m_KeyBuf.Value(), KEY_SIZE_BITS, m_Context) )
83     {
84       print_ssl_error();
85       return RESULT_CRYPT_INIT;
86     }
87
88   return RESULT_OK;
89 }
90
91
92 // Set the value of the 16 byte CBC Initialization Vector. This operation may be performed
93 // any number of times for a given key.
94 // Returns error if the i_vec argument is NULL.
95 ASDCP::Result_t
96 ASDCP::AESEncContext::SetIVec(const byte_t* i_vec)
97 {
98   KM_TEST_NULL_L(i_vec);
99
100   if ( ! m_Context )
101     return  RESULT_INIT;
102
103   memcpy(m_Context->m_IVec, i_vec, CBC_BLOCK_SIZE);
104   return RESULT_OK;
105 }
106
107
108 // Retrieve the value of the  16 byte CBC Initialization Vector.
109 // Returns error if the i_vec argument is NULL.
110 ASDCP::Result_t
111 ASDCP::AESEncContext::GetIVec(byte_t* i_vec) const
112 {
113   KM_TEST_NULL_L(i_vec);
114
115   if ( ! m_Context )
116     return  RESULT_INIT;
117
118   memcpy(i_vec, m_Context->m_IVec, CBC_BLOCK_SIZE);
119   return RESULT_OK;
120 }
121
122
123 // Encrypt a 16 byte block of data.
124 // Returns error if either argument is NULL.
125 ASDCP::Result_t
126 ASDCP::AESEncContext::EncryptBlock(const byte_t* pt_buf, byte_t* ct_buf, ui32_t block_size)
127 {
128   KM_TEST_NULL_L(pt_buf);
129   KM_TEST_NULL_L(ct_buf);
130   assert(block_size > 0);
131   assert( block_size % CBC_BLOCK_SIZE == 0 );
132
133   if ( m_Context.empty() )
134     return  RESULT_INIT;
135
136   h__AESContext* Ctx = m_Context;
137   byte_t tmp_buf[CBC_BLOCK_SIZE];
138   const byte_t* in_p = pt_buf;
139   byte_t* out_p = ct_buf;
140
141   while ( block_size )
142     {
143       // xor with the previous block
144       for ( ui32_t i = 0; i < CBC_BLOCK_SIZE; i++ )
145         tmp_buf[i] = in_p[i] ^ Ctx->m_IVec[i]; 
146           
147       AES_encrypt(tmp_buf, Ctx->m_IVec, Ctx);
148       memcpy(out_p, Ctx->m_IVec, CBC_BLOCK_SIZE);
149
150       in_p += CBC_BLOCK_SIZE;
151       out_p += CBC_BLOCK_SIZE;
152       block_size -= CBC_BLOCK_SIZE;
153     }
154
155   return RESULT_OK;
156 }
157
158
159 //------------------------------------------------------------------------------------------
160
161 class ASDCP::AESDecContext::h__AESContext : public AES_KEY
162 {
163 public:
164   Kumu::SymmetricKey m_KeyBuf;
165   byte_t m_IVec[CBC_BLOCK_SIZE];
166 };
167
168 ASDCP::AESDecContext::AESDecContext()  {}
169 ASDCP::AESDecContext::~AESDecContext() {}
170
171
172 // Initializes Rijndael CBC decryption context.
173 // Returns error if the key argument is NULL.
174 ASDCP::Result_t
175 ASDCP::AESDecContext::InitKey(const byte_t* key)
176 {
177   KM_TEST_NULL_L(key);
178
179   if ( m_Context )
180     return  RESULT_INIT;
181
182   m_Context = new h__AESContext;
183   m_Context->m_KeyBuf.Set(key);
184
185   if ( AES_set_decrypt_key(m_Context->m_KeyBuf.Value(), KEY_SIZE_BITS, m_Context) )
186     {
187       print_ssl_error();
188       return RESULT_CRYPT_INIT;
189     }
190
191   return RESULT_OK;
192 }
193
194 // Initializes 16 byte CBC Initialization Vector. This operation may be performed
195 // any number of times for a given key.
196 // Returns error if the i_vec argument is NULL.
197 ASDCP::Result_t
198 ASDCP::AESDecContext::SetIVec(const byte_t* i_vec)
199 {
200   KM_TEST_NULL_L(i_vec);
201
202   if ( ! m_Context )
203     return  RESULT_INIT;
204
205   memcpy(m_Context->m_IVec, i_vec, CBC_BLOCK_SIZE);
206   return RESULT_OK;
207 }
208
209 // Decrypt a 16 byte block of data.
210 // Returns error if either argument is NULL.
211 ASDCP::Result_t
212 ASDCP::AESDecContext::DecryptBlock(const byte_t* ct_buf, byte_t* pt_buf, ui32_t block_size)
213 {
214   KM_TEST_NULL_L(ct_buf);
215   KM_TEST_NULL_L(pt_buf);
216   assert(block_size > 0);
217   assert( block_size % CBC_BLOCK_SIZE == 0 );
218
219   if ( m_Context.empty() )
220     return  RESULT_INIT;
221
222   register h__AESContext* Ctx = m_Context;
223
224   const byte_t* in_p = ct_buf;
225   byte_t* out_p = pt_buf;
226
227   while ( block_size )
228     {
229       AES_decrypt(in_p, out_p, Ctx);  
230
231       for ( ui32_t i = 0; i < CBC_BLOCK_SIZE; i++ )
232         out_p[i] ^= Ctx->m_IVec[i];
233
234       memcpy(Ctx->m_IVec, in_p, CBC_BLOCK_SIZE);
235
236       in_p += CBC_BLOCK_SIZE;
237       out_p += CBC_BLOCK_SIZE;
238       block_size -= CBC_BLOCK_SIZE;
239     }
240
241   return RESULT_OK;
242 }
243
244 //------------------------------------------------------------------------------------------
245
246 static const ui32_t B_len = 64; // rfc 2104, Sec. 2
247
248 static byte_t const ipad_const = 0x36;
249 static byte_t const opad_const = 0x5c;
250
251 class HMACContext::h__HMACContext
252 {
253   SHA_CTX m_SHA;
254   byte_t  m_key[KeyLen];
255   ASDCP_NO_COPY_CONSTRUCT(h__HMACContext);
256
257 public:
258   byte_t     m_SHAValue[HMAC_SIZE];
259   bool       m_Final;
260
261   h__HMACContext() : m_Final(false) {}
262   ~h__HMACContext() {}
263
264   // SMPTE 429.6 MIC key generation
265   void SetKey(const byte_t* key)
266   {
267     byte_t rng_buf[SHA_DIGEST_LENGTH*2];
268     Kumu::Gen_FIPS_186_Value(key, KeyLen, rng_buf, SHA_DIGEST_LENGTH*2);
269
270     // rng_buf contains two rounds, x0 and x1 (each 160 bits).
271     // Use x1 per SMPTE 430-6-2006 Sec. 7.10
272     memcpy(m_key, rng_buf+SHA_DIGEST_LENGTH, KeyLen);
273     Reset();
274   }
275
276   // MXF Interop MIC key generation
277   void SetInteropKey(const byte_t* key)
278   {
279     static byte_t key_nonce[KeyLen] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 
280                                         0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
281     byte_t sha_buf[SHA_DIGEST_LENGTH];
282
283     // 7.10: MICKey = trunc( SHA1 ( key, key_nonce ) )
284     SHA_CTX SHA;
285     SHA1_Init(&SHA);
286     SHA1_Update(&SHA, key, KeyLen);
287     SHA1_Update(&SHA, key_nonce, KeyLen);
288     SHA1_Final(sha_buf, &SHA);
289     memcpy(m_key, sha_buf, KeyLen);
290     Reset();
291   }
292
293   //
294   void
295   Reset()
296   {
297     byte_t xor_buf[B_len];
298     memset(xor_buf, 0, B_len);
299     memcpy(xor_buf, m_key, KeyLen);
300
301     memset(m_SHAValue, 0, HMAC_SIZE);
302     m_Final = false;
303     SHA1_Init(&m_SHA);
304
305     // H(K XOR opad, H(K XOR ipad, text))
306     //                 ^^^^^^^^^^
307     for ( ui32_t i = 0; i < B_len; i++ )
308       xor_buf[i] ^= ipad_const;
309
310     SHA1_Update(&m_SHA, xor_buf, B_len);
311   }
312
313   //
314   void
315   Update(const byte_t* buf, ui32_t buf_len)
316   {
317     // H(K XOR opad, H(K XOR ipad, text))
318     //                             ^^^^
319     SHA1_Update(&m_SHA, buf, buf_len);
320   }
321
322   //
323   void
324   Finalize()
325   {
326     SHA_CTX SHA;
327     SHA1_Init(&SHA);
328
329     byte_t xor_buf[B_len];
330     memset(xor_buf, 0, B_len);
331     memcpy(xor_buf, m_key, KeyLen);
332
333     SHA1_Init(&SHA);
334
335     // H(K XOR opad, H(K XOR ipad, text))
336     //   ^^^^^^^^^^
337     for ( ui32_t i = 0; i < B_len; i++ )
338       xor_buf[i] ^= opad_const;
339
340     SHA1_Update(&SHA, xor_buf, B_len);
341
342     // H(K XOR opad, H(K XOR ipad, text))
343     //               ^
344     SHA1_Final(m_SHAValue, &m_SHA);
345     SHA1_Update(&SHA, m_SHAValue, HMAC_SIZE);
346
347     // H(K XOR opad, H(K XOR ipad, text))
348     // ^
349     SHA1_Final(m_SHAValue, &SHA);
350     m_Final = true;
351   }
352 };
353
354
355 HMACContext::HMACContext()
356 {
357 }
358
359 HMACContext::~HMACContext()
360 {
361 }
362
363
364 //
365 Result_t
366 HMACContext::InitKey(const byte_t* key, LabelSet_t SetType)
367 {
368   KM_TEST_NULL_L(key);
369
370   m_Context = new h__HMACContext;
371
372   switch ( SetType )
373     {
374     case LS_MXF_INTEROP: m_Context->SetInteropKey(key); break;
375     case LS_MXF_SMPTE:   m_Context->SetKey(key); break;
376     default:
377       m_Context = 0;
378       return RESULT_INIT;
379     }
380
381   return RESULT_OK;
382 }
383
384
385 //
386 void
387 HMACContext::Reset()
388 {
389   if ( ! m_Context.empty() )
390     m_Context->Reset();
391 }
392
393
394 //
395 Result_t
396 HMACContext::Update(const byte_t* buf, ui32_t buf_len)
397 {
398   KM_TEST_NULL_L(buf);
399
400   if ( m_Context.empty() || m_Context->m_Final )
401     return RESULT_INIT;
402
403   m_Context->Update(buf, buf_len);
404   return RESULT_OK;
405 }
406
407
408 //
409 Result_t
410 HMACContext::Finalize()
411 {
412   if ( m_Context.empty() || m_Context->m_Final )
413     return RESULT_INIT;
414   
415   m_Context->Finalize();
416   return RESULT_OK;
417 }
418
419
420 //
421 Result_t
422 HMACContext::GetHMACValue(byte_t* buf) const
423 {
424   KM_TEST_NULL_L(buf);
425
426   if ( m_Context.empty() || ! m_Context->m_Final )
427     return RESULT_INIT;
428
429   memcpy(buf, m_Context->m_SHAValue, HMAC_SIZE);
430   return RESULT_OK;
431 }
432
433
434 //
435 Result_t
436 HMACContext::TestHMACValue(const byte_t* buf) const
437 {
438   KM_TEST_NULL_L(buf);
439
440   if ( m_Context.empty() || ! m_Context->m_Final )
441     return RESULT_INIT;
442   
443   return ( memcmp(buf, m_Context->m_SHAValue, HMAC_SIZE) == 0 ) ? RESULT_OK : RESULT_HMACFAIL;
444 }
445
446
447
448 //
449 // end AS_DCP_AES.cpp
450 //