Implement AesPatternCryptor for pattern encryption/decryption
Issue #78 Change-Id: If0fadf6f83ef67dd39af29080bab6ed71fb35290
This commit is contained in:
parent
2adaf1712d
commit
1d74988159
|
@ -0,0 +1,84 @@
|
|||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#include "packager/media/base/aes_pattern_cryptor.h"
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <algorithm>
|
||||
#include "packager/base/logging.h"
|
||||
|
||||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
AesPatternCryptor::AesPatternCryptor(uint8_t crypt_byte_block,
|
||||
uint8_t skip_byte_block,
|
||||
ConstantIvFlag constant_iv_flag,
|
||||
scoped_ptr<AesCryptor> cryptor)
|
||||
: crypt_byte_block_(crypt_byte_block),
|
||||
skip_byte_block_(skip_byte_block),
|
||||
constant_iv_flag_(constant_iv_flag),
|
||||
cryptor_(cryptor.Pass()) {
|
||||
DCHECK(cryptor_);
|
||||
}
|
||||
|
||||
AesPatternCryptor::~AesPatternCryptor() {}
|
||||
|
||||
bool AesPatternCryptor::InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv) {
|
||||
iv_ = iv;
|
||||
return cryptor_->InitializeWithIv(key, iv);
|
||||
}
|
||||
|
||||
bool AesPatternCryptor::SetIv(const std::vector<uint8_t>& iv) {
|
||||
iv_ = iv;
|
||||
return cryptor_->SetIv(iv);
|
||||
}
|
||||
|
||||
void AesPatternCryptor::UpdateIv() {
|
||||
cryptor_->UpdateIv();
|
||||
}
|
||||
|
||||
bool AesPatternCryptor::CryptInternal(const uint8_t* text,
|
||||
size_t text_size,
|
||||
uint8_t* crypt_text,
|
||||
size_t* crypt_text_size) {
|
||||
if (constant_iv_flag_ == AesPatternCryptor::kUseConstantIv)
|
||||
CHECK(SetIv(iv_));
|
||||
|
||||
// |crypt_text_size| is always the same as |text_size| for pattern encryption.
|
||||
if (*crypt_text_size < text_size) {
|
||||
LOG(ERROR) << "Expecting output size of at least " << text_size
|
||||
<< " bytes.";
|
||||
return false;
|
||||
}
|
||||
*crypt_text_size = text_size;
|
||||
|
||||
while (text_size > 0) {
|
||||
const size_t crypt_byte_size = crypt_byte_block_ * AES_BLOCK_SIZE;
|
||||
if (text_size >= crypt_byte_size) {
|
||||
if (!cryptor_->Crypt(text, crypt_byte_size, crypt_text))
|
||||
return false;
|
||||
} else {
|
||||
// If there is not enough data, just keep it in clear.
|
||||
memcpy(crypt_text, text, text_size);
|
||||
return true;
|
||||
}
|
||||
text += crypt_byte_size;
|
||||
text_size -= crypt_byte_size;
|
||||
crypt_text += crypt_byte_size;
|
||||
|
||||
const size_t skip_byte_size = std::min(
|
||||
static_cast<size_t>(skip_byte_block_ * AES_BLOCK_SIZE), text_size);
|
||||
memcpy(crypt_text, text, skip_byte_size);
|
||||
text += skip_byte_size;
|
||||
text_size -= skip_byte_size;
|
||||
crypt_text += skip_byte_size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#include "packager/media/base/aes_cryptor.h"
|
||||
|
||||
#include "packager/base/macros.h"
|
||||
#include "packager/base/memory/scoped_ptr.h"
|
||||
|
||||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
/// Implements pattern-based encryption/decryption.
|
||||
class AesPatternCryptor : public AesCryptor {
|
||||
public:
|
||||
enum ConstantIvFlag {
|
||||
kUseConstantIv,
|
||||
kDontUseConstantIv,
|
||||
};
|
||||
|
||||
/// @param crypt_byte_block indicates number of encrypted blocks (16-byte) in
|
||||
/// pattern based encryption.
|
||||
/// @param skip_byte_block indicates number of unencrypted blocks (16-byte)
|
||||
/// in pattern based encryption.
|
||||
/// @param constant_iv_flag indicates whether a constant iv is used,
|
||||
/// kUseConstantIv means that the same iv is used for all Crypt calls
|
||||
/// until iv is changed via SetIv; otherwise, iv can be incremented
|
||||
/// (for counter mode) or chained (for cipher block chaining mode)
|
||||
/// internally inside Crypt call, i.e. iv will be updated across Crypt
|
||||
/// calls.
|
||||
/// @param cryptor points to an AesCryptor instance which performs the actual
|
||||
/// encryption/decryption.
|
||||
AesPatternCryptor(uint8_t crypt_byte_block,
|
||||
uint8_t skip_byte_block,
|
||||
ConstantIvFlag constant_iv_flag,
|
||||
scoped_ptr<AesCryptor> cryptor);
|
||||
~AesPatternCryptor() override;
|
||||
|
||||
/// @name AesCryptor implementation overrides.
|
||||
/// @{
|
||||
bool InitializeWithIv(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv) override;
|
||||
bool SetIv(const std::vector<uint8_t>& iv) override;
|
||||
void UpdateIv() override;
|
||||
/// @}
|
||||
|
||||
protected:
|
||||
bool CryptInternal(const uint8_t* text,
|
||||
size_t text_size,
|
||||
uint8_t* crypt_text,
|
||||
size_t* crypt_text_size) override;
|
||||
|
||||
private:
|
||||
const uint8_t crypt_byte_block_;
|
||||
const uint8_t skip_byte_block_;
|
||||
const ConstantIvFlag constant_iv_flag_;
|
||||
scoped_ptr<AesCryptor> cryptor_;
|
||||
std::vector<uint8_t> iv_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AesPatternCryptor);
|
||||
};
|
||||
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
|
@ -0,0 +1,178 @@
|
|||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "packager/base/strings/string_number_conversions.h"
|
||||
#include "packager/media/base/aes_pattern_cryptor.h"
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::Invoke;
|
||||
using ::testing::Return;
|
||||
|
||||
namespace {
|
||||
const uint8_t kCryptByteBlock = 2u;
|
||||
const uint8_t kSkipByteBlock = 1u;
|
||||
} // namespace
|
||||
|
||||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
class MockAesCryptor : public AesCryptor {
|
||||
public:
|
||||
MOCK_METHOD2(InitializeWithIv,
|
||||
bool(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& iv));
|
||||
MOCK_METHOD1(SetIv, bool(const std::vector<uint8_t>& iv));
|
||||
MOCK_METHOD0(UpdateIv, void());
|
||||
MOCK_METHOD4(CryptInternal,
|
||||
bool(const uint8_t* text,
|
||||
size_t text_size,
|
||||
uint8_t* crypt_text,
|
||||
size_t* crypt_text_size));
|
||||
};
|
||||
|
||||
class AesPatternCryptorTest : public ::testing::Test {
|
||||
public:
|
||||
AesPatternCryptorTest()
|
||||
: mock_cryptor_(new MockAesCryptor),
|
||||
pattern_cryptor_(kCryptByteBlock,
|
||||
kSkipByteBlock,
|
||||
AesPatternCryptor::kDontUseConstantIv,
|
||||
scoped_ptr<MockAesCryptor>(mock_cryptor_)) {}
|
||||
|
||||
protected:
|
||||
MockAesCryptor* mock_cryptor_;
|
||||
AesPatternCryptor pattern_cryptor_;
|
||||
};
|
||||
|
||||
TEST_F(AesPatternCryptorTest, InitializeWithIv) {
|
||||
std::vector<uint8_t> key(16, 'k');
|
||||
std::vector<uint8_t> iv(8, 'i');
|
||||
EXPECT_CALL(*mock_cryptor_, InitializeWithIv(key, iv)).WillOnce(Return(true));
|
||||
EXPECT_TRUE(pattern_cryptor_.InitializeWithIv(key, iv));
|
||||
}
|
||||
|
||||
TEST_F(AesPatternCryptorTest, UpdateIv) {
|
||||
EXPECT_CALL(*mock_cryptor_, UpdateIv());
|
||||
pattern_cryptor_.UpdateIv();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct PatternTestCase {
|
||||
const char* text_hex;
|
||||
const char* expected_crypt_text_hex;
|
||||
};
|
||||
|
||||
const PatternTestCase kPatternTestCases[] = {
|
||||
// Empty.
|
||||
{"", ""},
|
||||
// One partial block (not encrypted).
|
||||
{"010203", "010203"},
|
||||
// One block (not encrypted).
|
||||
{"01020304050607080910111213141516", "01020304050607080910111213141516"},
|
||||
// One block + partial block (not encrypted).
|
||||
{"010203040506070809101112131415161718",
|
||||
"010203040506070809101112131415161718"},
|
||||
// Two blocks (encrypted) - the mock encryptor adds every byte by 0x10.
|
||||
{"0102030405060708091011121314151617181920212223242526272829303132",
|
||||
"1112131415161718192021222324252627282930313233343536373839404142"},
|
||||
// Two blocks + partial block (only the first two blocks are encrypted).
|
||||
{"0102030405060708091011121314151617181920212223242526272829303132"
|
||||
"333435363738",
|
||||
"1112131415161718192021222324252627282930313233343536373839404142"
|
||||
"333435363738"},
|
||||
// Seven blocks.
|
||||
{// kCryptByteBlock (2) blocks encrypted.
|
||||
"0102030405060708091011121314151617181920212223242526272829303132"
|
||||
// kSkipByteBlock (1) block not encrypted.
|
||||
"33343536373839404142434445464748"
|
||||
// kCryptByteBlock (2) blocks encrypted.
|
||||
"4950515253545556575859606162636465666768697071727374757677787980"
|
||||
// kSkipByteBlock (1) block not encrypted.
|
||||
"81828384858687888990919293949596"
|
||||
// Less than kCryptByteBlock blocks remaining, so not encrypted.
|
||||
"97989900010203040506070809101112",
|
||||
"1112131415161718192021222324252627282930313233343536373839404142"
|
||||
"33343536373839404142434445464748"
|
||||
"5960616263646566676869707172737475767778798081828384858687888990"
|
||||
"81828384858687888990919293949596"
|
||||
"97989900010203040506070809101112"},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class AesPatternCryptorVerificationTest
|
||||
: public AesPatternCryptorTest,
|
||||
public ::testing::WithParamInterface<PatternTestCase> {};
|
||||
|
||||
TEST_P(AesPatternCryptorVerificationTest, PatternTest) {
|
||||
std::vector<uint8_t> text;
|
||||
std::string text_hex(GetParam().text_hex);
|
||||
if (!text_hex.empty())
|
||||
ASSERT_TRUE(base::HexStringToBytes(text_hex, &text));
|
||||
std::vector<uint8_t> expected_crypt_text;
|
||||
std::string expected_crypt_text_hex(GetParam().expected_crypt_text_hex);
|
||||
if (!expected_crypt_text_hex.empty()) {
|
||||
ASSERT_TRUE(
|
||||
base::HexStringToBytes(expected_crypt_text_hex, &expected_crypt_text));
|
||||
}
|
||||
|
||||
ON_CALL(*mock_cryptor_, CryptInternal(_, _, _, _))
|
||||
.WillByDefault(Invoke([](const uint8_t* text, size_t text_size,
|
||||
uint8_t* crypt_text, size_t* crypt_text_size) {
|
||||
*crypt_text_size = text_size;
|
||||
for (size_t i = 0; i < text_size; ++i) {
|
||||
*crypt_text++ = *text++ + 0x10;
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
|
||||
std::vector<uint8_t> crypt_text;
|
||||
ASSERT_TRUE(pattern_cryptor_.Crypt(text, &crypt_text));
|
||||
EXPECT_EQ(expected_crypt_text, crypt_text);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(PatternTestCases,
|
||||
AesPatternCryptorVerificationTest,
|
||||
::testing::ValuesIn(kPatternTestCases));
|
||||
|
||||
TEST(AesPatternCryptorConstIvTest, UseConstantIv) {
|
||||
MockAesCryptor* mock_cryptor = new MockAesCryptor;
|
||||
AesPatternCryptor pattern_cryptor(kCryptByteBlock, kSkipByteBlock,
|
||||
AesPatternCryptor::kUseConstantIv,
|
||||
scoped_ptr<MockAesCryptor>(mock_cryptor));
|
||||
|
||||
std::vector<uint8_t> iv(8, 'i');
|
||||
// SetIv will be called twice:
|
||||
// once by AesPatternCryptor::SetIv,
|
||||
// once by AesPatternCryptor::Crypt, to make sure the same iv is used.
|
||||
EXPECT_CALL(*mock_cryptor, SetIv(iv)).Times(2).WillRepeatedly(Return(true));
|
||||
EXPECT_TRUE(pattern_cryptor.SetIv(iv));
|
||||
|
||||
std::string crypt_text;
|
||||
ASSERT_TRUE(pattern_cryptor.Crypt("010203", &crypt_text));
|
||||
}
|
||||
|
||||
TEST(AesPatternCryptorConstIvTest, DontUseConstantIv) {
|
||||
MockAesCryptor* mock_cryptor = new MockAesCryptor;
|
||||
AesPatternCryptor pattern_cryptor(kCryptByteBlock, kSkipByteBlock,
|
||||
AesPatternCryptor::kDontUseConstantIv,
|
||||
scoped_ptr<MockAesCryptor>(mock_cryptor));
|
||||
|
||||
std::vector<uint8_t> iv(8, 'i');
|
||||
// SetIv will be called only once by AesPatternCryptor::SetIv.
|
||||
EXPECT_CALL(*mock_cryptor, SetIv(iv)).WillOnce(Return(true));
|
||||
EXPECT_TRUE(pattern_cryptor.SetIv(iv));
|
||||
|
||||
std::string crypt_text;
|
||||
ASSERT_TRUE(pattern_cryptor.Crypt("010203", &crypt_text));
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
|
@ -19,6 +19,8 @@
|
|||
'aes_decryptor.h',
|
||||
'aes_encryptor.cc',
|
||||
'aes_encryptor.h',
|
||||
'aes_pattern_cryptor.cc',
|
||||
'aes_pattern_cryptor.h',
|
||||
'audio_stream_info.cc',
|
||||
'audio_stream_info.h',
|
||||
'audio_timestamp_helper.cc',
|
||||
|
@ -116,6 +118,7 @@
|
|||
'type': '<(gtest_target_type)',
|
||||
'sources': [
|
||||
'aes_cryptor_unittest.cc',
|
||||
'aes_pattern_cryptor_unittest.cc',
|
||||
'audio_timestamp_helper_unittest.cc',
|
||||
'bit_reader_unittest.cc',
|
||||
'buffer_writer_unittest.cc',
|
||||
|
|
Loading…
Reference in New Issue