2 Copyright (c) 2004-2006, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
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.
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.
27 /*! \file AS_DCP_AES.h
29 \brief AS-DCP library, AES wrapper
36 using Kumu::DefaultLogSink;
38 using namespace ASDCP;
39 const int KEY_SIZE_BITS = 128;
42 #include <openssl/aes.h>
43 #include <openssl/sha.h>
44 #include <openssl/bn.h>
45 #include <openssl/err.h>
51 unsigned long errval = ERR_get_error();
52 DefaultLogSink().Error("OpenSSL: %s\n", ERR_error_string(errval, err_buf));
55 //------------------------------------------------------------------------------------------
57 class ASDCP::AESEncContext::h__AESContext : public AES_KEY
60 byte_t m_IVec[CBC_BLOCK_SIZE];
64 ASDCP::AESEncContext::AESEncContext() {}
65 ASDCP::AESEncContext::~AESEncContext() {}
67 // Initializes Rijndael CBC encryption context.
68 // Returns error if the key argument is NULL.
70 ASDCP::AESEncContext::InitKey(const byte_t* key)
77 m_Context = new h__AESContext;
79 if ( AES_set_encrypt_key(key, KEY_SIZE_BITS, m_Context) )
82 return RESULT_CRYPT_INIT;
89 // Set the value of the 16 byte CBC Initialization Vector. This operation may be performed
90 // any number of times for a given key.
91 // Returns error if the i_vec argument is NULL.
93 ASDCP::AESEncContext::SetIVec(const byte_t* i_vec)
95 ASDCP_TEST_NULL(i_vec);
100 memcpy(m_Context->m_IVec, i_vec, CBC_BLOCK_SIZE);
105 // Retrieve the value of the 16 byte CBC Initialization Vector.
106 // Returns error if the i_vec argument is NULL.
108 ASDCP::AESEncContext::GetIVec(byte_t* i_vec) const
110 ASDCP_TEST_NULL(i_vec);
115 memcpy(i_vec, m_Context->m_IVec, CBC_BLOCK_SIZE);
120 // Encrypt a 16 byte block of data.
121 // Returns error if either argument is NULL.
123 ASDCP::AESEncContext::EncryptBlock(const byte_t* pt_buf, byte_t* ct_buf, ui32_t block_size)
125 ASDCP_TEST_NULL(pt_buf);
126 ASDCP_TEST_NULL(ct_buf);
127 assert(block_size > 0);
128 assert( block_size % CBC_BLOCK_SIZE == 0 );
130 if ( m_Context.empty() )
133 h__AESContext* Ctx = m_Context;
134 byte_t tmp_buf[CBC_BLOCK_SIZE];
135 const byte_t* in_p = pt_buf;
136 byte_t* out_p = ct_buf;
140 // xor with the previous block
141 for ( ui32_t i = 0; i < CBC_BLOCK_SIZE; i++ )
142 tmp_buf[i] = in_p[i] ^ Ctx->m_IVec[i];
144 AES_encrypt(tmp_buf, Ctx->m_IVec, Ctx);
145 memcpy(out_p, Ctx->m_IVec, CBC_BLOCK_SIZE);
147 in_p += CBC_BLOCK_SIZE;
148 out_p += CBC_BLOCK_SIZE;
149 block_size -= CBC_BLOCK_SIZE;
156 //------------------------------------------------------------------------------------------
158 class ASDCP::AESDecContext::h__AESContext : public AES_KEY
161 byte_t m_IVec[CBC_BLOCK_SIZE];
164 ASDCP::AESDecContext::AESDecContext() {}
165 ASDCP::AESDecContext::~AESDecContext() {}
168 // Initializes Rijndael CBC decryption context.
169 // Returns error if the key argument is NULL.
171 ASDCP::AESDecContext::InitKey(const byte_t* key)
173 ASDCP_TEST_NULL(key);
178 m_Context = new h__AESContext;
180 if ( AES_set_decrypt_key(key, KEY_SIZE_BITS, m_Context) )
183 return RESULT_CRYPT_INIT;
189 // Initializes 16 byte CBC Initialization Vector. This operation may be performed
190 // any number of times for a given key.
191 // Returns error if the i_vec argument is NULL.
193 ASDCP::AESDecContext::SetIVec(const byte_t* i_vec)
195 ASDCP_TEST_NULL(i_vec);
200 memcpy(m_Context->m_IVec, i_vec, CBC_BLOCK_SIZE);
204 // Decrypt a 16 byte block of data.
205 // Returns error if either argument is NULL.
207 ASDCP::AESDecContext::DecryptBlock(const byte_t* ct_buf, byte_t* pt_buf, ui32_t block_size)
209 ASDCP_TEST_NULL(ct_buf);
210 ASDCP_TEST_NULL(pt_buf);
211 assert(block_size > 0);
212 assert( block_size % CBC_BLOCK_SIZE == 0 );
214 if ( m_Context.empty() )
217 register h__AESContext* Ctx = m_Context;
219 const byte_t* in_p = ct_buf;
220 byte_t* out_p = pt_buf;
224 AES_decrypt(in_p, out_p, Ctx);
226 for ( ui32_t i = 0; i < CBC_BLOCK_SIZE; i++ )
227 out_p[i] ^= Ctx->m_IVec[i];
229 memcpy(Ctx->m_IVec, in_p, CBC_BLOCK_SIZE);
231 in_p += CBC_BLOCK_SIZE;
232 out_p += CBC_BLOCK_SIZE;
233 block_size -= CBC_BLOCK_SIZE;
239 //------------------------------------------------------------------------------------------
242 static byte_t ipad[KeyLen] = { 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
243 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 };
245 static byte_t opad[KeyLen] = { 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
246 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c };
248 class HMACContext::h__HMACContext
251 byte_t m_key[KeyLen];
252 ASDCP_NO_COPY_CONSTRUCT(h__HMACContext);
255 byte_t sha_value[HMAC_SIZE];
258 h__HMACContext() : m_Final(false) {}
261 // SMPTE 429.6 MIC key generation
262 void SetKey(const byte_t* key)
264 // FIPS 186-2 Sec. 3.1 as modified by Change 1, section entitled "General Purpose Random Number Generation"
267 static byte_t t[SHA_DIGEST_LENGTH] = {
268 0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x89,
269 0x98, 0xba, 0xdc, 0xfe, 0x10, 0x32, 0x54, 0x76,
270 0xc3, 0xd2, 0xe1, 0xf0
273 byte_t sha_buf0[SHA_DIGEST_LENGTH];
274 byte_t sha_buf1[SHA_DIGEST_LENGTH];
276 BN_CTX* ctx1 = BN_CTX_new(); // used by BN_* functions
279 // create the 2^160 constant
280 BIGNUM c_2powb, c_2, c_160;
281 BN_init(&c_2powb); BN_init(&c_2); BN_init(&c_160);
282 BN_set_word(&c_2, 2);
283 BN_set_word(&c_160, 160);
284 BN_exp(&c_2powb, &c_2, &c_160, ctx1);
287 // step a -- SMPTE 429.6 sets XSEED = 0, so no need to do anything for this step
288 // step b -- (key mod 2^160) is moot because the input value is only 128 bits in length
290 // step c -- x = G(t,xkey)
292 SHA1_Update(&SHA, t, SHA_DIGEST_LENGTH);
293 SHA1_Update(&SHA, key, KeyLen);
294 SHA1_Final(sha_buf0, &SHA);
297 BIGNUM xkey1, xkey2, x0;
298 BN_init(&xkey1); BN_init(&xkey2); BN_init(&x0);
300 BN_bin2bn(key, KeyLen, &xkey1);
301 BN_bin2bn(sha_buf0, SHA_DIGEST_LENGTH, &x0);
302 BN_add_word(&xkey1, 1); // xkey += 1
303 BN_add(&xkey2, &xkey1, &x0); // xkey += x
304 BN_mod(&xkey1, &xkey2, &c_2powb, ctx1); // xkey = xkey mod (2^160)
307 // step a -- SMPTE 429.6 sets XSEED = 0, so no need to do anything for this step
308 // step b -- (key mod 2^160) is moot because xkey1 is the result of the same operation
310 byte_t bin_buf[SHA_DIGEST_LENGTH+1]; // we need xkey1 in bin form for use by SHA1_Update
311 ui32_t bin_buf_len = BN_num_bytes(&xkey1);
312 assert(bin_buf_len < SHA_DIGEST_LENGTH+1);
313 BN_bn2bin(&xkey1, bin_buf);
315 // step c -- x = G(t,xkey)
317 SHA1_Update(&SHA, t, SHA_DIGEST_LENGTH);
318 SHA1_Update(&SHA, bin_buf, bin_buf_len);
319 SHA1_Final(sha_buf1, &SHA);
321 assert(memcmp(sha_buf1, sha_buf0, SHA_DIGEST_LENGTH) != 0); // are x0 and x1 different?
324 memcpy(m_key, sha_buf1, KeyLen);
328 // MXF Interop MIC key generation
329 void SetInteropKey(const byte_t* key)
331 static byte_t key_nonce[KeyLen] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
332 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
333 byte_t sha_buf[SHA_DIGEST_LENGTH];
335 // 7.10: MICKey = trunc( SHA1 ( key, key_nonce ) )
338 SHA1_Update(&SHA, key, KeyLen);
339 SHA1_Update(&SHA, key_nonce, KeyLen);
340 SHA1_Final(sha_buf, &SHA);
341 memcpy(m_key, sha_buf, KeyLen);
349 byte_t xor_buf[KeyLen];
350 memset(sha_value, 0, HMAC_SIZE);
354 // H(K XOR opad, H(K XOR ipad, text))
356 for ( ui32_t i = 0; i < KeyLen; i++ )
357 xor_buf[i] = m_key[i] ^ ipad[i];
359 SHA1_Update(&m_SHA, xor_buf, KeyLen);
364 Update(const byte_t* buf, ui32_t buf_len)
366 // H(K XOR opad, H(K XOR ipad, text))
368 SHA1_Update(&m_SHA, buf, buf_len);
375 // H(K XOR opad, H(K XOR ipad, text))
377 SHA1_Final(sha_value, &m_SHA);
382 byte_t xor_buf[KeyLen];
384 for ( ui32_t i = 0; i < KeyLen; i++ )
385 xor_buf[i] = m_key[i] ^ opad[i];
387 SHA1_Update(&SHA, xor_buf, KeyLen);
388 SHA1_Update(&SHA, sha_value, HMAC_SIZE);
390 SHA1_Final(sha_value, &SHA);
396 HMACContext::HMACContext()
400 HMACContext::~HMACContext()
407 HMACContext::InitKey(const byte_t* key, LabelSet_t SetType)
409 ASDCP_TEST_NULL(key);
411 m_Context = new h__HMACContext;
415 case LS_MXF_INTEROP: m_Context->SetInteropKey(key); break;
416 case LS_MXF_SMPTE: m_Context->SetKey(key); break;
430 if ( ! m_Context.empty() )
437 HMACContext::Update(const byte_t* buf, ui32_t buf_len)
439 ASDCP_TEST_NULL(buf);
441 if ( m_Context.empty() || m_Context->m_Final )
444 m_Context->Update(buf, buf_len);
451 HMACContext::Finalize()
453 if ( m_Context.empty() || m_Context->m_Final )
456 m_Context->Finalize();
463 HMACContext::GetHMACValue(byte_t* buf) const
465 ASDCP_TEST_NULL(buf);
467 if ( m_Context.empty() || ! m_Context->m_Final )
470 memcpy(buf, m_Context->sha_value, HMAC_SIZE);
477 HMACContext::TestHMACValue(const byte_t* buf) const
479 ASDCP_TEST_NULL(buf);
481 if ( m_Context.empty() || ! m_Context->m_Final )
484 return ( memcmp(buf, m_Context->sha_value, HMAC_SIZE) == 0 ) ? RESULT_OK : RESULT_HMACFAIL;
490 // end AS_DCP_AES.cpp