2 Copyright (c) 2004-2009, 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
37 using Kumu::DefaultLogSink;
39 using namespace ASDCP;
40 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>
52 unsigned long errval = ERR_get_error();
53 DefaultLogSink().Error("OpenSSL: %s\n", ERR_error_string(errval, err_buf));
56 //------------------------------------------------------------------------------------------
58 class ASDCP::AESEncContext::h__AESContext : public AES_KEY
61 Kumu::SymmetricKey m_KeyBuf;
62 byte_t m_IVec[CBC_BLOCK_SIZE];
66 ASDCP::AESEncContext::AESEncContext() {}
67 ASDCP::AESEncContext::~AESEncContext() {}
69 // Initializes Rijndael CBC encryption context.
70 // Returns error if the key argument is NULL.
72 ASDCP::AESEncContext::InitKey(const byte_t* key)
79 m_Context = new h__AESContext;
80 m_Context->m_KeyBuf.Set(key);
82 if ( AES_set_encrypt_key(m_Context->m_KeyBuf.Value(), KEY_SIZE_BITS, m_Context) )
85 return RESULT_CRYPT_INIT;
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.
96 ASDCP::AESEncContext::SetIVec(const byte_t* i_vec)
98 KM_TEST_NULL_L(i_vec);
103 memcpy(m_Context->m_IVec, i_vec, CBC_BLOCK_SIZE);
108 // Retrieve the value of the 16 byte CBC Initialization Vector.
109 // Returns error if the i_vec argument is NULL.
111 ASDCP::AESEncContext::GetIVec(byte_t* i_vec) const
113 KM_TEST_NULL_L(i_vec);
118 memcpy(i_vec, m_Context->m_IVec, CBC_BLOCK_SIZE);
123 // Encrypt a 16 byte block of data.
124 // Returns error if either argument is NULL.
126 ASDCP::AESEncContext::EncryptBlock(const byte_t* pt_buf, byte_t* ct_buf, ui32_t block_size)
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 );
133 if ( m_Context.empty() )
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;
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];
147 AES_encrypt(tmp_buf, Ctx->m_IVec, Ctx);
148 memcpy(out_p, Ctx->m_IVec, CBC_BLOCK_SIZE);
150 in_p += CBC_BLOCK_SIZE;
151 out_p += CBC_BLOCK_SIZE;
152 block_size -= CBC_BLOCK_SIZE;
159 //------------------------------------------------------------------------------------------
161 class ASDCP::AESDecContext::h__AESContext : public AES_KEY
164 Kumu::SymmetricKey m_KeyBuf;
165 byte_t m_IVec[CBC_BLOCK_SIZE];
168 ASDCP::AESDecContext::AESDecContext() {}
169 ASDCP::AESDecContext::~AESDecContext() {}
172 // Initializes Rijndael CBC decryption context.
173 // Returns error if the key argument is NULL.
175 ASDCP::AESDecContext::InitKey(const byte_t* key)
182 m_Context = new h__AESContext;
183 m_Context->m_KeyBuf.Set(key);
185 if ( AES_set_decrypt_key(m_Context->m_KeyBuf.Value(), KEY_SIZE_BITS, m_Context) )
188 return RESULT_CRYPT_INIT;
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.
198 ASDCP::AESDecContext::SetIVec(const byte_t* i_vec)
200 KM_TEST_NULL_L(i_vec);
205 memcpy(m_Context->m_IVec, i_vec, CBC_BLOCK_SIZE);
209 // Decrypt a 16 byte block of data.
210 // Returns error if either argument is NULL.
212 ASDCP::AESDecContext::DecryptBlock(const byte_t* ct_buf, byte_t* pt_buf, ui32_t block_size)
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 );
219 if ( m_Context.empty() )
222 register h__AESContext* Ctx = m_Context;
224 const byte_t* in_p = ct_buf;
225 byte_t* out_p = pt_buf;
229 AES_decrypt(in_p, out_p, Ctx);
231 for ( ui32_t i = 0; i < CBC_BLOCK_SIZE; i++ )
232 out_p[i] ^= Ctx->m_IVec[i];
234 memcpy(Ctx->m_IVec, in_p, CBC_BLOCK_SIZE);
236 in_p += CBC_BLOCK_SIZE;
237 out_p += CBC_BLOCK_SIZE;
238 block_size -= CBC_BLOCK_SIZE;
244 //------------------------------------------------------------------------------------------
246 static const ui32_t B_len = 64; // rfc 2104, Sec. 2
248 static byte_t const ipad_const = 0x36;
249 static byte_t const opad_const = 0x5c;
251 class HMACContext::h__HMACContext
254 byte_t m_key[KeyLen];
255 ASDCP_NO_COPY_CONSTRUCT(h__HMACContext);
258 byte_t m_SHAValue[HMAC_SIZE];
261 h__HMACContext() : m_Final(false) {}
264 // SMPTE 429.6 MIC key generation
265 void SetKey(const byte_t* key)
267 byte_t rng_buf[SHA_DIGEST_LENGTH*2];
268 Kumu::Gen_FIPS_186_Value(key, KeyLen, rng_buf, SHA_DIGEST_LENGTH*2);
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);
276 // MXF Interop MIC key generation
277 void SetInteropKey(const byte_t* key)
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];
283 // 7.10: MICKey = trunc( SHA1 ( key, key_nonce ) )
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);
297 byte_t xor_buf[B_len];
298 memset(xor_buf, 0, B_len);
299 memcpy(xor_buf, m_key, KeyLen);
301 memset(m_SHAValue, 0, HMAC_SIZE);
305 // H(K XOR opad, H(K XOR ipad, text))
307 for ( ui32_t i = 0; i < B_len; i++ )
308 xor_buf[i] ^= ipad_const;
310 SHA1_Update(&m_SHA, xor_buf, B_len);
315 Update(const byte_t* buf, ui32_t buf_len)
317 // H(K XOR opad, H(K XOR ipad, text))
319 SHA1_Update(&m_SHA, buf, buf_len);
329 byte_t xor_buf[B_len];
330 memset(xor_buf, 0, B_len);
331 memcpy(xor_buf, m_key, KeyLen);
335 // H(K XOR opad, H(K XOR ipad, text))
337 for ( ui32_t i = 0; i < B_len; i++ )
338 xor_buf[i] ^= opad_const;
340 SHA1_Update(&SHA, xor_buf, B_len);
342 // H(K XOR opad, H(K XOR ipad, text))
344 SHA1_Final(m_SHAValue, &m_SHA);
345 SHA1_Update(&SHA, m_SHAValue, HMAC_SIZE);
347 // H(K XOR opad, H(K XOR ipad, text))
349 SHA1_Final(m_SHAValue, &SHA);
355 HMACContext::HMACContext()
359 HMACContext::~HMACContext()
366 HMACContext::InitKey(const byte_t* key, LabelSet_t SetType)
370 m_Context = new h__HMACContext;
374 case LS_MXF_INTEROP: m_Context->SetInteropKey(key); break;
375 case LS_MXF_SMPTE: m_Context->SetKey(key); break;
389 if ( ! m_Context.empty() )
396 HMACContext::Update(const byte_t* buf, ui32_t buf_len)
400 if ( m_Context.empty() || m_Context->m_Final )
403 m_Context->Update(buf, buf_len);
410 HMACContext::Finalize()
412 if ( m_Context.empty() || m_Context->m_Final )
415 m_Context->Finalize();
422 HMACContext::GetHMACValue(byte_t* buf) const
426 if ( m_Context.empty() || ! m_Context->m_Final )
429 memcpy(buf, m_Context->m_SHAValue, HMAC_SIZE);
436 HMACContext::TestHMACValue(const byte_t* buf) const
440 if ( m_Context.empty() || ! m_Context->m_Final )
443 return ( memcmp(buf, m_Context->m_SHAValue, HMAC_SIZE) == 0 ) ? RESULT_OK : RESULT_HMACFAIL;
449 // end AS_DCP_AES.cpp