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