OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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/cdm/aes_decryptor.h" | 5 #include "media/cdm/aes_decryptor.h" |
6 | 6 |
7 #include <list> | 7 #include <list> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 return key_list_.end(); | 98 return key_list_.end(); |
99 } | 99 } |
100 | 100 |
101 void AesDecryptor::SessionIdDecryptionKeyMap::Erase( | 101 void AesDecryptor::SessionIdDecryptionKeyMap::Erase( |
102 KeyList::iterator position) { | 102 KeyList::iterator position) { |
103 DCHECK(position->second); | 103 DCHECK(position->second); |
104 delete position->second; | 104 delete position->second; |
105 key_list_.erase(position); | 105 key_list_.erase(position); |
106 } | 106 } |
107 | 107 |
108 uint32 AesDecryptor::next_session_id_ = 1; | 108 uint32_t AesDecryptor::next_session_id_ = 1; |
109 | 109 |
110 enum ClearBytesBufferSel { | 110 enum ClearBytesBufferSel { |
111 kSrcContainsClearBytes, | 111 kSrcContainsClearBytes, |
112 kDstContainsClearBytes | 112 kDstContainsClearBytes |
113 }; | 113 }; |
114 | 114 |
115 static void CopySubsamples(const std::vector<SubsampleEntry>& subsamples, | 115 static void CopySubsamples(const std::vector<SubsampleEntry>& subsamples, |
116 const ClearBytesBufferSel sel, | 116 const ClearBytesBufferSel sel, |
117 const uint8* src, | 117 const uint8_t* src, |
118 uint8* dst) { | 118 uint8_t* dst) { |
119 for (size_t i = 0; i < subsamples.size(); i++) { | 119 for (size_t i = 0; i < subsamples.size(); i++) { |
120 const SubsampleEntry& subsample = subsamples[i]; | 120 const SubsampleEntry& subsample = subsamples[i]; |
121 if (sel == kSrcContainsClearBytes) { | 121 if (sel == kSrcContainsClearBytes) { |
122 src += subsample.clear_bytes; | 122 src += subsample.clear_bytes; |
123 } else { | 123 } else { |
124 dst += subsample.clear_bytes; | 124 dst += subsample.clear_bytes; |
125 } | 125 } |
126 memcpy(dst, src, subsample.cypher_bytes); | 126 memcpy(dst, src, subsample.cypher_bytes); |
127 src += subsample.cypher_bytes; | 127 src += subsample.cypher_bytes; |
128 dst += subsample.cypher_bytes; | 128 dst += subsample.cypher_bytes; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 if (input.decrypt_config()->subsamples().empty()) { | 160 if (input.decrypt_config()->subsamples().empty()) { |
161 std::string decrypted_text; | 161 std::string decrypted_text; |
162 base::StringPiece encrypted_text(sample, sample_size); | 162 base::StringPiece encrypted_text(sample, sample_size); |
163 if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) { | 163 if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) { |
164 DVLOG(1) << "Could not decrypt data."; | 164 DVLOG(1) << "Could not decrypt data."; |
165 return NULL; | 165 return NULL; |
166 } | 166 } |
167 | 167 |
168 // TODO(xhwang): Find a way to avoid this data copy. | 168 // TODO(xhwang): Find a way to avoid this data copy. |
169 return DecoderBuffer::CopyFrom( | 169 return DecoderBuffer::CopyFrom( |
170 reinterpret_cast<const uint8*>(decrypted_text.data()), | 170 reinterpret_cast<const uint8_t*>(decrypted_text.data()), |
171 decrypted_text.size()); | 171 decrypted_text.size()); |
172 } | 172 } |
173 | 173 |
174 const std::vector<SubsampleEntry>& subsamples = | 174 const std::vector<SubsampleEntry>& subsamples = |
175 input.decrypt_config()->subsamples(); | 175 input.decrypt_config()->subsamples(); |
176 | 176 |
177 size_t total_clear_size = 0; | 177 size_t total_clear_size = 0; |
178 size_t total_encrypted_size = 0; | 178 size_t total_encrypted_size = 0; |
179 for (size_t i = 0; i < subsamples.size(); i++) { | 179 for (size_t i = 0; i < subsamples.size(); i++) { |
180 total_clear_size += subsamples[i].clear_bytes; | 180 total_clear_size += subsamples[i].clear_bytes; |
181 total_encrypted_size += subsamples[i].cypher_bytes; | 181 total_encrypted_size += subsamples[i].cypher_bytes; |
182 // Check for overflow. This check is valid because *_size is unsigned. | 182 // Check for overflow. This check is valid because *_size is unsigned. |
183 DCHECK(total_clear_size >= subsamples[i].clear_bytes); | 183 DCHECK(total_clear_size >= subsamples[i].clear_bytes); |
184 if (total_encrypted_size < subsamples[i].cypher_bytes) | 184 if (total_encrypted_size < subsamples[i].cypher_bytes) |
185 return NULL; | 185 return NULL; |
186 } | 186 } |
187 size_t total_size = total_clear_size + total_encrypted_size; | 187 size_t total_size = total_clear_size + total_encrypted_size; |
188 if (total_size < total_clear_size || total_size != sample_size) { | 188 if (total_size < total_clear_size || total_size != sample_size) { |
189 DVLOG(1) << "Subsample sizes do not equal input size"; | 189 DVLOG(1) << "Subsample sizes do not equal input size"; |
190 return NULL; | 190 return NULL; |
191 } | 191 } |
192 | 192 |
193 // No need to decrypt if there is no encrypted data. | 193 // No need to decrypt if there is no encrypted data. |
194 if (total_encrypted_size <= 0) { | 194 if (total_encrypted_size <= 0) { |
195 return DecoderBuffer::CopyFrom(reinterpret_cast<const uint8*>(sample), | 195 return DecoderBuffer::CopyFrom(reinterpret_cast<const uint8_t*>(sample), |
196 sample_size); | 196 sample_size); |
197 } | 197 } |
198 | 198 |
199 // The encrypted portions of all subsamples must form a contiguous block, | 199 // The encrypted portions of all subsamples must form a contiguous block, |
200 // such that an encrypted subsample that ends away from a block boundary is | 200 // such that an encrypted subsample that ends away from a block boundary is |
201 // immediately followed by the start of the next encrypted subsample. We | 201 // immediately followed by the start of the next encrypted subsample. We |
202 // copy all encrypted subsamples to a contiguous buffer, decrypt them, then | 202 // copy all encrypted subsamples to a contiguous buffer, decrypt them, then |
203 // copy the decrypted bytes over the encrypted bytes in the output. | 203 // copy the decrypted bytes over the encrypted bytes in the output. |
204 // TODO(strobe): attempt to reduce number of memory copies | 204 // TODO(strobe): attempt to reduce number of memory copies |
205 scoped_ptr<uint8[]> encrypted_bytes(new uint8[total_encrypted_size]); | 205 scoped_ptr<uint8_t[]> encrypted_bytes(new uint8_t[total_encrypted_size]); |
206 CopySubsamples(subsamples, kSrcContainsClearBytes, | 206 CopySubsamples(subsamples, kSrcContainsClearBytes, |
207 reinterpret_cast<const uint8*>(sample), encrypted_bytes.get()); | 207 reinterpret_cast<const uint8_t*>(sample), |
| 208 encrypted_bytes.get()); |
208 | 209 |
209 base::StringPiece encrypted_text( | 210 base::StringPiece encrypted_text( |
210 reinterpret_cast<const char*>(encrypted_bytes.get()), | 211 reinterpret_cast<const char*>(encrypted_bytes.get()), |
211 total_encrypted_size); | 212 total_encrypted_size); |
212 std::string decrypted_text; | 213 std::string decrypted_text; |
213 if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) { | 214 if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) { |
214 DVLOG(1) << "Could not decrypt data."; | 215 DVLOG(1) << "Could not decrypt data."; |
215 return NULL; | 216 return NULL; |
216 } | 217 } |
217 DCHECK_EQ(decrypted_text.size(), encrypted_text.size()); | 218 DCHECK_EQ(decrypted_text.size(), encrypted_text.size()); |
218 | 219 |
219 scoped_refptr<DecoderBuffer> output = DecoderBuffer::CopyFrom( | 220 scoped_refptr<DecoderBuffer> output = DecoderBuffer::CopyFrom( |
220 reinterpret_cast<const uint8*>(sample), sample_size); | 221 reinterpret_cast<const uint8_t*>(sample), sample_size); |
221 CopySubsamples(subsamples, kDstContainsClearBytes, | 222 CopySubsamples(subsamples, kDstContainsClearBytes, |
222 reinterpret_cast<const uint8*>(decrypted_text.data()), | 223 reinterpret_cast<const uint8_t*>(decrypted_text.data()), |
223 output->writable_data()); | 224 output->writable_data()); |
224 return output; | 225 return output; |
225 } | 226 } |
226 | 227 |
227 AesDecryptor::AesDecryptor(const GURL& /* security_origin */, | 228 AesDecryptor::AesDecryptor(const GURL& /* security_origin */, |
228 const SessionMessageCB& session_message_cb, | 229 const SessionMessageCB& session_message_cb, |
229 const SessionClosedCB& session_closed_cb, | 230 const SessionClosedCB& session_closed_cb, |
230 const SessionKeysChangeCB& session_keys_change_cb) | 231 const SessionKeysChangeCB& session_keys_change_cb) |
231 : session_message_cb_(session_message_cb), | 232 : session_message_cb_(session_message_cb), |
232 session_closed_cb_(session_closed_cb), | 233 session_closed_cb_(session_closed_cb), |
233 session_keys_change_cb_(session_keys_change_cb) { | 234 session_keys_change_cb_(session_keys_change_cb) { |
234 // AesDecryptor doesn't keep any persistent data, so no need to do anything | 235 // AesDecryptor doesn't keep any persistent data, so no need to do anything |
235 // with |security_origin|. | 236 // with |security_origin|. |
236 DCHECK(!session_message_cb_.is_null()); | 237 DCHECK(!session_message_cb_.is_null()); |
237 DCHECK(!session_closed_cb_.is_null()); | 238 DCHECK(!session_closed_cb_.is_null()); |
238 DCHECK(!session_keys_change_cb_.is_null()); | 239 DCHECK(!session_keys_change_cb_.is_null()); |
239 } | 240 } |
240 | 241 |
241 AesDecryptor::~AesDecryptor() { | 242 AesDecryptor::~AesDecryptor() { |
242 key_map_.clear(); | 243 key_map_.clear(); |
243 } | 244 } |
244 | 245 |
245 void AesDecryptor::SetServerCertificate(const uint8* certificate_data, | 246 void AesDecryptor::SetServerCertificate(const std::vector<uint8_t>& certificate, |
246 int certificate_data_length, | |
247 scoped_ptr<SimpleCdmPromise> promise) { | 247 scoped_ptr<SimpleCdmPromise> promise) { |
248 promise->reject( | 248 promise->reject( |
249 NOT_SUPPORTED_ERROR, 0, "SetServerCertificate() is not supported."); | 249 NOT_SUPPORTED_ERROR, 0, "SetServerCertificate() is not supported."); |
250 } | 250 } |
251 | 251 |
252 void AesDecryptor::CreateSessionAndGenerateRequest( | 252 void AesDecryptor::CreateSessionAndGenerateRequest( |
253 SessionType session_type, | 253 SessionType session_type, |
254 EmeInitDataType init_data_type, | 254 EmeInitDataType init_data_type, |
255 const uint8* init_data, | 255 const std::vector<uint8_t>& init_data, |
256 int init_data_length, | |
257 scoped_ptr<NewSessionCdmPromise> promise) { | 256 scoped_ptr<NewSessionCdmPromise> promise) { |
258 std::string session_id(base::UintToString(next_session_id_++)); | 257 std::string session_id(base::UintToString(next_session_id_++)); |
259 valid_sessions_.insert(session_id); | 258 valid_sessions_.insert(session_id); |
260 | 259 |
261 // For now, the AesDecryptor does not care about |session_type|. | 260 // For now, the AesDecryptor does not care about |session_type|. |
262 // TODO(jrummell): Validate |session_type|. | 261 // TODO(jrummell): Validate |session_type|. |
263 | 262 |
264 std::vector<uint8> message; | 263 std::vector<uint8_t> message; |
265 // TODO(jrummell): Since unprefixed will never send NULL, remove this check | 264 // TODO(jrummell): Since unprefixed will never send NULL, remove this check |
266 // when prefixed EME is removed (http://crbug.com/249976). | 265 // when prefixed EME is removed (http://crbug.com/249976). |
267 if (init_data && init_data_length) { | 266 if (!init_data.empty()) { |
268 std::vector<std::vector<uint8>> keys; | 267 std::vector<std::vector<uint8_t>> keys; |
269 switch (init_data_type) { | 268 switch (init_data_type) { |
270 case EmeInitDataType::WEBM: | 269 case EmeInitDataType::WEBM: |
271 // |init_data| is simply the key needed. | 270 // |init_data| is simply the key needed. |
272 keys.push_back( | 271 keys.push_back(init_data); |
273 std::vector<uint8>(init_data, init_data + init_data_length)); | |
274 break; | 272 break; |
275 case EmeInitDataType::CENC: | 273 case EmeInitDataType::CENC: |
276 // |init_data| is a set of 0 or more concatenated 'pssh' boxes. | 274 // |init_data| is a set of 0 or more concatenated 'pssh' boxes. |
277 if (!GetKeyIdsForCommonSystemId(init_data, init_data_length, &keys)) { | 275 if (!GetKeyIdsForCommonSystemId(init_data, &keys)) { |
278 promise->reject(NOT_SUPPORTED_ERROR, 0, | 276 promise->reject(NOT_SUPPORTED_ERROR, 0, |
279 "No supported PSSH box found."); | 277 "No supported PSSH box found."); |
280 return; | 278 return; |
281 } | 279 } |
282 break; | 280 break; |
283 case EmeInitDataType::KEYIDS: { | 281 case EmeInitDataType::KEYIDS: { |
284 std::string init_data_string(init_data, init_data + init_data_length); | 282 std::string init_data_string(init_data.begin(), init_data.end()); |
285 std::string error_message; | 283 std::string error_message; |
286 if (!ExtractKeyIdsFromKeyIdsInitData(init_data_string, &keys, | 284 if (!ExtractKeyIdsFromKeyIdsInitData(init_data_string, &keys, |
287 &error_message)) { | 285 &error_message)) { |
288 promise->reject(NOT_SUPPORTED_ERROR, 0, error_message); | 286 promise->reject(NOT_SUPPORTED_ERROR, 0, error_message); |
289 return; | 287 return; |
290 } | 288 } |
291 break; | 289 break; |
292 } | 290 } |
293 default: | 291 default: |
294 NOTREACHED(); | 292 NOTREACHED(); |
(...skipping 13 matching lines...) Expand all Loading... |
308 | 306 |
309 void AesDecryptor::LoadSession(SessionType session_type, | 307 void AesDecryptor::LoadSession(SessionType session_type, |
310 const std::string& session_id, | 308 const std::string& session_id, |
311 scoped_ptr<NewSessionCdmPromise> promise) { | 309 scoped_ptr<NewSessionCdmPromise> promise) { |
312 // TODO(xhwang): Change this to NOTREACHED() when blink checks for key systems | 310 // TODO(xhwang): Change this to NOTREACHED() when blink checks for key systems |
313 // that do not support loadSession. See http://crbug.com/342481 | 311 // that do not support loadSession. See http://crbug.com/342481 |
314 promise->reject(NOT_SUPPORTED_ERROR, 0, "LoadSession() is not supported."); | 312 promise->reject(NOT_SUPPORTED_ERROR, 0, "LoadSession() is not supported."); |
315 } | 313 } |
316 | 314 |
317 void AesDecryptor::UpdateSession(const std::string& session_id, | 315 void AesDecryptor::UpdateSession(const std::string& session_id, |
318 const uint8* response, | 316 const std::vector<uint8_t>& response, |
319 int response_length, | |
320 scoped_ptr<SimpleCdmPromise> promise) { | 317 scoped_ptr<SimpleCdmPromise> promise) { |
321 CHECK(response); | 318 CHECK(!response.empty()); |
322 CHECK_GT(response_length, 0); | |
323 | 319 |
324 // TODO(jrummell): Convert back to a DCHECK once prefixed EME is removed. | 320 // TODO(jrummell): Convert back to a DCHECK once prefixed EME is removed. |
325 if (valid_sessions_.find(session_id) == valid_sessions_.end()) { | 321 if (valid_sessions_.find(session_id) == valid_sessions_.end()) { |
326 promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist."); | 322 promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist."); |
327 return; | 323 return; |
328 } | 324 } |
329 | 325 |
330 std::string key_string(reinterpret_cast<const char*>(response), | 326 std::string key_string(response.begin(), response.end()); |
331 response_length); | |
332 | 327 |
333 KeyIdAndKeyPairs keys; | 328 KeyIdAndKeyPairs keys; |
334 SessionType session_type = MediaKeys::TEMPORARY_SESSION; | 329 SessionType session_type = MediaKeys::TEMPORARY_SESSION; |
335 if (!ExtractKeysFromJWKSet(key_string, &keys, &session_type)) { | 330 if (!ExtractKeysFromJWKSet(key_string, &keys, &session_type)) { |
336 promise->reject( | 331 promise->reject( |
337 INVALID_ACCESS_ERROR, 0, "Response is not a valid JSON Web Key Set."); | 332 INVALID_ACCESS_ERROR, 0, "Response is not a valid JSON Web Key Set."); |
338 return; | 333 return; |
339 } | 334 } |
340 | 335 |
341 // Make sure that at least one key was extracted. | 336 // Make sure that at least one key was extracted. |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
600 bool AesDecryptor::DecryptionKey::Init() { | 595 bool AesDecryptor::DecryptionKey::Init() { |
601 CHECK(!secret_.empty()); | 596 CHECK(!secret_.empty()); |
602 decryption_key_.reset(crypto::SymmetricKey::Import( | 597 decryption_key_.reset(crypto::SymmetricKey::Import( |
603 crypto::SymmetricKey::AES, secret_)); | 598 crypto::SymmetricKey::AES, secret_)); |
604 if (!decryption_key_) | 599 if (!decryption_key_) |
605 return false; | 600 return false; |
606 return true; | 601 return true; |
607 } | 602 } |
608 | 603 |
609 } // namespace media | 604 } // namespace media |
OLD | NEW |