Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(63)

Side by Side Diff: media/crypto/hmac_aes_decryptor.cc

Issue 10535029: Add support for encrypted WebM files as defined in the RFC. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Updated encrypted WebM test data. Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "media/crypto/hmac_aes_decryptor.h"
6
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "base/string_piece.h"
10 #include "crypto/encryptor.h"
11 #include "crypto/hmac.h"
12 #include "crypto/symmetric_key.h"
13 #include "media/base/decoder_buffer.h"
14 #include "media/base/decrypt_config.h"
15
16 namespace media {
17
18 // Derives a key from an HAMC using SHA1. |secret| is the base secret to derive
19 // the key from. |seed| is the knwon input to the HMAC. |key_size| is how many
20 // bytes are returned in the key. Returns a string containing the key on
21 // success. Returns an empty string on failure.
22 static std::string DeriveKey(const std::string& secret,
23 const std::string& seed,
24 int key_size) {
25 CHECK_EQ(secret.length(), static_cast<size_t>(DecryptConfig::kKeySize));
26 CHECK(!seed.empty());
27 CHECK_GT(key_size, 0);
28
29 std::string key;
30 crypto::HMAC hmac(crypto::HMAC::SHA1);
31 if (!hmac.Init(reinterpret_cast<const uint8*>(secret.data()),
32 secret.size())) {
33 DVLOG(1) << "Could not initialize HMAC with secret data.";
34 return key;
35 }
36
37 uint8 calculated_hmac[HmacAesDecryptor::kSha1DigestSize];
38 if (!hmac.Sign(seed, calculated_hmac, HmacAesDecryptor::kSha1DigestSize)) {
39 DVLOG(1) << "Could not calculate HMAC.";
40 return key;
41 }
42 key.assign(reinterpret_cast<const char*>(calculated_hmac), key_size);
43 return key;
44 }
45
46 // Integrity check of |input|'s data. Checks that the first
47 // |kWebMIntegrityCheckSize| in bytes of |ipunt| matches the rest of the data
48 // in |input|. The check is defined in the WebM specification. Current WebM
49 // encrypted request for comments specification is here
50 // http://wiki.webmproject.org/encryption/webm-encryption-rfc.
51 // |hmac_key| is the key of the HMAC algorithm. Returns true if the integrity
52 // check is good.
53 static bool CheckData(const DecoderBuffer& input,
54 const std::string& hmac_key) {
55 CHECK(input.GetDataSize());
56 CHECK(input.GetDecryptConfig());
57 CHECK(!hmac_key.empty());
58
59 crypto::HMAC hmac(crypto::HMAC::SHA1);
60 if (!hmac.Init(reinterpret_cast<const uint8*>(hmac_key.data()),
61 hmac_key.size())) {
62 DVLOG(1) << "Could not initialize HMAC.";
63 return false;
64 }
65
66 // The HMAC covers the IV and the frame data.
67 const char* iv_frame = reinterpret_cast<const char*>(input.GetData() +
ddorwin 2012/06/14 21:41:24 Is "iv_frame" really "iv_and_frame"? As mentioned
fgalligan1 2012/07/03 22:00:15 I only send the IV and frame data in the input buf
68 DecryptConfig::kWebMIntegrityCheckSize);
ddorwin 2012/06/14 21:41:24 Would like to avoid any WebM-specific values in th
fgalligan1 2012/07/03 22:00:15 Done.
69 int iv_frame_size =
70 input.GetDataSize() - DecryptConfig::kWebMIntegrityCheckSize;
71 std::string data_to_check(iv_frame, iv_frame_size);
ddorwin 2012/06/14 21:41:24 Can we avoid this memory copy? (If we separate IV
fgalligan1 2012/07/03 22:00:15 Done.
72
73 uint8 calculated_hmac[HmacAesDecryptor::kSha1DigestSize];
74 if (!hmac.Sign(data_to_check,
75 calculated_hmac,
76 HmacAesDecryptor::kSha1DigestSize)) {
77 DVLOG(1) << "Could not calculate HMAC.";
78 return false;
79 }
80
81 if (memcmp(input.GetDecryptConfig()->hmac(),
82 calculated_hmac,
83 input.GetDecryptConfig()->hmac_size()) != 0) {
84 DVLOG(1) << "Integrity check failure.";
85 return false;
86 }
87 return true;
88 }
89
90 const char HmacAesDecryptor::kHmacSeed[] = "hmac-key";
91 const char HmacAesDecryptor::kEncryptionSeed[] = "encryption-key";
92
93 HmacAesDecryptor::HmacAesDecryptor() {}
94
95 HmacAesDecryptor::~HmacAesDecryptor() {
96 STLDeleteValues(&keys_map_);
97 }
98
99 void HmacAesDecryptor::AddKey(const uint8* key_id, int key_id_size,
100 const uint8* key, int key_size) {
101 CHECK(key_id && key);
102 CHECK_GT(key_id_size, 0);
103 CHECK_GT(key_size, 0);
104
105 std::string key_id_string(reinterpret_cast<const char*>(key_id), key_id_size);
106 std::string key_string(reinterpret_cast<const char*>(key) , key_size);
107
108 HmacEncryptionKeys* keys = new HmacEncryptionKeys(key_string);
109 if (!keys) {
110 DVLOG(1) << "Could not create keys.";
111 return;
112 }
113 if (!keys->Init()) {
114 delete keys;
115 DVLOG(1) << "Could not create keys.";
116 return;
117 }
118
119 base::AutoLock auto_lock(lock_);
120 KeysMap::iterator found = keys_map_.find(key_id_string);
121 if (found != keys_map_.end()) {
122 delete found->second;
123 keys_map_.erase(found);
124 }
125 keys_map_[key_id_string] = keys;
126 }
127
128 scoped_refptr<DecoderBuffer> HmacAesDecryptor::Decrypt(
129 const scoped_refptr<DecoderBuffer>& encrypted) {
130 CHECK(encrypted->GetDecryptConfig());
131 const uint8* key_id = encrypted->GetDecryptConfig()->key_id();
132 const int key_id_size = encrypted->GetDecryptConfig()->key_id_size();
133
134 // TODO(xhwang): Avoid always constructing a string with StringPiece?
135 std::string key_id_string(reinterpret_cast<const char*>(key_id), key_id_size);
136
137 HmacEncryptionKeys* keys = NULL;
138 {
139 base::AutoLock auto_lock(lock_);
140 KeysMap::const_iterator found = keys_map_.find(key_id_string);
141 if (found == keys_map_.end()) {
142 DVLOG(1) << "Could not find a matching key for given key ID.";
143 return NULL;
144 }
145 keys = found->second;
146 }
147
148 if (!CheckData(*encrypted, keys->hmac_key())) {
ddorwin 2012/06/14 21:41:24 Support containers without HMAC support: if (HasHm
fgalligan1 2012/07/03 22:00:15 Done.
149 DVLOG(1) << "Integrity check failed.";
150 return NULL;
151 }
152
153 scoped_refptr<DecoderBuffer> decrypted =
154 Decryptor::DecryptData(*encrypted,
155 keys->encryption_key(),
156 DecryptConfig::kWebMIntegrityCheckSize +
157 DecryptConfig::kIvSize);
158 if (decrypted) {
159 decrypted->SetTimestamp(encrypted->GetTimestamp());
160 decrypted->SetDuration(encrypted->GetDuration());
161 }
162
163 return decrypted;
164 }
165
166 HmacAesDecryptor::HmacEncryptionKeys::HmacEncryptionKeys(
167 const std::string& secret)
168 : secret_(secret) {
169 }
170
171 HmacAesDecryptor::HmacEncryptionKeys::~HmacEncryptionKeys() {}
172
173 bool HmacAesDecryptor::HmacEncryptionKeys::Init() {
174 CHECK(!secret_.empty());
175
176 std::string raw_key = DeriveKey(secret_,
177 kEncryptionSeed,
178 DecryptConfig::kKeySize);
179 if (raw_key.empty()) {
180 DVLOG(1) << "Could not create encryption key.";
181 return false;
182 }
183 encryption_key_.reset(crypto::SymmetricKey::Import(crypto::SymmetricKey::AES,
184 raw_key));
185 if (!encryption_key_.get()) {
186 DVLOG(1) << "Could not create encryption key.";
187 return false;
188 }
189
190 hmac_key_ = DeriveKey(secret_, kHmacSeed, kSha1DigestSize);
191 if (hmac_key_.empty()) {
192 DVLOG(1) << "Could not create HMAC key.";
193 return false;
194 }
195 return true;
196 }
197
198 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698