3d3656653c82f89be794723247529b97bbc63393
[asdcplib.git] / src / AS_DCP_AES.cpp
1 /*
2 Copyright (c) 2004, 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
36 using namespace ASDCP;
37 const int KEY_SIZE_BITS = 128;
38
39
40 #ifndef ASDCP_WITHOUT_OPENSSL
41 #include <openssl/aes.h>
42 #include <openssl/sha.h>
43 #include <openssl/err.h>
44
45 void
46 print_ssl_error()
47 {
48   char err_buf[256];
49   unsigned long errval = ERR_get_error();
50   DefaultLogSink().Error("OpenSSL: %s\n", ERR_error_string(errval, err_buf));
51 }
52
53 #endif
54
55
56 //------------------------------------------------------------------------------------------
57
58 #ifdef ASDCP_WITHOUT_OPENSSL
59 class ASDCP::AESEncContext::h__AESContext
60 #else
61 class ASDCP::AESEncContext::h__AESContext : public AES_KEY
62 #endif
63 {
64 public:
65   byte_t m_IVec[CBC_BLOCK_SIZE];
66 };
67
68
69 ASDCP::AESEncContext::AESEncContext()  {}
70 ASDCP::AESEncContext::~AESEncContext() {}
71
72 // Initializes Rijndael CBC encryption context.
73 // Returns error if the key argument is NULL.
74 ASDCP::Result_t
75 ASDCP::AESEncContext::InitKey(const byte_t* key)
76 {
77   ASDCP_TEST_NULL(key);
78
79   if ( m_Context )
80     return RESULT_INIT;
81
82 #ifndef ASDCP_WITHOUT_OPENSSL
83   m_Context = new h__AESContext;
84
85   if ( AES_set_encrypt_key(key, KEY_SIZE_BITS, m_Context) )
86     {
87       print_ssl_error();
88       return RESULT_CRYPT_INIT;
89     }
90
91   return RESULT_OK;
92 #else // ASDCP_WITHOUT_OPENSSL
93   return RESULT_FAIL;
94 #endif // ASDCP_WITHOUT_OPENSSL
95 }
96
97
98 // Set the value of the 16 byte CBC Initialization Vector. This operation may be performed
99 // any number of times for a given key.
100 // Returns error if the i_vec argument is NULL.
101 ASDCP::Result_t
102 ASDCP::AESEncContext::SetIVec(const byte_t* i_vec)
103 {
104   ASDCP_TEST_NULL(i_vec);
105
106   if ( ! m_Context )
107     return  RESULT_INIT;
108
109 #ifndef ASDCP_WITHOUT_OPENSSL
110   memcpy(m_Context->m_IVec, i_vec, CBC_BLOCK_SIZE);
111   return RESULT_OK;
112 #else // ASDCP_WITHOUT_OPENSSL
113   return RESULT_FAIL;
114 #endif // ASDCP_WITHOUT_OPENSSL
115 }
116
117
118 // Retrieve the value of the  16 byte CBC Initialization Vector.
119 // Returns error if the i_vec argument is NULL.
120 ASDCP::Result_t
121 ASDCP::AESEncContext::GetIVec(byte_t* i_vec) const
122 {
123   ASDCP_TEST_NULL(i_vec);
124
125   if ( ! m_Context )
126     return  RESULT_INIT;
127
128 #ifndef ASDCP_WITHOUT_OPENSSL
129   memcpy(i_vec, m_Context->m_IVec, CBC_BLOCK_SIZE);
130   return RESULT_OK;
131 #else // ASDCP_WITHOUT_OPENSSL
132   return RESULT_FAIL;
133 #endif // ASDCP_WITHOUT_OPENSSL
134 }
135
136
137 // Encrypt a 16 byte block of data.
138 // Returns error if either argument is NULL.
139 ASDCP::Result_t
140 ASDCP::AESEncContext::EncryptBlock(const byte_t* pt_buf, byte_t* ct_buf, ui32_t block_size)
141 {
142   ASDCP_TEST_NULL(pt_buf);
143   ASDCP_TEST_NULL(ct_buf);
144   assert(block_size > 0);
145   assert( block_size % CBC_BLOCK_SIZE == 0 );
146
147   if ( m_Context.empty() )
148     return  RESULT_INIT;
149
150 #ifndef ASDCP_WITHOUT_OPENSSL
151   h__AESContext* Ctx = m_Context;
152   byte_t tmp_buf[CBC_BLOCK_SIZE];
153   const byte_t* in_p = pt_buf;
154   byte_t* out_p = ct_buf;
155
156   while ( block_size )
157     {
158       // xor with the previous block
159       for ( ui32_t i = 0; i < CBC_BLOCK_SIZE; i++ )
160         tmp_buf[i] = in_p[i] ^ Ctx->m_IVec[i]; 
161           
162       AES_encrypt(tmp_buf, Ctx->m_IVec, Ctx);
163       memcpy(out_p, Ctx->m_IVec, CBC_BLOCK_SIZE);
164
165       in_p += CBC_BLOCK_SIZE;
166       out_p += CBC_BLOCK_SIZE;
167       block_size -= CBC_BLOCK_SIZE;
168     }
169
170   return RESULT_OK;
171 #else // ASDCP_WITHOUT_OPENSSL
172   return RESULT_FAIL;
173 #endif // ASDCP_WITHOUT_OPENSSL
174 }
175
176
177 //------------------------------------------------------------------------------------------
178
179 #ifdef ASDCP_WITHOUT_OPENSSL
180 class ASDCP::AESDecContext::h__AESContext
181 #else
182 class ASDCP::AESDecContext::h__AESContext : public AES_KEY
183 #endif
184 {
185 public:
186   byte_t m_IVec[CBC_BLOCK_SIZE];
187 };
188
189 ASDCP::AESDecContext::AESDecContext()  {}
190 ASDCP::AESDecContext::~AESDecContext() {}
191
192
193 // Initializes Rijndael CBC decryption context.
194 // Returns error if the key argument is NULL.
195 ASDCP::Result_t
196 ASDCP::AESDecContext::InitKey(const byte_t* key)
197 {
198   ASDCP_TEST_NULL(key);
199
200   if ( m_Context )
201     return  RESULT_INIT;
202
203 #ifndef ASDCP_WITHOUT_OPENSSL
204   m_Context = new h__AESContext;
205
206   if ( AES_set_decrypt_key(key, KEY_SIZE_BITS, m_Context) )
207     {
208       print_ssl_error();
209       return RESULT_CRYPT_INIT;
210     }
211
212   return RESULT_OK;
213 #else // ASDCP_WITHOUT_OPENSSL
214   return RESULT_FAIL;
215 #endif // ASDCP_WITHOUT_OPENSSL
216 }
217
218 // Initializes 16 byte CBC Initialization Vector. This operation may be performed
219 // any number of times for a given key.
220 // Returns error if the i_vec argument is NULL.
221 ASDCP::Result_t
222 ASDCP::AESDecContext::SetIVec(const byte_t* i_vec)
223 {
224   ASDCP_TEST_NULL(i_vec);
225
226   if ( ! m_Context )
227     return  RESULT_INIT;
228
229 #ifndef ASDCP_WITHOUT_OPENSSL
230   memcpy(m_Context->m_IVec, i_vec, CBC_BLOCK_SIZE);
231   return RESULT_OK;
232 #else // ASDCP_WITHOUT_OPENSSL
233   return RESULT_FAIL;
234 #endif // ASDCP_WITHOUT_OPENSSL
235 }
236
237 // Decrypt a 16 byte block of data.
238 // Returns error if either argument is NULL.
239 ASDCP::Result_t
240 ASDCP::AESDecContext::DecryptBlock(const byte_t* ct_buf, byte_t* pt_buf, ui32_t block_size)
241 {
242   ASDCP_TEST_NULL(ct_buf);
243   ASDCP_TEST_NULL(pt_buf);
244   assert(block_size > 0);
245   assert( block_size % CBC_BLOCK_SIZE == 0 );
246
247   if ( m_Context.empty() )
248     return  RESULT_INIT;
249
250 #ifndef ASDCP_WITHOUT_OPENSSL
251   register h__AESContext* Ctx = m_Context;
252
253   const byte_t* in_p = ct_buf;
254   byte_t* out_p = pt_buf;
255
256   while ( block_size )
257     {
258       AES_decrypt(in_p, out_p, Ctx);  
259
260       for ( ui32_t i = 0; i < CBC_BLOCK_SIZE; i++ )
261         out_p[i] ^= Ctx->m_IVec[i];
262
263       memcpy(Ctx->m_IVec, in_p, CBC_BLOCK_SIZE);
264
265       in_p += CBC_BLOCK_SIZE;
266       out_p += CBC_BLOCK_SIZE;
267       block_size -= CBC_BLOCK_SIZE;
268     }
269
270   return RESULT_OK;
271 #else // ASDCP_WITHOUT_OPENSSL
272   return RESULT_FAIL;
273 #endif // ASDCP_WITHOUT_OPENSSL
274 }
275
276 //------------------------------------------------------------------------------------------
277
278
279 static byte_t ipad[KeyLen] = { 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
280                                0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 };
281
282 static byte_t opad[KeyLen] = { 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
283                                0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c };
284
285 class HMACContext::h__HMACContext
286 {
287 #ifndef ASDCP_WITHOUT_OPENSSL
288   SHA_CTX m_SHA;
289 #endif // ASDCP_WITHOUT_OPENSSL
290   byte_t m_key[KeyLen];
291   ASDCP_NO_COPY_CONSTRUCT(h__HMACContext);
292
293 public:
294   byte_t sha_value[HMAC_SIZE];
295   bool   m_Final;
296
297   h__HMACContext() : m_Final(false) {}
298   ~h__HMACContext() {}
299
300   //
301   void SetKey(const byte_t* key)
302   {
303     static byte_t key_nonce[KeyLen] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 
304                                         0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
305 #ifndef ASDCP_WITHOUT_OPENSSL
306     byte_t sha_buf[SHA_DIGEST_LENGTH];
307
308     // 7.10: MICKey = trunc( SHA1 ( key, key_nonce ) )
309     SHA_CTX SHA;
310     SHA1_Init(&SHA);
311     SHA1_Update(&SHA, key, KeyLen);
312     SHA1_Update(&SHA, key_nonce, KeyLen);
313     SHA1_Final(sha_buf, &SHA);
314     memcpy(m_key, sha_buf, KeyLen);
315
316     Reset();
317 #endif // ASDCP_WITHOUT_OPENSSL
318   }
319
320   void
321   Reset()
322   {
323 #ifndef ASDCP_WITHOUT_OPENSSL
324     byte_t xor_buf[KeyLen];
325     memset(sha_value, 0, HMAC_SIZE);
326     m_Final = false;
327     SHA1_Init(&m_SHA);
328
329     // H(K XOR opad, H(K XOR ipad, text))
330     //                 ^^^^^^^^^^
331     for ( ui32_t i = 0; i < KeyLen; i++ )
332       xor_buf[i] = m_key[i] ^ ipad[i];
333
334     SHA1_Update(&m_SHA, xor_buf, KeyLen);
335 #endif // ASDCP_WITHOUT_OPENSSL
336   }
337
338   //
339   void
340   Update(const byte_t* buf, ui32_t buf_len)
341   {
342 #ifndef ASDCP_WITHOUT_OPENSSL
343     // H(K XOR opad, H(K XOR ipad, text))
344     //                             ^^^^
345     SHA1_Update(&m_SHA, buf, buf_len);
346 #endif // ASDCP_WITHOUT_OPENSSL
347   }
348
349   //
350   void
351   Finalize()
352   {
353 #ifndef ASDCP_WITHOUT_OPENSSL
354     // H(K XOR opad, H(K XOR ipad, text))
355     // ^^^^^^^^^^^^^^^
356     SHA1_Final(sha_value, &m_SHA);
357
358     SHA_CTX SHA;
359     SHA1_Init(&SHA);
360
361     byte_t xor_buf[KeyLen];
362
363     for ( ui32_t i = 0; i < KeyLen; i++ )
364       xor_buf[i] = m_key[i] ^ opad[i];
365     
366     SHA1_Update(&SHA, xor_buf, KeyLen);
367     SHA1_Update(&SHA, sha_value, HMAC_SIZE);
368
369     SHA1_Final(sha_value, &SHA);
370     m_Final = true;
371 #endif // ASDCP_WITHOUT_OPENSSL
372   }
373 };
374
375
376 HMACContext::HMACContext()
377 {
378 }
379
380 HMACContext::~HMACContext()
381 {
382 }
383
384
385 //
386 Result_t
387 HMACContext::InitKey(const byte_t* key)
388 {
389   ASDCP_TEST_NULL(key);
390
391   m_Context = new h__HMACContext;
392   m_Context->SetKey(key);
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   ASDCP_TEST_NULL(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   ASDCP_TEST_NULL(buf);
437
438   if ( m_Context.empty() || ! m_Context->m_Final )
439     return RESULT_INIT;
440
441   memcpy(buf, m_Context->sha_value, HMAC_SIZE);
442   return RESULT_OK;
443 }
444
445
446 //
447 Result_t
448 HMACContext::TestHMACValue(const byte_t* buf) const
449 {
450   ASDCP_TEST_NULL(buf);
451
452   if ( m_Context.empty() || ! m_Context->m_Final )
453     return RESULT_INIT;
454   
455   return ( memcmp(buf, m_Context->sha_value, HMAC_SIZE) == 0 ) ? RESULT_OK : RESULT_HMACFAIL;
456 }
457
458
459
460 //
461 // end AS_DCP_AES.cpp
462 //