/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //#define LOG_NDEBUG 0 #define LOG_TAG "HlsSampleDecryptor" #include "HlsSampleDecryptor.h" #include #include #include namespace android { HlsSampleDecryptor::HlsSampleDecryptor() : mValidKeyInfo(false) { } HlsSampleDecryptor::HlsSampleDecryptor(const sp &sampleAesKeyItem) : mValidKeyInfo(false) { signalNewSampleAesKey(sampleAesKeyItem); } void HlsSampleDecryptor::signalNewSampleAesKey(const sp &sampleAesKeyItem) { if (sampleAesKeyItem == NULL) { mValidKeyInfo = false; ALOGW("signalNewSampleAesKey: sampleAesKeyItem is NULL"); return; } sp keyDataBuffer, initVecBuffer; sampleAesKeyItem->findBuffer("keyData", &keyDataBuffer); sampleAesKeyItem->findBuffer("initVec", &initVecBuffer); if (keyDataBuffer != NULL && keyDataBuffer->size() == AES_BLOCK_SIZE && initVecBuffer != NULL && initVecBuffer->size() == AES_BLOCK_SIZE) { ALOGV("signalNewSampleAesKey: Key: %s IV: %s", aesBlockToStr(keyDataBuffer->data()).c_str(), aesBlockToStr(initVecBuffer->data()).c_str()); uint8_t KeyData[AES_BLOCK_SIZE]; memcpy(KeyData, keyDataBuffer->data(), AES_BLOCK_SIZE); memcpy(mAESInitVec, initVecBuffer->data(), AES_BLOCK_SIZE); mValidKeyInfo = (AES_set_decrypt_key(KeyData, 8*AES_BLOCK_SIZE/*128*/, &mAesKey) == 0); if (!mValidKeyInfo) { ALOGE("signalNewSampleAesKey: failed to set AES decryption key."); } } else { // Media scanner might try extract/parse the TS files without knowing the key. // Otherwise, shouldn't get here (unless an invalid playlist has swaped SAMPLE-AES with // NONE method while still sample-encrypted stream is parsed). mValidKeyInfo = false; ALOGE("signalNewSampleAesKey Can't decrypt; keyDataBuffer: %p(%zu) initVecBuffer: %p(%zu)", keyDataBuffer.get(), (keyDataBuffer.get() == NULL)? -1 : keyDataBuffer->size(), initVecBuffer.get(), (initVecBuffer.get() == NULL)? -1 : initVecBuffer->size()); } } size_t HlsSampleDecryptor::processNal(uint8_t *nalData, size_t nalSize) { unsigned nalType = nalData[0] & 0x1f; if (!mValidKeyInfo) { ALOGV("processNal[%d]: (%p)/%zu Skipping due to invalid key", nalType, nalData, nalSize); return nalSize; } bool isEncrypted = (nalSize > VIDEO_CLEAR_LEAD + AES_BLOCK_SIZE); ALOGV("processNal[%d]: (%p)/%zu isEncrypted: %d", nalType, nalData, nalSize, isEncrypted); if (isEncrypted) { // Encrypted NALUs have extra start code emulation prevention that must be // stripped out before we can decrypt it. size_t newSize = unescapeStream(nalData, nalSize); ALOGV("processNal:unescapeStream[%d]: %zu -> %zu", nalType, nalSize, newSize); nalSize = newSize; //Encrypted_nal_unit () { // nal_unit_type_byte // 1 byte // unencrypted_leader // 31 bytes // while (bytes_remaining() > 0) { // if (bytes_remaining() > 16) { // encrypted_block // 16 bytes // } // unencrypted_block // MIN(144, bytes_remaining()) bytes // } //} size_t offset = VIDEO_CLEAR_LEAD; size_t remainingBytes = nalSize - VIDEO_CLEAR_LEAD; // a copy of initVec as decryptBlock updates it unsigned char AESInitVec[AES_BLOCK_SIZE]; memcpy(AESInitVec, mAESInitVec, AES_BLOCK_SIZE); while (remainingBytes > 0) { // encrypted_block: protected block uses 10% skip encryption if (remainingBytes > AES_BLOCK_SIZE) { uint8_t *encrypted = nalData + offset; status_t ret = decryptBlock(encrypted, AES_BLOCK_SIZE, AESInitVec); if (ret != OK) { ALOGE("processNal failed with %d", ret); return nalSize; // revisit this } offset += AES_BLOCK_SIZE; remainingBytes -= AES_BLOCK_SIZE; } // unencrypted_block size_t clearBytes = std::min(remainingBytes, (size_t)(9 * AES_BLOCK_SIZE)); offset += clearBytes; remainingBytes -= clearBytes; } // while } else { // isEncrypted == false ALOGV("processNal[%d]: Unencrypted NALU (%p)/%zu", nalType, nalData, nalSize); } return nalSize; } void HlsSampleDecryptor::processAAC(size_t adtsHdrSize, uint8_t *data, size_t size) { if (!mValidKeyInfo) { ALOGV("processAAC: (%p)/%zu Skipping due to invalid key", data, size); return; } // ADTS header is included in the size if (size < adtsHdrSize) { ALOGV("processAAC: size (%zu) < adtsHdrSize (%zu)", size, adtsHdrSize); android_errorWriteLog(0x534e4554, "128433933"); return; } size_t offset = adtsHdrSize; size_t remainingBytes = size - adtsHdrSize; bool isEncrypted = (remainingBytes >= AUDIO_CLEAR_LEAD + AES_BLOCK_SIZE); ALOGV("processAAC: header: %zu data: %p(%zu) isEncrypted: %d", adtsHdrSize, data, size, isEncrypted); //Encrypted_AAC_Frame () { // ADTS_Header // 7 or 9 bytes // unencrypted_leader // 16 bytes // while (bytes_remaining() >= 16) { // encrypted_block // 16 bytes // } // unencrypted_trailer // 0-15 bytes //} // with lead bytes if (remainingBytes >= AUDIO_CLEAR_LEAD) { offset += AUDIO_CLEAR_LEAD; remainingBytes -= AUDIO_CLEAR_LEAD; // encrypted_block if (remainingBytes >= AES_BLOCK_SIZE) { size_t encryptedBytes = (remainingBytes / AES_BLOCK_SIZE) * AES_BLOCK_SIZE; unsigned char AESInitVec[AES_BLOCK_SIZE]; memcpy(AESInitVec, mAESInitVec, AES_BLOCK_SIZE); // decrypting all blocks at once uint8_t *encrypted = data + offset; status_t ret = decryptBlock(encrypted, encryptedBytes, AESInitVec); if (ret != OK) { ALOGE("processAAC: decryptBlock failed with %d", ret); return; } offset += encryptedBytes; remainingBytes -= encryptedBytes; } // encrypted // unencrypted_trailer size_t clearBytes = remainingBytes; if (clearBytes > 0) { CHECK(clearBytes < AES_BLOCK_SIZE); } } else { // without lead bytes ALOGV("processAAC: Unencrypted frame (without lead bytes) size %zu = %zu (hdr) + %zu (rem)", size, adtsHdrSize, remainingBytes); } } void HlsSampleDecryptor::processAC3(uint8_t *data, size_t size) { if (!mValidKeyInfo) { ALOGV("processAC3: (%p)/%zu Skipping due to invalid key", data, size); return; } bool isEncrypted = (size >= AUDIO_CLEAR_LEAD + AES_BLOCK_SIZE); ALOGV("processAC3 %p(%zu) isEncrypted: %d", data, size, isEncrypted); //Encrypted_AC3_Frame () { // unencrypted_leader // 16 bytes // while (bytes_remaining() >= 16) { // encrypted_block // 16 bytes // } // unencrypted_trailer // 0-15 bytes //} if (size >= AUDIO_CLEAR_LEAD) { // unencrypted_leader size_t offset = AUDIO_CLEAR_LEAD; size_t remainingBytes = size - AUDIO_CLEAR_LEAD; if (remainingBytes >= AES_BLOCK_SIZE) { size_t encryptedBytes = (remainingBytes / AES_BLOCK_SIZE) * AES_BLOCK_SIZE; // encrypted_block unsigned char AESInitVec[AES_BLOCK_SIZE]; memcpy(AESInitVec, mAESInitVec, AES_BLOCK_SIZE); // decrypting all blocks at once uint8_t *encrypted = data + offset; status_t ret = decryptBlock(encrypted, encryptedBytes, AESInitVec); if (ret != OK) { ALOGE("processAC3: decryptBlock failed with %d", ret); return; } offset += encryptedBytes; remainingBytes -= encryptedBytes; } // encrypted // unencrypted_trailer size_t clearBytes = remainingBytes; if (clearBytes > 0) { CHECK(clearBytes < AES_BLOCK_SIZE); } } else { ALOGV("processAC3: Unencrypted frame (without lead bytes) size %zu", size); } } // Unescapes data replacing occurrences of [0, 0, 3] with [0, 0] and returns the new size size_t HlsSampleDecryptor::unescapeStream(uint8_t *data, size_t limit) const { Vector scratchEscapePositions; size_t position = 0; while (position < limit) { position = findNextUnescapeIndex(data, position, limit); if (position < limit) { scratchEscapePositions.add(position); position += 3; } } size_t scratchEscapeCount = scratchEscapePositions.size(); size_t escapedPosition = 0; // The position being read from. size_t unescapedPosition = 0; // The position being written to. for (size_t i = 0; i < scratchEscapeCount; i++) { size_t nextEscapePosition = scratchEscapePositions[i]; //TODO: add 2 and get rid of the later = 0 assignments size_t copyLength = nextEscapePosition - escapedPosition; memmove(data+unescapedPosition, data+escapedPosition, copyLength); unescapedPosition += copyLength; data[unescapedPosition++] = 0; data[unescapedPosition++] = 0; escapedPosition += copyLength + 3; } size_t unescapedLength = limit - scratchEscapeCount; size_t remainingLength = unescapedLength - unescapedPosition; memmove(data+unescapedPosition, data+escapedPosition, remainingLength); return unescapedLength; } size_t HlsSampleDecryptor::findNextUnescapeIndex(uint8_t *data, size_t offset, size_t limit) const { for (size_t i = offset; i < limit - 2; i++) { //TODO: speed if (data[i] == 0x00 && data[i + 1] == 0x00 && data[i + 2] == 0x03) { return i; } } return limit; } status_t HlsSampleDecryptor::decryptBlock(uint8_t *buffer, size_t size, uint8_t AESInitVec[AES_BLOCK_SIZE]) { if (size == 0) { return OK; } if ((size % AES_BLOCK_SIZE) != 0) { ALOGE("decryptBlock: size (%zu) not a multiple of block size", size); return ERROR_MALFORMED; } ALOGV("decryptBlock: %p (%zu)", buffer, size); AES_cbc_encrypt(buffer, buffer, size, &mAesKey, AESInitVec, AES_DECRYPT); return OK; } AString HlsSampleDecryptor::aesBlockToStr(uint8_t block[AES_BLOCK_SIZE]) { AString result; if (block == NULL) { result = AString("null"); } else { result = AStringPrintf("0x%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", block[0], block[1], block[2], block[3], block[4], block[5], block[6], block[7], block[8], block[9], block[10], block[11], block[12], block[13], block[14], block[15]); } return result; } } // namespace android