1 /*****************************************************************
2 |
3 | AP4 - OMA DCF Support
4 |
5 | Copyright 2002-2008 Axiomatic Systems, LLC
6 |
7 |
8 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
9 |
10 | Unless you have obtained Bento4 under a difference license,
11 | this version of Bento4 is Bento4|GPL.
12 | Bento4|GPL is free software; you can redistribute it and/or modify
13 | it under the terms of the GNU General Public License as published by
14 | the Free Software Foundation; either version 2, or (at your option)
15 | any later version.
16 |
17 | Bento4|GPL is distributed in the hope that it will be useful,
18 | but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | GNU General Public License for more details.
21 |
22 | You should have received a copy of the GNU General Public License
23 | along with Bento4|GPL; see the file COPYING. If not, write to the
24 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 | 02111-1307, USA.
26 |
27 ****************************************************************/
28
29 /*----------------------------------------------------------------------
30 | includes
31 +---------------------------------------------------------------------*/
32 #include "Ap4SchmAtom.h"
33 #include "Ap4StsdAtom.h"
34 #include "Ap4Sample.h"
35 #include "Ap4StreamCipher.h"
36 #include "Ap4IsfmAtom.h"
37 #include "Ap4FrmaAtom.h"
38 #include "Ap4IkmsAtom.h"
39 #include "Ap4IsfmAtom.h"
40 #include "Ap4IsltAtom.h"
41 #include "Ap4Utils.h"
42 #include "Ap4TrakAtom.h"
43 #include "Ap4OdafAtom.h"
44 #include "Ap4OmaDcf.h"
45 #include "Ap4OhdrAtom.h"
46 #include "Ap4OddaAtom.h"
47 #include "Ap4OdheAtom.h"
48 #include "Ap4FtypAtom.h"
49 #include "Ap4GrpiAtom.h"
50 #include "Ap4HdlrAtom.h"
51
52 /*----------------------------------------------------------------------
53 | AP4_OmaDrmInfo Dynamic Cast Anchor
54 +---------------------------------------------------------------------*/
AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_OmaDrmInfo)55 AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_OmaDrmInfo)
56
57 /*----------------------------------------------------------------------
58 | AP4_OmaDcfAtomDecrypter::DecryptAtoms
59 +---------------------------------------------------------------------*/
60 AP4_Result
61 AP4_OmaDcfAtomDecrypter::DecryptAtoms(AP4_AtomParent& atoms,
62 AP4_Processor::ProgressListener* /*listener*/,
63 AP4_BlockCipherFactory* block_cipher_factory,
64 AP4_ProtectionKeyMap& key_map)
65 {
66 // default factory
67 if (block_cipher_factory == NULL) {
68 block_cipher_factory = &AP4_DefaultBlockCipherFactory::Instance;
69 }
70
71 unsigned int index = 1;
72 for (AP4_List<AP4_Atom>::Item* item = atoms.GetChildren().FirstItem();
73 item;
74 item = item->GetNext()) {
75 AP4_Atom* atom = item->GetData();
76 if (atom->GetType() != AP4_ATOM_TYPE_ODRM) continue;
77
78 // check that we have the key
79 const AP4_DataBuffer* key = key_map.GetKey(index++);
80 if (key == NULL) return AP4_ERROR_INVALID_PARAMETERS;
81
82 // check that we have all the atoms we need
83 AP4_ContainerAtom* odrm = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
84 if (odrm == NULL) continue; // not enough info
85 AP4_OdheAtom* odhe = AP4_DYNAMIC_CAST(AP4_OdheAtom, odrm->GetChild(AP4_ATOM_TYPE_ODHE));
86 if (odhe == NULL) continue; // not enough info
87 AP4_OddaAtom* odda = AP4_DYNAMIC_CAST(AP4_OddaAtom, odrm->GetChild(AP4_ATOM_TYPE_ODDA));;
88 if (odda == NULL) continue; // not enough info
89 AP4_OhdrAtom* ohdr = AP4_DYNAMIC_CAST(AP4_OhdrAtom, odhe->GetChild(AP4_ATOM_TYPE_OHDR));
90 if (ohdr == NULL) continue; // not enough info
91
92 // do nothing if the atom is not encrypted
93 if (ohdr->GetEncryptionMethod() == AP4_OMA_DCF_ENCRYPTION_METHOD_NULL) {
94 continue;
95 }
96
97 // create the byte stream
98 AP4_ByteStream* cipher_stream = NULL;
99 AP4_Result result = CreateDecryptingStream(*odrm,
100 key->GetData(),
101 key->GetDataSize(),
102 block_cipher_factory,
103 cipher_stream);
104 if (AP4_SUCCEEDED(result)) {
105 // replace the odda atom's payload with the decrypted stream
106 odda->SetEncryptedPayload(*cipher_stream, ohdr->GetPlaintextLength());
107 cipher_stream->Release();
108
109 // the atom will now be in the clear
110 ohdr->SetEncryptionMethod(AP4_OMA_DCF_ENCRYPTION_METHOD_NULL);
111 ohdr->SetPaddingScheme(AP4_OMA_DCF_PADDING_SCHEME_NONE);
112 }
113 }
114
115 return AP4_SUCCESS;
116 }
117
118 /*----------------------------------------------------------------------
119 | AP4_OmaDcfAtomDecrypter::CreateDecryptingStream
120 +---------------------------------------------------------------------*/
121 AP4_Result
CreateDecryptingStream(AP4_ContainerAtom & odrm,const AP4_UI08 * key,AP4_Size key_size,AP4_BlockCipherFactory * block_cipher_factory,AP4_ByteStream * & stream)122 AP4_OmaDcfAtomDecrypter::CreateDecryptingStream(
123 AP4_ContainerAtom& odrm,
124 const AP4_UI08* key,
125 AP4_Size key_size,
126 AP4_BlockCipherFactory* block_cipher_factory,
127 AP4_ByteStream*& stream)
128 {
129 // default return values
130 stream = NULL;
131
132 AP4_OdheAtom* odhe = AP4_DYNAMIC_CAST(AP4_OdheAtom, odrm.GetChild(AP4_ATOM_TYPE_ODHE));
133 if (odhe == NULL) return AP4_ERROR_INVALID_FORMAT;
134 AP4_OddaAtom* odda = AP4_DYNAMIC_CAST(AP4_OddaAtom, odrm.GetChild(AP4_ATOM_TYPE_ODDA));;
135 if (odda == NULL) return AP4_ERROR_INVALID_FORMAT;
136 AP4_OhdrAtom* ohdr = AP4_DYNAMIC_CAST(AP4_OhdrAtom, odhe->GetChild(AP4_ATOM_TYPE_OHDR));
137 if (ohdr == NULL) return AP4_ERROR_INVALID_FORMAT;
138
139 // default cipher factory
140 if (block_cipher_factory == NULL) {
141 block_cipher_factory = &AP4_DefaultBlockCipherFactory::Instance;
142 }
143
144 // shortcut for non-encrypted files
145 if (ohdr->GetEncryptionMethod() == AP4_OMA_DCF_ENCRYPTION_METHOD_NULL) {
146 stream = &odda->GetEncryptedPayload();
147 stream->AddReference();
148 return AP4_SUCCESS;
149 }
150
151 // if this is part of a group, use the group key to obtain the content
152 // key (note that the field called GroupKey in the spec is actually not
153 // the group key but the content key encrypted with the group key...
154 AP4_GrpiAtom* grpi = AP4_DYNAMIC_CAST(AP4_GrpiAtom, ohdr->GetChild(AP4_ATOM_TYPE_GRPI));
155 AP4_UI08* key_buffer = NULL;
156 if (grpi) {
157 // sanity check on the encrypted key size
158 if (grpi->GetGroupKey().GetDataSize() < 32) {
159 return AP4_ERROR_INVALID_FORMAT;
160 }
161
162 // create a block cipher to decrypt the content key
163 AP4_BlockCipher* block_cipher = NULL;
164 AP4_Result result;
165
166 // create a stream cipher from the block cipher
167 AP4_StreamCipher* stream_cipher = NULL;
168 switch (ohdr->GetEncryptionMethod()) {
169 case AP4_OMA_DCF_ENCRYPTION_METHOD_AES_CBC:
170 result = block_cipher_factory->CreateCipher(AP4_BlockCipher::AES_128,
171 AP4_BlockCipher::DECRYPT,
172 AP4_BlockCipher::CBC,
173 NULL,
174 key,
175 key_size,
176 block_cipher);
177 if (AP4_FAILED(result)) return result;
178 stream_cipher = new AP4_CbcStreamCipher(block_cipher);
179 break;
180
181 case AP4_OMA_DCF_ENCRYPTION_METHOD_AES_CTR: {
182 AP4_BlockCipher::CtrParams ctr_params;
183 ctr_params.counter_size = 16;
184 result = block_cipher_factory->CreateCipher(AP4_BlockCipher::AES_128,
185 AP4_BlockCipher::DECRYPT,
186 AP4_BlockCipher::CTR,
187 &ctr_params,
188 key,
189 key_size,
190 block_cipher);
191 if (AP4_FAILED(result)) return result;
192 stream_cipher = new AP4_CtrStreamCipher(block_cipher, 16);
193 break;
194 }
195
196 default:
197 return AP4_ERROR_NOT_SUPPORTED;
198 }
199
200 // set the IV
201 stream_cipher->SetIV(grpi->GetGroupKey().GetData());
202
203 // decrypt the content key
204 AP4_Size key_buffer_size = grpi->GetGroupKey().GetDataSize(); // worst case
205 key_buffer = new AP4_UI08[key_buffer_size];
206 result = stream_cipher->ProcessBuffer(grpi->GetGroupKey().GetData()+16,
207 grpi->GetGroupKey().GetDataSize()-16,
208 key_buffer,
209 &key_buffer_size,
210 true);
211 delete stream_cipher; // this will also delete the block cipher
212 if (AP4_FAILED(result)) {
213 delete[] key_buffer;
214 return result;
215 }
216
217 // point to the new key value
218 key = key_buffer;
219 key_size = key_buffer_size;
220 }
221
222 AP4_OmaDcfCipherMode mode;
223 switch (ohdr->GetEncryptionMethod()) {
224 case AP4_OMA_DCF_ENCRYPTION_METHOD_AES_CBC:
225 mode = AP4_OMA_DCF_CIPHER_MODE_CBC;
226 break;
227 case AP4_OMA_DCF_ENCRYPTION_METHOD_AES_CTR:
228 mode = AP4_OMA_DCF_CIPHER_MODE_CTR;
229 break;
230 default:
231 return AP4_ERROR_NOT_SUPPORTED;
232 }
233
234 AP4_Result result;
235 result = CreateDecryptingStream(mode,
236 odda->GetEncryptedPayload(),
237 ohdr->GetPlaintextLength(),
238 key, key_size,
239 block_cipher_factory,
240 stream);
241
242 // cleanup
243 delete[] key_buffer;
244
245 return result;
246 }
247
248 /*----------------------------------------------------------------------
249 | AP4_OmaDcfAtomDecrypter::CreateDecryptingStream
250 +---------------------------------------------------------------------*/
251 AP4_Result
CreateDecryptingStream(AP4_OmaDcfCipherMode mode,AP4_ByteStream & encrypted_stream,AP4_LargeSize cleartext_size,const AP4_UI08 * key,AP4_Size key_size,AP4_BlockCipherFactory * block_cipher_factory,AP4_ByteStream * & stream)252 AP4_OmaDcfAtomDecrypter::CreateDecryptingStream(
253 AP4_OmaDcfCipherMode mode,
254 AP4_ByteStream& encrypted_stream,
255 AP4_LargeSize cleartext_size,
256 const AP4_UI08* key,
257 AP4_Size key_size,
258 AP4_BlockCipherFactory* block_cipher_factory,
259 AP4_ByteStream*& stream)
260 {
261 // default return value
262 stream = NULL;
263
264 // default factory
265 if (block_cipher_factory == NULL) {
266 block_cipher_factory = &AP4_DefaultBlockCipherFactory::Instance;
267 }
268
269 // get the encrypted size (includes IV and padding)
270 AP4_LargeSize encrypted_size = 0;
271 AP4_Result result = encrypted_stream.GetSize(encrypted_size);
272 if (AP4_FAILED(result)) return result;
273
274 // check that the encrypted size is consistent with the cipher mode
275 AP4_BlockCipher::CipherMode cipher_mode;
276 if (mode == AP4_OMA_DCF_CIPHER_MODE_CBC) {
277 // we need at least 16 bytes of IV and 32 bytes of data+padding
278 // we also need a multiple of the block size
279 if (encrypted_size < 48 || ((encrypted_size % 16) != 0)) {
280 return AP4_ERROR_INVALID_FORMAT;
281 }
282 cipher_mode = AP4_BlockCipher::CBC;
283 } else if (mode == AP4_OMA_DCF_CIPHER_MODE_CTR) {
284 // we need at least 16 bytes of IV
285 if (encrypted_size < 16) {
286 return AP4_ERROR_INVALID_FORMAT;
287 }
288 cipher_mode = AP4_BlockCipher::CTR;
289 } else {
290 return AP4_ERROR_NOT_SUPPORTED;
291 }
292
293 // read the IV
294 AP4_UI08 iv[16];
295 result = encrypted_stream.Seek(0);
296 if (AP4_FAILED(result)) return result;
297 result = encrypted_stream.Read(iv, 16);
298 if (AP4_FAILED(result)) return result;
299
300 // create a sub stream with just the encrypted payload without the IV
301 AP4_ByteStream* sub_stream = new AP4_SubStream(encrypted_stream, 16, encrypted_size-16);
302
303 // create the decrypting cipher
304 result = AP4_DecryptingStream::Create(cipher_mode,
305 *sub_stream,
306 cleartext_size,
307 iv,
308 16,
309 key,
310 key_size,
311 block_cipher_factory,
312 stream);
313
314 // we don't keep our own reference to the sub stream
315 sub_stream->Release();
316
317 return result;
318 }
319
320 /*----------------------------------------------------------------------
321 | AP4_OmaDcfSampleDecrypter::Create
322 +---------------------------------------------------------------------*/
323 AP4_Result
Create(AP4_ProtectedSampleDescription * sample_description,const AP4_UI08 * key,AP4_Size key_size,AP4_BlockCipherFactory * block_cipher_factory,AP4_OmaDcfSampleDecrypter * & cipher)324 AP4_OmaDcfSampleDecrypter::Create(AP4_ProtectedSampleDescription* sample_description,
325 const AP4_UI08* key,
326 AP4_Size key_size,
327 AP4_BlockCipherFactory* block_cipher_factory,
328 AP4_OmaDcfSampleDecrypter*& cipher)
329 {
330 // check the parameters
331 if (key == NULL || block_cipher_factory == NULL) {
332 return AP4_ERROR_INVALID_PARAMETERS;
333 }
334
335 // default return value
336 cipher = NULL;
337
338 // default factory
339 if (block_cipher_factory == NULL) {
340 block_cipher_factory = &AP4_DefaultBlockCipherFactory::Instance;
341 }
342
343 // get the scheme info atom
344 AP4_ContainerAtom* schi = sample_description->GetSchemeInfo()->GetSchiAtom();
345 if (schi == NULL) return AP4_ERROR_INVALID_FORMAT;
346
347 // get and check the cipher params
348 // NOTE: we only support an IV Length less than or equal to the cipher block size,
349 // and we don't know how to deal with a key indicator length != 0
350 AP4_OdafAtom* odaf = AP4_DYNAMIC_CAST(AP4_OdafAtom, schi->FindChild("odkm/odaf"));
351 if (odaf) {
352 if (odaf->GetIvLength() > AP4_CIPHER_BLOCK_SIZE) return AP4_ERROR_INVALID_FORMAT;
353 if (odaf->GetKeyIndicatorLength() != 0) return AP4_ERROR_INVALID_FORMAT;
354 } else {
355 return AP4_ERROR_INVALID_FORMAT;
356 }
357
358 // check the scheme details and create the cipher
359 AP4_OhdrAtom* ohdr = AP4_DYNAMIC_CAST(AP4_OhdrAtom, schi->FindChild("odkm/ohdr"));
360 if (ohdr == NULL) return AP4_ERROR_INVALID_FORMAT;
361 AP4_UI08 encryption_method = ohdr->GetEncryptionMethod();
362 if (encryption_method == AP4_OMA_DCF_ENCRYPTION_METHOD_AES_CBC) {
363 // in CBC mode, we only support IVs of the same size as the cipher block size
364 if (odaf->GetIvLength() != AP4_CIPHER_BLOCK_SIZE) return AP4_ERROR_INVALID_FORMAT;
365
366 // require RFC_2630 padding
367 if (ohdr->GetPaddingScheme() != AP4_OMA_DCF_PADDING_SCHEME_RFC_2630) {
368 return AP4_ERROR_NOT_SUPPORTED;
369 }
370
371 // create the block cipher
372 AP4_BlockCipher* block_cipher = NULL;
373 AP4_Result result = block_cipher_factory->CreateCipher(AP4_BlockCipher::AES_128,
374 AP4_BlockCipher::DECRYPT,
375 AP4_BlockCipher::CBC,
376 NULL,
377 key,
378 key_size,
379 block_cipher);
380 if (AP4_FAILED(result)) return result;
381
382 // create the cipher
383 cipher = new AP4_OmaDcfCbcSampleDecrypter(block_cipher,
384 odaf->GetSelectiveEncryption());
385 return AP4_SUCCESS;
386 } else if (encryption_method == AP4_OMA_DCF_ENCRYPTION_METHOD_AES_CTR) {
387 // require NONE padding
388 if (ohdr->GetPaddingScheme() != AP4_OMA_DCF_PADDING_SCHEME_NONE) {
389 return AP4_ERROR_INVALID_FORMAT;
390 }
391
392 // create the block cipher
393 AP4_BlockCipher* block_cipher = NULL;
394 AP4_BlockCipher::CtrParams ctr_params;
395 ctr_params.counter_size = odaf->GetIvLength();
396 AP4_Result result = block_cipher_factory->CreateCipher(AP4_BlockCipher::AES_128,
397 AP4_BlockCipher::DECRYPT,
398 AP4_BlockCipher::CTR,
399 &ctr_params,
400 key,
401 key_size,
402 block_cipher);
403 if (AP4_FAILED(result)) return result;
404
405 // create the cipher
406 cipher = new AP4_OmaDcfCtrSampleDecrypter(block_cipher,
407 odaf->GetIvLength(),
408 odaf->GetSelectiveEncryption());
409 return AP4_SUCCESS;
410 } else {
411 return AP4_ERROR_NOT_SUPPORTED;
412 }
413 }
414
415 /*----------------------------------------------------------------------
416 | AP4_OmaDcfCtrSampleDecrypter::AP4_OmaDcfCtrSampleDecrypter
417 +---------------------------------------------------------------------*/
AP4_OmaDcfCtrSampleDecrypter(AP4_BlockCipher * block_cipher,AP4_Size iv_length,bool selective_encryption)418 AP4_OmaDcfCtrSampleDecrypter::AP4_OmaDcfCtrSampleDecrypter(
419 AP4_BlockCipher* block_cipher,
420 AP4_Size iv_length,
421 bool selective_encryption) :
422 AP4_OmaDcfSampleDecrypter(iv_length, selective_encryption)
423 {
424 m_Cipher = new AP4_CtrStreamCipher(block_cipher, iv_length);
425 }
426
427 /*----------------------------------------------------------------------
428 | AP4_OmaDcfCtrSampleDecrypter::~AP4_OmaDcfCtrSampleDecrypter
429 +---------------------------------------------------------------------*/
~AP4_OmaDcfCtrSampleDecrypter()430 AP4_OmaDcfCtrSampleDecrypter::~AP4_OmaDcfCtrSampleDecrypter()
431 {
432 delete m_Cipher;
433 }
434
435 /*----------------------------------------------------------------------
436 | AP4_OmaDcfCtrSampleDecrypter::DecryptSampleData
437 +---------------------------------------------------------------------*/
438 AP4_Result
DecryptSampleData(AP4_DataBuffer & data_in,AP4_DataBuffer & data_out,const AP4_UI08 *)439 AP4_OmaDcfCtrSampleDecrypter::DecryptSampleData(AP4_DataBuffer& data_in,
440 AP4_DataBuffer& data_out,
441 const AP4_UI08* /*iv*/)
442 {
443 bool is_encrypted = true;
444 const unsigned char* in = data_in.GetData();
445 AP4_Size in_size = data_in.GetDataSize();
446
447 // default to 0 output
448 AP4_CHECK(data_out.SetDataSize(0));
449
450 // check the selective encryption flag
451 if (m_SelectiveEncryption) {
452 if (in_size < 1) return AP4_ERROR_INVALID_FORMAT;
453 is_encrypted = ((in[0]&0x80)!=0);
454 in++;
455 }
456
457 // check the size
458 unsigned int header_size = (m_SelectiveEncryption?1:0)+(is_encrypted?m_IvLength:0);
459 if (header_size > in_size) return AP4_ERROR_INVALID_FORMAT;
460
461 // process the sample data
462 AP4_Size payload_size = in_size-header_size;
463 AP4_CHECK(data_out.Reserve(payload_size));
464 unsigned char* out = data_out.UseData();
465 if (is_encrypted) {
466 // set the IV
467 if (m_IvLength == 16) {
468 m_Cipher->SetIV(in);
469 } else {
470 AP4_UI08 iv[16];
471 AP4_SetMemory(iv, 0, 16);
472 AP4_CopyMemory(iv+16-m_IvLength, in, m_IvLength);
473 m_Cipher->SetIV(iv);
474 }
475 AP4_CHECK(m_Cipher->ProcessBuffer(in+m_IvLength,
476 payload_size,
477 out));
478 } else {
479 AP4_CopyMemory(out, in, payload_size);
480 }
481 AP4_CHECK(data_out.SetDataSize(payload_size));
482
483 return AP4_SUCCESS;
484 }
485
486 /*----------------------------------------------------------------------
487 | AP4_OmaDcfCtrSampleDecrypter::GetDecryptedSampleSize
488 +---------------------------------------------------------------------*/
489 AP4_Size
GetDecryptedSampleSize(AP4_Sample & sample)490 AP4_OmaDcfCtrSampleDecrypter::GetDecryptedSampleSize(AP4_Sample& sample)
491 {
492 if (m_Cipher == NULL) return 0;
493
494 // decide if this sample is encrypted or not
495 bool is_encrypted;
496 if (m_SelectiveEncryption) {
497 // read the first byte to see if the sample is encrypted or not
498 AP4_Byte h;
499 AP4_DataBuffer peek_buffer;
500 peek_buffer.SetBuffer(&h, 1);
501 sample.ReadData(peek_buffer, 1);
502 is_encrypted = ((h&0x80)!=0);
503 } else {
504 is_encrypted = true;
505 }
506
507 AP4_Size crypto_header_size = (m_SelectiveEncryption?1:0)+(is_encrypted?m_IvLength:0);
508 return sample.GetSize()-crypto_header_size;
509 }
510
511 /*----------------------------------------------------------------------
512 | AP4_OmaDcfCbcSampleDecrypter::AP4_OmaDcfCbcSampleDecrypter
513 +---------------------------------------------------------------------*/
AP4_OmaDcfCbcSampleDecrypter(AP4_BlockCipher * block_cipher,bool selective_encryption)514 AP4_OmaDcfCbcSampleDecrypter::AP4_OmaDcfCbcSampleDecrypter(
515 AP4_BlockCipher* block_cipher,
516 bool selective_encryption) :
517 AP4_OmaDcfSampleDecrypter(AP4_CIPHER_BLOCK_SIZE, selective_encryption)
518 {
519 m_Cipher = new AP4_CbcStreamCipher(block_cipher);
520 }
521
522 /*----------------------------------------------------------------------
523 | AP4_OmaDcfCbcSampleDecrypter::~AP4_OmaDcfCbcSampleDecrypter
524 +---------------------------------------------------------------------*/
~AP4_OmaDcfCbcSampleDecrypter()525 AP4_OmaDcfCbcSampleDecrypter::~AP4_OmaDcfCbcSampleDecrypter()
526 {
527 delete m_Cipher;
528 }
529
530 /*----------------------------------------------------------------------
531 | AP4_OmaDbcCbcSampleDecrypter::DecryptSampleData
532 +---------------------------------------------------------------------*/
533 AP4_Result
DecryptSampleData(AP4_DataBuffer & data_in,AP4_DataBuffer & data_out,const AP4_UI08 *)534 AP4_OmaDcfCbcSampleDecrypter::DecryptSampleData(AP4_DataBuffer& data_in,
535 AP4_DataBuffer& data_out,
536 const AP4_UI08* /*iv*/)
537 {
538 bool is_encrypted = true;
539 const unsigned char* in = data_in.GetData();
540 AP4_Size in_size = data_in.GetDataSize();
541 AP4_Size out_size;
542
543 // default to 0 output
544 AP4_CHECK(data_out.SetDataSize(0));
545
546 // check the selective encryption flag
547 if (m_SelectiveEncryption) {
548 if (in_size < 1) return AP4_ERROR_INVALID_FORMAT;
549 is_encrypted = ((in[0]&0x80)!=0);
550 in++;
551 }
552
553 // check the size
554 unsigned int header_size = (m_SelectiveEncryption?1:0)+(is_encrypted?m_IvLength:0);
555 if (header_size > in_size) return AP4_ERROR_INVALID_FORMAT;
556
557 // process the sample data
558 unsigned int payload_size = in_size-header_size;
559 data_out.Reserve(payload_size);
560 unsigned char* out = data_out.UseData();
561 if (is_encrypted) {
562 // get the IV
563 const AP4_UI08* iv = (const AP4_UI08*)in;
564 in += AP4_CIPHER_BLOCK_SIZE;
565
566 m_Cipher->SetIV(iv);
567 out_size = payload_size;
568 AP4_CHECK(m_Cipher->ProcessBuffer(in, payload_size, out, &out_size, true));
569 } else {
570 AP4_CopyMemory(out, in, payload_size);
571 out_size = payload_size;
572 }
573
574 AP4_CHECK(data_out.SetDataSize(out_size));
575
576 return AP4_SUCCESS;
577 }
578
579 /*----------------------------------------------------------------------
580 | AP4_OmaDcfCbcSampleDecrypter::GetDecryptedSampleSize
581 +---------------------------------------------------------------------*/
582 AP4_Size
GetDecryptedSampleSize(AP4_Sample & sample)583 AP4_OmaDcfCbcSampleDecrypter::GetDecryptedSampleSize(AP4_Sample& sample)
584 {
585 if (m_Cipher == NULL) return 0;
586
587 // decide if this sample is encrypted or not
588 bool is_encrypted;
589 if (m_SelectiveEncryption) {
590 // read the first byte to see if the sample is encrypted or not
591 AP4_Byte h;
592 AP4_DataBuffer peek_buffer;
593 peek_buffer.SetBuffer(&h, 1);
594 sample.ReadData(peek_buffer, 1);
595 is_encrypted = ((h&0x80)!=0);
596 } else {
597 is_encrypted = true;
598 }
599
600 if (is_encrypted) {
601 // with CBC, we need to decrypt the last block to know what the padding was
602 AP4_Size crypto_header_size = (m_SelectiveEncryption?1:0)+m_IvLength;
603 AP4_Size encrypted_size = sample.GetSize()-crypto_header_size;
604 AP4_DataBuffer encrypted;
605 AP4_DataBuffer decrypted;
606 AP4_Size decrypted_size = AP4_CIPHER_BLOCK_SIZE;
607 if (sample.GetSize() < crypto_header_size+AP4_CIPHER_BLOCK_SIZE) {
608 return 0;
609 }
610 AP4_Size offset = sample.GetSize()-2*AP4_CIPHER_BLOCK_SIZE;
611 if (AP4_FAILED(sample.ReadData(encrypted, 2*AP4_CIPHER_BLOCK_SIZE, offset))) {
612 return 0;
613 }
614 decrypted.Reserve(decrypted_size);
615 m_Cipher->SetIV(encrypted.GetData());
616 if (AP4_FAILED(m_Cipher->ProcessBuffer(encrypted.GetData()+AP4_CIPHER_BLOCK_SIZE,
617 AP4_CIPHER_BLOCK_SIZE,
618 decrypted.UseData(),
619 &decrypted_size,
620 true))) {
621 return 0;
622 }
623 unsigned int padding_size = AP4_CIPHER_BLOCK_SIZE-decrypted_size;
624 return encrypted_size-padding_size;
625 } else {
626 return sample.GetSize()-(m_SelectiveEncryption?1:0);
627 }
628 }
629
630 /*----------------------------------------------------------------------
631 | AP4_OmaDcfSampleEncrypter::AP4_OmaDcfSampleEncrypter
632 +---------------------------------------------------------------------*/
AP4_OmaDcfSampleEncrypter(const AP4_UI08 * salt)633 AP4_OmaDcfSampleEncrypter::AP4_OmaDcfSampleEncrypter(const AP4_UI08* salt)
634 {
635 // left-align the salt
636 unsigned int i=0;
637 if (salt) {
638 for (; i<8; i++) {
639 m_Salt[i] = salt[i];
640 }
641 }
642 for (; i<sizeof(m_Salt)/sizeof(m_Salt[0]); i++) {
643 m_Salt[i] = 0;
644 }
645 }
646
647 /*----------------------------------------------------------------------
648 | AP4_OmaDcfCtrSampleEncrypter::AP4_OmaDcfCtrSampleEncrypter
649 +---------------------------------------------------------------------*/
AP4_OmaDcfCtrSampleEncrypter(AP4_BlockCipher * block_cipher,const AP4_UI08 * salt)650 AP4_OmaDcfCtrSampleEncrypter::AP4_OmaDcfCtrSampleEncrypter(AP4_BlockCipher* block_cipher,
651 const AP4_UI08* salt) :
652 AP4_OmaDcfSampleEncrypter(salt)
653 {
654 m_Cipher = new AP4_CtrStreamCipher(block_cipher, 16);
655 }
656
657 /*----------------------------------------------------------------------
658 | AP4_OmaDcfCtrSampleEncrypter::~AP4_OmaDcfCtrSampleEncrypter
659 +---------------------------------------------------------------------*/
~AP4_OmaDcfCtrSampleEncrypter()660 AP4_OmaDcfCtrSampleEncrypter::~AP4_OmaDcfCtrSampleEncrypter()
661 {
662 delete m_Cipher;
663 }
664
665 /*----------------------------------------------------------------------
666 | AP4_OmaDcfCtrSampleEncrypter::EncryptSampleData
667 +---------------------------------------------------------------------*/
668 AP4_Result
EncryptSampleData(AP4_DataBuffer & data_in,AP4_DataBuffer & data_out,AP4_UI64 counter,bool)669 AP4_OmaDcfCtrSampleEncrypter::EncryptSampleData(AP4_DataBuffer& data_in,
670 AP4_DataBuffer& data_out,
671 AP4_UI64 counter,
672 bool /*skip_encryption*/)
673 {
674 // setup the buffers
675 const unsigned char* in = data_in.GetData();
676 AP4_CHECK(data_out.SetDataSize(data_in.GetDataSize()+AP4_CIPHER_BLOCK_SIZE+1));
677 unsigned char* out = data_out.UseData();
678
679 // selective encryption flag
680 *out++ = 0x80;
681
682 // IV on 16 bytes: [SSSSSSSSXXXXXXXX]
683 // where SSSSSSSS is the 64-bit salt and
684 // XXXXXXXX is the 64-bit base counter
685 AP4_CopyMemory(out, m_Salt, 8);
686 AP4_BytesFromUInt64BE(&out[8], counter);
687
688 // encrypt the payload
689 AP4_Size data_size = data_in.GetDataSize();
690 m_Cipher->SetIV(out);
691 m_Cipher->ProcessBuffer(in, data_size, out+AP4_CIPHER_BLOCK_SIZE);
692
693 return AP4_SUCCESS;
694 }
695
696 /*----------------------------------------------------------------------
697 | AP4_OmaDcfCtrSampleEncrypter::GetEncryptedSampleSize
698 +---------------------------------------------------------------------*/
699 AP4_Size
GetEncryptedSampleSize(AP4_Sample & sample)700 AP4_OmaDcfCtrSampleEncrypter::GetEncryptedSampleSize(AP4_Sample& sample)
701 {
702 return sample.GetSize()+AP4_CIPHER_BLOCK_SIZE+1;
703 }
704
705 /*----------------------------------------------------------------------
706 | AP4_OmaDcfCbcSampleEncrypter::AP4_OmaDcfCbcSampleEncrypter
707 +---------------------------------------------------------------------*/
AP4_OmaDcfCbcSampleEncrypter(AP4_BlockCipher * block_cipher,const AP4_UI08 * salt)708 AP4_OmaDcfCbcSampleEncrypter::AP4_OmaDcfCbcSampleEncrypter(AP4_BlockCipher* block_cipher,
709 const AP4_UI08* salt) :
710 AP4_OmaDcfSampleEncrypter(salt)
711 {
712 m_Cipher = new AP4_CbcStreamCipher(block_cipher);
713 }
714
715 /*----------------------------------------------------------------------
716 | AP4_OmaDcfCbcSampleEncrypter::~AP4_OmaDcfCbcSampleEncrypter
717 +---------------------------------------------------------------------*/
~AP4_OmaDcfCbcSampleEncrypter()718 AP4_OmaDcfCbcSampleEncrypter::~AP4_OmaDcfCbcSampleEncrypter()
719 {
720 delete m_Cipher;
721 }
722
723 /*----------------------------------------------------------------------
724 | AP4_OmaDcfCbcSampleEncrypter::EncryptSampleData
725 +---------------------------------------------------------------------*/
726 AP4_Result
EncryptSampleData(AP4_DataBuffer & data_in,AP4_DataBuffer & data_out,AP4_UI64 counter,bool)727 AP4_OmaDcfCbcSampleEncrypter::EncryptSampleData(AP4_DataBuffer& data_in,
728 AP4_DataBuffer& data_out,
729 AP4_UI64 counter,
730 bool /*skip_encryption*/)
731 {
732 // make sure there is enough space in the output buffer
733 data_out.Reserve(data_in.GetDataSize()+2*AP4_CIPHER_BLOCK_SIZE+1);
734
735 // setup the buffers
736 AP4_Size out_size = data_in.GetDataSize()+AP4_CIPHER_BLOCK_SIZE;
737 unsigned char* out = data_out.UseData();
738
739 // selective encryption flag
740 *out++ = 0x80;
741
742 // IV on 16 bytes: [SSSSSSSSXXXXXXXX]
743 // where SSSSSSSS is the 64-bit salt and
744 // XXXXXXXX is the 64-bit base counter
745 AP4_CopyMemory(out, m_Salt, 8);
746 AP4_BytesFromUInt64BE(&out[8], counter);
747
748 // encrypt the payload
749 m_Cipher->SetIV(out);
750 m_Cipher->ProcessBuffer(data_in.GetData(),
751 data_in.GetDataSize(),
752 out+AP4_CIPHER_BLOCK_SIZE,
753 &out_size,
754 true);
755 AP4_CHECK(data_out.SetDataSize(out_size+AP4_CIPHER_BLOCK_SIZE+1));
756
757 return AP4_SUCCESS;
758 }
759
760 /*----------------------------------------------------------------------
761 | AP4_OmaDcfCbcSampleEncrypter::GetEncryptedSampleSize
762 +---------------------------------------------------------------------*/
763 AP4_Size
GetEncryptedSampleSize(AP4_Sample & sample)764 AP4_OmaDcfCbcSampleEncrypter::GetEncryptedSampleSize(AP4_Sample& sample)
765 {
766 AP4_Size sample_size = sample.GetSize();
767 AP4_Size padding_size = AP4_CIPHER_BLOCK_SIZE-(sample_size%AP4_CIPHER_BLOCK_SIZE);
768 return sample_size+padding_size+AP4_CIPHER_BLOCK_SIZE+1;
769 }
770
771 /*----------------------------------------------------------------------
772 | AP4_OmaDcfTrackDecrypter::Create
773 +---------------------------------------------------------------------*/
774 AP4_Result
Create(const AP4_UI08 * key,AP4_Size key_size,AP4_ProtectedSampleDescription * sample_description,AP4_SampleEntry * sample_entry,AP4_BlockCipherFactory * block_cipher_factory,AP4_OmaDcfTrackDecrypter * & decrypter)775 AP4_OmaDcfTrackDecrypter::Create(
776 const AP4_UI08* key,
777 AP4_Size key_size,
778 AP4_ProtectedSampleDescription* sample_description,
779 AP4_SampleEntry* sample_entry,
780 AP4_BlockCipherFactory* block_cipher_factory,
781 AP4_OmaDcfTrackDecrypter*& decrypter)
782 {
783 // check and set defaults
784 if (key == NULL) {
785 return AP4_ERROR_INVALID_PARAMETERS;
786 }
787 if (block_cipher_factory == NULL) {
788 block_cipher_factory = &AP4_DefaultBlockCipherFactory::Instance;
789 }
790 decrypter = NULL;
791
792 // create the cipher
793 AP4_OmaDcfSampleDecrypter* cipher = NULL;
794 AP4_Result result = AP4_OmaDcfSampleDecrypter::Create(sample_description,
795 key,
796 key_size,
797 block_cipher_factory,
798 cipher);
799 if (AP4_FAILED(result)) return result;
800
801 // instantiate the object
802 decrypter = new AP4_OmaDcfTrackDecrypter(cipher,
803 sample_entry,
804 sample_description->GetOriginalFormat());
805 return AP4_SUCCESS;
806 }
807
808 /*----------------------------------------------------------------------
809 | AP4_OmaDcfTrackDecrypter::AP4_OmaDcfTrackDecrypter
810 +---------------------------------------------------------------------*/
AP4_OmaDcfTrackDecrypter(AP4_OmaDcfSampleDecrypter * cipher,AP4_SampleEntry * sample_entry,AP4_UI32 original_format)811 AP4_OmaDcfTrackDecrypter::AP4_OmaDcfTrackDecrypter(AP4_OmaDcfSampleDecrypter* cipher,
812 AP4_SampleEntry* sample_entry,
813 AP4_UI32 original_format) :
814 m_Cipher(cipher),
815 m_SampleEntry(sample_entry),
816 m_OriginalFormat(original_format)
817 {
818 }
819
820 /*----------------------------------------------------------------------
821 | AP4_OmaDcfTrackDecrypter::~AP4_OmaDcfTrackDecrypter
822 +---------------------------------------------------------------------*/
~AP4_OmaDcfTrackDecrypter()823 AP4_OmaDcfTrackDecrypter::~AP4_OmaDcfTrackDecrypter()
824 {
825 delete m_Cipher;
826 }
827
828 /*----------------------------------------------------------------------
829 | AP4_OmaDcfTrackDecrypter::GetProcessedSampleSize
830 +---------------------------------------------------------------------*/
831 AP4_Size
GetProcessedSampleSize(AP4_Sample & sample)832 AP4_OmaDcfTrackDecrypter::GetProcessedSampleSize(AP4_Sample& sample)
833 {
834 if (m_Cipher == NULL) return 0;
835 return m_Cipher->GetDecryptedSampleSize(sample);
836 }
837
838 /*----------------------------------------------------------------------
839 | AP4_OmaDcfTrackDecrypter::ProcessTrack
840 +---------------------------------------------------------------------*/
841 AP4_Result
ProcessTrack()842 AP4_OmaDcfTrackDecrypter::ProcessTrack()
843 {
844 m_SampleEntry->SetType(m_OriginalFormat);
845 m_SampleEntry->DeleteChild(AP4_ATOM_TYPE_SINF);
846 return AP4_SUCCESS;
847 }
848
849 /*----------------------------------------------------------------------
850 | AP4_OmaDcfDecrypter::ProcessSample
851 +---------------------------------------------------------------------*/
852 AP4_Result
ProcessSample(AP4_DataBuffer & data_in,AP4_DataBuffer & data_out)853 AP4_OmaDcfTrackDecrypter::ProcessSample(AP4_DataBuffer& data_in,
854 AP4_DataBuffer& data_out)
855 {
856 return m_Cipher->DecryptSampleData(data_in, data_out);
857 }
858
859 /*----------------------------------------------------------------------
860 | AP4_OmaDcfTrackEncrypter
861 +---------------------------------------------------------------------*/
862 class AP4_OmaDcfTrackEncrypter : public AP4_Processor::TrackHandler {
863 public:
864 // constructor
865 AP4_OmaDcfTrackEncrypter(AP4_OmaDcfCipherMode cipher_mode,
866 AP4_BlockCipher* block_cipher,
867 const AP4_UI08* iv,
868 AP4_SampleEntry* sample_entry,
869 AP4_UI32 format,
870 const char* content_id,
871 const char* rights_issuer_url,
872 const AP4_Byte* textual_headers,
873 AP4_Size textual_headers_size);
874 virtual ~AP4_OmaDcfTrackEncrypter();
875
876 // methods
877 virtual AP4_Size GetProcessedSampleSize(AP4_Sample& sample);
878 virtual AP4_Result ProcessTrack();
879 virtual AP4_Result ProcessSample(AP4_DataBuffer& data_in,
880 AP4_DataBuffer& data_out);
881
882 private:
883 // members
884 AP4_OmaDcfSampleEncrypter* m_Cipher;
885 AP4_UI08 m_CipherMode;
886 AP4_UI08 m_CipherPadding;
887 AP4_SampleEntry* m_SampleEntry;
888 AP4_UI32 m_Format;
889 AP4_String m_ContentId;
890 AP4_String m_RightsIssuerUrl;
891 AP4_DataBuffer m_TextualHeaders;
892 AP4_UI64 m_Counter;
893 };
894
895 /*----------------------------------------------------------------------
896 | AP4_OmaDcfTrackEncrypter::AP4_OmaDcfTrackEncrypter
897 +---------------------------------------------------------------------*/
AP4_OmaDcfTrackEncrypter(AP4_OmaDcfCipherMode cipher_mode,AP4_BlockCipher * block_cipher,const AP4_UI08 * salt,AP4_SampleEntry * sample_entry,AP4_UI32 format,const char * content_id,const char * rights_issuer_url,const AP4_Byte * textual_headers,AP4_Size textual_headers_size)898 AP4_OmaDcfTrackEncrypter::AP4_OmaDcfTrackEncrypter(
899 AP4_OmaDcfCipherMode cipher_mode,
900 AP4_BlockCipher* block_cipher,
901 const AP4_UI08* salt,
902 AP4_SampleEntry* sample_entry,
903 AP4_UI32 format,
904 const char* content_id,
905 const char* rights_issuer_url,
906 const AP4_Byte* textual_headers,
907 AP4_Size textual_headers_size) :
908 m_SampleEntry(sample_entry),
909 m_Format(format),
910 m_ContentId(content_id),
911 m_RightsIssuerUrl(rights_issuer_url),
912 m_TextualHeaders(textual_headers, textual_headers_size),
913 m_Counter(0)
914 {
915 // instantiate the cipher (fixed params for now)
916 if (cipher_mode == AP4_OMA_DCF_CIPHER_MODE_CBC) {
917 m_Cipher = new AP4_OmaDcfCbcSampleEncrypter(block_cipher, salt);
918 m_CipherMode = AP4_OMA_DCF_ENCRYPTION_METHOD_AES_CBC;
919 m_CipherPadding = AP4_OMA_DCF_PADDING_SCHEME_RFC_2630;
920 } else {
921 m_Cipher = new AP4_OmaDcfCtrSampleEncrypter(block_cipher, salt);
922 m_CipherMode = AP4_OMA_DCF_ENCRYPTION_METHOD_AES_CTR;
923 m_CipherPadding = AP4_OMA_DCF_PADDING_SCHEME_NONE;
924 }
925 }
926
927 /*----------------------------------------------------------------------
928 | AP4_OmaDcfTrackEncrypter::~AP4_OmaDcfTrackEncrypter
929 +---------------------------------------------------------------------*/
~AP4_OmaDcfTrackEncrypter()930 AP4_OmaDcfTrackEncrypter::~AP4_OmaDcfTrackEncrypter()
931 {
932 delete m_Cipher;
933 }
934
935 /*----------------------------------------------------------------------
936 | AP4_OmaDcfTrackEncrypter::GetProcessedSampleSize
937 +---------------------------------------------------------------------*/
938 AP4_Size
GetProcessedSampleSize(AP4_Sample & sample)939 AP4_OmaDcfTrackEncrypter::GetProcessedSampleSize(AP4_Sample& sample)
940 {
941 return m_Cipher->GetEncryptedSampleSize(sample);
942 }
943
944 /*----------------------------------------------------------------------
945 | AP4_OmaDcfTrackEncrypter::ProcessTrack
946 +---------------------------------------------------------------------*/
947 AP4_Result
ProcessTrack()948 AP4_OmaDcfTrackEncrypter::ProcessTrack()
949 {
950 // original format
951 AP4_FrmaAtom* frma = new AP4_FrmaAtom(m_SampleEntry->GetType());
952
953 // scheme info
954 AP4_OdafAtom* odaf = new AP4_OdafAtom(true, 0, AP4_CIPHER_BLOCK_SIZE);
955 AP4_OhdrAtom* ohdr = new AP4_OhdrAtom(m_CipherMode,
956 m_CipherPadding,
957 0,
958 m_ContentId.GetChars(),
959 m_RightsIssuerUrl.GetChars(),
960 m_TextualHeaders.GetData(),
961 m_TextualHeaders.GetDataSize());
962 AP4_SchmAtom* schm = new AP4_SchmAtom(AP4_PROTECTION_SCHEME_TYPE_OMA,
963 AP4_PROTECTION_SCHEME_VERSION_OMA_20);
964
965 // populate the odkm container
966 AP4_ContainerAtom* odkm = new AP4_ContainerAtom(AP4_ATOM_TYPE_ODKM, (AP4_UI32)0, (AP4_UI32)0);
967 odkm->AddChild(odaf);
968 odkm->AddChild(ohdr);
969
970 // populate the schi container
971 AP4_ContainerAtom* schi = new AP4_ContainerAtom(AP4_ATOM_TYPE_SCHI);
972 schi->AddChild(odkm);
973
974 // populate the sinf container
975 AP4_ContainerAtom* sinf = new AP4_ContainerAtom(AP4_ATOM_TYPE_SINF);
976 sinf->AddChild(frma);
977 sinf->AddChild(schm);
978 sinf->AddChild(schi);
979
980 // add the sinf atom to the sample description
981 m_SampleEntry->AddChild(sinf);
982
983 // change the atom type of the sample description
984 m_SampleEntry->SetType(m_Format);
985
986 return AP4_SUCCESS;
987 }
988
989 /*----------------------------------------------------------------------
990 | AP4_OmaDcfTrackEncrypter::ProcessSample
991 +---------------------------------------------------------------------*/
992 AP4_Result
ProcessSample(AP4_DataBuffer & data_in,AP4_DataBuffer & data_out)993 AP4_OmaDcfTrackEncrypter::ProcessSample(AP4_DataBuffer& data_in,
994 AP4_DataBuffer& data_out)
995 {
996 AP4_Result result = m_Cipher->EncryptSampleData(data_in,
997 data_out,
998 m_Counter,
999 false);
1000 if (AP4_FAILED(result)) return result;
1001
1002 m_Counter += (data_in.GetDataSize()+AP4_CIPHER_BLOCK_SIZE-1)/AP4_CIPHER_BLOCK_SIZE;
1003 return AP4_SUCCESS;
1004 }
1005
1006 /*----------------------------------------------------------------------
1007 | AP4_OmaDcfDecryptingProcessor:AP4_OmaDcfDecryptingProcessor
1008 +---------------------------------------------------------------------*/
AP4_OmaDcfDecryptingProcessor(const AP4_ProtectionKeyMap * key_map,AP4_BlockCipherFactory * block_cipher_factory)1009 AP4_OmaDcfDecryptingProcessor::AP4_OmaDcfDecryptingProcessor(
1010 const AP4_ProtectionKeyMap* key_map /* = NULL */,
1011 AP4_BlockCipherFactory* block_cipher_factory /* = NULL */)
1012 {
1013 if (key_map) {
1014 // copy the keys
1015 m_KeyMap.SetKeys(*key_map);
1016 }
1017
1018 if (block_cipher_factory == NULL) {
1019 m_BlockCipherFactory = &AP4_DefaultBlockCipherFactory::Instance;
1020 } else {
1021 m_BlockCipherFactory = block_cipher_factory;
1022 }
1023 }
1024
1025 /*----------------------------------------------------------------------
1026 | AP4_OmaDcfDecryptingProcessor:Initialize
1027 +---------------------------------------------------------------------*/
1028 AP4_Result
Initialize(AP4_AtomParent & top_level,AP4_ByteStream &,ProgressListener * listener)1029 AP4_OmaDcfDecryptingProcessor::Initialize(AP4_AtomParent& top_level,
1030 AP4_ByteStream& /* stream */,
1031 ProgressListener* listener)
1032 {
1033 // decide which processor to instantiate based on the file type
1034 AP4_FtypAtom* ftyp = AP4_DYNAMIC_CAST(AP4_FtypAtom, top_level.GetChild(AP4_ATOM_TYPE_FTYP));
1035 if (ftyp) {
1036 if (ftyp->GetMajorBrand() == AP4_OMA_DCF_BRAND_ODCF || ftyp->HasCompatibleBrand(AP4_OMA_DCF_BRAND_ODCF)) {
1037 return AP4_OmaDcfAtomDecrypter::DecryptAtoms(top_level, listener, m_BlockCipherFactory, m_KeyMap);
1038 } else {
1039 return AP4_ERROR_INVALID_FORMAT;
1040 }
1041 } else {
1042 return AP4_SUCCESS;
1043 }
1044 }
1045
1046 /*----------------------------------------------------------------------
1047 | AP4_OmaDcfEncryptingProcessor:AP4_OmaDcfEncryptingProcessor
1048 +---------------------------------------------------------------------*/
AP4_OmaDcfEncryptingProcessor(AP4_OmaDcfCipherMode cipher_mode,AP4_BlockCipherFactory * block_cipher_factory)1049 AP4_OmaDcfEncryptingProcessor::AP4_OmaDcfEncryptingProcessor(AP4_OmaDcfCipherMode cipher_mode,
1050 AP4_BlockCipherFactory* block_cipher_factory) :
1051 m_CipherMode(cipher_mode)
1052 {
1053 if (block_cipher_factory == NULL) {
1054 m_BlockCipherFactory = &AP4_DefaultBlockCipherFactory::Instance;
1055 } else {
1056 m_BlockCipherFactory = block_cipher_factory;
1057 }
1058 }
1059
1060 /*----------------------------------------------------------------------
1061 | AP4_OmaDcfEncryptingProcessor::Initialize
1062 +---------------------------------------------------------------------*/
1063 AP4_Result
Initialize(AP4_AtomParent & top_level,AP4_ByteStream &,AP4_Processor::ProgressListener *)1064 AP4_OmaDcfEncryptingProcessor::Initialize(AP4_AtomParent& top_level,
1065 AP4_ByteStream& /*stream*/,
1066 AP4_Processor::ProgressListener* /*listener*/)
1067 {
1068 AP4_FtypAtom* ftyp = AP4_DYNAMIC_CAST(AP4_FtypAtom, top_level.GetChild(AP4_ATOM_TYPE_FTYP));
1069 if (ftyp) {
1070 // remove the atom, it will be replaced with a new one
1071 top_level.RemoveChild(ftyp);
1072
1073 // keep the existing brand and compatible brands
1074 AP4_Array<AP4_UI32> compatible_brands;
1075 compatible_brands.EnsureCapacity(ftyp->GetCompatibleBrands().ItemCount()+1);
1076 for (unsigned int i=0; i<ftyp->GetCompatibleBrands().ItemCount(); i++) {
1077 compatible_brands.Append(ftyp->GetCompatibleBrands()[i]);
1078 }
1079
1080 // add the OMA compatible brand if it is not already there
1081 if (!ftyp->HasCompatibleBrand(AP4_OMA_DCF_BRAND_OPF2)) {
1082 compatible_brands.Append(AP4_OMA_DCF_BRAND_OPF2);
1083 }
1084
1085 // create a replacement
1086 AP4_FtypAtom* new_ftyp = new AP4_FtypAtom(ftyp->GetMajorBrand(),
1087 ftyp->GetMinorVersion(),
1088 &compatible_brands[0],
1089 compatible_brands.ItemCount());
1090 delete ftyp;
1091 ftyp = new_ftyp;
1092 } else {
1093 AP4_UI32 opf2 = AP4_OMA_DCF_BRAND_OPF2;
1094 ftyp = new AP4_FtypAtom(AP4_FTYP_BRAND_ISOM, 0, &opf2, 1);
1095 }
1096
1097 // insert the ftyp atom as the first child
1098 return top_level.AddChild(ftyp, 0);
1099 }
1100
1101 /*----------------------------------------------------------------------
1102 | AP4_OmaDcfEncryptingProcessor:CreateTrackHandler
1103 +---------------------------------------------------------------------*/
1104 AP4_Processor::TrackHandler*
CreateTrackHandler(AP4_TrakAtom * trak)1105 AP4_OmaDcfEncryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak)
1106 {
1107 // find the stsd atom
1108 AP4_StsdAtom* stsd = AP4_DYNAMIC_CAST(AP4_StsdAtom, trak->FindChild("mdia/minf/stbl/stsd"));
1109
1110 // avoid tracks with no stsd atom (should not happen)
1111 if (stsd == NULL) return NULL;
1112
1113 // only look at the first sample description
1114 AP4_SampleEntry* entry = stsd->GetSampleEntry(0);
1115 if (entry == NULL) return NULL;
1116
1117 // create a handler for this track if we have a key for it and we know
1118 // how to map the type
1119 const AP4_DataBuffer* key;
1120 const AP4_DataBuffer* iv;
1121 AP4_UI32 format = 0;
1122 if (AP4_SUCCEEDED(m_KeyMap.GetKeyAndIv(trak->GetId(), key, iv))) {
1123 switch (entry->GetType()) {
1124 case AP4_ATOM_TYPE_MP4A:
1125 format = AP4_ATOM_TYPE_ENCA;
1126 break;
1127
1128 case AP4_ATOM_TYPE_MP4V:
1129 case AP4_ATOM_TYPE_AVC1:
1130 case AP4_ATOM_TYPE_AVC2:
1131 case AP4_ATOM_TYPE_AVC3:
1132 case AP4_ATOM_TYPE_AVC4:
1133 case AP4_ATOM_TYPE_HEV1:
1134 case AP4_ATOM_TYPE_HVC1:
1135 format = AP4_ATOM_TYPE_ENCV;
1136 break;
1137
1138 default: {
1139 // try to find if this is audio or video
1140 AP4_HdlrAtom* hdlr = AP4_DYNAMIC_CAST(AP4_HdlrAtom, trak->FindChild("mdia/hdlr"));
1141 if (hdlr) {
1142 switch (hdlr->GetHandlerType()) {
1143 case AP4_HANDLER_TYPE_SOUN:
1144 format = AP4_ATOM_TYPE_ENCA;
1145 break;
1146
1147 case AP4_HANDLER_TYPE_VIDE:
1148 format = AP4_ATOM_TYPE_ENCV;
1149 break;
1150 }
1151 }
1152 break;
1153 }
1154 }
1155 if (format) {
1156 const char* content_id = m_PropertyMap.GetProperty(trak->GetId(), "ContentId");
1157 const char* rights_issuer_url = m_PropertyMap.GetProperty(trak->GetId(), "RightsIssuerUrl");
1158 AP4_DataBuffer textual_headers;
1159 AP4_Result result = m_PropertyMap.GetTextualHeaders(trak->GetId(), textual_headers);
1160 if (AP4_FAILED(result)) textual_headers.SetDataSize(0);
1161
1162 // create the block cipher
1163 AP4_BlockCipher* block_cipher = NULL;
1164 AP4_BlockCipher::CtrParams ctr_params;
1165 AP4_BlockCipher::CipherMode cipher_mode;
1166 const void* cipher_params = NULL;
1167 if (m_CipherMode == AP4_OMA_DCF_CIPHER_MODE_CBC) {
1168 cipher_mode = AP4_BlockCipher::CBC;
1169 } else if (m_CipherMode == AP4_OMA_DCF_CIPHER_MODE_CTR) {
1170 cipher_mode = AP4_BlockCipher::CTR;
1171 ctr_params.counter_size = 16;
1172 cipher_params = &ctr_params;
1173 } else {
1174 return NULL;
1175 }
1176 result = m_BlockCipherFactory->CreateCipher(AP4_BlockCipher::AES_128,
1177 AP4_BlockCipher::ENCRYPT,
1178 cipher_mode,
1179 cipher_params,
1180 key->GetData(),
1181 key->GetDataSize(),
1182 block_cipher);
1183 if (AP4_FAILED(result)) return NULL;
1184 return new AP4_OmaDcfTrackEncrypter(m_CipherMode,
1185 block_cipher,
1186 iv->GetData(),
1187 entry,
1188 format,
1189 content_id,
1190 rights_issuer_url,
1191 textual_headers.GetData(),
1192 textual_headers.GetDataSize());
1193 }
1194 }
1195
1196 return NULL;
1197 }
1198