1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 #include "base/basictypes.h"
10 #include "base/json/json_reader.h"
11 #include "base/values.h"
12 #include "media/base/cdm_callback_promise.h"
13 #include "media/base/cdm_key_information.h"
14 #include "media/base/decoder_buffer.h"
15 #include "media/base/decrypt_config.h"
16 #include "media/base/mock_filters.h"
17 #include "media/cdm/aes_decryptor.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
23 using ::testing::IsNull
;
24 using ::testing::NotNull
;
25 using ::testing::SaveArg
;
26 using ::testing::StrNe
;
27 using ::testing::Unused
;
29 MATCHER(IsEmpty
, "") { return arg
.empty(); }
30 MATCHER(IsNotEmpty
, "") { return !arg
.empty(); }
31 MATCHER(IsJSONDictionary
, "") {
32 std::string
result(arg
.begin(), arg
.end());
33 scoped_ptr
<base::Value
> root(base::JSONReader().ReadToValue(result
));
34 return (root
.get() && root
->GetType() == base::Value::TYPE_DICTIONARY
);
41 const uint8 kOriginalData
[] = "Original subsample data.";
42 const int kOriginalDataSize
= 24;
44 // In the examples below, 'k'(key) has to be 16 bytes, and will always require
45 // 2 bytes of padding. 'kid'(keyid) is variable length, and may require 0, 1,
46 // or 2 bytes of padding.
48 const uint8 kKeyId
[] = {
49 // base64 equivalent is AAECAw
50 0x00, 0x01, 0x02, 0x03
53 // Key is 0x0405060708090a0b0c0d0e0f10111213,
54 // base64 equivalent is BAUGBwgJCgsMDQ4PEBESEw.
55 const char kKeyAsJWK
[] =
60 " \"alg\": \"A128KW\","
61 " \"kid\": \"AAECAw\","
62 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
65 " \"type\": \"temporary\""
68 // Same kid as kKeyAsJWK, key to decrypt kEncryptedData2
69 const char kKeyAlternateAsJWK
[] =
74 " \"alg\": \"A128KW\","
75 " \"kid\": \"AAECAw\","
76 " \"k\": \"FBUWFxgZGhscHR4fICEiIw\""
81 const char kWrongKeyAsJWK
[] =
86 " \"alg\": \"A128KW\","
87 " \"kid\": \"AAECAw\","
88 " \"k\": \"7u7u7u7u7u7u7u7u7u7u7g\""
93 const char kWrongSizedKeyAsJWK
[] =
98 " \"alg\": \"A128KW\","
99 " \"kid\": \"AAECAw\","
105 const uint8 kIv
[] = {
106 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
110 // kOriginalData encrypted with kKey and kIv but without any subsamples (or
111 // equivalently using kSubsampleEntriesCypherOnly).
112 const uint8 kEncryptedData
[] = {
113 0x2f, 0x03, 0x09, 0xef, 0x71, 0xaf, 0x31, 0x16,
114 0xfa, 0x9d, 0x18, 0x43, 0x1e, 0x96, 0x71, 0xb5,
115 0xbf, 0xf5, 0x30, 0x53, 0x9a, 0x20, 0xdf, 0x95
118 // kOriginalData encrypted with kSubsampleKey and kSubsampleIv using
119 // kSubsampleEntriesNormal.
120 const uint8 kSubsampleEncryptedData
[] = {
121 0x4f, 0x72, 0x09, 0x16, 0x09, 0xe6, 0x79, 0xad,
122 0x70, 0x73, 0x75, 0x62, 0x09, 0xbb, 0x83, 0x1d,
123 0x4d, 0x08, 0xd7, 0x78, 0xa4, 0xa7, 0xf1, 0x2e
126 const uint8 kOriginalData2
[] = "Changed Original data.";
128 const uint8 kIv2
[] = {
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
133 const uint8 kKeyId2
[] = {
134 // base64 equivalent is AAECAwQFBgcICQoLDA0ODxAREhM=
135 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
136 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
137 0x10, 0x11, 0x12, 0x13
140 const char kKey2AsJWK
[] =
145 " \"alg\": \"A128KW\","
146 " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\","
147 " \"k\": \"FBUWFxgZGhscHR4fICEiIw\""
152 // 'k' in bytes is x14x15x16x17x18x19x1ax1bx1cx1dx1ex1fx20x21x22x23
154 const uint8 kEncryptedData2
[] = {
155 0x57, 0x66, 0xf4, 0x12, 0x1a, 0xed, 0xb5, 0x79,
156 0x1c, 0x8e, 0x25, 0xd7, 0x17, 0xe7, 0x5e, 0x16,
157 0xe3, 0x40, 0x08, 0x27, 0x11, 0xe9
160 // Subsample entries for testing. The sum of |cypher_bytes| and |clear_bytes| of
161 // all entries must be equal to kOriginalDataSize to make the subsample entries
164 const SubsampleEntry kSubsampleEntriesNormal
[] = {
170 const SubsampleEntry kSubsampleEntriesWrongSize
[] = {
171 { 3, 6 }, // This entry doesn't match the correct entry.
176 const SubsampleEntry kSubsampleEntriesInvalidTotalSize
[] = {
177 { 1, 1000 }, // This entry is too large.
182 const SubsampleEntry kSubsampleEntriesClearOnly
[] = {
188 const SubsampleEntry kSubsampleEntriesCypherOnly
[] = {
194 static scoped_refptr
<DecoderBuffer
> CreateEncryptedBuffer(
195 const std::vector
<uint8
>& data
,
196 const std::vector
<uint8
>& key_id
,
197 const std::vector
<uint8
>& iv
,
198 const std::vector
<SubsampleEntry
>& subsample_entries
) {
199 DCHECK(!data
.empty());
200 scoped_refptr
<DecoderBuffer
> encrypted_buffer(new DecoderBuffer(data
.size()));
201 memcpy(encrypted_buffer
->writable_data(), &data
[0], data
.size());
202 CHECK(encrypted_buffer
.get());
203 std::string
key_id_string(
204 reinterpret_cast<const char*>(key_id
.empty() ? NULL
: &key_id
[0]),
206 std::string
iv_string(
207 reinterpret_cast<const char*>(iv
.empty() ? NULL
: &iv
[0]), iv
.size());
208 encrypted_buffer
->set_decrypt_config(scoped_ptr
<DecryptConfig
>(
209 new DecryptConfig(key_id_string
, iv_string
, subsample_entries
)));
210 return encrypted_buffer
;
213 enum PromiseResult
{ RESOLVED
, REJECTED
};
215 class AesDecryptorTest
: public testing::Test
{
218 : decryptor_(base::Bind(&AesDecryptorTest::OnSessionMessage
,
219 base::Unretained(this)),
220 base::Bind(&AesDecryptorTest::OnSessionClosed
,
221 base::Unretained(this)),
222 base::Bind(&AesDecryptorTest::OnSessionKeysChange
,
223 base::Unretained(this))),
224 decrypt_cb_(base::Bind(&AesDecryptorTest::BufferDecrypted
,
225 base::Unretained(this))),
226 original_data_(kOriginalData
, kOriginalData
+ kOriginalDataSize
),
227 encrypted_data_(kEncryptedData
,
228 kEncryptedData
+ arraysize(kEncryptedData
)),
229 subsample_encrypted_data_(
230 kSubsampleEncryptedData
,
231 kSubsampleEncryptedData
+ arraysize(kSubsampleEncryptedData
)),
232 key_id_(kKeyId
, kKeyId
+ arraysize(kKeyId
)),
233 iv_(kIv
, kIv
+ arraysize(kIv
)),
234 normal_subsample_entries_(
235 kSubsampleEntriesNormal
,
236 kSubsampleEntriesNormal
+ arraysize(kSubsampleEntriesNormal
)) {
240 void OnResolveWithSession(PromiseResult expected_result
,
241 const std::string
& session_id
) {
242 EXPECT_EQ(expected_result
, RESOLVED
) << "Unexpectedly resolved.";
243 EXPECT_GT(session_id
.length(), 0ul);
244 session_id_
= session_id
;
247 void OnResolve(PromiseResult expected_result
) {
248 EXPECT_EQ(expected_result
, RESOLVED
) << "Unexpectedly resolved.";
251 void OnReject(PromiseResult expected_result
,
252 MediaKeys::Exception exception_code
,
254 const std::string
& error_message
) {
255 EXPECT_EQ(expected_result
, REJECTED
)
256 << "Unexpectedly rejected with message: " << error_message
;
259 scoped_ptr
<SimpleCdmPromise
> CreatePromise(PromiseResult expected_result
) {
260 scoped_ptr
<SimpleCdmPromise
> promise(
261 new CdmCallbackPromise
<>(base::Bind(&AesDecryptorTest::OnResolve
,
262 base::Unretained(this),
264 base::Bind(&AesDecryptorTest::OnReject
,
265 base::Unretained(this),
267 return promise
.Pass();
270 scoped_ptr
<NewSessionCdmPromise
> CreateSessionPromise(
271 PromiseResult expected_result
) {
272 scoped_ptr
<NewSessionCdmPromise
> promise(
273 new CdmCallbackPromise
<std::string
>(
274 base::Bind(&AesDecryptorTest::OnResolveWithSession
,
275 base::Unretained(this),
277 base::Bind(&AesDecryptorTest::OnReject
,
278 base::Unretained(this),
280 return promise
.Pass();
283 // Creates a new session using |key_id|. Returns the session ID.
284 std::string
CreateSession(const std::vector
<uint8
>& key_id
) {
285 DCHECK(!key_id
.empty());
286 EXPECT_CALL(*this, OnSessionMessage(IsNotEmpty(), _
, IsJSONDictionary(),
288 decryptor_
.CreateSessionAndGenerateRequest(
289 MediaKeys::TEMPORARY_SESSION
, EmeInitDataType::WEBM
, &key_id
[0],
290 key_id
.size(), CreateSessionPromise(RESOLVED
));
291 // This expects the promise to be called synchronously, which is the case
296 // Closes the session specified by |session_id|.
297 void CloseSession(const std::string
& session_id
) {
298 EXPECT_CALL(*this, OnSessionClosed(session_id
));
299 decryptor_
.CloseSession(session_id
, CreatePromise(RESOLVED
));
302 // Removes the session specified by |session_id|. This should simply do a
304 // TODO(jrummell): Clean this up when the prefixed API is removed.
305 // http://crbug.com/249976.
306 void RemoveSession(const std::string
& session_id
) {
307 EXPECT_CALL(*this, OnSessionClosed(session_id
));
308 decryptor_
.RemoveSession(session_id
, CreatePromise(RESOLVED
));
311 MOCK_METHOD2(OnSessionKeysChangeCalled
,
312 void(const std::string
& session_id
,
313 bool has_additional_usable_key
));
315 void OnSessionKeysChange(const std::string
& session_id
,
316 bool has_additional_usable_key
,
317 CdmKeysInfo keys_info
) {
318 keys_info_
.swap(keys_info
);
319 OnSessionKeysChangeCalled(session_id
, has_additional_usable_key
);
322 // Updates the session specified by |session_id| with |key|. |result|
323 // tests that the update succeeds or generates an error.
324 void UpdateSessionAndExpect(std::string session_id
,
325 const std::string
& key
,
326 PromiseResult expected_result
,
327 bool new_key_expected
) {
328 DCHECK(!key
.empty());
330 if (expected_result
== RESOLVED
) {
332 OnSessionKeysChangeCalled(session_id
, new_key_expected
));
334 EXPECT_CALL(*this, OnSessionKeysChangeCalled(_
, _
)).Times(0);
337 decryptor_
.UpdateSession(session_id
,
338 reinterpret_cast<const uint8
*>(key
.c_str()),
340 CreatePromise(expected_result
));
343 bool KeysInfoContains(std::vector
<uint8
> expected
) {
344 for (const auto& key_id
: keys_info_
) {
345 if (key_id
->key_id
== expected
)
351 MOCK_METHOD2(BufferDecrypted
, void(Decryptor::Status
,
352 const scoped_refptr
<DecoderBuffer
>&));
354 enum DecryptExpectation
{
357 DATA_AND_SIZE_MISMATCH
,
362 void DecryptAndExpect(const scoped_refptr
<DecoderBuffer
>& encrypted
,
363 const std::vector
<uint8
>& plain_text
,
364 DecryptExpectation result
) {
365 scoped_refptr
<DecoderBuffer
> decrypted
;
370 case DATA_AND_SIZE_MISMATCH
:
371 EXPECT_CALL(*this, BufferDecrypted(Decryptor::kSuccess
, NotNull()))
372 .WillOnce(SaveArg
<1>(&decrypted
));
375 EXPECT_CALL(*this, BufferDecrypted(Decryptor::kError
, IsNull()))
376 .WillOnce(SaveArg
<1>(&decrypted
));
379 EXPECT_CALL(*this, BufferDecrypted(Decryptor::kNoKey
, IsNull()))
380 .WillOnce(SaveArg
<1>(&decrypted
));
384 decryptor_
.Decrypt(Decryptor::kVideo
, encrypted
, decrypt_cb_
);
386 std::vector
<uint8
> decrypted_text
;
387 if (decrypted
.get() && decrypted
->data_size()) {
388 decrypted_text
.assign(
389 decrypted
->data(), decrypted
->data() + decrypted
->data_size());
394 EXPECT_EQ(plain_text
, decrypted_text
);
397 EXPECT_EQ(plain_text
.size(), decrypted_text
.size());
398 EXPECT_NE(plain_text
, decrypted_text
);
400 case DATA_AND_SIZE_MISMATCH
:
401 EXPECT_NE(plain_text
.size(), decrypted_text
.size());
405 EXPECT_TRUE(decrypted_text
.empty());
410 MOCK_METHOD4(OnSessionMessage
,
411 void(const std::string
& session_id
,
412 MediaKeys::MessageType message_type
,
413 const std::vector
<uint8
>& message
,
414 const GURL
& legacy_destination_url
));
415 MOCK_METHOD1(OnSessionClosed
, void(const std::string
& session_id
));
417 AesDecryptor decryptor_
;
418 AesDecryptor::DecryptCB decrypt_cb_
;
419 std::string session_id_
;
420 CdmKeysInfo keys_info_
;
422 // Constants for testing.
423 const std::vector
<uint8
> original_data_
;
424 const std::vector
<uint8
> encrypted_data_
;
425 const std::vector
<uint8
> subsample_encrypted_data_
;
426 const std::vector
<uint8
> key_id_
;
427 const std::vector
<uint8
> iv_
;
428 const std::vector
<SubsampleEntry
> normal_subsample_entries_
;
429 const std::vector
<SubsampleEntry
> no_subsample_entries_
;
432 TEST_F(AesDecryptorTest
, CreateSessionWithNullInitData
) {
434 OnSessionMessage(IsNotEmpty(), _
, IsEmpty(), GURL::EmptyGURL()));
435 decryptor_
.CreateSessionAndGenerateRequest(MediaKeys::TEMPORARY_SESSION
,
436 EmeInitDataType::WEBM
, NULL
, 0,
437 CreateSessionPromise(RESOLVED
));
440 TEST_F(AesDecryptorTest
, MultipleCreateSession
) {
442 OnSessionMessage(IsNotEmpty(), _
, IsEmpty(), GURL::EmptyGURL()));
443 decryptor_
.CreateSessionAndGenerateRequest(MediaKeys::TEMPORARY_SESSION
,
444 EmeInitDataType::WEBM
, NULL
, 0,
445 CreateSessionPromise(RESOLVED
));
448 OnSessionMessage(IsNotEmpty(), _
, IsEmpty(), GURL::EmptyGURL()));
449 decryptor_
.CreateSessionAndGenerateRequest(MediaKeys::TEMPORARY_SESSION
,
450 EmeInitDataType::WEBM
, NULL
, 0,
451 CreateSessionPromise(RESOLVED
));
454 OnSessionMessage(IsNotEmpty(), _
, IsEmpty(), GURL::EmptyGURL()));
455 decryptor_
.CreateSessionAndGenerateRequest(MediaKeys::TEMPORARY_SESSION
,
456 EmeInitDataType::WEBM
, NULL
, 0,
457 CreateSessionPromise(RESOLVED
));
460 TEST_F(AesDecryptorTest
, CreateSessionWithCencInitData
) {
461 const uint8 init_data
[] = {
462 0x00, 0x00, 0x00, 0x44, // size = 68
463 0x70, 0x73, 0x73, 0x68, // 'pssh'
465 0x00, 0x00, 0x00, // flags
466 0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02, // SystemID
467 0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B,
468 0x00, 0x00, 0x00, 0x02, // key count
469 0x7E, 0x57, 0x1D, 0x03, 0x7E, 0x57, 0x1D, 0x03, // key1
470 0x7E, 0x57, 0x1D, 0x03, 0x7E, 0x57, 0x1D, 0x03,
471 0x7E, 0x57, 0x1D, 0x04, 0x7E, 0x57, 0x1D, 0x04, // key2
472 0x7E, 0x57, 0x1D, 0x04, 0x7E, 0x57, 0x1D, 0x04,
473 0x00, 0x00, 0x00, 0x00 // datasize
475 EXPECT_CALL(*this, OnSessionMessage(IsNotEmpty(), _
, IsJSONDictionary(),
477 decryptor_
.CreateSessionAndGenerateRequest(
478 MediaKeys::TEMPORARY_SESSION
, EmeInitDataType::CENC
, init_data
,
479 arraysize(init_data
), CreateSessionPromise(RESOLVED
));
482 TEST_F(AesDecryptorTest
, CreateSessionWithKeyIdsInitData
) {
483 const char init_data
[] =
484 "{\"kids\":[\"AQI\",\"AQIDBA\",\"AQIDBAUGBwgJCgsMDQ4PEA\"]}";
486 EXPECT_CALL(*this, OnSessionMessage(IsNotEmpty(), _
, IsJSONDictionary(),
488 decryptor_
.CreateSessionAndGenerateRequest(
489 MediaKeys::TEMPORARY_SESSION
, EmeInitDataType::KEYIDS
,
490 reinterpret_cast<const uint8
*>(init_data
), arraysize(init_data
) - 1,
491 CreateSessionPromise(RESOLVED
));
494 TEST_F(AesDecryptorTest
, NormalDecryption
) {
495 std::string session_id
= CreateSession(key_id_
);
496 UpdateSessionAndExpect(session_id
, kKeyAsJWK
, RESOLVED
, true);
497 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
498 encrypted_data_
, key_id_
, iv_
, no_subsample_entries_
);
499 DecryptAndExpect(encrypted_buffer
, original_data_
, SUCCESS
);
502 TEST_F(AesDecryptorTest
, UnencryptedFrame
) {
503 // An empty iv string signals that the frame is unencrypted.
504 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
505 original_data_
, key_id_
, std::vector
<uint8
>(), no_subsample_entries_
);
506 DecryptAndExpect(encrypted_buffer
, original_data_
, SUCCESS
);
509 TEST_F(AesDecryptorTest
, WrongKey
) {
510 std::string session_id
= CreateSession(key_id_
);
511 UpdateSessionAndExpect(session_id
, kWrongKeyAsJWK
, RESOLVED
, true);
512 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
513 encrypted_data_
, key_id_
, iv_
, no_subsample_entries_
);
514 DecryptAndExpect(encrypted_buffer
, original_data_
, DATA_MISMATCH
);
517 TEST_F(AesDecryptorTest
, NoKey
) {
518 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
519 encrypted_data_
, key_id_
, iv_
, no_subsample_entries_
);
520 EXPECT_CALL(*this, BufferDecrypted(AesDecryptor::kNoKey
, IsNull()));
521 decryptor_
.Decrypt(Decryptor::kVideo
, encrypted_buffer
, decrypt_cb_
);
524 TEST_F(AesDecryptorTest
, KeyReplacement
) {
525 std::string session_id
= CreateSession(key_id_
);
526 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
527 encrypted_data_
, key_id_
, iv_
, no_subsample_entries_
);
529 UpdateSessionAndExpect(session_id
, kWrongKeyAsJWK
, RESOLVED
, true);
530 ASSERT_NO_FATAL_FAILURE(DecryptAndExpect(
531 encrypted_buffer
, original_data_
, DATA_MISMATCH
));
533 UpdateSessionAndExpect(session_id
, kKeyAsJWK
, RESOLVED
, false);
534 ASSERT_NO_FATAL_FAILURE(
535 DecryptAndExpect(encrypted_buffer
, original_data_
, SUCCESS
));
538 TEST_F(AesDecryptorTest
, WrongSizedKey
) {
539 std::string session_id
= CreateSession(key_id_
);
540 UpdateSessionAndExpect(session_id
, kWrongSizedKeyAsJWK
, REJECTED
, true);
543 TEST_F(AesDecryptorTest
, MultipleKeysAndFrames
) {
544 std::string session_id
= CreateSession(key_id_
);
545 UpdateSessionAndExpect(session_id
, kKeyAsJWK
, RESOLVED
, true);
546 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
547 encrypted_data_
, key_id_
, iv_
, no_subsample_entries_
);
548 ASSERT_NO_FATAL_FAILURE(
549 DecryptAndExpect(encrypted_buffer
, original_data_
, SUCCESS
));
551 UpdateSessionAndExpect(session_id
, kKey2AsJWK
, RESOLVED
, true);
553 // The first key is still available after we added a second key.
554 ASSERT_NO_FATAL_FAILURE(
555 DecryptAndExpect(encrypted_buffer
, original_data_
, SUCCESS
));
557 // The second key is also available.
558 encrypted_buffer
= CreateEncryptedBuffer(
559 std::vector
<uint8
>(kEncryptedData2
,
560 kEncryptedData2
+ arraysize(kEncryptedData2
)),
561 std::vector
<uint8
>(kKeyId2
, kKeyId2
+ arraysize(kKeyId2
)),
562 std::vector
<uint8
>(kIv2
, kIv2
+ arraysize(kIv2
)),
563 no_subsample_entries_
);
564 ASSERT_NO_FATAL_FAILURE(DecryptAndExpect(
566 std::vector
<uint8
>(kOriginalData2
,
567 kOriginalData2
+ arraysize(kOriginalData2
) - 1),
571 TEST_F(AesDecryptorTest
, CorruptedIv
) {
572 std::string session_id
= CreateSession(key_id_
);
573 UpdateSessionAndExpect(session_id
, kKeyAsJWK
, RESOLVED
, true);
575 std::vector
<uint8
> bad_iv
= iv_
;
578 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
579 encrypted_data_
, key_id_
, bad_iv
, no_subsample_entries_
);
581 DecryptAndExpect(encrypted_buffer
, original_data_
, DATA_MISMATCH
);
584 TEST_F(AesDecryptorTest
, CorruptedData
) {
585 std::string session_id
= CreateSession(key_id_
);
586 UpdateSessionAndExpect(session_id
, kKeyAsJWK
, RESOLVED
, true);
588 std::vector
<uint8
> bad_data
= encrypted_data_
;
591 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
592 bad_data
, key_id_
, iv_
, no_subsample_entries_
);
593 DecryptAndExpect(encrypted_buffer
, original_data_
, DATA_MISMATCH
);
596 TEST_F(AesDecryptorTest
, EncryptedAsUnencryptedFailure
) {
597 std::string session_id
= CreateSession(key_id_
);
598 UpdateSessionAndExpect(session_id
, kKeyAsJWK
, RESOLVED
, true);
599 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
600 encrypted_data_
, key_id_
, std::vector
<uint8
>(), no_subsample_entries_
);
601 DecryptAndExpect(encrypted_buffer
, original_data_
, DATA_MISMATCH
);
604 TEST_F(AesDecryptorTest
, SubsampleDecryption
) {
605 std::string session_id
= CreateSession(key_id_
);
606 UpdateSessionAndExpect(session_id
, kKeyAsJWK
, RESOLVED
, true);
607 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
608 subsample_encrypted_data_
, key_id_
, iv_
, normal_subsample_entries_
);
609 DecryptAndExpect(encrypted_buffer
, original_data_
, SUCCESS
);
612 // Ensures noninterference of data offset and subsample mechanisms. We never
613 // expect to encounter this in the wild, but since the DecryptConfig doesn't
614 // disallow such a configuration, it should be covered.
615 TEST_F(AesDecryptorTest
, SubsampleDecryptionWithOffset
) {
616 std::string session_id
= CreateSession(key_id_
);
617 UpdateSessionAndExpect(session_id
, kKeyAsJWK
, RESOLVED
, true);
618 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
619 subsample_encrypted_data_
, key_id_
, iv_
, normal_subsample_entries_
);
620 DecryptAndExpect(encrypted_buffer
, original_data_
, SUCCESS
);
623 TEST_F(AesDecryptorTest
, SubsampleWrongSize
) {
624 std::string session_id
= CreateSession(key_id_
);
625 UpdateSessionAndExpect(session_id
, kKeyAsJWK
, RESOLVED
, true);
627 std::vector
<SubsampleEntry
> subsample_entries_wrong_size(
628 kSubsampleEntriesWrongSize
,
629 kSubsampleEntriesWrongSize
+ arraysize(kSubsampleEntriesWrongSize
));
631 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
632 subsample_encrypted_data_
, key_id_
, iv_
, subsample_entries_wrong_size
);
633 DecryptAndExpect(encrypted_buffer
, original_data_
, DATA_MISMATCH
);
636 TEST_F(AesDecryptorTest
, SubsampleInvalidTotalSize
) {
637 std::string session_id
= CreateSession(key_id_
);
638 UpdateSessionAndExpect(session_id
, kKeyAsJWK
, RESOLVED
, true);
640 std::vector
<SubsampleEntry
> subsample_entries_invalid_total_size(
641 kSubsampleEntriesInvalidTotalSize
,
642 kSubsampleEntriesInvalidTotalSize
+
643 arraysize(kSubsampleEntriesInvalidTotalSize
));
645 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
646 subsample_encrypted_data_
, key_id_
, iv_
,
647 subsample_entries_invalid_total_size
);
648 DecryptAndExpect(encrypted_buffer
, original_data_
, DECRYPT_ERROR
);
651 // No cypher bytes in any of the subsamples.
652 TEST_F(AesDecryptorTest
, SubsampleClearBytesOnly
) {
653 std::string session_id
= CreateSession(key_id_
);
654 UpdateSessionAndExpect(session_id
, kKeyAsJWK
, RESOLVED
, true);
656 std::vector
<SubsampleEntry
> clear_only_subsample_entries(
657 kSubsampleEntriesClearOnly
,
658 kSubsampleEntriesClearOnly
+ arraysize(kSubsampleEntriesClearOnly
));
660 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
661 original_data_
, key_id_
, iv_
, clear_only_subsample_entries
);
662 DecryptAndExpect(encrypted_buffer
, original_data_
, SUCCESS
);
665 // No clear bytes in any of the subsamples.
666 TEST_F(AesDecryptorTest
, SubsampleCypherBytesOnly
) {
667 std::string session_id
= CreateSession(key_id_
);
668 UpdateSessionAndExpect(session_id
, kKeyAsJWK
, RESOLVED
, true);
670 std::vector
<SubsampleEntry
> cypher_only_subsample_entries(
671 kSubsampleEntriesCypherOnly
,
672 kSubsampleEntriesCypherOnly
+ arraysize(kSubsampleEntriesCypherOnly
));
674 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
675 encrypted_data_
, key_id_
, iv_
, cypher_only_subsample_entries
);
676 DecryptAndExpect(encrypted_buffer
, original_data_
, SUCCESS
);
679 TEST_F(AesDecryptorTest
, CloseSession
) {
680 std::string session_id
= CreateSession(key_id_
);
681 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
682 encrypted_data_
, key_id_
, iv_
, no_subsample_entries_
);
684 UpdateSessionAndExpect(session_id
, kKeyAsJWK
, RESOLVED
, true);
685 ASSERT_NO_FATAL_FAILURE(
686 DecryptAndExpect(encrypted_buffer
, original_data_
, SUCCESS
));
688 CloseSession(session_id
);
691 TEST_F(AesDecryptorTest
, RemoveSession
) {
692 // TODO(jrummell): Clean this up when the prefixed API is removed.
693 // http://crbug.com/249976.
694 std::string session_id
= CreateSession(key_id_
);
695 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
696 encrypted_data_
, key_id_
, iv_
, no_subsample_entries_
);
698 UpdateSessionAndExpect(session_id
, kKeyAsJWK
, RESOLVED
, true);
699 ASSERT_NO_FATAL_FAILURE(
700 DecryptAndExpect(encrypted_buffer
, original_data_
, SUCCESS
));
702 RemoveSession(session_id
);
705 TEST_F(AesDecryptorTest
, NoKeyAfterCloseSession
) {
706 std::string session_id
= CreateSession(key_id_
);
707 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
708 encrypted_data_
, key_id_
, iv_
, no_subsample_entries_
);
710 UpdateSessionAndExpect(session_id
, kKeyAsJWK
, RESOLVED
, true);
711 ASSERT_NO_FATAL_FAILURE(
712 DecryptAndExpect(encrypted_buffer
, original_data_
, SUCCESS
));
714 CloseSession(session_id
);
715 ASSERT_NO_FATAL_FAILURE(
716 DecryptAndExpect(encrypted_buffer
, original_data_
, NO_KEY
));
719 TEST_F(AesDecryptorTest
, LatestKeyUsed
) {
720 std::string session_id1
= CreateSession(key_id_
);
721 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
722 encrypted_data_
, key_id_
, iv_
, no_subsample_entries_
);
724 // Add alternate key, buffer should not be decoded properly.
725 UpdateSessionAndExpect(session_id1
, kKeyAlternateAsJWK
, RESOLVED
, true);
726 ASSERT_NO_FATAL_FAILURE(
727 DecryptAndExpect(encrypted_buffer
, original_data_
, DATA_MISMATCH
));
729 // Create a second session with a correct key value for key_id_.
730 std::string session_id2
= CreateSession(key_id_
);
731 UpdateSessionAndExpect(session_id2
, kKeyAsJWK
, RESOLVED
, true);
733 // Should be able to decode with latest key.
734 ASSERT_NO_FATAL_FAILURE(
735 DecryptAndExpect(encrypted_buffer
, original_data_
, SUCCESS
));
738 TEST_F(AesDecryptorTest
, LatestKeyUsedAfterCloseSession
) {
739 std::string session_id1
= CreateSession(key_id_
);
740 scoped_refptr
<DecoderBuffer
> encrypted_buffer
= CreateEncryptedBuffer(
741 encrypted_data_
, key_id_
, iv_
, no_subsample_entries_
);
742 UpdateSessionAndExpect(session_id1
, kKeyAsJWK
, RESOLVED
, true);
743 ASSERT_NO_FATAL_FAILURE(
744 DecryptAndExpect(encrypted_buffer
, original_data_
, SUCCESS
));
746 // Create a second session with a different key value for key_id_.
747 std::string session_id2
= CreateSession(key_id_
);
748 UpdateSessionAndExpect(session_id2
, kKeyAlternateAsJWK
, RESOLVED
, true);
750 // Should not be able to decode with new key.
751 ASSERT_NO_FATAL_FAILURE(
752 DecryptAndExpect(encrypted_buffer
, original_data_
, DATA_MISMATCH
));
754 // Close second session, should revert to original key.
755 CloseSession(session_id2
);
756 ASSERT_NO_FATAL_FAILURE(
757 DecryptAndExpect(encrypted_buffer
, original_data_
, SUCCESS
));
760 TEST_F(AesDecryptorTest
, JWKKey
) {
761 std::string session_id
= CreateSession(key_id_
);
763 // Try a simple JWK key (i.e. not in a set)
764 const std::string kJwkSimple
=
767 " \"alg\": \"A128KW\","
768 " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\","
769 " \"k\": \"FBUWFxgZGhscHR4fICEiIw\""
771 UpdateSessionAndExpect(session_id
, kJwkSimple
, REJECTED
, true);
773 // Try a key list with multiple entries.
774 const std::string kJwksMultipleEntries
=
779 " \"alg\": \"A128KW\","
780 " \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\","
781 " \"k\": \"FBUWFxgZGhscHR4fICEiIw\""
785 " \"alg\": \"A128KW\","
786 " \"kid\": \"JCUmJygpKissLS4vMA\","
787 " \"k\":\"MTIzNDU2Nzg5Ojs8PT4_QA\""
791 UpdateSessionAndExpect(session_id
, kJwksMultipleEntries
, RESOLVED
, true);
793 // Try a key with no spaces and some \n plus additional fields.
794 const std::string kJwksNoSpaces
=
795 "\n\n{\"something\":1,\"keys\":[{\n\n\"kty\":\"oct\",\"alg\":\"A128KW\","
796 "\"kid\":\"AQIDBAUGBwgJCgsMCg4PAA\",\"k\":\"GawgguFyGrWKav7AX4VKUg"
797 "\",\"foo\":\"bar\"}]}\n\n";
798 UpdateSessionAndExpect(session_id
, kJwksNoSpaces
, RESOLVED
, true);
800 // Try some non-ASCII characters.
801 UpdateSessionAndExpect(session_id
,
802 "This is not ASCII due to \xff\xfe\xfd in it.",
805 // Try a badly formatted key. Assume that the JSON parser is fully tested,
806 // so we won't try a lot of combinations. However, need a test to ensure
807 // that the code doesn't crash if invalid JSON received.
808 UpdateSessionAndExpect(session_id
, "This is not a JSON key.", REJECTED
, true);
810 // Try passing some valid JSON that is not a dictionary at the top level.
811 UpdateSessionAndExpect(session_id
, "40", REJECTED
, true);
813 // Try an empty dictionary.
814 UpdateSessionAndExpect(session_id
, "{ }", REJECTED
, true);
816 // Try an empty 'keys' dictionary.
817 UpdateSessionAndExpect(session_id
, "{ \"keys\": [] }", REJECTED
, true);
819 // Try with 'keys' not a dictionary.
820 UpdateSessionAndExpect(session_id
, "{ \"keys\":\"1\" }", REJECTED
, true);
822 // Try with 'keys' a list of integers.
823 UpdateSessionAndExpect(session_id
, "{ \"keys\": [ 1, 2, 3 ] }", REJECTED
,
826 // Try padding(=) at end of 'k' base64 string.
827 const std::string kJwksWithPaddedKey
=
832 " \"alg\": \"A128KW\","
833 " \"kid\": \"AAECAw\","
834 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw==\""
838 UpdateSessionAndExpect(session_id
, kJwksWithPaddedKey
, REJECTED
, true);
840 // Try padding(=) at end of 'kid' base64 string.
841 const std::string kJwksWithPaddedKeyId
=
846 " \"alg\": \"A128KW\","
847 " \"kid\": \"AAECAw==\","
848 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
852 UpdateSessionAndExpect(session_id
, kJwksWithPaddedKeyId
, REJECTED
, true);
854 // Try a key with invalid base64 encoding.
855 const std::string kJwksWithInvalidBase64
=
860 " \"alg\": \"A128KW\","
861 " \"kid\": \"!@#$%^&*()\","
862 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
866 UpdateSessionAndExpect(session_id
, kJwksWithInvalidBase64
, REJECTED
, true);
868 // Try a 3-byte 'kid' where no base64 padding is required.
869 // |kJwksMultipleEntries| above has 2 'kid's that require 1 and 2 padding
870 // bytes. Note that 'k' has to be 16 bytes, so it will always require padding.
871 const std::string kJwksWithNoPadding
=
876 " \"alg\": \"A128KW\","
877 " \"kid\": \"Kiss\","
878 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
882 UpdateSessionAndExpect(session_id
, kJwksWithNoPadding
, RESOLVED
, true);
885 const std::string kJwksWithEmptyKeyId
=
890 " \"alg\": \"A128KW\","
892 " \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
896 UpdateSessionAndExpect(session_id
, kJwksWithEmptyKeyId
, REJECTED
, true);
897 CloseSession(session_id
);
900 TEST_F(AesDecryptorTest
, GetKeyIds
) {
901 std::vector
<uint8
> key_id1(kKeyId
, kKeyId
+ arraysize(kKeyId
));
902 std::vector
<uint8
> key_id2(kKeyId2
, kKeyId2
+ arraysize(kKeyId2
));
904 std::string session_id
= CreateSession(key_id_
);
905 EXPECT_FALSE(KeysInfoContains(key_id1
));
906 EXPECT_FALSE(KeysInfoContains(key_id2
));
908 // Add 1 key, verify it is returned.
909 UpdateSessionAndExpect(session_id
, kKeyAsJWK
, RESOLVED
, true);
910 EXPECT_TRUE(KeysInfoContains(key_id1
));
911 EXPECT_FALSE(KeysInfoContains(key_id2
));
913 // Add second key, verify both IDs returned.
914 UpdateSessionAndExpect(session_id
, kKey2AsJWK
, RESOLVED
, true);
915 EXPECT_TRUE(KeysInfoContains(key_id1
));
916 EXPECT_TRUE(KeysInfoContains(key_id2
));
919 TEST_F(AesDecryptorTest
, NoKeysChangeForSameKey
) {
920 std::vector
<uint8
> key_id(kKeyId
, kKeyId
+ arraysize(kKeyId
));
922 std::string session_id
= CreateSession(key_id_
);
923 EXPECT_FALSE(KeysInfoContains(key_id
));
925 // Add key, verify it is returned.
926 UpdateSessionAndExpect(session_id
, kKeyAsJWK
, RESOLVED
, true);
927 EXPECT_TRUE(KeysInfoContains(key_id
));
929 // Add key a second time.
930 UpdateSessionAndExpect(session_id
, kKeyAsJWK
, RESOLVED
, false);
931 EXPECT_TRUE(KeysInfoContains(key_id
));
933 // Create a new session. Add key, should indicate key added for this session.
934 std::string session_id2
= CreateSession(key_id_
);
935 UpdateSessionAndExpect(session_id2
, kKeyAsJWK
, RESOLVED
, true);