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