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

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

Issue 10822013: Code clean-up in AesDecryptor and test. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 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 | Annotate | Revision Log
OLDNEW
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 "media/crypto/aes_decryptor.h" 5 #include "media/crypto/aes_decryptor.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/stl_util.h" 8 #include "base/stl_util.h"
9 #include "base/string_number_conversions.h" 9 #include "base/string_number_conversions.h"
10 #include "crypto/encryptor.h" 10 #include "crypto/encryptor.h"
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 76
77 DCHECK(input.GetDecryptConfig()->checksum_size() <= 77 DCHECK(input.GetDecryptConfig()->checksum_size() <=
78 static_cast<int>(hmac.DigestLength())); 78 static_cast<int>(hmac.DigestLength()));
79 if (memcmp(input.GetDecryptConfig()->checksum(), 79 if (memcmp(input.GetDecryptConfig()->checksum(),
80 calculated_hmac.get(), 80 calculated_hmac.get(),
81 input.GetDecryptConfig()->checksum_size()) != 0) 81 input.GetDecryptConfig()->checksum_size()) != 0)
82 return false; 82 return false;
83 return true; 83 return true;
84 } 84 }
85 85
86 // Decrypts |input| using |key|. |encrypted_data_offset| is the number of bytes 86 // Decrypts |encrypted_data| using |key|.
87 // into |input| that the encrypted data starts. 87 // Returns true and fill |decrypted_text| if if decryption succeeded.
fgalligan1 2012/07/25 19:33:50 s/fill/fills/ s/if if/if/
xhwang 2012/07/26 23:36:47 Done.
88 // Returns a DecoderBuffer with the decrypted data if decryption succeeded or 88 // Returns false and leave |decrypted_text| as is if decryption failed.
fgalligan1 2012/07/25 19:33:50 s/leave/leaves/
ddorwin 2012/07/26 21:24:07 I think this is pretty common practice and thus do
xhwang 2012/07/26 23:36:47 Done.
89 // NULL if decryption failed. 89 static bool DecryptData(
90 static scoped_refptr<DecoderBuffer> DecryptData(const DecoderBuffer& input, 90 const uint8* encrypted_data, int encrypted_data_size,
91 crypto::SymmetricKey* key, 91 const uint8* iv, int iv_size,
92 int encrypted_data_offset) { 92 crypto::SymmetricKey* key,
93 CHECK(input.GetDataSize()); 93 std::string* decrypted_text) {
ddorwin 2012/07/26 21:24:07 nit: Odd that the output is a different type from
xhwang 2012/07/26 23:36:47 Done.
94 CHECK(input.GetDecryptConfig()); 94 DCHECK(decrypted_text->empty());
fgalligan1 2012/07/25 19:33:50 Why does decrypted_text need to be empty()?
xhwang 2012/07/26 23:36:47 Done.
95 CHECK(key);
96 95
97 // Initialize decryptor. 96 // Initialize decryptor.
98 crypto::Encryptor encryptor; 97 crypto::Encryptor encryptor;
99 if (!encryptor.Init(key, crypto::Encryptor::CTR, "")) { 98 if (!encryptor.Init(key, crypto::Encryptor::CTR, "")) {
100 DVLOG(1) << "Could not initialize decryptor."; 99 DVLOG(1) << "Could not initialize decryptor.";
101 return NULL; 100 return false;
102 } 101 }
103 102
104 DCHECK_EQ(input.GetDecryptConfig()->iv_size(), 103 DCHECK_EQ(iv_size, DecryptConfig::kDecryptionKeySize);
105 DecryptConfig::kDecryptionKeySize);
106 // Set the counter block. 104 // Set the counter block.
107 base::StringPiece counter_block( 105 base::StringPiece counter_block(reinterpret_cast<const char*>(iv),iv_size);
ddorwin 2012/07/26 21:24:07 space after ,
xhwang 2012/07/26 23:36:47 Done.
108 reinterpret_cast<const char*>(input.GetDecryptConfig()->iv()),
109 input.GetDecryptConfig()->iv_size());
110 if (counter_block.empty()) { 106 if (counter_block.empty()) {
111 DVLOG(1) << "Could not generate counter block."; 107 DVLOG(1) << "Could not generate counter block.";
112 return NULL; 108 return false;
113 } 109 }
114 if (!encryptor.SetCounter(counter_block)) { 110 if (!encryptor.SetCounter(counter_block)) {
115 DVLOG(1) << "Could not set counter block."; 111 DVLOG(1) << "Could not set counter block.";
116 return NULL; 112 return false;
117 } 113 }
118 114
115 base::StringPiece encrypted_text(
116 reinterpret_cast<const char*>(encrypted_data), encrypted_data_size);
117 if (!encryptor.Decrypt(encrypted_text, decrypted_text)) {
118 DVLOG(1) << "Could not decrypt data.";
119 DCHECK(decrypted_text->empty());
fgalligan1 2012/07/25 19:33:50 I don't think you need this check here if you remo
xhwang 2012/07/26 23:36:47 Done.
120 return false;
121 }
122
123 DCHECK(!decrypted_text->empty());
124 return true;
125 }
126
127 // Decrypts |encrypted_buffer| using |key|.
128 // Fires the |decrypt_cb| with kSuccess and the decrypted buffer if decryption
129 // succeeded.
130 // Fires the |decrypt_cb| with kError and NULL if decryption failed.
ddorwin 2012/07/26 21:24:07 Otherwise fires ... NULL.
xhwang 2012/07/26 23:36:47 Done.
131 static void DecryptBuffer(const Decryptor::DecryptCB& decrypt_cb,
132 const scoped_refptr<DecoderBuffer>& encrypted_buffer,
133 crypto::SymmetricKey* key) {
134 CHECK(encrypted_buffer->GetDataSize());
135 CHECK(encrypted_buffer->GetDecryptConfig());
136 CHECK(key);
137
119 std::string decrypted_text; 138 std::string decrypted_text;
120 const char* frame = 139 int encrypted_data_offset =
121 reinterpret_cast<const char*>(input.GetData() + encrypted_data_offset); 140 encrypted_buffer->GetDecryptConfig()->encrypted_frame_offset();
122 int frame_size = input.GetDataSize() - encrypted_data_offset; 141
123 base::StringPiece encrypted_text(frame, frame_size); 142 bool succeed = DecryptData(
124 if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) { 143 encrypted_buffer->GetData() + encrypted_data_offset,
125 DVLOG(1) << "Could not decrypt data."; 144 encrypted_buffer->GetDataSize() - encrypted_data_offset,
126 return NULL; 145 encrypted_buffer->GetDecryptConfig()->iv(),
146 encrypted_buffer->GetDecryptConfig()->iv_size(),
147 key,
148 &decrypted_text);
149
150 if (!succeed) {
151 DVLOG(1) << "Decryption failed.";
152 decrypt_cb.Run(Decryptor::kError, NULL);
153 return;
127 } 154 }
128 155
129 // TODO(xhwang): Find a way to avoid this data copy. 156 // TODO(xhwang): Find a way to avoid this data copy.
130 return DecoderBuffer::CopyFrom( 157 scoped_refptr<DecoderBuffer> decrypted_buffer = DecoderBuffer::CopyFrom(
131 reinterpret_cast<const uint8*>(decrypted_text.data()), 158 reinterpret_cast<const uint8*>(decrypted_text.data()),
132 decrypted_text.size()); 159 decrypted_text.size());
160
161 decrypted_buffer->SetTimestamp(encrypted_buffer->GetTimestamp());
162 decrypted_buffer->SetDuration(encrypted_buffer->GetDuration());
163 decrypt_cb.Run(Decryptor::kSuccess, decrypted_buffer);
133 } 164 }
134 165
135 AesDecryptor::AesDecryptor(DecryptorClient* client) 166 AesDecryptor::AesDecryptor(DecryptorClient* client)
136 : client_(client) { 167 : client_(client) {
137 } 168 }
138 169
139 AesDecryptor::~AesDecryptor() { 170 AesDecryptor::~AesDecryptor() {
140 STLDeleteValues(&key_map_); 171 STLDeleteValues(&key_map_);
141 } 172 }
142 173
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 } 223 }
193 224
194 // TODO(fgalligan): When ISO is added we will need to figure out how to 225 // TODO(fgalligan): When ISO is added we will need to figure out how to
195 // detect if the encrypted data will contain an HMAC. 226 // detect if the encrypted data will contain an HMAC.
196 if (!decryption_key->Init(true)) { 227 if (!decryption_key->Init(true)) {
197 DVLOG(1) << "Could not initialize decryption key."; 228 DVLOG(1) << "Could not initialize decryption key.";
198 client_->KeyError(key_system, session_id, Decryptor::kUnknownError, 0); 229 client_->KeyError(key_system, session_id, Decryptor::kUnknownError, 0);
199 return; 230 return;
200 } 231 }
201 232
202 { 233 SetKey(key_id_string, decryption_key.Pass());
203 base::AutoLock auto_lock(key_map_lock_);
204 KeyMap::iterator found = key_map_.find(key_id_string);
205 if (found != key_map_.end()) {
206 delete found->second;
207 key_map_.erase(found);
208 }
209 key_map_[key_id_string] = decryption_key.release();
210 }
211
212 client_->KeyAdded(key_system, session_id); 234 client_->KeyAdded(key_system, session_id);
213 } 235 }
214 236
215 void AesDecryptor::CancelKeyRequest(const std::string& key_system, 237 void AesDecryptor::CancelKeyRequest(const std::string& key_system,
216 const std::string& session_id) { 238 const std::string& session_id) {
217 } 239 }
218 240
219 void AesDecryptor::Decrypt(const scoped_refptr<DecoderBuffer>& encrypted, 241 void AesDecryptor::Decrypt(const scoped_refptr<DecoderBuffer>& encrypted,
ddorwin 2012/07/26 21:24:07 "encrypted" isn't really a noun. I realize changin
xhwang 2012/07/26 23:36:47 Chatted with ddorwin@ offline. We'll use: a) "encr
220 const DecryptCB& decrypt_cb) { 242 const DecryptCB& decrypt_cb) {
221 CHECK(encrypted->GetDecryptConfig()); 243 CHECK(encrypted->GetDecryptConfig());
222 const uint8* key_id = encrypted->GetDecryptConfig()->key_id(); 244 const uint8* key_id = encrypted->GetDecryptConfig()->key_id();
223 const int key_id_size = encrypted->GetDecryptConfig()->key_id_size(); 245 const int key_id_size = encrypted->GetDecryptConfig()->key_id_size();
224 246
225 // TODO(xhwang): Avoid always constructing a string with StringPiece? 247 // TODO(xhwang): Avoid always constructing a string with StringPiece?
226 std::string key_id_string(reinterpret_cast<const char*>(key_id), key_id_size); 248 std::string key_id_string(reinterpret_cast<const char*>(key_id), key_id_size);
227 249 DecryptionKey* key = GetKey(key_id_string);
228 DecryptionKey* key = NULL;
229 {
230 base::AutoLock auto_lock(key_map_lock_);
231 KeyMap::const_iterator found = key_map_.find(key_id_string);
232 if (found != key_map_.end())
233 key = found->second;
234 }
235 250
236 if (!key) { 251 if (!key) {
237 // TODO(fgalligan): Fire a need_key event here and add a test. 252 DVLOG(1) << "Could not find a matching key for the given key ID.";
ddorwin 2012/07/26 21:24:07 This is still temporary, right? So there should st
xhwang 2012/07/26 23:36:47 Done.
238 DVLOG(1) << "Could not find a matching key for given key ID.";
239 decrypt_cb.Run(kError, NULL); 253 decrypt_cb.Run(kError, NULL);
240 return; 254 return;
241 } 255 }
242 256
243 int checksum_size = encrypted->GetDecryptConfig()->checksum_size(); 257 int checksum_size = encrypted->GetDecryptConfig()->checksum_size();
244 // According to the WebM encrypted specification, it is an open question 258 // According to the WebM encrypted specification, it is an open question
245 // what should happen when a frame fails the integrity check. 259 // what should happen when a frame fails the integrity check.
246 // http://wiki.webmproject.org/encryption/webm-encryption-rfc 260 // http://wiki.webmproject.org/encryption/webm-encryption-rfc
247 if (checksum_size > 0 && 261 if (checksum_size > 0 &&
248 !key->hmac_key().empty() && 262 !key->hmac_key().empty() &&
249 !CheckData(*encrypted, key->hmac_key())) { 263 !CheckData(*encrypted, key->hmac_key())) {
250 DVLOG(1) << "Integrity check failed."; 264 DVLOG(1) << "Integrity check failed.";
251 decrypt_cb.Run(kError, NULL); 265 decrypt_cb.Run(kError, NULL);
252 return; 266 return;
253 } 267 }
254 268
255 scoped_refptr<DecoderBuffer> decrypted = 269 DecryptBuffer(decrypt_cb, encrypted, key->decryption_key());
256 DecryptData(*encrypted,
257 key->decryption_key(),
258 encrypted->GetDecryptConfig()->encrypted_frame_offset());
259 if (!decrypted) {
260 DVLOG(1) << "Decryption failed.";
261 decrypt_cb.Run(kError, NULL);
262 return;
263 }
264
265 decrypted->SetTimestamp(encrypted->GetTimestamp());
266 decrypted->SetDuration(encrypted->GetDuration());
267 decrypt_cb.Run(kSuccess, decrypted);
268 } 270 }
269 271
270 AesDecryptor::DecryptionKey::DecryptionKey( 272 void AesDecryptor::SetKey(const std::string& key_id,
271 const std::string& secret) 273 scoped_ptr<DecryptionKey> decryption_key) {
ddorwin 2012/07/26 21:24:07 Why not just a raw pointer with a note in .h that
xhwang 2012/07/26 23:36:47 Passing in scoped_ptr<> enforces that the AesDecry
274 base::AutoLock auto_lock(key_map_lock_);
275 KeyMap::iterator found = key_map_.find(key_id);
276 if (found != key_map_.end()) {
277 delete found->second;
278 key_map_.erase(found);
279 }
280 key_map_[key_id] = decryption_key.release();
281 }
282
283 AesDecryptor::DecryptionKey* AesDecryptor::GetKey(
284 const std::string& key_id) const {
285 base::AutoLock auto_lock(key_map_lock_);
286 KeyMap::const_iterator found = key_map_.find(key_id);
287 if (found != key_map_.end())
ddorwin 2012/07/26 21:24:07 I'd swap such that the success case is at the end
xhwang 2012/07/26 23:36:47 Done.
288 return found->second;
289 return NULL;
290 }
291
292 AesDecryptor::DecryptionKey::DecryptionKey(const std::string& secret)
272 : secret_(secret) { 293 : secret_(secret) {
273 } 294 }
274 295
275 AesDecryptor::DecryptionKey::~DecryptionKey() {} 296 AesDecryptor::DecryptionKey::~DecryptionKey() {}
276 297
277 bool AesDecryptor::DecryptionKey::Init(bool derive_webm_keys) { 298 bool AesDecryptor::DecryptionKey::Init(bool derive_webm_keys) {
278 CHECK(!secret_.empty()); 299 CHECK(!secret_.empty());
279 300
280 if (derive_webm_keys) { 301 if (derive_webm_keys) {
281 std::string raw_key = DeriveKey(secret_, 302 std::string raw_key = DeriveKey(secret_,
(...skipping 17 matching lines...) Expand all
299 320
300 decryption_key_.reset( 321 decryption_key_.reset(
301 crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, secret_)); 322 crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, secret_));
302 if (!decryption_key_.get()) { 323 if (!decryption_key_.get()) {
303 return false; 324 return false;
304 } 325 }
305 return true; 326 return true;
306 } 327 }
307 328
308 } // namespace media 329 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698