- /*
- * Copyright (c) 2005 Gilles Boccon-Gibod
- */
- /*----------------------------------------------------------------------
- | includes
- +---------------------------------------------------------------------*/
- #include "Ap4StreamCipher.h"
- /*----------------------------------------------------------------------
- | AP4_StreamCipher::AP4_StreamCipher
- +---------------------------------------------------------------------*/
- AP4_StreamCipher::AP4_StreamCipher(const AP4_UI08* key,
- const AP4_UI08* salt,
- AP4_Size iv_size) :
- m_StreamOffset(0),
- m_IvSize(iv_size),
- m_BlockCipher(NULL)
- {
- // clamp the IV size to the max supported size
- if (iv_size > 4) {
- m_IvSize = 4;
- }
- // set the initial state
- Reset(key, salt);
- }
- /*----------------------------------------------------------------------
- | AP4_StreamCipher::~AP4_StreamCipher
- +---------------------------------------------------------------------*/
- AP4_StreamCipher::~AP4_StreamCipher()
- {
- // delete the block cipher
- if (m_BlockCipher) {
- delete m_BlockCipher;
- }
- }
- /*----------------------------------------------------------------------
- | AP4_StreamCipher::Reset
- +---------------------------------------------------------------------*/
- AP4_Result
- AP4_StreamCipher::Reset(const AP4_UI08* key, const AP4_UI08* salt)
- {
- if (salt) {
- // initialize the counter with a salting key
- for (AP4_UI32 i=0; i<AP4_AES_BLOCK_SIZE; i++) {
- m_CBlock[i] = salt[i];
- }
- } else {
- // initialize the counter with no salting key
- for (AP4_UI32 i = 0; i < AP4_AES_BLOCK_SIZE; i++) {
- m_CBlock[i] = 0;
- }
- }
- // (re)create the block cipher
- if (key != NULL) {
- // delete the block cipher if needed
- if (m_BlockCipher) {
- delete m_BlockCipher;
- }
- // (re)create one
- m_BlockCipher = new AP4_AesBlockCipher(key);
- }
- // reset the stream offset
- SetStreamOffset(0);
- return AP4_SUCCESS;
- }
- /*----------------------------------------------------------------------
- | AP4_StreamCipher::SetCounter
- +---------------------------------------------------------------------*/
- void
- AP4_StreamCipher::SetCounter(AP4_Offset block_offset)
- {
- // set the counter bytes
- for (AP4_UI32 i = 0; i < m_IvSize; i++) {
- m_CBlock[AP4_AES_BLOCK_SIZE-1-i] =
- (AP4_UI08)((block_offset>>(8*i)) & 0xFF);
- }
- }
- /*----------------------------------------------------------------------
- | AP4_StreamCipher::SetStreamOffset
- +---------------------------------------------------------------------*/
- AP4_Result
- AP4_StreamCipher::SetStreamOffset(AP4_Offset offset)
- {
- // do nothing if we're already at that offset
- if (offset == m_StreamOffset) return AP4_SUCCESS;
- // update the offset
- m_StreamOffset = offset;
- // update the key stream if necessary
- if (m_StreamOffset & 0xF) {
- return UpdateKeyStream(m_StreamOffset/AP4_AES_BLOCK_SIZE);
- }
- return AP4_SUCCESS;
- }
- /*----------------------------------------------------------------------
- | AP4_StreamCipher::UpdateKeyStream
- +---------------------------------------------------------------------*/
- AP4_Result
- AP4_StreamCipher::UpdateKeyStream(AP4_Offset block_offset)
- {
- // compute the new counter
- SetCounter(block_offset);
- // compute the key block (x) from the counter block (c)
- return m_BlockCipher->EncryptBlock(m_CBlock, m_XBlock);
- }
- /*----------------------------------------------------------------------
- | AP4_StreamCipher::ProcessBuffer
- +---------------------------------------------------------------------*/
- AP4_Result
- AP4_StreamCipher::ProcessBuffer(const AP4_UI08* in,
- AP4_UI08* out,
- AP4_Size size)
- {
- if (m_BlockCipher == NULL) return AP4_ERROR_INVALID_STATE;
- while (size) {
- // compute the number of bytes available in this chunk
- AP4_UI32 index = m_StreamOffset & (AP4_AES_BLOCK_SIZE-1);
- AP4_UI32 chunk;
- // update the key stream if we are on a boundary
- if (index == 0) {
- UpdateKeyStream(m_StreamOffset/AP4_AES_BLOCK_SIZE);
- chunk = AP4_AES_BLOCK_SIZE;
- }
- // compute the number of bytes remaining in the chunk
- chunk = AP4_AES_BLOCK_SIZE - index;
- if (chunk > size) chunk = size;
- // encrypt/decrypt the chunk
- AP4_UI08* x = &m_XBlock[index];
- for (AP4_UI32 i = 0; i < chunk; i++) {
- *out++ = *in++ ^ *x++;
- }
- // update offset and size
- m_StreamOffset += chunk;
- size -= chunk;
- }
- return AP4_SUCCESS;
- }