1 /*****************************************************************
2 |
3 |    AP4 - Protected Stream 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 "Ap4Protection.h"
33 #include "Ap4SchmAtom.h"
34 #include "Ap4StsdAtom.h"
35 #include "Ap4FtypAtom.h"
36 #include "Ap4Sample.h"
37 #include "Ap4StreamCipher.h"
38 #include "Ap4IsfmAtom.h"
39 #include "Ap4FrmaAtom.h"
40 #include "Ap4IkmsAtom.h"
41 #include "Ap4IsfmAtom.h"
42 #include "Ap4IsltAtom.h"
43 #include "Ap4Utils.h"
44 #include "Ap4TrakAtom.h"
45 #include "Ap4IsmaCryp.h"
46 #include "Ap4AesBlockCipher.h"
47 #include "Ap4OmaDcf.h"
48 #include "Ap4Marlin.h"
49 #include "Ap4Piff.h"
50 #include "Ap4CommonEncryption.h"
51 
52 /*----------------------------------------------------------------------
53 |   dynamic cast support
54 +---------------------------------------------------------------------*/
AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_ProtectedSampleDescription)55 AP4_DEFINE_DYNAMIC_CAST_ANCHOR(AP4_ProtectedSampleDescription)
56 
57 /*----------------------------------------------------------------------
58 |   AP4_EncaSampleEntry::AP4_EncaSampleEntry
59 +---------------------------------------------------------------------*/
60 AP4_EncaSampleEntry::AP4_EncaSampleEntry(AP4_UI32         type,
61                                          AP4_Size         size,
62                                          AP4_ByteStream&  stream,
63                                          AP4_AtomFactory& atom_factory) :
64     AP4_AudioSampleEntry(type, size, stream, atom_factory)
65 {
66 }
67 
68 /*----------------------------------------------------------------------
69 |   AP4_EncaSampleEntry::AP4_EncaSampleEntry
70 +---------------------------------------------------------------------*/
AP4_EncaSampleEntry(AP4_Size size,AP4_ByteStream & stream,AP4_AtomFactory & atom_factory)71 AP4_EncaSampleEntry::AP4_EncaSampleEntry(AP4_Size         size,
72                                          AP4_ByteStream&  stream,
73                                          AP4_AtomFactory& atom_factory) :
74     AP4_AudioSampleEntry(AP4_ATOM_TYPE_ENCA, size, stream, atom_factory)
75 {
76 }
77 
78 /*----------------------------------------------------------------------
79 |   AP4_EncaSampleEntry::ToSampleDescription
80 +---------------------------------------------------------------------*/
81 AP4_SampleDescription*
ToSampleDescription()82 AP4_EncaSampleEntry::ToSampleDescription()
83 {
84     // get the original sample format
85     AP4_FrmaAtom* frma = AP4_DYNAMIC_CAST(AP4_FrmaAtom, FindChild("sinf/frma"));
86 
87     // get the schi atom
88     AP4_ContainerAtom* schi;
89     schi = AP4_DYNAMIC_CAST(AP4_ContainerAtom, FindChild("sinf/schi"));
90 
91     // get the scheme info
92     AP4_SchmAtom* schm = AP4_DYNAMIC_CAST(AP4_SchmAtom, FindChild("sinf/schm"));
93     AP4_UI32 original_format = frma?frma->GetOriginalFormat():AP4_ATOM_TYPE_MP4A;
94     if (schm) {
95         // create the original sample description
96         return new AP4_ProtectedSampleDescription(
97             m_Type,
98             ToTargetSampleDescription(original_format),
99             original_format,
100             schm->GetSchemeType(),
101             schm->GetSchemeVersion(),
102             schm->GetSchemeUri().GetChars(),
103             schi);
104     } else if (schi) {
105         // try to see if we can guess the protection scheme from the 'schi' contents
106         AP4_Atom* odkm = schi->GetChild(AP4_ATOM_TYPE_ODKM);
107         if (odkm) {
108             // create the original sample description
109             return new AP4_ProtectedSampleDescription(
110                 m_Type,
111                 ToTargetSampleDescription(original_format),
112                 original_format,
113                 AP4_PROTECTION_SCHEME_TYPE_OMA,
114                 AP4_PROTECTION_SCHEME_VERSION_OMA_20,
115                 NULL,
116                 schi);
117         }
118     }
119 
120     // unknown scheme
121     return NULL;
122 }
123 
124 /*----------------------------------------------------------------------
125 |   AP4_EncaSampleEntry::ToTargetSampleDescription
126 +---------------------------------------------------------------------*/
127 AP4_SampleDescription*
ToTargetSampleDescription(AP4_UI32 format)128 AP4_EncaSampleEntry::ToTargetSampleDescription(AP4_UI32 format)
129 {
130     switch (format) {
131         case AP4_ATOM_TYPE_MP4A: {
132             AP4_EsdsAtom* esds = AP4_DYNAMIC_CAST(AP4_EsdsAtom, GetChild(AP4_ATOM_TYPE_ESDS));
133             if (esds == NULL) {
134                 // check if this is a quicktime style sample description
135                 if (m_QtVersion > 0) {
136                     esds = AP4_DYNAMIC_CAST(AP4_EsdsAtom, FindChild("wave/esds"));
137                 }
138             }
139             return new AP4_MpegAudioSampleDescription(
140                 GetSampleRate(),
141                 GetSampleSize(),
142                 GetChannelCount(),
143                 esds);
144         }
145 
146         default:
147             return new AP4_GenericAudioSampleDescription(
148                 format,
149                 GetSampleRate(),
150                 GetSampleSize(),
151                 GetChannelCount(),
152                 this);
153     }
154 }
155 
156 /*----------------------------------------------------------------------
157 |   AP4_EncvSampleEntry::AP4_EncvSampleEntry
158 +---------------------------------------------------------------------*/
AP4_EncvSampleEntry(AP4_UI32 type,AP4_Size size,AP4_ByteStream & stream,AP4_AtomFactory & atom_factory)159 AP4_EncvSampleEntry::AP4_EncvSampleEntry(AP4_UI32         type,
160                                          AP4_Size         size,
161                                          AP4_ByteStream&  stream,
162                                          AP4_AtomFactory& atom_factory) :
163     AP4_VisualSampleEntry(type, size, stream, atom_factory)
164 {
165 }
166 
167 /*----------------------------------------------------------------------
168 |   AP4_EncvSampleEntry::AP4_EncvSampleEntry
169 +---------------------------------------------------------------------*/
AP4_EncvSampleEntry(AP4_Size size,AP4_ByteStream & stream,AP4_AtomFactory & atom_factory)170 AP4_EncvSampleEntry::AP4_EncvSampleEntry(AP4_Size         size,
171                                          AP4_ByteStream&  stream,
172                                          AP4_AtomFactory& atom_factory) :
173     AP4_VisualSampleEntry(AP4_ATOM_TYPE_ENCV, size, stream, atom_factory)
174 {
175 }
176 
177 /*----------------------------------------------------------------------
178 |   AP4_EncvSampleEntry::ToSampleDescription
179 +---------------------------------------------------------------------*/
180 AP4_SampleDescription*
ToSampleDescription()181 AP4_EncvSampleEntry::ToSampleDescription()
182 {
183     // get the original sample format
184     AP4_FrmaAtom* frma = AP4_DYNAMIC_CAST(AP4_FrmaAtom, FindChild("sinf/frma"));
185 
186     // get the schi atom
187     AP4_ContainerAtom* schi;
188     schi = AP4_DYNAMIC_CAST(AP4_ContainerAtom, FindChild("sinf/schi"));
189 
190     // get the scheme info
191     AP4_SchmAtom* schm = AP4_DYNAMIC_CAST(AP4_SchmAtom, FindChild("sinf/schm"));
192     AP4_UI32 original_format = frma?frma->GetOriginalFormat():AP4_ATOM_TYPE_MP4V;
193     if (schm) {
194         // create the sample description
195         return new AP4_ProtectedSampleDescription(
196             m_Type,
197             ToTargetSampleDescription(original_format),
198             original_format,
199             schm->GetSchemeType(),
200             schm->GetSchemeVersion(),
201             schm->GetSchemeUri().GetChars(),
202             schi);
203     } else if (schi) {
204         // try to see if we can guess the protection scheme from the 'schi' contents
205         AP4_Atom* odkm = schi->GetChild(AP4_ATOM_TYPE_ODKM);
206         if (odkm) {
207             // create the original sample description
208             return new AP4_ProtectedSampleDescription(
209                 m_Type,
210                 ToTargetSampleDescription(original_format),
211                 original_format,
212                 AP4_PROTECTION_SCHEME_TYPE_OMA,
213                 AP4_PROTECTION_SCHEME_VERSION_OMA_20,
214                 NULL,
215                 schi);
216         }
217     }
218 
219     // unknown scheme
220     return NULL;
221 
222 }
223 
224 /*----------------------------------------------------------------------
225 |   AP4_EncvSampleEntry::ToTargetSampleDescription
226 +---------------------------------------------------------------------*/
227 AP4_SampleDescription*
ToTargetSampleDescription(AP4_UI32 format)228 AP4_EncvSampleEntry::ToTargetSampleDescription(AP4_UI32 format)
229 {
230     switch (format) {
231         case AP4_SAMPLE_FORMAT_AVC1:
232         case AP4_SAMPLE_FORMAT_AVC2:
233         case AP4_SAMPLE_FORMAT_AVC3:
234         case AP4_SAMPLE_FORMAT_AVC4:
235         case AP4_SAMPLE_FORMAT_DVAV:
236         case AP4_SAMPLE_FORMAT_DVA1:
237             return new AP4_AvcSampleDescription(
238                 format,
239                 m_Width,
240                 m_Height,
241                 m_Depth,
242                 m_CompressorName.GetChars(),
243                 this);
244 
245         case AP4_SAMPLE_FORMAT_HVC1:
246         case AP4_SAMPLE_FORMAT_HEV1:
247         case AP4_SAMPLE_FORMAT_DVHE:
248         case AP4_SAMPLE_FORMAT_DVH1:
249             return new AP4_HevcSampleDescription(
250                 format,
251                 m_Width,
252                 m_Height,
253                 m_Depth,
254                 m_CompressorName.GetChars(),
255                 this);
256 
257         case AP4_SAMPLE_FORMAT_AV01:
258             return new AP4_Av1SampleDescription(
259                 format,
260                 m_Width,
261                 m_Height,
262                 m_Depth,
263                 m_CompressorName.GetChars(),
264                 this);
265 
266         case AP4_ATOM_TYPE_MP4V:
267             return new AP4_MpegVideoSampleDescription(
268                 m_Width,
269                 m_Height,
270                 m_Depth,
271                 m_CompressorName.GetChars(),
272                 AP4_DYNAMIC_CAST(AP4_EsdsAtom, GetChild(AP4_ATOM_TYPE_ESDS)));
273 
274         default:
275             return new AP4_GenericVideoSampleDescription(
276                 format,
277                 m_Width,
278                 m_Height,
279                 m_Depth,
280                 m_CompressorName.GetChars(),
281                 this);
282     }
283 }
284 
285 /*----------------------------------------------------------------------
286 |   AP4_DrmsSampleEntry::AP4_DrmsSampleEntry
287 +---------------------------------------------------------------------*/
AP4_DrmsSampleEntry(AP4_Size size,AP4_ByteStream & stream,AP4_AtomFactory & atom_factory)288 AP4_DrmsSampleEntry::AP4_DrmsSampleEntry(AP4_Size         size,
289                                          AP4_ByteStream&  stream,
290                                          AP4_AtomFactory& atom_factory) :
291     AP4_EncaSampleEntry(AP4_ATOM_TYPE_DRMS, size, stream, atom_factory)
292 {
293 }
294 
295 /*----------------------------------------------------------------------
296 |   AP4_DrmiSampleEntry::AP4_DrmiSampleEntry
297 +---------------------------------------------------------------------*/
AP4_DrmiSampleEntry(AP4_Size size,AP4_ByteStream & stream,AP4_AtomFactory & atom_factory)298 AP4_DrmiSampleEntry::AP4_DrmiSampleEntry(AP4_Size         size,
299                                          AP4_ByteStream&  stream,
300                                          AP4_AtomFactory& atom_factory) :
301     AP4_EncvSampleEntry(AP4_ATOM_TYPE_DRMI, size, stream, atom_factory)
302 {
303 }
304 
305 /*----------------------------------------------------------------------
306 |   AP4_ProtectionSchemeInfo::~AP4_ProtectionSchemeInfo
307 +---------------------------------------------------------------------*/
~AP4_ProtectionSchemeInfo()308 AP4_ProtectionSchemeInfo::~AP4_ProtectionSchemeInfo()
309 {
310     delete m_SchiAtom;
311 }
312 
313 /*----------------------------------------------------------------------
314 |   AP4_ProtectionSchemeInfo::AP4_ProtectionSchemeInfo
315 +---------------------------------------------------------------------*/
AP4_ProtectionSchemeInfo(AP4_ContainerAtom * schi)316 AP4_ProtectionSchemeInfo::AP4_ProtectionSchemeInfo(AP4_ContainerAtom* schi)
317 {
318     if (schi) {
319         m_SchiAtom = static_cast<AP4_ContainerAtom*>(schi->Clone());
320     } else {
321         m_SchiAtom = NULL;
322     }
323 }
324 
325 /*----------------------------------------------------------------------
326 |   AP4_ProtectionKeyMap::AP4_ProtectionKeyMap
327 +---------------------------------------------------------------------*/
AP4_ProtectionKeyMap()328 AP4_ProtectionKeyMap::AP4_ProtectionKeyMap()
329 {
330 }
331 
332 /*----------------------------------------------------------------------
333 |   AP4_ProtectionKeyMap::~AP4_ProtectionKeyMap
334 +---------------------------------------------------------------------*/
~AP4_ProtectionKeyMap()335 AP4_ProtectionKeyMap::~AP4_ProtectionKeyMap()
336 {
337     m_KeyEntries.DeleteReferences();
338 }
339 
340 /*----------------------------------------------------------------------
341 |   AP4_ProtectionKeyMap::SetKey
342 +---------------------------------------------------------------------*/
343 AP4_Result
SetKey(AP4_UI32 track_id,const AP4_UI08 * key,AP4_Size key_size,const AP4_UI08 * iv,AP4_Size iv_size)344 AP4_ProtectionKeyMap::SetKey(AP4_UI32        track_id,
345                              const AP4_UI08* key,
346                              AP4_Size        key_size,
347                              const AP4_UI08* iv,
348                              AP4_Size        iv_size)
349 {
350     KeyEntry* entry = GetEntry(track_id);
351     if (entry == NULL) {
352         m_KeyEntries.Add(new KeyEntry(track_id, key, key_size, iv, iv_size));
353     } else {
354         entry->SetKey(key, key_size, iv, iv_size);
355     }
356 
357     return AP4_SUCCESS;
358 }
359 
360 /*----------------------------------------------------------------------
361 |   AP4_ProtectionKeyMap::SetKeyForKid
362 +---------------------------------------------------------------------*/
363 AP4_Result
SetKeyForKid(const AP4_UI08 * kid,const AP4_UI08 * key,AP4_Size key_size,const AP4_UI08 * iv,AP4_Size iv_size)364 AP4_ProtectionKeyMap::SetKeyForKid(const AP4_UI08* kid,
365                                    const AP4_UI08* key,
366                                    AP4_Size        key_size,
367                                    const AP4_UI08* iv,
368                                    AP4_Size        iv_size)
369 {
370     KeyEntry* entry = GetEntryByKid(kid);
371     if (entry == NULL) {
372         m_KeyEntries.Add(new KeyEntry(kid, key, key_size, iv, iv_size));
373     } else {
374         entry->SetKey(key, key_size, iv, iv_size);
375     }
376 
377     return AP4_SUCCESS;
378 }
379 
380 /*----------------------------------------------------------------------
381 |   AP4_ProtectionKeyMap::SetKey
382 +---------------------------------------------------------------------*/
383 AP4_Result
SetKeys(const AP4_ProtectionKeyMap & key_map)384 AP4_ProtectionKeyMap::SetKeys(const AP4_ProtectionKeyMap& key_map)
385 {
386     AP4_List<KeyEntry>::Item* item = key_map.m_KeyEntries.FirstItem();
387     while (item) {
388         KeyEntry* entry = item->GetData();
389         m_KeyEntries.Add(new KeyEntry(entry->m_TrackId,
390                                       entry->m_Key.GetData(),
391                                       entry->m_Key.GetDataSize(),
392                                       entry->m_IV.GetData(),
393                                       entry->m_IV.GetDataSize()));
394         item = item->GetNext();
395     }
396     return AP4_SUCCESS;
397 }
398 
399 /*----------------------------------------------------------------------
400 |   AP4_ProtectionKeyMap::GetKeyAndIv
401 +---------------------------------------------------------------------*/
402 AP4_Result
GetKeyAndIv(AP4_UI32 track_id,const AP4_DataBuffer * & key,const AP4_DataBuffer * & iv)403 AP4_ProtectionKeyMap::GetKeyAndIv(AP4_UI32               track_id,
404                                   const AP4_DataBuffer*& key,
405                                   const AP4_DataBuffer*& iv)
406 {
407     KeyEntry* entry = GetEntry(track_id);
408     if (entry) {
409         key = &entry->m_Key;
410         iv = &entry->m_IV;
411         return AP4_SUCCESS;
412     } else {
413         key = NULL;
414         iv = NULL;
415         return AP4_ERROR_NO_SUCH_ITEM;
416     }
417 }
418 
419 /*----------------------------------------------------------------------
420 |   AP4_ProtectionKeyMap::GetKeyAndIvByKid
421 +---------------------------------------------------------------------*/
422 AP4_Result
GetKeyAndIvByKid(const AP4_UI08 * kid,const AP4_DataBuffer * & key,const AP4_DataBuffer * & iv)423 AP4_ProtectionKeyMap::GetKeyAndIvByKid(const AP4_UI08*        kid,
424                                        const AP4_DataBuffer*& key,
425                                        const AP4_DataBuffer*& iv)
426 {
427     KeyEntry* entry = GetEntryByKid(kid);
428     if (entry) {
429         key = &entry->m_Key;
430         iv = &entry->m_IV;
431         return AP4_SUCCESS;
432     } else {
433         key = NULL;
434         iv = NULL;
435         return AP4_ERROR_NO_SUCH_ITEM;
436     }
437 }
438 
439 /*----------------------------------------------------------------------
440 |   AP4_ProtectionKeyMap::GetKey
441 +---------------------------------------------------------------------*/
442 const AP4_DataBuffer*
GetKey(AP4_UI32 track_id) const443 AP4_ProtectionKeyMap::GetKey(AP4_UI32 track_id) const
444 {
445     KeyEntry* entry = GetEntry(track_id);
446     if (entry) {
447         return &entry->m_Key;
448     } else {
449         return NULL;
450     }
451 }
452 
453 /*----------------------------------------------------------------------
454 |   AP4_ProtectionKeyMap::GetKeyByKid
455 +---------------------------------------------------------------------*/
456 const AP4_DataBuffer*
GetKeyByKid(const AP4_UI08 * kid) const457 AP4_ProtectionKeyMap::GetKeyByKid(const AP4_UI08* kid) const
458 {
459     KeyEntry* entry = GetEntryByKid(kid);
460     if (entry) {
461         return &entry->m_Key;
462     } else {
463         return NULL;
464     }
465 }
466 
467 /*----------------------------------------------------------------------
468 |   AP4_ProtectionKeyMap::GetEntry
469 +---------------------------------------------------------------------*/
470 AP4_ProtectionKeyMap::KeyEntry*
GetEntry(AP4_UI32 track_id) const471 AP4_ProtectionKeyMap::GetEntry(AP4_UI32 track_id) const
472 {
473     AP4_List<KeyEntry>::Item* item = m_KeyEntries.FirstItem();
474     while (item) {
475         KeyEntry* entry = item->GetData();
476         if (entry->m_TrackId == track_id) return entry;
477         item = item->GetNext();
478     }
479 
480     return NULL;
481 }
482 
483 /*----------------------------------------------------------------------
484 |   AP4_ProtectionKeyMap::GetEntryByKid
485 +---------------------------------------------------------------------*/
486 AP4_ProtectionKeyMap::KeyEntry*
GetEntryByKid(const AP4_UI08 * kid) const487 AP4_ProtectionKeyMap::GetEntryByKid(const AP4_UI08* kid) const
488 {
489     AP4_List<KeyEntry>::Item* item = m_KeyEntries.FirstItem();
490     while (item) {
491         KeyEntry* entry = item->GetData();
492         if (AP4_CompareMemory(entry->m_KID, kid, 16) == 0) return entry;
493         item = item->GetNext();
494     }
495 
496     return NULL;
497 }
498 
499 /*----------------------------------------------------------------------
500 |   AP4_ProtectionKeyMap::KeyEntry::KeyEntry
501 +---------------------------------------------------------------------*/
KeyEntry(AP4_UI32 track_id,const AP4_UI08 * key,AP4_Size key_size,const AP4_UI08 * iv,AP4_Size iv_size)502 AP4_ProtectionKeyMap::KeyEntry::KeyEntry(AP4_UI32        track_id,
503                                          const AP4_UI08* key,
504                                          AP4_Size        key_size,
505                                          const AP4_UI08* iv,
506                                          AP4_Size        iv_size) :
507     m_TrackId(track_id)
508 {
509     AP4_SetMemory(m_KID, 0, 16);
510     SetKey(key, key_size, iv, iv_size);
511 }
512 
513 /*----------------------------------------------------------------------
514 |   AP4_ProtectionKeyMap::KeyEntry::KeyEntry
515 +---------------------------------------------------------------------*/
KeyEntry(const AP4_UI08 * kid,const AP4_UI08 * key,AP4_Size key_size,const AP4_UI08 * iv,AP4_Size iv_size)516 AP4_ProtectionKeyMap::KeyEntry::KeyEntry(const AP4_UI08* kid,
517                                          const AP4_UI08* key,
518                                          AP4_Size        key_size,
519                                          const AP4_UI08* iv,
520                                          AP4_Size        iv_size) :
521     m_TrackId(0)
522 {
523     AP4_CopyMemory(m_KID, kid, 16);
524     SetKey(key, key_size, iv, iv_size);
525 }
526 
527 /*----------------------------------------------------------------------
528 |   AP4_ProtectionKeyMap::KeyEntry::SetKey
529 +---------------------------------------------------------------------*/
530 void
SetKey(const AP4_UI08 * key,AP4_Size key_size,const AP4_UI08 * iv,AP4_Size iv_size)531 AP4_ProtectionKeyMap::KeyEntry::SetKey(const AP4_UI08* key, AP4_Size key_size,
532                                        const AP4_UI08* iv,  AP4_Size iv_size)
533 {
534     if (key) {
535         m_Key.SetData(key, key_size);
536     }
537     if (iv) {
538         m_IV.SetData(iv, iv_size);
539     } else {
540         m_IV.SetDataSize(16);
541         AP4_SetMemory(m_IV.UseData(), 0, 16);
542     }
543 }
544 
545 /*----------------------------------------------------------------------
546 |   AP4_TrackPropertyMap::~AP4_TrackPropertyMap
547 +---------------------------------------------------------------------*/
~AP4_TrackPropertyMap()548 AP4_TrackPropertyMap::~AP4_TrackPropertyMap()
549 {
550     m_Entries.DeleteReferences();
551 }
552 
553 /*----------------------------------------------------------------------
554 |   AP4_TrackPropertyMap::SetProperty
555 +---------------------------------------------------------------------*/
556 AP4_Result
SetProperty(AP4_UI32 track_id,const char * name,const char * value)557 AP4_TrackPropertyMap::SetProperty(AP4_UI32    track_id,
558                                   const char* name,
559                                   const char* value)
560 {
561     return m_Entries.Add(new Entry(track_id, name, value));
562 }
563 
564 /*----------------------------------------------------------------------
565 |   AP4_TrackPropertyMap::SetProperties
566 +---------------------------------------------------------------------*/
567 AP4_Result
SetProperties(const AP4_TrackPropertyMap & properties)568 AP4_TrackPropertyMap::SetProperties(const AP4_TrackPropertyMap& properties)
569 {
570     AP4_List<Entry>::Item* item = properties.m_Entries.FirstItem();
571     while (item) {
572         Entry* entry = item->GetData();
573         m_Entries.Add(new Entry(entry->m_TrackId,
574                                 entry->m_Name.GetChars(),
575                                 entry->m_Value.GetChars()));
576         item = item->GetNext();
577     }
578     return AP4_SUCCESS;
579 }
580 
581 /*----------------------------------------------------------------------
582 |   AP4_TrackPropertyMap::GetProperty
583 +---------------------------------------------------------------------*/
584 const char*
GetProperty(AP4_UI32 track_id,const char * name)585 AP4_TrackPropertyMap::GetProperty(AP4_UI32 track_id, const char* name)
586 {
587     AP4_List<Entry>::Item* item = m_Entries.FirstItem();
588     while (item) {
589         Entry* entry = item->GetData();
590         if (entry->m_TrackId == track_id &&
591             AP4_CompareStrings(entry->m_Name.GetChars(), name) == 0) {
592             return entry->m_Value.GetChars();
593         }
594         item = item->GetNext();
595     }
596 
597     // not found
598     return NULL;
599 }
600 
601 /*----------------------------------------------------------------------
602 |   AP4_TrackPropertyMap::GetTextualHeaders
603 +---------------------------------------------------------------------*/
604 AP4_Result
GetTextualHeaders(AP4_UI32 track_id,AP4_DataBuffer & textual_headers)605 AP4_TrackPropertyMap::GetTextualHeaders(AP4_UI32 track_id, AP4_DataBuffer& textual_headers)
606 {
607     AP4_Size    buffer_size = 0;
608     AP4_Result  result      = AP4_SUCCESS;
609     AP4_Byte*   data_buffer;
610 
611     // get the size needed for the textual headers
612     AP4_List<Entry>::Item* item = m_Entries.FirstItem();
613     while (item) {
614         Entry* entry = item->GetData();
615         if (entry->m_TrackId == track_id) {
616             const char* name = entry->m_Name.GetChars();
617             if (AP4_CompareStrings(name, "ContentId")       != 0 &&
618                 AP4_CompareStrings(name, "RightsIssuerUrl") != 0 &&
619                 AP4_CompareStrings(name, "KID")             != 0) {
620                 buffer_size += (entry->m_Name.GetLength()  +
621                                 entry->m_Value.GetLength() +
622                                 2); // colon + nul
623 
624             }
625         }
626         item = item->GetNext();
627     }
628 
629     result = textual_headers.SetDataSize(buffer_size);
630     AP4_CHECK(result);
631 
632     data_buffer = textual_headers.UseData();
633 
634     // set the textual headers
635     item = m_Entries.FirstItem();
636     while (item) {
637         Entry* entry = item->GetData();
638         if (entry->m_TrackId == track_id) {
639             const char* name       = entry->m_Name.GetChars();
640             const char* value      = NULL;
641             AP4_Size    name_len   = 0;
642             AP4_Size    value_len  = 0;
643 
644             if (AP4_CompareStrings(name, "ContentId")       != 0 &&
645                 AP4_CompareStrings(name, "RightsIssuerUrl") != 0 &&
646                 AP4_CompareStrings(name, "KID")             != 0) {
647                 name_len  = entry->m_Name.GetLength();
648                 value     = entry->m_Value.GetChars();
649                 value_len = entry->m_Value.GetLength();
650 
651                 // format is name:value\0
652                 if (name && value) {
653                     AP4_CopyMemory(data_buffer, name, name_len);
654                     data_buffer[name_len] = ':';
655                     data_buffer += (1+name_len);
656                     AP4_CopyMemory(data_buffer, value, value_len);
657                     data_buffer[value_len] = '\0';
658                     data_buffer += (1+value_len);
659                 }
660             }
661         }
662         item = item->GetNext();
663     }
664 
665     // success path
666     return AP4_SUCCESS;
667 }
668 
669 /*----------------------------------------------------------------------
670 |   AP4_ProtectedSampleDescription::AP4_ProtectedSampleDescription
671 +---------------------------------------------------------------------*/
AP4_ProtectedSampleDescription(AP4_UI32 format,AP4_SampleDescription * original_sample_description,AP4_UI32 original_format,AP4_UI32 scheme_type,AP4_UI32 scheme_version,const char * scheme_uri,AP4_ContainerAtom * schi,bool transfer_ownership_of_original)672 AP4_ProtectedSampleDescription::AP4_ProtectedSampleDescription(
673     AP4_UI32               format,
674     AP4_SampleDescription* original_sample_description,
675     AP4_UI32               original_format,
676     AP4_UI32               scheme_type,
677     AP4_UI32               scheme_version,
678     const char*            scheme_uri,
679     AP4_ContainerAtom*     schi,
680     bool                   transfer_ownership_of_original /* = true */) :
681     AP4_SampleDescription(TYPE_PROTECTED, format, NULL),
682     m_OriginalSampleDescription(original_sample_description),
683     m_OriginalSampleDescriptionIsOwned(transfer_ownership_of_original),
684     m_OriginalFormat(original_format),
685     m_SchemeType(scheme_type),
686     m_SchemeVersion(scheme_version),
687     m_SchemeUri(scheme_uri)
688 {
689     m_SchemeInfo = new AP4_ProtectionSchemeInfo(schi);
690 }
691 
692 /*----------------------------------------------------------------------
693 |   AP4_ProtectedSampleDescription::~AP4_ProtectedSampleDescription
694 +---------------------------------------------------------------------*/
~AP4_ProtectedSampleDescription()695 AP4_ProtectedSampleDescription::~AP4_ProtectedSampleDescription()
696 {
697     delete m_SchemeInfo;
698     if (m_OriginalSampleDescriptionIsOwned) delete m_OriginalSampleDescription;
699 }
700 
701 /*----------------------------------------------------------------------
702 |   AP4_ProtectedSampleDescription::ToAtom
703 +---------------------------------------------------------------------*/
704 AP4_Atom*
ToAtom() const705 AP4_ProtectedSampleDescription::ToAtom() const
706 {
707     // construct the atom for the original sample description
708     if (m_OriginalSampleDescription == NULL) return NULL;
709     AP4_Atom* atom = m_OriginalSampleDescription->ToAtom();
710 
711     // switch the atom type
712     atom->SetType(m_Format);
713 
714     // check that the constructed atom is a container
715     AP4_ContainerAtom* container = AP4_DYNAMIC_CAST(AP4_ContainerAtom, atom);
716     if (container == NULL) return atom; // not a container ?? return now.
717 
718     // create the sinf atom
719     AP4_ContainerAtom* sinf = new AP4_ContainerAtom(AP4_ATOM_TYPE_SINF);
720 
721     // create and add a frma atom
722     AP4_FrmaAtom* frma = new AP4_FrmaAtom(m_OriginalFormat);
723     sinf->AddChild(frma);
724 
725     // create and add a schm atom
726     AP4_SchmAtom* schm = new AP4_SchmAtom(m_SchemeType, m_SchemeVersion, m_SchemeUri.GetChars());
727     sinf->AddChild(schm);
728 
729     // add the schi atom
730     if (m_SchemeInfo && m_SchemeInfo->GetSchiAtom()) {
731         sinf->AddChild(m_SchemeInfo->GetSchiAtom()->Clone());
732     }
733 
734     // add the sinf to the returned atom
735     container->AddChild(sinf);
736 
737     return atom;
738 }
739 
740 /*----------------------------------------------------------------------
741 |   AP4_SampleDecrypter:Create
742 +---------------------------------------------------------------------*/
743 AP4_SampleDecrypter*
Create(AP4_ProtectedSampleDescription * sample_description,const AP4_UI08 * key,AP4_Size key_size,AP4_BlockCipherFactory * block_cipher_factory)744 AP4_SampleDecrypter::Create(AP4_ProtectedSampleDescription* sample_description,
745                             const AP4_UI08*                 key,
746                             AP4_Size                        key_size,
747                             AP4_BlockCipherFactory*         block_cipher_factory)
748 {
749     if (sample_description == NULL || key == NULL) return NULL;
750 
751     // select the block cipher factory
752     if (block_cipher_factory == NULL) {
753         block_cipher_factory = &AP4_DefaultBlockCipherFactory::Instance;
754     }
755 
756     switch(sample_description->GetSchemeType()) {
757         case AP4_PROTECTION_SCHEME_TYPE_OMA: {
758             AP4_OmaDcfSampleDecrypter* decrypter = NULL;
759             AP4_Result result = AP4_OmaDcfSampleDecrypter::Create(sample_description,
760                                                                   key,
761                                                                   key_size,
762                                                                   block_cipher_factory,
763                                                                   decrypter);
764             if (AP4_FAILED(result)) return NULL;
765             return decrypter;
766         }
767 
768         case AP4_PROTECTION_SCHEME_TYPE_IAEC: {
769             AP4_IsmaCipher* decrypter = NULL;
770             AP4_Result result = AP4_IsmaCipher::CreateSampleDecrypter(sample_description,
771                                                                       key,
772                                                                       key_size,
773                                                                       block_cipher_factory,
774                                                                       decrypter);
775             if (AP4_FAILED(result)) return NULL;
776             return decrypter;
777         }
778 
779         default:
780             return NULL;
781     }
782 
783     // unreachable - return NULL;
784 }
785 
786 /*----------------------------------------------------------------------
787 |   AP4_SampleDecrypter:Create
788 +---------------------------------------------------------------------*/
789 AP4_SampleDecrypter*
Create(AP4_ProtectedSampleDescription * sample_description,AP4_ContainerAtom * traf,AP4_ByteStream & aux_info_data,AP4_Position aux_info_data_offset,const AP4_UI08 * key,AP4_Size key_size,AP4_BlockCipherFactory * block_cipher_factory)790 AP4_SampleDecrypter::Create(AP4_ProtectedSampleDescription* sample_description,
791                             AP4_ContainerAtom*              traf,
792                             AP4_ByteStream&                 aux_info_data,
793                             AP4_Position                    aux_info_data_offset,
794                             const AP4_UI08*                 key,
795                             AP4_Size                        key_size,
796                             AP4_BlockCipherFactory*         block_cipher_factory)
797 {
798     if (sample_description == NULL || traf == NULL || key == NULL) return NULL;
799 
800     // select the block cipher factory
801     if (block_cipher_factory == NULL) {
802         block_cipher_factory = &AP4_DefaultBlockCipherFactory::Instance;
803     }
804 
805     switch(sample_description->GetSchemeType()) {
806         case AP4_PROTECTION_SCHEME_TYPE_PIFF:
807         case AP4_PROTECTION_SCHEME_TYPE_CENC: {
808             AP4_CencSampleDecrypter* decrypter = NULL;
809             AP4_Result result = AP4_CencSampleDecrypter::Create(sample_description,
810                                                                 traf,
811                                                                 aux_info_data,
812                                                                 aux_info_data_offset,
813                                                                 key,
814                                                                 key_size,
815                                                                 block_cipher_factory,
816                                                                 decrypter);
817             if (AP4_FAILED(result)) return NULL;
818             return decrypter;
819         }
820 
821         default:
822             return NULL;
823     }
824 
825     // unreachable - return NULL;
826 }
827 
828 /*----------------------------------------------------------------------
829 |   AP4_StandardDecryptingProcessor:AP4_StandardDecryptingProcessor
830 +---------------------------------------------------------------------*/
AP4_StandardDecryptingProcessor(const AP4_ProtectionKeyMap * key_map,AP4_BlockCipherFactory * block_cipher_factory)831 AP4_StandardDecryptingProcessor::AP4_StandardDecryptingProcessor(
832     const AP4_ProtectionKeyMap* key_map              /* = NULL */,
833     AP4_BlockCipherFactory*     block_cipher_factory /* = NULL */)
834 {
835     if (key_map) {
836         // copy the keys
837         m_KeyMap.SetKeys(*key_map);
838     }
839 
840     if (block_cipher_factory == NULL) {
841         m_BlockCipherFactory = &AP4_DefaultBlockCipherFactory::Instance;
842     } else {
843         m_BlockCipherFactory = block_cipher_factory;
844     }
845 }
846 
847 /*----------------------------------------------------------------------
848  |   AP4_StandardDecryptingProcessor:Initialize
849  +---------------------------------------------------------------------*/
850 AP4_Result
Initialize(AP4_AtomParent & top_level,AP4_ByteStream &,ProgressListener *)851 AP4_StandardDecryptingProcessor::Initialize(AP4_AtomParent&   top_level,
852                                             AP4_ByteStream&   /*stream*/,
853                                             ProgressListener* /*listener*/)
854 {
855     AP4_FtypAtom* ftyp = AP4_DYNAMIC_CAST(AP4_FtypAtom, top_level.GetChild(AP4_ATOM_TYPE_FTYP));
856     if (ftyp) {
857         // remove the atom, it will be replaced with a new one
858         top_level.RemoveChild(ftyp);
859 
860         // keep the existing brand and compatible brands except for the ones we want to remove
861         AP4_Array<AP4_UI32> compatible_brands;
862         compatible_brands.EnsureCapacity(ftyp->GetCompatibleBrands().ItemCount());
863         for (unsigned int i=0; i<ftyp->GetCompatibleBrands().ItemCount(); i++) {
864             if (ftyp->GetCompatibleBrands()[i] != AP4_OMA_DCF_BRAND_OPF2) {
865                 compatible_brands.Append(ftyp->GetCompatibleBrands()[i]);
866             }
867         }
868 
869         // create a replacement for the major brand
870         top_level.AddChild(new AP4_FtypAtom(ftyp->GetMajorBrand(),
871                                             ftyp->GetMinorVersion(),
872                                             &compatible_brands[0],
873                                             compatible_brands.ItemCount()), 0);
874         delete ftyp;
875     }
876 
877     return AP4_SUCCESS;
878 }
879 
880 /*----------------------------------------------------------------------
881 |   AP4_StandardDecryptingProcessor:CreateTrackHandler
882 +---------------------------------------------------------------------*/
883 AP4_Processor::TrackHandler*
CreateTrackHandler(AP4_TrakAtom * trak)884 AP4_StandardDecryptingProcessor::CreateTrackHandler(AP4_TrakAtom* trak)
885 {
886     // find the stsd atom
887     AP4_StsdAtom* stsd = AP4_DYNAMIC_CAST(AP4_StsdAtom, trak->FindChild("mdia/minf/stbl/stsd"));
888 
889     // avoid tracks with no stsd atom (should not happen)
890     if (stsd == NULL) return NULL;
891 
892     // we only look at the first sample description
893     AP4_SampleDescription* desc = stsd->GetSampleDescription(0);
894     AP4_SampleEntry* entry = stsd->GetSampleEntry(0);
895     if (desc == NULL || entry == NULL) return NULL;
896     if (desc->GetType() == AP4_SampleDescription::TYPE_PROTECTED) {
897         // create a handler for this track
898         AP4_ProtectedSampleDescription* protected_desc =
899             static_cast<AP4_ProtectedSampleDescription*>(desc);
900         if (protected_desc->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_OMA) {
901             const AP4_DataBuffer* key = m_KeyMap.GetKey(trak->GetId());
902             if (key) {
903                 AP4_OmaDcfTrackDecrypter* handler = NULL;
904                 AP4_Result result = AP4_OmaDcfTrackDecrypter::Create(key->GetData(),
905                                                                      key->GetDataSize(),
906                                                                      protected_desc,
907                                                                      entry,
908                                                                      m_BlockCipherFactory,
909                                                                      handler);
910                 if (AP4_FAILED(result)) return NULL;
911                 return handler;
912             }
913         } else if (protected_desc->GetSchemeType() == AP4_PROTECTION_SCHEME_TYPE_IAEC) {
914             const AP4_DataBuffer* key = m_KeyMap.GetKey(trak->GetId());
915             if (key) {
916                 AP4_IsmaTrackDecrypter* handler = NULL;
917                 AP4_Result result = AP4_IsmaTrackDecrypter::Create(key->GetData(),
918                                                                    key->GetDataSize(),
919                                                                    protected_desc,
920                                                                    entry,
921                                                                    m_BlockCipherFactory,
922                                                                    handler);
923                 if (AP4_FAILED(result)) return NULL;
924                 return handler;
925             }
926         }
927     }
928 
929     return NULL;
930 }
931 
932 /*----------------------------------------------------------------------
933 |   AP4_DecryptingStream::AP4_DecryptingStream
934 +---------------------------------------------------------------------*/
935 AP4_Result
Create(AP4_BlockCipher::CipherMode mode,AP4_ByteStream & encrypted_stream,AP4_LargeSize cleartext_size,const AP4_UI08 * iv,AP4_Size iv_size,const AP4_UI08 * key,AP4_Size key_size,AP4_BlockCipherFactory * block_cipher_factory,AP4_ByteStream * & stream)936 AP4_DecryptingStream::Create(AP4_BlockCipher::CipherMode mode,
937                              AP4_ByteStream&             encrypted_stream,
938                              AP4_LargeSize               cleartext_size,
939                              const AP4_UI08*             iv,
940                              AP4_Size                    iv_size,
941                              const AP4_UI08*             key,
942                              AP4_Size                    key_size,
943                              AP4_BlockCipherFactory*     block_cipher_factory,
944                              AP4_ByteStream*&            stream)
945 {
946     // default return value
947     stream = NULL;
948 
949     // default cipher settings
950     if (block_cipher_factory == NULL) {
951         block_cipher_factory = &AP4_DefaultBlockCipherFactory::Instance;
952     }
953 
954     // get the encrypted size (includes padding)
955     AP4_LargeSize encrypted_size = 0;
956     AP4_Result result = encrypted_stream.GetSize(encrypted_size);
957     if (AP4_FAILED(result)) return result;
958 
959     // check IV
960     if (iv == NULL || iv_size != 16) return AP4_ERROR_INVALID_PARAMETERS;
961 
962     // check that the encrypted size is consistent with the cipher mode
963     AP4_BlockCipher::CtrParams ctr_params;
964     const void*                mode_params = NULL;
965     if (mode == AP4_BlockCipher::CBC) {
966         // we need at least 16 bytes of data+padding
967         // we also need a multiple of the block size
968         if (encrypted_size < 16 || ((encrypted_size % 16) != 0)) {
969             return AP4_ERROR_INVALID_FORMAT;
970         }
971     } else if (mode == AP4_BlockCipher::CTR) {
972         ctr_params.counter_size = 16;
973         mode_params = &ctr_params;
974     } else {
975         return AP4_ERROR_NOT_SUPPORTED;
976     }
977 
978     // create the stream cipher
979     AP4_BlockCipher* block_cipher;
980     result = block_cipher_factory->CreateCipher(AP4_BlockCipher::AES_128,
981                                                 AP4_BlockCipher::DECRYPT,
982                                                 mode,
983                                                 mode_params,
984                                                 key,
985                                                 key_size,
986                                                 block_cipher);
987     if (AP4_FAILED(result)) return result;
988 
989     // keep a reference to the source stream
990     encrypted_stream.AddReference();
991 
992     // create the cipher according to the mode
993     AP4_StreamCipher* stream_cipher = NULL;
994     switch (mode) {
995         case AP4_BlockCipher::CBC:
996             stream_cipher = new AP4_CbcStreamCipher(block_cipher);
997             break;
998         case AP4_BlockCipher::CTR:
999             stream_cipher = new AP4_CtrStreamCipher(block_cipher, AP4_CIPHER_BLOCK_SIZE);
1000             break;
1001         default:
1002             // should never occur
1003             return AP4_ERROR_NOT_SUPPORTED;
1004     }
1005 
1006     // set the IV
1007     stream_cipher->SetIV(iv);
1008 
1009     // create the stream
1010     stream = new AP4_DecryptingStream(cleartext_size,
1011                                       &encrypted_stream,
1012                                       encrypted_size,
1013                                       stream_cipher);
1014 
1015     return AP4_SUCCESS;
1016 }
1017 
1018 /*----------------------------------------------------------------------
1019 |   AP4_DecryptingStream::~AP4_DecryptingStream
1020 +---------------------------------------------------------------------*/
~AP4_DecryptingStream()1021 AP4_DecryptingStream::~AP4_DecryptingStream()
1022 {
1023     delete m_StreamCipher;
1024     m_EncryptedStream->Release();
1025 }
1026 
1027 /*----------------------------------------------------------------------
1028 |   AP4_DecryptingStream::AddReference
1029 +---------------------------------------------------------------------*/
1030 void
AddReference()1031 AP4_DecryptingStream::AddReference()
1032 {
1033     ++m_ReferenceCount;
1034 }
1035 
1036 /*----------------------------------------------------------------------
1037 |   AP4_DecryptingStream::Release
1038 +---------------------------------------------------------------------*/
1039 void
Release()1040 AP4_DecryptingStream::Release()
1041 {
1042     if (--m_ReferenceCount == 0) delete this;
1043 }
1044 
1045 /*----------------------------------------------------------------------
1046 |   AP4_DecryptingStream::ReadPartial
1047 +---------------------------------------------------------------------*/
1048 AP4_Result
ReadPartial(void * buffer,AP4_Size bytes_to_read,AP4_Size & bytes_read)1049 AP4_DecryptingStream::ReadPartial(void*     buffer,
1050                                   AP4_Size  bytes_to_read,
1051                                   AP4_Size& bytes_read)
1052 {
1053     bytes_read = 0;
1054 
1055     // never read more than what's available
1056     AP4_LargeSize available = m_CleartextSize-m_CleartextPosition;
1057     if (available < bytes_to_read) {
1058         if (available == 0) {
1059             return AP4_ERROR_EOS;
1060         }
1061         bytes_to_read = (AP4_Size)available;
1062     }
1063 
1064     if (m_BufferFullness) {
1065         // we have some leftovers
1066         AP4_Size chunk = bytes_to_read;
1067         if (chunk > m_BufferFullness) chunk = m_BufferFullness;
1068         AP4_CopyMemory(buffer, &m_Buffer[m_BufferOffset], chunk);
1069         buffer = (char*)buffer+chunk;
1070         m_CleartextPosition += chunk;
1071         available           -= chunk;
1072         bytes_to_read       -= chunk;
1073         m_BufferFullness    -= chunk;
1074         m_BufferOffset      += chunk;
1075         bytes_read          += chunk;
1076     }
1077     if (bytes_to_read == 0) return AP4_SUCCESS;
1078 
1079     // seek to the right place in the input
1080     m_EncryptedStream->Seek(m_EncryptedPosition);
1081 
1082     while (bytes_to_read) {
1083         // read from the source
1084         AP4_UI08 encrypted[1024];
1085         AP4_Size encrypted_read = 0;
1086         AP4_Result result = m_EncryptedStream->ReadPartial(encrypted, sizeof(encrypted), encrypted_read);
1087         if (result == AP4_ERROR_EOS) {
1088             if (bytes_read == 0) {
1089                 return AP4_ERROR_EOS;
1090             } else {
1091                 return AP4_SUCCESS;
1092             }
1093         } else if (result != AP4_SUCCESS) {
1094             return result;
1095         } else {
1096             m_EncryptedPosition += encrypted_read;
1097         }
1098         bool is_last_buffer = (m_EncryptedPosition >= m_EncryptedSize);
1099         AP4_Size buffer_size = sizeof(m_Buffer);
1100         result = m_StreamCipher->ProcessBuffer(encrypted,
1101                                                encrypted_read,
1102                                                m_Buffer,
1103                                                &buffer_size,
1104                                                is_last_buffer);
1105         if (AP4_FAILED(result)) return result;
1106         m_BufferOffset   = 0;
1107         m_BufferFullness = buffer_size;
1108 
1109         AP4_Size chunk = bytes_to_read;
1110         if (chunk > m_BufferFullness) chunk = m_BufferFullness;
1111         if (chunk) AP4_CopyMemory(buffer, &m_Buffer[m_BufferOffset], chunk);
1112         buffer = (char*)buffer+chunk;
1113         m_CleartextPosition += chunk;
1114         available           -= chunk;
1115         bytes_to_read       -= chunk;
1116         m_BufferFullness    -= chunk;
1117         m_BufferOffset      += chunk;
1118         bytes_read          += chunk;
1119     }
1120 
1121     return AP4_SUCCESS;
1122 }
1123 
1124 /*----------------------------------------------------------------------
1125 |   AP4_DecryptingStream::WritePartial
1126 +---------------------------------------------------------------------*/
1127 AP4_Result
WritePartial(const void *,AP4_Size,AP4_Size &)1128 AP4_DecryptingStream::WritePartial(const void* /* buffer         */,
1129                                    AP4_Size    /* bytes_to_write */,
1130                                    AP4_Size&   /* bytes_written  */)
1131 {
1132     return AP4_ERROR_NOT_SUPPORTED;
1133 }
1134 
1135 /*----------------------------------------------------------------------
1136 |   AP4_DecryptingStream::Seek
1137 +---------------------------------------------------------------------*/
1138 AP4_Result
Seek(AP4_Position position)1139 AP4_DecryptingStream::Seek(AP4_Position position)
1140 {
1141     AP4_Cardinal preroll = 0;
1142 
1143     // check for no-op seek requests
1144     if (position == m_CleartextPosition) {
1145         return AP4_SUCCESS;
1146     }
1147 
1148     // check bounds
1149     if (position > m_CleartextSize) {
1150         return AP4_ERROR_INVALID_PARAMETERS;
1151     }
1152 
1153     // try to put the stream cipher at the right offset
1154     AP4_CHECK(m_StreamCipher->SetStreamOffset(position, &preroll));
1155 
1156     // seek in the source stream
1157     AP4_CHECK(m_EncryptedStream->Seek(position-preroll));
1158 
1159     // if we need to, process the preroll bytes
1160     if (preroll > 0) {
1161         AP4_Size out_size = 0;
1162         AP4_UI08 buffer[2*AP4_CIPHER_BLOCK_SIZE]; // bigger than preroll
1163         AP4_CHECK(m_EncryptedStream->Read(buffer, preroll));
1164         AP4_CHECK(m_StreamCipher->ProcessBuffer(buffer, preroll, buffer, &out_size));
1165         AP4_ASSERT(out_size == 0); // we're just feeding prerolled bytes,
1166                                    // there can be no output
1167     }
1168 
1169     // update the counters
1170     m_CleartextPosition = position;
1171     m_EncryptedPosition = position;
1172     m_BufferFullness    = 0;
1173     m_BufferOffset      = 0;
1174 
1175     return AP4_SUCCESS;
1176 }
1177 
1178 /*----------------------------------------------------------------------
1179 |   AP4_DecryptingStream::Tell
1180 +---------------------------------------------------------------------*/
1181 AP4_Result
Tell(AP4_Position & position)1182 AP4_DecryptingStream::Tell(AP4_Position& position)
1183 {
1184     position = m_CleartextPosition;
1185     return AP4_SUCCESS;
1186 }
1187 
1188 /*----------------------------------------------------------------------
1189 |   AP4_DecryptingStream::GetSize
1190 +---------------------------------------------------------------------*/
1191 AP4_Result
GetSize(AP4_LargeSize & size)1192 AP4_DecryptingStream::GetSize(AP4_LargeSize& size)
1193 {
1194     size = m_CleartextSize;
1195     return AP4_SUCCESS;
1196 }
1197 
1198 /*----------------------------------------------------------------------
1199 |   AP4_EncryptingStream::AP4_EncryptingStream
1200 +---------------------------------------------------------------------*/
1201 AP4_Result
Create(AP4_BlockCipher::CipherMode mode,AP4_ByteStream & cleartext_stream,const AP4_UI08 * iv,AP4_Size iv_size,const AP4_UI08 * key,AP4_Size key_size,bool prepend_iv,AP4_BlockCipherFactory * block_cipher_factory,AP4_ByteStream * & stream)1202 AP4_EncryptingStream::Create(AP4_BlockCipher::CipherMode mode,
1203                              AP4_ByteStream&             cleartext_stream,
1204                              const AP4_UI08*             iv,
1205                              AP4_Size                    iv_size,
1206                              const AP4_UI08*             key,
1207                              AP4_Size                    key_size,
1208                              bool                        prepend_iv,
1209                              AP4_BlockCipherFactory*     block_cipher_factory,
1210                              AP4_ByteStream*&            stream)
1211 {
1212     // default return value
1213     stream = NULL;
1214 
1215     // get the cleartext size
1216     AP4_LargeSize cleartext_size = 0;
1217     AP4_Result result = cleartext_stream.GetSize(cleartext_size);
1218     if (AP4_FAILED(result)) return result;
1219 
1220     // check IV
1221     if (iv == NULL || iv_size != 16) return AP4_ERROR_INVALID_PARAMETERS;
1222 
1223     // compute the encrypted size and set cipher params
1224     AP4_LargeSize              encrypted_size = cleartext_size;
1225     const void*                mode_params = NULL;
1226     AP4_BlockCipher::CtrParams ctr_params;
1227     if (mode == AP4_BlockCipher::CBC) {
1228         encrypted_size += (16-(cleartext_size%16)); // with padding
1229     } else {
1230         ctr_params.counter_size = 16;
1231         mode_params = &ctr_params;
1232     }
1233 
1234     // create the stream cipher
1235     AP4_BlockCipher* block_cipher;
1236     result = block_cipher_factory->CreateCipher(AP4_BlockCipher::AES_128,
1237                                                 AP4_BlockCipher::ENCRYPT,
1238                                                 mode,
1239                                                 mode_params,
1240                                                 key,
1241                                                 key_size,
1242                                                 block_cipher);
1243     if (AP4_FAILED(result)) return result;
1244 
1245     // keep a reference to the source stream
1246     cleartext_stream.AddReference();
1247 
1248     // create the cipher according to the mode
1249     AP4_StreamCipher* stream_cipher = NULL;
1250     switch (mode) {
1251         case AP4_BlockCipher::CBC:
1252             stream_cipher = new AP4_CbcStreamCipher(block_cipher);
1253             break;
1254         case AP4_BlockCipher::CTR:
1255             stream_cipher = new AP4_CtrStreamCipher(block_cipher, AP4_CIPHER_BLOCK_SIZE);
1256             break;
1257         default:
1258             // should never occur
1259             AP4_ASSERT(0);
1260     }
1261 
1262     // set the IV
1263     stream_cipher->SetIV(iv);
1264 
1265     // create the stream
1266     AP4_EncryptingStream* enc_stream = new AP4_EncryptingStream(cleartext_size,
1267                                                                 &cleartext_stream,
1268                                                                 encrypted_size,
1269                                                                 stream_cipher);
1270     stream = enc_stream;
1271 
1272     // deal with the prepended IV if required
1273     if (prepend_iv) {
1274         enc_stream->m_EncryptedSize += 16;
1275         enc_stream->m_BufferFullness = 16;
1276         AP4_CopyMemory(enc_stream->m_Buffer, iv, 16);
1277     }
1278 
1279     return AP4_SUCCESS;
1280 }
1281 
1282 /*----------------------------------------------------------------------
1283 |   AP4_EncryptingStream::~AP4_EncryptingStream
1284 +---------------------------------------------------------------------*/
~AP4_EncryptingStream()1285 AP4_EncryptingStream::~AP4_EncryptingStream()
1286 {
1287     delete m_StreamCipher;
1288     m_CleartextStream->Release();
1289 }
1290 
1291 /*----------------------------------------------------------------------
1292 |   AP4_EncryptingStream::AddReference
1293 +---------------------------------------------------------------------*/
1294 void
AddReference()1295 AP4_EncryptingStream::AddReference()
1296 {
1297     ++m_ReferenceCount;
1298 }
1299 
1300 /*----------------------------------------------------------------------
1301 |   AP4_EncryptingStream::Release
1302 +---------------------------------------------------------------------*/
1303 void
Release()1304 AP4_EncryptingStream::Release()
1305 {
1306     if (--m_ReferenceCount == 0) delete this;
1307 }
1308 
1309 /*----------------------------------------------------------------------
1310 |   AP4_EncryptingStream::ReadPartial
1311 +---------------------------------------------------------------------*/
1312 AP4_Result
ReadPartial(void * buffer,AP4_Size bytes_to_read,AP4_Size & bytes_read)1313 AP4_EncryptingStream::ReadPartial(void*     buffer,
1314                                   AP4_Size  bytes_to_read,
1315                                   AP4_Size& bytes_read)
1316 {
1317     bytes_read = 0;
1318 
1319     // never read more than what's available
1320     AP4_LargeSize available = m_EncryptedSize-m_EncryptedPosition;
1321     if (available < bytes_to_read) {
1322         if (available == 0) return AP4_ERROR_EOS;
1323         bytes_to_read = (AP4_Size)available;
1324     }
1325 
1326     if (m_BufferFullness) {
1327         // we have some leftovers
1328         AP4_Size chunk = bytes_to_read;
1329         if (chunk > m_BufferFullness) chunk = m_BufferFullness;
1330         AP4_CopyMemory(buffer, &m_Buffer[m_BufferOffset], chunk);
1331         buffer = (char*)buffer+chunk;
1332         m_EncryptedPosition += chunk;
1333         available           -= chunk;
1334         bytes_to_read       -= chunk;
1335         m_BufferFullness    -= chunk;
1336         m_BufferOffset      += chunk;
1337         bytes_read          += chunk;
1338     }
1339 
1340     // seek to the right place in the input
1341     m_CleartextStream->Seek(m_CleartextPosition);
1342 
1343     while (bytes_to_read) {
1344         // read from the source
1345         AP4_UI08 cleartext[1024];
1346         AP4_Size cleartext_read = 0;
1347         AP4_Result result = m_CleartextStream->ReadPartial(cleartext, sizeof(cleartext), cleartext_read);
1348         if (result == AP4_ERROR_EOS) {
1349             if (bytes_read == 0) {
1350                 return AP4_ERROR_EOS;
1351             } else {
1352                 return AP4_SUCCESS;
1353             }
1354         } else if (result != AP4_SUCCESS) {
1355             return result;
1356         } else {
1357             m_CleartextPosition += cleartext_read;
1358         }
1359         bool is_last_buffer = (m_CleartextPosition >= m_CleartextSize);
1360         AP4_Size buffer_size = sizeof(m_Buffer);
1361         result = m_StreamCipher->ProcessBuffer(cleartext,
1362                                                cleartext_read,
1363                                                m_Buffer,
1364                                                &buffer_size,
1365                                                is_last_buffer);
1366         if (AP4_FAILED(result)) return result;
1367         m_BufferOffset   = 0;
1368         m_BufferFullness = buffer_size;
1369 
1370         AP4_Size chunk = bytes_to_read;
1371         if (chunk > m_BufferFullness) chunk = m_BufferFullness;
1372         if (chunk) {
1373             AP4_CopyMemory(buffer, &m_Buffer[m_BufferOffset], chunk);
1374             buffer = (char*)buffer+chunk;
1375             m_EncryptedPosition += chunk;
1376             available           -= chunk;
1377             bytes_to_read       -= chunk;
1378             m_BufferFullness    -= chunk;
1379             m_BufferOffset      += chunk;
1380             bytes_read          += chunk;
1381         }
1382     }
1383 
1384     return AP4_SUCCESS;
1385 }
1386 
1387 /*----------------------------------------------------------------------
1388 |   AP4_EncryptingStream::WritePartial
1389 +---------------------------------------------------------------------*/
1390 AP4_Result
WritePartial(const void *,AP4_Size,AP4_Size &)1391 AP4_EncryptingStream::WritePartial(const void* /* buffer         */,
1392                                    AP4_Size    /* bytes_to_write */,
1393                                    AP4_Size&   /* bytes_written  */)
1394 {
1395     return AP4_ERROR_NOT_SUPPORTED;
1396 }
1397 
1398 /*----------------------------------------------------------------------
1399 |   AP4_EncryptingStream::Seek
1400 +---------------------------------------------------------------------*/
1401 AP4_Result
Seek(AP4_Position position)1402 AP4_EncryptingStream::Seek(AP4_Position position)
1403 {
1404     if (position == m_EncryptedPosition) {
1405         return AP4_SUCCESS;
1406     } else {
1407         return AP4_ERROR_NOT_SUPPORTED;
1408     }
1409 }
1410 
1411 /*----------------------------------------------------------------------
1412 |   AP4_EncryptingStream::Tell
1413 +---------------------------------------------------------------------*/
1414 AP4_Result
Tell(AP4_Position & position)1415 AP4_EncryptingStream::Tell(AP4_Position& position)
1416 {
1417     position = m_EncryptedPosition;
1418     return AP4_SUCCESS;
1419 }
1420 
1421 /*----------------------------------------------------------------------
1422 |   AP4_EncryptingStream::GetSize
1423 +---------------------------------------------------------------------*/
1424 AP4_Result
GetSize(AP4_LargeSize & size)1425 AP4_EncryptingStream::GetSize(AP4_LargeSize& size)
1426 {
1427     size = m_EncryptedSize;
1428     return AP4_SUCCESS;
1429 }
1430 
1431 /*----------------------------------------------------------------------
1432 |   AP4_DefaultBlockCipherFactory::Instance
1433 +---------------------------------------------------------------------*/
1434 AP4_DefaultBlockCipherFactory AP4_DefaultBlockCipherFactory::Instance;
1435 
1436 /*----------------------------------------------------------------------
1437 |   AP4_DefaultBlockCipherFactory
1438 +---------------------------------------------------------------------*/
1439 AP4_Result
CreateCipher(AP4_BlockCipher::CipherType type,AP4_BlockCipher::CipherDirection direction,AP4_BlockCipher::CipherMode mode,const void * mode_params,const AP4_UI08 * key,AP4_Size key_size,AP4_BlockCipher * & cipher)1440 AP4_DefaultBlockCipherFactory::CreateCipher(AP4_BlockCipher::CipherType      type,
1441                                             AP4_BlockCipher::CipherDirection direction,
1442                                             AP4_BlockCipher::CipherMode      mode,
1443                                             const void*                      mode_params,
1444                                             const AP4_UI08*                  key,
1445                                             AP4_Size                         key_size,
1446                                             AP4_BlockCipher*&                cipher)
1447 {
1448     // setup default return vaule
1449     cipher = NULL;
1450 
1451     switch (type) {
1452         case AP4_BlockCipher::AES_128:
1453             // check cipher parameters
1454             if (key == NULL || key_size != AP4_AES_BLOCK_SIZE) {
1455                 return AP4_ERROR_INVALID_PARAMETERS;
1456             }
1457 
1458             // create the cipher
1459             {
1460                 AP4_AesBlockCipher* aes_cipher = NULL;
1461                 AP4_Result result =  AP4_AesBlockCipher::Create(key, direction, mode, mode_params, aes_cipher);
1462                 if (AP4_FAILED(result)) return result;
1463                 cipher = aes_cipher;
1464                 return AP4_SUCCESS;
1465             }
1466 
1467         default:
1468             // not supported
1469             return AP4_ERROR_NOT_SUPPORTED;
1470     }
1471 }
1472 
1473 /*----------------------------------------------------------------------
1474 |   AP4_DefaultBlockCipherFactory::AP4_DefaultBlockCipherFactory
1475 +---------------------------------------------------------------------*/
AP4_DefaultBlockCipherFactory()1476 AP4_DefaultBlockCipherFactory::AP4_DefaultBlockCipherFactory() :
1477     m_Initialized(true)
1478 {
1479 }
1480 
1481 /*----------------------------------------------------------------------
1482 |   AP4_DefaultBlockCipherFactory::Initialize
1483 +---------------------------------------------------------------------*/
1484 AP4_Result
Initialize()1485 AP4_DefaultBlockCipherFactory::Initialize()
1486 {
1487     m_Initialized = true;
1488     return AP4_SUCCESS;
1489 }
1490