summaryrefslogtreecommitdiffstats
path: root/drm
diff options
context:
space:
mode:
authorJohn "Juce" Bruce <juce@google.com>2014-06-10 21:12:56 -0700
committerFred Gylys-Colwell <fredgc@google.com>2014-07-01 03:26:37 +0000
commit6b3c1473199927264691bb50445cf0b35c2f8892 (patch)
tree544711204babcd928e566bdba7a3cc76865d5687 /drm
parent16dfdcff6e4bb025220b88d5fc132ae48e7cb437 (diff)
downloadframeworks_av-6b3c1473199927264691bb50445cf0b35c2f8892.zip
frameworks_av-6b3c1473199927264691bb50445cf0b35c2f8892.tar.gz
frameworks_av-6b3c1473199927264691bb50445cf0b35c2f8892.tar.bz2
Implement ClearKey Init Data Parser
Implements an object that can convert ISO-CENC or WebM initialization data into a ClearKey license request. Change-Id: Ib95012afcf40fc9e3f45510a468c305fb7bc216e
Diffstat (limited to 'drm')
-rw-r--r--drm/mediadrm/plugins/clearkey/Android.mk1
-rw-r--r--drm/mediadrm/plugins/clearkey/InitDataParser.cpp147
-rw-r--r--drm/mediadrm/plugins/clearkey/InitDataParser.h47
3 files changed, 195 insertions, 0 deletions
diff --git a/drm/mediadrm/plugins/clearkey/Android.mk b/drm/mediadrm/plugins/clearkey/Android.mk
index 59e992b..9cc81e8 100644
--- a/drm/mediadrm/plugins/clearkey/Android.mk
+++ b/drm/mediadrm/plugins/clearkey/Android.mk
@@ -18,6 +18,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
AesCtrDecryptor.cpp \
+ InitDataParser.cpp \
JsonWebKey.cpp \
Utils.cpp \
diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
new file mode 100644
index 0000000..c22d73a
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2014 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 "ClearKeyCryptoPlugin"
+#include <utils/Log.h>
+
+#include <endian.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/base64.h>
+#include <media/stagefright/MediaErrors.h>
+#include <string.h>
+
+#include "InitDataParser.h"
+
+#include "ClearKeyUUID.h"
+#include "Utils.h"
+
+namespace clearkeydrm {
+
+using android::AString;
+using android::String8;
+using android::Vector;
+
+namespace {
+ const size_t kKeyIdSize = 16;
+ const size_t kSystemIdSize = 16;
+}
+
+android::status_t InitDataParser::parse(const Vector<uint8_t>& initData,
+ const String8& initDataType,
+ Vector<uint8_t>* licenseRequest) {
+ // Build a list of the key IDs
+ Vector<const uint8_t*> keyIds;
+ if (initDataType == "cenc") {
+ android::status_t res = parsePssh(initData, &keyIds);
+ if (res != android::OK) {
+ return res;
+ }
+ } else if (initDataType == "webm") {
+ // WebM "init data" is just a single key ID
+ if (initData.size() != kKeyIdSize) {
+ return android::ERROR_DRM_CANNOT_HANDLE;
+ }
+ keyIds.push(initData.array());
+ } else {
+ return android::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ // Build the request
+ String8 requestJson = generateRequest(keyIds);
+ licenseRequest->clear();
+ licenseRequest->appendArray(
+ reinterpret_cast<const uint8_t*>(requestJson.string()),
+ requestJson.size());
+ return android::OK;
+}
+
+android::status_t InitDataParser::parsePssh(const Vector<uint8_t>& initData,
+ Vector<const uint8_t*>* keyIds) {
+ size_t readPosition = 0;
+
+ // Validate size field
+ uint32_t expectedSize = initData.size();
+ expectedSize = htonl(expectedSize);
+ if (memcmp(&initData[readPosition], &expectedSize,
+ sizeof(expectedSize)) != 0) {
+ return android::ERROR_DRM_CANNOT_HANDLE;
+ }
+ readPosition += sizeof(expectedSize);
+
+ // Validate PSSH box identifier
+ const char psshIdentifier[4] = {'p', 's', 's', 'h'};
+ if (memcmp(&initData[readPosition], psshIdentifier,
+ sizeof(psshIdentifier)) != 0) {
+ return android::ERROR_DRM_CANNOT_HANDLE;
+ }
+ readPosition += sizeof(psshIdentifier);
+
+ // Validate EME version number
+ const uint8_t psshVersion1[4] = {1, 0, 0, 0};
+ if (memcmp(&initData[readPosition], psshVersion1,
+ sizeof(psshVersion1)) != 0) {
+ return android::ERROR_DRM_CANNOT_HANDLE;
+ }
+ readPosition += sizeof(psshVersion1);
+
+ // Validate system ID
+ if (!isClearKeyUUID(&initData[readPosition])) {
+ return android::ERROR_DRM_CANNOT_HANDLE;
+ }
+ readPosition += kSystemIdSize;
+
+ // Read key ID count
+ uint32_t keyIdCount;
+ memcpy(&keyIdCount, &initData[readPosition], sizeof(keyIdCount));
+ keyIdCount = ntohl(keyIdCount);
+ readPosition += sizeof(keyIdCount);
+ if (readPosition + (keyIdCount * kKeyIdSize) !=
+ initData.size() - sizeof(uint32_t)) {
+ return android::ERROR_DRM_CANNOT_HANDLE;
+ }
+
+ // Calculate the key ID offsets
+ for (uint32_t i = 0; i < keyIdCount; ++i) {
+ size_t keyIdPosition = readPosition + (i * kKeyIdSize);
+ keyIds->push(&initData[keyIdPosition]);
+ }
+ return android::OK;
+}
+
+String8 InitDataParser::generateRequest(const Vector<const uint8_t*>& keyIds) {
+ const String8 kRequestPrefix("{\"kids\":[");
+ const String8 kRequestSuffix("],\"type\":\"temporary\"}");
+ const String8 kBase64Padding("=");
+
+ String8 request(kRequestPrefix);
+ AString encodedId;
+ for (size_t i = 0; i < keyIds.size(); ++i) {
+ encodedId.clear();
+ android::encodeBase64(keyIds[i], kKeyIdSize, &encodedId);
+ if (i != 0) {
+ request.append(",");
+ }
+ request.appendFormat("\"%s\"", encodedId.c_str());
+ }
+ request.append(kRequestSuffix);
+
+ // Android's Base64 encoder produces padding. EME forbids padding.
+ request.removeAll(kBase64Padding);
+ return request;
+}
+
+} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.h b/drm/mediadrm/plugins/clearkey/InitDataParser.h
new file mode 100644
index 0000000..9505d2a
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/InitDataParser.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef CLEARKEY_INIT_DATA_PARSER_H_
+#define CLEARKEY_INIT_DATA_PARSER_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace clearkeydrm {
+
+class InitDataParser {
+public:
+ InitDataParser() {}
+
+ android::status_t parse(const android::Vector<uint8_t>& initData,
+ const android::String8& initDataType,
+ android::Vector<uint8_t>* licenseRequest);
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(InitDataParser);
+
+ android::status_t parsePssh(const android::Vector<uint8_t>& initData,
+ android::Vector<const uint8_t*>* keyIds);
+
+ android::String8 generateRequest(
+ const android::Vector<const uint8_t*>& keyIds);
+};
+
+} // namespace clearkeydrm
+
+#endif // CLEARKEY_INIT_DATA_PARSER_H_