📄 rfccrypto.cpp
字号:
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is MPEG4IP. * * The Initial Developer of the Original Code is Cisco Systems Inc. * Portions created by Cisco Systems Inc. are * Copyright (C) Cisco Systems Inc. 2000-2004. All Rights Reserved. * * Contributor(s): * Dave Mackie dmackie@cisco.com * Mark Baugher mbaugher@cisco.com * Alix Marchandise-Franquet alix@cisco.com * Alex Vanzella alexv@cisco.com */#include <mp4av_common.h>// definitions// mjb: ismacryp declarations#define ISMACRYP_CRYPTO_SUITE 0 //index into settings array#define ISMACRYP_CRYPTO_SUITE_DEFAULT 0#define ISMACRYP_IV_LENGTH 1 //index into settings array#define ISMACRYP_IV_LENGTH_DEFAULT 4#define ISMACRYP_IV_DELTA_LENGTH 2 //index into settings array#define ISMACRYP_IV_DELTA_LENGTH_DEFAULT 0#define ISMACRYP_SELECTIVE_ENCRYPTION 3 //index into settings array#define ISMACRYP_SELECTIVE_ENCRYPTION_DEFAULT 0#define ISMACRYP_KEY_INDICATOR_LENGTH 4 //index into settings array#define ISMACRYP_KEY_INDICATOR_LENGTH_DEFAULT 0#define ISMACRYP_KEY_INDICATOR_PER_AU 5 //index into settings array#define ISMACRYP_KEY_INDICATOR_PER_AU_DEFAULT 0#define ISMACRYP_SALT_LENGTH 6 //index into settings array#define ISMACRYP_SALT_LENGTH_DEFAULT 8 //number of bytes in salt key#define ISMACRYP_KEY_LENGTH 7 //index into settings array#define ISMACRYP_KEY_LENGTH_DEFAULT 16 //number of bytes in master key#define ISMACRYP_KEY_COUNT 8 //index into settings array#define ISMACRYP_MAX_KEYS 6 //max number of salts and keys#define ISMACRYP_MAX_KEY_LENGTH ISMACRYP_KEY_LENGTH_DEFAULT#define ISMACRYP_MAX_SALT_LENGTH ISMACRYP_SALT_LENGTH_DEFAULT// default scheme is "iAEC"#define ISMACRYP_DEFAULT_SCHEME_HEX 0x69414543#define ISMACRYP_SDP_CONFIG_MAX_LEN 256#define ISMACRYP_SDP_ADDITIONAL_CONFIG_MAX_LEN 256// change this if any of the following strings is longer than 64#define ISMACRYP_SDP_CONFIG_MAX_SUBSTR_LEN 64// if any of these strings is longer than ISMACRYP_SDP_CONFIG_MAX_SUBSTR_LEN,// change ISMACRYP_SDP_CONFIG_MAX_SUBSTR_LEN to reflect longest string + 1 for '\0'// pay special attention to the key string (str 7).#define ISMACRYP_SDP_CONFIG_STR_1 " ISMACrypCryptoSuite=AES_CTR_128;"#define ISMACRYP_SDP_CONFIG_STR_2 " ISMACrypIVLength=%u;"#define ISMACRYP_SDP_CONFIG_STR_3 " ISMACrypIVDeltaLength=%u;"#define ISMACRYP_SDP_CONFIG_STR_4 " ISMACrypSelectiveEncryption=%u;"#define ISMACRYP_SDP_CONFIG_STR_5 " ISMACrypKeyIndicatorLength=%u;"#define ISMACRYP_SDP_CONFIG_STR_6 " ISMACrypKeyIndicatorPerAU=%u;"#define ISMACRYP_SDP_CONFIG_STR_7 " ISMACrypKey=(key)%s/%u"// These structs hold ISMACRYP protocol variables related to an// encryption session. Used to construct SDP signalling information// for the session.typedef struct ismacryp_config_table { u_int8_t lifetime; u_int8_t settings[9]; u_int8_t* salts[ISMACRYP_MAX_KEYS]; u_int8_t* keys[ISMACRYP_MAX_KEYS]; char indices[ISMACRYP_MAX_KEYS][255];} ISMACrypConfigTable_t;typedef struct ismaCrypSampleHdrDataInfo { u_int8_t hasEncField; // if selective encryption u_int8_t isEncrypted; u_int8_t hasIVField; u_int8_t hasKIField;} ismaCrypSampleHdrDataInfo_t;// forward declarations.static bool MP4AV_RfcCryptoConcatenator( MP4FileHandle mp4File, MP4TrackId mediaTrackId, MP4TrackId hintTrackId, u_int8_t samplesThisHint, MP4SampleId* pSampleIds, MP4Duration hintDuration, u_int16_t maxPayloadSize, mp4av_ismacrypParams *icPp, bool isInterleaved);static bool MP4AV_RfcCryptoFragmenter( MP4FileHandle mp4File, MP4TrackId mediaTrackId, MP4TrackId hintTrackId, MP4SampleId sampleId, u_int32_t sampleSize, MP4Duration sampleDuration, u_int16_t maxPayloadSize, mp4av_ismacrypParams *icPp);/* start sdp code */// ismac_table will contain all the setting to create the SDP// initialize this table with settings from the ismacryp library static bool InitISMACrypConfigTable (ISMACrypConfigTable_t* ismac_table, mp4av_ismacrypParams *icPp){ u_int32_t fourCC; u_int8_t yes; ismac_table->settings[ISMACRYP_KEY_COUNT]=icPp->key_count; if(!ismac_table || ismac_table->salts[0] || ismac_table->keys[0]) return false; if(!(ismac_table->salts[0]=(u_int8_t*)malloc(icPp->salt_len))) return false; if(!(ismac_table->keys[0]=(u_int8_t*)malloc(icPp->key_len))){ free(ismac_table->salts[0]); return false; } ismac_table->settings[ISMACRYP_KEY_LENGTH] = icPp->key_len; ismac_table->settings[ISMACRYP_SALT_LENGTH] = icPp->salt_len; ismac_table->lifetime = icPp->key_life; memcpy(ismac_table->keys[0],icPp->key,icPp->key_len); memcpy(ismac_table->salts[0],icPp->salt,icPp->salt_len); ismac_table->settings[ISMACRYP_KEY_INDICATOR_LENGTH] = icPp->key_ind_len; yes = icPp->key_ind_perau; if (!yes) ismac_table->settings[ISMACRYP_KEY_INDICATOR_PER_AU] = 0; else ismac_table->settings[ISMACRYP_KEY_INDICATOR_PER_AU] = 1; yes = icPp->selective_enc; if (!yes) ismac_table->settings[ISMACRYP_SELECTIVE_ENCRYPTION] = 0; else ismac_table->settings[ISMACRYP_SELECTIVE_ENCRYPTION] = 1; ismac_table->settings[ISMACRYP_IV_DELTA_LENGTH] = icPp->delta_iv_len; ismac_table->settings[ISMACRYP_IV_LENGTH] = icPp->delta_iv_len; fourCC = icPp->scheme; if (fourCC == ISMACRYP_DEFAULT_SCHEME_HEX) ismac_table->settings[ISMACRYP_CRYPTO_SUITE]=0; else return false; return true; }// Checks validity of the ismacryp SDP settings returned from the ismacryp librarystatic bool MP4AV_RfcCryptoPolicyOk (ISMACrypConfigTable_t* ismac_table){ if(ismac_table->settings[ISMACRYP_CRYPTO_SUITE] != ISMACRYP_CRYPTO_SUITE_DEFAULT) return false; if(ismac_table->settings[ISMACRYP_IV_LENGTH] >8) return false; if(ismac_table->settings[ISMACRYP_IV_DELTA_LENGTH] > 2) return false; if(ismac_table->settings[ISMACRYP_SELECTIVE_ENCRYPTION] > 1) return false; if(ismac_table->settings[ISMACRYP_KEY_INDICATOR_PER_AU] > 1) return false; if((ismac_table->settings[ISMACRYP_SALT_LENGTH] != ISMACRYP_SALT_LENGTH_DEFAULT) || (ismac_table->settings[ISMACRYP_KEY_LENGTH] != ISMACRYP_KEY_LENGTH_DEFAULT)) return false; return true;}// assemble the ismacryp SDP string into sISMACrypConfigstatic bool MP4AV_RfcCryptoConfigure(ISMACrypConfigTable_t* ismac_table, char** sISMACrypConfig){ if (ismac_table == NULL ) return false; *sISMACrypConfig = (char *)malloc(ISMACRYP_SDP_CONFIG_MAX_LEN); if (*sISMACrypConfig == NULL ) return false; char temp[ISMACRYP_SDP_CONFIG_MAX_SUBSTR_LEN]; int lenstr1, lenstr2, totlen; // first string is ISMACrypCryptoSuite totlen = strlen(ISMACRYP_SDP_CONFIG_STR_1) + 1; // add 1 for '\0' if ( totlen < ISMACRYP_SDP_CONFIG_MAX_LEN - 1 ) snprintf(*sISMACrypConfig, totlen, "%s", ISMACRYP_SDP_CONFIG_STR_1); else { free(*sISMACrypConfig); return false; } // second string is ISMACrypIVLength snprintf(temp, ISMACRYP_SDP_CONFIG_MAX_SUBSTR_LEN, ISMACRYP_SDP_CONFIG_STR_2, ismac_table->settings[ISMACRYP_IV_LENGTH]); lenstr1 = strlen(*sISMACrypConfig); lenstr2 = strlen(temp) + 1; // add 1 for '\0' totlen = lenstr1 + lenstr2; if ( totlen < ISMACRYP_SDP_CONFIG_MAX_LEN ) snprintf( *sISMACrypConfig+lenstr1,lenstr2, "%s", temp); else { free(*sISMACrypConfig); return false; } // third string is ISMACrypIVDeltaLength snprintf(temp, ISMACRYP_SDP_CONFIG_MAX_SUBSTR_LEN, ISMACRYP_SDP_CONFIG_STR_3, ismac_table->settings[ISMACRYP_IV_DELTA_LENGTH]); lenstr1 = strlen(*sISMACrypConfig); lenstr2 = strlen(temp) + 1; // add 1 for '\0' totlen = lenstr1 + lenstr2; if ( totlen < ISMACRYP_SDP_CONFIG_MAX_LEN ) snprintf( *sISMACrypConfig+lenstr1,lenstr2, "%s", temp); else { free(*sISMACrypConfig); return false; } // fourth string is ISMACrypSelectiveEncryption snprintf(temp, ISMACRYP_SDP_CONFIG_MAX_SUBSTR_LEN, ISMACRYP_SDP_CONFIG_STR_4, ismac_table->settings[ISMACRYP_SELECTIVE_ENCRYPTION]); lenstr1 = strlen(*sISMACrypConfig); lenstr2 = strlen(temp) + 1; // add 1 for '\0' totlen = lenstr1 + lenstr2; if ( totlen < ISMACRYP_SDP_CONFIG_MAX_LEN ) snprintf( *sISMACrypConfig+lenstr1,lenstr2, "%s", temp); else { free(*sISMACrypConfig); return false; } // fifth string is ISMACrypKeyIndicatorLength snprintf(temp, ISMACRYP_SDP_CONFIG_MAX_SUBSTR_LEN, ISMACRYP_SDP_CONFIG_STR_5, ismac_table->settings[ISMACRYP_KEY_INDICATOR_LENGTH]); lenstr1 = strlen(*sISMACrypConfig); lenstr2 = strlen(temp) + 1; // add 1 for '\0' totlen = lenstr1 + lenstr2; if ( totlen < ISMACRYP_SDP_CONFIG_MAX_LEN ) snprintf( *sISMACrypConfig+lenstr1,lenstr2, "%s", temp); else { free(*sISMACrypConfig); return false; } // sixth string is ISMACrypKeyIndicatorPerAU snprintf(temp, ISMACRYP_SDP_CONFIG_MAX_SUBSTR_LEN, ISMACRYP_SDP_CONFIG_STR_6, ismac_table->settings[ISMACRYP_KEY_INDICATOR_PER_AU]); lenstr1 = strlen(*sISMACrypConfig); lenstr2 = strlen(temp) + 1; // add 1 for '\0' totlen = lenstr1 + lenstr2; if ( totlen < ISMACRYP_SDP_CONFIG_MAX_LEN ) snprintf( *sISMACrypConfig+lenstr1,lenstr2, "%s", temp); else { free(*sISMACrypConfig); return false; } // convert the concatenated, binary keys to Base 64 u_int8_t keymat[ISMACRYP_KEY_LENGTH_DEFAULT+ISMACRYP_SALT_LENGTH_DEFAULT]; memcpy(keymat,ismac_table->salts[0],ISMACRYP_SALT_LENGTH_DEFAULT); memcpy(&keymat[ISMACRYP_SALT_LENGTH_DEFAULT],ismac_table->keys[0],ISMACRYP_KEY_LENGTH_DEFAULT); char* base64keymat = MP4BinaryToBase64((u_int8_t*)keymat, ISMACRYP_SALT_LENGTH_DEFAULT + ISMACRYP_KEY_LENGTH_DEFAULT); // seventh string is ISMACrypKey snprintf(temp, ISMACRYP_SDP_CONFIG_MAX_SUBSTR_LEN, ISMACRYP_SDP_CONFIG_STR_7, base64keymat, ismac_table->lifetime); lenstr1 = strlen(*sISMACrypConfig); lenstr2 = strlen(temp) + 1; // add 1 for '\0' totlen = lenstr1 + lenstr2; if ( totlen < ISMACRYP_SDP_CONFIG_MAX_LEN ) snprintf( *sISMACrypConfig+lenstr1,lenstr2, "%s", temp); else { free(*sISMACrypConfig); free(base64keymat); return false; } free(base64keymat); return true;}/* end sdp code */// MP4AV_CryptoAudioConsecutiveHinter: figures out how to put the samples into packets// When a hint is defined (the sample ids of the hint are in pSampleIds)// call MP4AV_RfcCryptoConcatenator to create it // Note: This is a modified clone of MP4AV_AudioConsecutiveHinter in audio_hinters.cppstatic bool MP4AV_CryptoAudioConsecutiveHinter(MP4FileHandle mp4File, MP4TrackId mediaTrackId, MP4TrackId hintTrackId, MP4Duration sampleDuration, u_int8_t perPacketHeaderSize, u_int8_t perSampleHeaderSize, u_int8_t maxSamplesPerPacket, u_int16_t maxPayloadSize, MP4AV_AudioSampleSizer pSizer, mp4av_ismacrypParams *icPp){ bool rc; u_int32_t numSamples = MP4GetTrackNumberOfSamples(mp4File, mediaTrackId); u_int16_t bytesThisHint = perPacketHeaderSize; u_int16_t samplesThisHint = 0; MP4SampleId* pSampleIds = new MP4SampleId[maxSamplesPerPacket]; for (MP4SampleId sampleId = 1; sampleId <= numSamples; sampleId++) { u_int32_t sampleSize = (*pSizer)(mp4File, mediaTrackId, sampleId); // sample won't fit in this packet // or we've reached the limit on samples per packet if ((int16_t)(sampleSize + perSampleHeaderSize) > maxPayloadSize - bytesThisHint || samplesThisHint == maxSamplesPerPacket) { if (samplesThisHint > 0) { rc = MP4AV_RfcCryptoConcatenator(mp4File, mediaTrackId, hintTrackId, samplesThisHint, pSampleIds, samplesThisHint * sampleDuration, maxPayloadSize, icPp, false); if (!rc) { delete [] pSampleIds; return false; } } // start a new hint samplesThisHint = 0; bytesThisHint = perPacketHeaderSize; // fall thru } // sample is less than remaining payload size if ((int16_t)(sampleSize + perSampleHeaderSize) <= maxPayloadSize - bytesThisHint) { // add it to this hint bytesThisHint += (sampleSize + perSampleHeaderSize); pSampleIds[samplesThisHint++] = sampleId; } else { // jumbo frame, need to fragment it rc = MP4AV_RfcCryptoFragmenter(mp4File, mediaTrackId, hintTrackId, sampleId, sampleSize, sampleDuration, maxPayloadSize, icPp); if (!rc) { delete [] pSampleIds; return false; } // start a new hint samplesThisHint = 0; bytesThisHint = perPacketHeaderSize; } } if (samplesThisHint > 0) { rc = MP4AV_RfcCryptoConcatenator(mp4File, mediaTrackId, hintTrackId, samplesThisHint, pSampleIds, samplesThisHint * sampleDuration, maxPayloadSize, icPp, false); if (!rc) { delete [] pSampleIds; return false; } } delete [] pSampleIds; return true;}// MP4AV_CryptoAudioInterleaveHinter: figures out how to put the samples into packets// When a hint is defined (the sample ids of the hint are in pSampleIds)// call MP4AV_RfcCryptoConcatenator to create it. The samples are interleaved. // Note: This is a modified clone of MP4AV_AudioInterleaveHinter in audio_hinters.cppstatic bool MP4AV_CryptoAudioInterleaveHinter(MP4FileHandle mp4File, MP4TrackId mediaTrackId, MP4TrackId hintTrackId, MP4Duration sampleDuration, u_int8_t stride, u_int8_t bundle, u_int16_t maxPayloadSize, mp4av_ismacrypParams *icPp){ bool rc; u_int32_t numSamples = MP4GetTrackNumberOfSamples(mp4File, mediaTrackId); MP4SampleId* pSampleIds = new MP4SampleId[bundle]; uint32_t sampleIds = 0; for (u_int32_t i = 1; i <= numSamples; i += stride * bundle) { for (u_int32_t j = 0; j < stride; j++) { u_int32_t k; for (k = 0; k < bundle; k++) { MP4SampleId sampleId = i + j + (k * stride); // out of samples for this bundle if (sampleId > numSamples) { break; } // add sample to this hint pSampleIds[k] = sampleId; sampleIds++; } if (k == 0) { break; } // compute hint duration // note this is used to control the RTP timestamps // that are emitted for the packet, // it isn't the actual duration of the samples in the packet MP4Duration hintDuration; if (j + 1 == stride) { // at the end of the track if (i + (stride * bundle) > numSamples) { hintDuration = ((numSamples - i) - j) * sampleDuration; if (hintDuration == 0) { hintDuration = sampleDuration; } } else { hintDuration = ((stride * bundle) - j) * sampleDuration; } } else { hintDuration = sampleDuration; } // write hint rc = MP4AV_RfcCryptoConcatenator(mp4File, mediaTrackId, hintTrackId, k, pSampleIds, hintDuration, maxPayloadSize, icPp, true); sampleIds = 0; if (!rc) { delete [] pSampleIds; return false; } } } delete [] pSampleIds; return true;}// returns the size of the ismacryp sample header:// selective encryption flag, IV, key indicatorstatic u_int32_t MP4AV_GetIsmaCrypSampleHdrSize ( ismaCrypSampleHdrDataInfo_t iCrypSampleHdrInfo, u_int8_t IVlen, u_int8_t KIlen){ // the ismaCryp sample header always has the IV and the KI u_int32_t iCrypSampleHdrSize = (iCrypSampleHdrInfo.hasEncField ? 1: 0) + IVlen + KIlen; return iCrypSampleHdrSize;}// get the key indicator length, the IV length and the selective // encryption flag from the iSFM atom in the filestatic bool MP4AV_GetiSFMSettings(MP4FileHandle mp4File, MP4TrackId mediaTrackId, u_int8_t *useSelectiveEnc, u_int8_t *KIlen, u_int8_t *IVlen, bool isAudio){ const char *part1 = "mdia.minf.stbl.stsd."; const char *part2a = "enca"; const char *part2v = "encv"; const char *part3 = ".sinf.schi.iSFM."; const char *part4se = "selective-encryption";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -