Fix ClearKey Drm base64 en/decoding to use base64url.

ClearKey's base64  en/decoding should use '-' and '_'
instead of '+' and '/' (web safe coding). Add support
for base64url coding in libstagefright foundation library
and update ClearKey plugins.

Test: CTS - ClearSystemTests
  ANDROID_BUILD_droid-cts/tools/cts-tradefed run cts -m
  CtsMediaTestCases --test android.media.cts.ClearKeySystemTest

Test: CTS - NativeClearSystemTests
  ANDROID_BUILD_droid-cts/tools/cts-tradefed run cts -m
  CtsMediaTestCases --test android.media.cts.NativeClearKeySystemTest

Test: libstagefright/foundation/tests/Base64_test
  adb shell /data/nativetest64/sf_foundation_test/sf_foundation_test

Test: ClearKeyDrmUnitTest
  adb shell LD_LIBRARY_PATH="/vendor/lib/mediadrm"
  /data/nativetest/ClearKeyDrmUnitTest/ClearKeyDrmUnitTest

Test: Vts
  vts-tradefed run commandAndExit vts -m VtsHalDrmV1_0Target
  --primary-abi-only -l VERBOSE

bug: 64388098
Change-Id: Ic08515fd491f15e088600c64603149401c117f4a
gugelfrei
Edwin Wong 7 years ago
parent faf18c58ba
commit 999782fa3f

@ -136,7 +136,7 @@ String8 InitDataParser::generateRequest(const Vector<const uint8_t*>& keyIds) {
AString encodedId;
for (size_t i = 0; i < keyIds.size(); ++i) {
encodedId.clear();
android::encodeBase64(keyIds[i], kKeyIdSize, &encodedId);
android::encodeBase64Url(keyIds[i], kKeyIdSize, &encodedId);
if (i != 0) {
request.append(",");
}

@ -59,7 +59,7 @@ class InitDataParserTest : public ::testing::Test {
(size_t)requestString.find(kRequestSuffix));
for (size_t i = 0; i < expectedKeys.size(); ++i) {
AString encodedIdAString;
android::encodeBase64(expectedKeys[i], kKeyIdSize,
android::encodeBase64Url(expectedKeys[i], kKeyIdSize,
&encodedIdAString);
String8 encodedId(encodedIdAString.c_str());
encodedId.removeAll(kBase64Padding);
@ -231,5 +231,4 @@ TEST_F(InitDataParserTest, FailsForPsshBadKeyCount) {
attemptParseExpectingFailure(initData, kCencMimeType);
}
} // namespace clearkeydrm

@ -284,14 +284,14 @@ TEST_F(JsonWebKeyTest, ExtractKeys) {
"\"keys\":"
"[{"
"\"kid\":\"Y2xlYXJrZXlrZXlpZDAx\""
"\"k\":\"SGVsbG8gRnJpZW5kISE\""
"\"k\":\"SGVsbG8gRnJpZW5kICE-Pw\""
"\"kty\":\"oct\""
"\"alg\":\"A128KW1\""
"}"
"{"
"\"kty\":\"oct\""
"\"alg\":\"A128KW2\""
"\"k\":\"SGVsbG8gRnJpZW5kIQ\""
"\"k\":\"SGVsbG8gRnJpZW5kICE_\""
"\"kid\":\"Y2xlYXJrZXlrZXlpZDAy\""
"}"
"{"
@ -303,7 +303,7 @@ TEST_F(JsonWebKeyTest, ExtractKeys) {
"{"
"\"alg\":\"A128KW3\""
"\"kid\":\"Y2xlYXJrZXlrZXlpZDAz\""
"\"k\":\"R29vZCBkYXkh\""
"\"k\":\"SGVsbG8gPz4-IEZyaWVuZCA_Pg\""
"\"kty\":\"oct\""
"}]"
"}");
@ -313,8 +313,8 @@ TEST_F(JsonWebKeyTest, ExtractKeys) {
EXPECT_TRUE(keys.size() == 3);
const String8 clearKeys[] =
{ String8("Hello Friend!!"), String8("Hello Friend!"),
String8("Good day!") };
{ String8("Hello Friend !>?"), String8("Hello Friend !?"),
String8("Hello ?>> Friend ?>") };
verifyKeys(keys, clearKeys);
}

@ -23,6 +23,7 @@ namespace android {
sp<ABuffer> decodeBase64(const AString &s) {
size_t n = s.size();
if ((n % 4) != 0) {
return NULL;
}
@ -45,7 +46,6 @@ sp<ABuffer> decodeBase64(const AString &s) {
size_t outLen = (n / 4) * 3 - padding;
sp<ABuffer> buffer = new ABuffer(outLen);
uint8_t *out = buffer->data();
if (out == NULL || buffer->size() < outLen) {
return NULL;
@ -61,9 +61,9 @@ sp<ABuffer> decodeBase64(const AString &s) {
value = 26 + c - 'a';
} else if (c >= '0' && c <= '9') {
value = 52 + c - '0';
} else if (c == '+') {
} else if (c == '+' || c == '-') {
value = 62;
} else if (c == '/') {
} else if (c == '/' || c == '_') {
value = 63;
} else if (c != '=') {
return NULL;
@ -144,4 +144,26 @@ void encodeBase64(
}
}
void encodeBase64Url(
const void *_data, size_t size, AString *out) {
encodeBase64(_data, size, out);
if ((-1 != out->find("+")) || (-1 != out->find("/"))) {
size_t outLen = out->size();
char *base64url = new char[outLen];
for (size_t i = 0; i < outLen; ++i) {
if (out->c_str()[i] == '+')
base64url[i] = '-';
else if (out->c_str()[i] == '/')
base64url[i] = '_';
else
base64url[i] = out->c_str()[i];
}
out->setTo(base64url, outLen);
delete[] base64url;
}
}
} // namespace android

@ -28,6 +28,8 @@ struct AString;
sp<ABuffer> decodeBase64(const AString &s);
void encodeBase64(const void *data, size_t size, AString *out);
void encodeBase64Url(const void *data, size_t size, AString *out);
} // namespace android
#endif // BASE_64_H_

@ -9,11 +9,13 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
AData_test.cpp \
Base64_test.cpp \
Flagged_test.cpp \
TypeTraits_test.cpp \
Utils_test.cpp \
LOCAL_SHARED_LIBRARIES := \
liblog \
libstagefright_foundation \
libutils \

@ -0,0 +1,155 @@
/*
* 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.
*/
#include <utils/Log.h>
#include "gtest/gtest.h"
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/foundation/AStringUtils.h>
#include <media/stagefright/foundation/base64.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
namespace {
const android::String8 kBase64Padding("=");
};
namespace android {
class Base64Test : public ::testing::Test {
};
void verifyDecode(const AString* expected, const AString* in) {
size_t numTests = 0;
while (!expected[numTests].empty())
++numTests;
for (size_t i = 0; i < numTests; ++i) {
// Since android::decodeBase64() requires padding characters,
// add them so length of encoded text is exactly a multiple of 4.
int remainder = in[i].size() % 4;
String8 paddedText(in[i].c_str());
if (remainder > 0) {
for (int i = 0; i < 4 - remainder; ++i) {
paddedText.append(kBase64Padding);
}
}
sp<ABuffer> result = decodeBase64(AString(paddedText.string()));
ASSERT_EQ(AStringUtils::Compare(expected[i].c_str(),
reinterpret_cast<char*>(result->data()),
expected[i].size(), false), 0);
}
}
void verifyEncode(const AString* expected, const AString* in) {
size_t numTests = 0;
while (!expected[numTests].empty())
++numTests;
AString out = AString("");
for (size_t i = 0; i < numTests; ++i) {
encodeBase64Url(in[i].c_str(), in[i].size(), &out);
ASSERT_EQ(AStringUtils::Compare(expected[i].c_str(), out.c_str(),
expected[i].size(), false), 0);
}
}
TEST_F(Base64Test, TestDecodeBase64) {
const AString base64[] = {
AString("SGVsbG8gRnJpZW5kIQ"),
AString("R29vZCBkYXkh"),
AString("") // string to signal end of array
};
const AString clearText[] = {
AString("Hello Friend!"),
AString("Good day!"),
AString("")
};
verifyDecode(clearText, base64);
}
TEST_F(Base64Test, TestDecodeBase64Url) {
const AString base64Url[] = {
AString("SGVsbG8gRnJpZW5kICE-Pw"),
AString("SGVsbG8gRnJpZW5kICE_"),
AString("SGVsbG8gPz4-IEZyaWVuZCA_Pg"),
AString("")
};
const AString clearText[] = {
AString("Hello Friend !>?"),
AString("Hello Friend !?"),
AString("Hello ?>> Friend ?>"),
AString("")
};
verifyDecode(clearText, base64Url);
}
TEST_F(Base64Test, TestDecodeMalformedBase64) {
const AString base64Url[] = {
AString("1?GawgguFyGrWKav7AX4VKUg"), // fail on parsing
AString("GawgguFyGrWKav7AX4V???"), // fail on length not multiple of 4
AString("GawgguFyGrWKav7AX4VKUg"), // ditto
};
for (size_t i = 0; i < 3; ++i) {
sp<ABuffer> result = decodeBase64(AString(base64Url[i]));
EXPECT_TRUE(result == nullptr);
}
}
TEST_F(Base64Test, TestEncodeBase64) {
const AString clearText[] = {
AString("Hello Friend!"),
AString("Good day!"),
AString("")
};
const AString base64[] = {
AString("SGVsbG8gRnJpZW5kIQ=="),
AString("R29vZCBkYXkh"),
AString("")
};
verifyEncode(base64, clearText);
}
TEST_F(Base64Test, TestEncodeBase64Url) {
const AString clearText[] = {
AString("Hello Friend !>?"),
AString("Hello Friend !?"),
AString("Hello ?>> Friend ?>"),
AString("")
};
const AString base64Url[] = {
AString("SGVsbG8gRnJpZW5kICE-Pw=="),
AString("SGVsbG8gRnJpZW5kICE_"),
AString("SGVsbG8gPz4-IEZyaWVuZCA_Pg"),
AString("")
};
verifyEncode(base64Url, clearText);
}
} // namespace android
Loading…
Cancel
Save