Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <string> | 5 #include <string> |
| 6 | 6 |
| 7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 8 #include "media/base/decoder_buffer.h" | 8 #include "media/base/decoder_buffer.h" |
| 9 #include "media/base/decrypt_config.h" | 9 #include "media/base/decrypt_config.h" |
| 10 #include "media/base/mock_filters.h" | 10 #include "media/base/mock_filters.h" |
| 11 #include "media/crypto/aes_decryptor.h" | 11 #include "media/crypto/aes_decryptor.h" |
| 12 #include "testing/gtest/include/gtest/gtest.h" | 12 #include "testing/gtest/include/gtest/gtest.h" |
| 13 | 13 |
| 14 using ::testing::_; | 14 using ::testing::_; |
| 15 using ::testing::Gt; | 15 using ::testing::Gt; |
| 16 using ::testing::NotNull; | 16 using ::testing::NotNull; |
| 17 using ::testing::SaveArg; | 17 using ::testing::SaveArg; |
| 18 using ::testing::StrNe; | 18 using ::testing::StrNe; |
| 19 | 19 |
| 20 namespace media { | 20 namespace media { |
| 21 | 21 |
| 22 static const char kClearKeySystem[] = "org.w3.clearkey"; | 22 static const char kClearKeySystem[] = "org.w3.clearkey"; |
| 23 static const uint8 kInitData[] = { 0x69, 0x6e, 0x69, 0x74 }; | 23 static const uint8 kInitData[] = { 0x69, 0x6e, 0x69, 0x74 }; |
| 24 // |kEncryptedData| is encrypted from |kOriginalData| using |kRightKey|. | |
| 25 // Modifying any of these independently would fail the test. | |
| 26 static const uint8 kOriginalData[] = { | 24 static const uint8 kOriginalData[] = { |
| 27 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, | 25 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, |
| 28 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e | 26 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x20, 0x33, |
| 27 0x30, 0x20, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, | |
| 28 0x6f, 0x66, 0x20, 0x69, 0x74, 0x2e | |
| 29 }; | 29 }; |
| 30 static const uint8 kEncryptedData[] = { | 30 |
| 31 0x82, 0x3A, 0x76, 0x92, 0xEC, 0x7F, 0xF8, 0x85, | 31 // |kCbcEncryptedData| is |kOriginalData| encrypted with |kRightKey| and the |
| 32 0xEC, 0x23, 0x52, 0xFB, 0x19, 0xB1, 0xB9, 0x09 | 32 // default IV embedded in aes_decryptor.cc. |
| 33 // | |
| 34 // TODO(strobe): CBC is only used for an early draft of WebM encryption. | |
| 35 // Remove when https://chromiumcodereview.appspot.com/10535029 lands. | |
| 36 static const uint8 kCbcEncryptedData[] = { | |
| 37 0x16, 0xeb, 0x06, 0xf8, 0x99, 0x87, 0xce, 0x09, | |
| 38 0x0e, 0x91, 0x5a, 0xa3, 0x88, 0xc3, 0x5b, 0xf5, | |
| 39 0xe9, 0xac, 0x40, 0x53, 0x95, 0x85, 0x5f, 0x09, | |
| 40 0x3d, 0xa0, 0x4f, 0xbe, 0x66, 0xf5, 0x15, 0xb5 | |
| 33 }; | 41 }; |
| 42 | |
| 43 // |kCtrEncryptedData| is |kOriginalData| encrypted with |kRightKey|, using | |
| 44 // initial counter |kInitialIv|. | |
| 45 static const uint8 kCtrEncryptedData[] = { | |
| 46 0x06, 0x53, 0x1d, 0x16, 0x67, 0xd4, 0x2d, 0x5c, | |
| 47 0xa8, 0xba, 0x3b, 0x82, 0xc4, 0xdc, 0x14, 0x89, | |
| 48 0xea, 0x2e, 0x8c, 0x64, 0x4c, 0x4b, 0x6b, 0xda, | |
| 49 0x39, 0xbb, 0xe8, 0xc1, 0x25, 0x35 | |
| 50 }; | |
| 51 | |
| 52 // |kCtrSubsampleEncryptedData| is |kOriginalData|, subsampled according to | |
| 53 // |kSubsamples|, with ciphered portions encrypted with |kRightKey|, using | |
| 54 // initial counter |kInitialIv|. | |
| 55 static const uint8 kCtrSubsampleEncryptedData[] = { | |
| 56 0x4f, 0x72, 0x69, 0x2e, 0x48, 0x1a, 0x10, 0x62, | |
| 57 0x20, 0xde, 0x2d, 0x44, 0xe9, 0xf0, 0x7a, 0xc5, | |
| 58 0x95, 0xd2, 0x56, 0xc3, 0xae, 0x6b, 0x9d, 0x3d, | |
| 59 0x57, 0x48, 0x38, 0x93, 0x74, 0x2e | |
| 60 }; | |
| 61 | |
| 34 static const uint8 kRightKey[] = { | 62 static const uint8 kRightKey[] = { |
| 35 0x41, 0x20, 0x77, 0x6f, 0x6e, 0x64, 0x65, 0x72, | 63 0x41, 0x20, 0x77, 0x6f, 0x6e, 0x64, 0x65, 0x72, |
| 36 0x66, 0x75, 0x6c, 0x20, 0x6b, 0x65, 0x79, 0x21 | 64 0x66, 0x75, 0x6c, 0x20, 0x6b, 0x65, 0x79, 0x21 |
| 37 }; | 65 }; |
| 38 static const uint8 kWrongKey[] = { | 66 static const uint8 kWrongKey[] = { |
| 39 0x49, 0x27, 0x6d, 0x20, 0x61, 0x20, 0x77, 0x72, | 67 0x49, 0x27, 0x6d, 0x20, 0x61, 0x20, 0x77, 0x72, |
| 40 0x6f, 0x6e, 0x67, 0x20, 0x6b, 0x65, 0x79, 0x2e | 68 0x6f, 0x6e, 0x67, 0x20, 0x6b, 0x65, 0x79, 0x2e |
| 41 }; | 69 }; |
| 42 static const uint8 kWrongSizedKey[] = { 0x20, 0x20 }; | 70 static const uint8 kWrongSizedKey[] = { 0x20, 0x20 }; |
| 43 static const uint8 kKeyId1[] = { | 71 static const uint8 kKeyId1[] = { |
| 44 0x4b, 0x65, 0x79, 0x20, 0x49, 0x44, 0x20, 0x31 | 72 0x4b, 0x65, 0x79, 0x20, 0x49, 0x44, 0x20, 0x31 |
| 45 }; | 73 }; |
| 46 static const uint8 kKeyId2[] = { | 74 static const uint8 kKeyId2[] = { |
| 47 0x4b, 0x65, 0x79, 0x20, 0x49, 0x44, 0x20, 0x32 | 75 0x4b, 0x65, 0x79, 0x20, 0x49, 0x44, 0x20, 0x32 |
| 48 }; | 76 }; |
| 77 static const uint8 kInitialIv[] = { | |
| 78 0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x56, 0x31, | |
| 79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |
| 80 }; | |
| 81 static const SubsampleEntry kSubsamples[] = { | |
| 82 { 3, 5 }, | |
| 83 { 1, 19 }, | |
| 84 { 2, 0 } | |
| 85 }; | |
| 49 | 86 |
| 50 class AesDecryptorTest : public testing::Test { | 87 class AesDecryptorTest : public testing::Test { |
| 51 public: | 88 public: |
| 52 AesDecryptorTest() : decryptor_(&client_) { | 89 AesDecryptorTest() : decryptor_(&client_) {} |
| 53 encrypted_data_ = DecoderBuffer::CopyFrom(kEncryptedData, | 90 |
| 54 arraysize(kEncryptedData)); | 91 protected: |
| 92 void InitCbc() { | |
| 93 encrypted_data_ = DecoderBuffer::CopyFrom( | |
| 94 kCbcEncryptedData, arraysize(kCbcEncryptedData)); | |
| 95 encrypted_data_->SetDecryptConfig( | |
| 96 scoped_ptr<DecryptConfig>(new DecryptConfig( | |
| 97 kKeyId1, arraysize(kKeyId1)))); | |
| 55 } | 98 } |
| 56 | 99 |
| 57 protected: | 100 void InitCtr() { |
| 101 encrypted_data_ = DecoderBuffer::CopyFrom( | |
| 102 kCtrEncryptedData, arraysize(kCtrEncryptedData)); | |
| 103 encrypted_data_->SetDecryptConfig( | |
| 104 scoped_ptr<DecryptConfig>(new DecryptConfig( | |
| 105 kKeyId1, arraysize(kKeyId1), | |
| 106 std::string(kInitialIv, kInitialIv + arraysize(kInitialIv)), | |
|
ddorwin
2012/07/17 01:14:21
Why not just size as the second parameter?
strobe_
2012/07/19 02:43:35
Would require typecasting.
ddorwin
2012/07/19 06:11:10
Just curious: to what?
strobe_
2012/07/19 16:55:02
uint8 to int8.
ddorwin
2012/07/24 01:00:09
The first parameter? uint8* to char*?
So, it would
strobe_
2012/07/25 01:05:13
Will get this in next bundle since it touches many
| |
| 107 std::vector<SubsampleEntry>()))); | |
| 108 } | |
| 109 | |
| 110 void InitCtrSubsample() { | |
| 111 encrypted_data_ = DecoderBuffer::CopyFrom( | |
| 112 kCtrSubsampleEncryptedData, arraysize(kCtrSubsampleEncryptedData)); | |
| 113 std::vector<SubsampleEntry> subsamples( | |
| 114 kSubsamples, kSubsamples + arraysize(kSubsamples)); | |
| 115 encrypted_data_->SetDecryptConfig( | |
| 116 scoped_ptr<DecryptConfig>(new DecryptConfig( | |
| 117 kKeyId1, arraysize(kKeyId1), | |
| 118 std::string(kInitialIv, kInitialIv + arraysize(kInitialIv)), | |
| 119 subsamples))); | |
| 120 } | |
| 121 | |
| 58 void GenerateKeyRequest() { | 122 void GenerateKeyRequest() { |
| 59 EXPECT_CALL(client_, KeyMessageMock(kClearKeySystem, StrNe(std::string()), | 123 EXPECT_CALL(client_, KeyMessageMock(kClearKeySystem, StrNe(std::string()), |
| 60 NotNull(), Gt(0), "")) | 124 NotNull(), Gt(0), "")) |
| 61 .WillOnce(SaveArg<1>(&session_id_string_)); | 125 .WillOnce(SaveArg<1>(&session_id_string_)); |
| 62 decryptor_.GenerateKeyRequest(kClearKeySystem, | 126 decryptor_.GenerateKeyRequest(kClearKeySystem, |
| 63 kInitData, arraysize(kInitData)); | 127 kInitData, arraysize(kInitData)); |
| 64 } | 128 } |
| 65 | 129 |
| 66 template <int KeyIdSize, int KeySize> | 130 template <int KeyIdSize, int KeySize> |
| 67 void AddKeyAndExpectToSucceed(const uint8 (&key_id)[KeyIdSize], | 131 void AddKeyAndExpectToSucceed(const uint8 (&key_id)[KeyIdSize], |
| 68 const uint8 (&key)[KeySize]) { | 132 const uint8 (&key)[KeySize]) { |
| 69 EXPECT_CALL(client_, KeyAdded(kClearKeySystem, session_id_string_)); | 133 EXPECT_CALL(client_, KeyAdded(kClearKeySystem, session_id_string_)); |
| 70 decryptor_.AddKey(kClearKeySystem, key, KeySize, key_id, KeyIdSize, | 134 decryptor_.AddKey(kClearKeySystem, key, KeySize, key_id, KeyIdSize, |
| 71 session_id_string_); | 135 session_id_string_); |
| 72 } | 136 } |
| 73 | 137 |
| 74 template <int KeyIdSize, int KeySize> | 138 template <int KeyIdSize, int KeySize> |
| 75 void AddKeyAndExpectToFail(const uint8 (&key_id)[KeyIdSize], | 139 void AddKeyAndExpectToFail(const uint8 (&key_id)[KeyIdSize], |
| 76 const uint8 (&key)[KeySize]) { | 140 const uint8 (&key)[KeySize]) { |
| 77 EXPECT_CALL(client_, KeyError(kClearKeySystem, session_id_string_, | 141 EXPECT_CALL(client_, KeyError(kClearKeySystem, session_id_string_, |
| 78 Decryptor::kUnknownError, 0)); | 142 Decryptor::kUnknownError, 0)); |
| 79 decryptor_.AddKey(kClearKeySystem, key, KeySize, key_id, KeyIdSize, | 143 decryptor_.AddKey(kClearKeySystem, key, KeySize, key_id, KeyIdSize, |
| 80 session_id_string_); | 144 session_id_string_); |
| 81 } | 145 } |
| 82 | 146 |
| 83 template <int KeyIdSize> | |
| 84 void SetKeyIdForEncryptedData(const uint8 (&key_id)[KeyIdSize]) { | |
| 85 encrypted_data_->SetDecryptConfig( | |
| 86 scoped_ptr<DecryptConfig>(new DecryptConfig(key_id, KeyIdSize))); | |
| 87 } | |
| 88 | |
| 89 void DecryptAndExpectToSucceed() { | 147 void DecryptAndExpectToSucceed() { |
| 90 scoped_refptr<DecoderBuffer> decrypted = | 148 scoped_refptr<DecoderBuffer> decrypted = |
| 91 decryptor_.Decrypt(encrypted_data_); | 149 decryptor_.Decrypt(encrypted_data_); |
| 92 ASSERT_TRUE(decrypted); | 150 ASSERT_TRUE(decrypted); |
| 93 int data_length = sizeof(kOriginalData); | 151 int data_length = sizeof(kOriginalData); |
| 94 ASSERT_EQ(data_length, decrypted->GetDataSize()); | 152 ASSERT_EQ(data_length, decrypted->GetDataSize()); |
| 95 EXPECT_EQ(0, memcmp(kOriginalData, decrypted->GetData(), data_length)); | 153 EXPECT_EQ(0, memcmp(kOriginalData, decrypted->GetData(), data_length)); |
| 96 } | 154 } |
| 97 | 155 |
| 156 // This function depends on PKCS#5 verification, which is only performed by | |
| 157 // CBC. | |
| 158 // TODO(strobe): Remove along with CBC. | |
| 98 void DecryptAndExpectToFail() { | 159 void DecryptAndExpectToFail() { |
| 99 scoped_refptr<DecoderBuffer> decrypted = | 160 scoped_refptr<DecoderBuffer> decrypted = |
| 100 decryptor_.Decrypt(encrypted_data_); | 161 decryptor_.Decrypt(encrypted_data_); |
| 101 EXPECT_FALSE(decrypted); | 162 ASSERT_FALSE(decrypted); |
| 163 } | |
| 164 | |
| 165 void DecryptAndExpectIncorrectData() { | |
| 166 scoped_refptr<DecoderBuffer> decrypted = | |
| 167 decryptor_.Decrypt(encrypted_data_); | |
| 168 ASSERT_TRUE(decrypted); | |
| 169 int data_length = sizeof(kOriginalData); | |
| 170 ASSERT_EQ(data_length, decrypted->GetDataSize()); | |
| 171 EXPECT_NE(0, memcmp(kOriginalData, decrypted->GetData(), data_length)); | |
| 102 } | 172 } |
| 103 | 173 |
| 104 scoped_refptr<DecoderBuffer> encrypted_data_; | 174 scoped_refptr<DecoderBuffer> encrypted_data_; |
| 105 MockDecryptorClient client_; | 175 MockDecryptorClient client_; |
| 106 AesDecryptor decryptor_; | 176 AesDecryptor decryptor_; |
| 107 std::string session_id_string_; | 177 std::string session_id_string_; |
| 108 }; | 178 }; |
| 109 | 179 |
| 110 TEST_F(AesDecryptorTest, NormalDecryption) { | 180 TEST_F(AesDecryptorTest, NormalDecryption) { |
| 181 InitCtr(); | |
|
ddorwin
2012/07/17 01:14:21
Skipping. Will review after rebase.
| |
| 111 GenerateKeyRequest(); | 182 GenerateKeyRequest(); |
| 112 AddKeyAndExpectToSucceed(kKeyId1, kRightKey); | 183 AddKeyAndExpectToSucceed(kKeyId1, kRightKey); |
| 113 SetKeyIdForEncryptedData(kKeyId1); | |
| 114 ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed()); | 184 ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed()); |
| 115 } | 185 } |
| 116 | 186 |
| 187 TEST_F(AesDecryptorTest, NormalCbcDecryption) { | |
| 188 InitCbc(); | |
| 189 GenerateKeyRequest(); | |
| 190 AddKeyAndExpectToSucceed(kKeyId1, kRightKey); | |
| 191 ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed()); | |
| 192 } | |
| 193 | |
| 194 TEST_F(AesDecryptorTest, NormalCtrSubsampleDecryption) { | |
| 195 InitCtrSubsample(); | |
| 196 GenerateKeyRequest(); | |
| 197 AddKeyAndExpectToSucceed(kKeyId1, kRightKey); | |
| 198 ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed()); | |
| 199 } | |
| 200 | |
| 201 TEST_F(AesDecryptorTest, WrongSubsampleSize) { | |
| 202 InitCtrSubsample(); | |
| 203 const DecryptConfig& config = *encrypted_data_->GetDecryptConfig(); | |
| 204 std::vector<SubsampleEntry> subsamples = config.subsamples(); | |
| 205 subsamples[0].clear_bytes += 2; | |
| 206 encrypted_data_->SetDecryptConfig( | |
| 207 scoped_ptr<DecryptConfig>(new DecryptConfig( | |
| 208 config.key_id(), config.key_id_size(), | |
| 209 config.iv(), subsamples))); | |
| 210 GenerateKeyRequest(); | |
| 211 AddKeyAndExpectToSucceed(kKeyId1, kRightKey); | |
| 212 ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToFail()); | |
| 213 } | |
| 214 | |
| 117 TEST_F(AesDecryptorTest, WrongKey) { | 215 TEST_F(AesDecryptorTest, WrongKey) { |
| 216 InitCtr(); | |
| 118 GenerateKeyRequest(); | 217 GenerateKeyRequest(); |
| 119 AddKeyAndExpectToSucceed(kKeyId1, kWrongKey); | 218 AddKeyAndExpectToSucceed(kKeyId1, kWrongKey); |
| 120 SetKeyIdForEncryptedData(kKeyId1); | 219 ASSERT_NO_FATAL_FAILURE(DecryptAndExpectIncorrectData()); |
| 220 } | |
| 221 | |
| 222 // This test relies on CBC verification of PKCS#5 padding, which CTR mode does | |
| 223 // not expect or verify. | |
| 224 // TODO(strobe): Remove along with CBC. | |
| 225 TEST_F(AesDecryptorTest, WrongCbcKey) { | |
| 226 InitCbc(); | |
| 227 GenerateKeyRequest(); | |
| 228 AddKeyAndExpectToSucceed(kKeyId1, kWrongKey); | |
| 121 ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToFail()); | 229 ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToFail()); |
| 122 } | 230 } |
| 123 | 231 |
| 124 TEST_F(AesDecryptorTest, MultipleKeys) { | 232 TEST_F(AesDecryptorTest, MultipleKeys) { |
| 233 InitCtr(); | |
| 125 GenerateKeyRequest(); | 234 GenerateKeyRequest(); |
| 126 AddKeyAndExpectToSucceed(kKeyId1, kRightKey); | 235 AddKeyAndExpectToSucceed(kKeyId1, kRightKey); |
| 127 AddKeyAndExpectToSucceed(kKeyId2, kWrongKey); | 236 AddKeyAndExpectToSucceed(kKeyId2, kWrongKey); |
| 128 SetKeyIdForEncryptedData(kKeyId1); | |
| 129 ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed()); | 237 ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed()); |
| 130 } | 238 } |
| 131 | 239 |
| 132 TEST_F(AesDecryptorTest, KeyReplacement) { | 240 TEST_F(AesDecryptorTest, KeyReplacement) { |
| 241 InitCtr(); | |
| 133 GenerateKeyRequest(); | 242 GenerateKeyRequest(); |
| 134 SetKeyIdForEncryptedData(kKeyId1); | |
| 135 AddKeyAndExpectToSucceed(kKeyId1, kWrongKey); | 243 AddKeyAndExpectToSucceed(kKeyId1, kWrongKey); |
| 136 ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToFail()); | 244 ASSERT_NO_FATAL_FAILURE(DecryptAndExpectIncorrectData()); |
| 137 AddKeyAndExpectToSucceed(kKeyId1, kRightKey); | 245 AddKeyAndExpectToSucceed(kKeyId1, kRightKey); |
| 138 ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed()); | 246 ASSERT_NO_FATAL_FAILURE(DecryptAndExpectToSucceed()); |
| 139 } | 247 } |
| 140 | 248 |
| 141 TEST_F(AesDecryptorTest, WrongSizedKey) { | 249 TEST_F(AesDecryptorTest, WrongSizedKey) { |
| 250 InitCtr(); | |
| 142 GenerateKeyRequest(); | 251 GenerateKeyRequest(); |
| 143 AddKeyAndExpectToFail(kKeyId1, kWrongSizedKey); | 252 AddKeyAndExpectToFail(kKeyId1, kWrongSizedKey); |
| 144 } | 253 } |
| 145 | 254 |
| 146 } // media | 255 } // media |
| OLD | NEW |