This source file includes following definitions.
- EncodeBase64
- DecodeBase64
- GenerateJWKSet
- ConvertJwkToKeyPair
- ExtractKeysFromJWKSet
#include "media/cdm/json_web_key.h"
#include "base/base64.h"
#include "base/json/json_reader.h"
#include "base/json/json_string_value_serializer.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_util.h"
#include "base/values.h"
namespace media {
const char kKeysTag[] = "keys";
const char kKeyTypeTag[] = "kty";
const char kSymmetricKeyValue[] = "oct";
const char kKeyTag[] = "k";
const char kKeyIdTag[] = "kid";
const char kBase64Padding = '=';
static std::string EncodeBase64(const uint8* input, int input_length) {
std::string encoded_text;
base::Base64Encode(
std::string(reinterpret_cast<const char*>(input), input_length),
&encoded_text);
size_t found = encoded_text.find_last_not_of(kBase64Padding);
if (found != std::string::npos)
encoded_text.erase(found + 1);
return encoded_text;
}
static std::string DecodeBase64(const std::string& encoded_text) {
if (encoded_text.find_first_of(kBase64Padding) != std::string::npos)
return std::string();
size_t num_last_grouping_chars = encoded_text.length() % 4;
std::string modified_text = encoded_text;
if (num_last_grouping_chars > 0)
modified_text.append(4 - num_last_grouping_chars, kBase64Padding);
std::string decoded_text;
if (!base::Base64Decode(modified_text, &decoded_text))
return std::string();
return decoded_text;
}
std::string GenerateJWKSet(const uint8* key, int key_length,
const uint8* key_id, int key_id_length) {
std::string key_base64 = EncodeBase64(key, key_length);
std::string key_id_base64 = EncodeBase64(key_id, key_id_length);
scoped_ptr<base::DictionaryValue> jwk(new base::DictionaryValue());
jwk->SetString(kKeyTypeTag, kSymmetricKeyValue);
jwk->SetString(kKeyTag, key_base64);
jwk->SetString(kKeyIdTag, key_id_base64);
scoped_ptr<base::ListValue> list(new base::ListValue());
list->Append(jwk.release());
base::DictionaryValue jwk_set;
jwk_set.Set(kKeysTag, list.release());
std::string serialized_jwk;
JSONStringValueSerializer serializer(&serialized_jwk);
serializer.Serialize(jwk_set);
return serialized_jwk;
}
static bool ConvertJwkToKeyPair(const base::DictionaryValue& jwk,
KeyIdAndKeyPair* jwk_key) {
std::string type;
if (!jwk.GetString(kKeyTypeTag, &type) || type != kSymmetricKeyValue) {
DVLOG(1) << "JWK is not a symmetric key";
return false;
}
std::string encoded_key_id;
std::string encoded_key;
if (!jwk.GetString(kKeyIdTag, &encoded_key_id)) {
DVLOG(1) << "Missing '" << kKeyIdTag << "' parameter";
return false;
}
if (!jwk.GetString(kKeyTag, &encoded_key)) {
DVLOG(1) << "Missing '" << kKeyTag << "' parameter";
return false;
}
std::string raw_key_id = DecodeBase64(encoded_key_id);
if (raw_key_id.empty()) {
DVLOG(1) << "Invalid '" << kKeyIdTag << "' value: " << encoded_key_id;
return false;
}
std::string raw_key = DecodeBase64(encoded_key);
if (raw_key.empty()) {
DVLOG(1) << "Invalid '" << kKeyTag << "' value: " << encoded_key;
return false;
}
*jwk_key = std::make_pair(raw_key_id, raw_key);
return true;
}
bool ExtractKeysFromJWKSet(const std::string& jwk_set, KeyIdAndKeyPairs* keys) {
if (!IsStringASCII(jwk_set))
return false;
scoped_ptr<base::Value> root(base::JSONReader().ReadToValue(jwk_set));
if (!root.get() || root->GetType() != base::Value::TYPE_DICTIONARY)
return false;
base::DictionaryValue* dictionary =
static_cast<base::DictionaryValue*>(root.get());
base::ListValue* list_val = NULL;
if (!dictionary->GetList(kKeysTag, &list_val)) {
DVLOG(1) << "Missing '" << kKeysTag
<< "' parameter or not a list in JWK Set";
return false;
}
KeyIdAndKeyPairs local_keys;
for (size_t i = 0; i < list_val->GetSize(); ++i) {
base::DictionaryValue* jwk = NULL;
if (!list_val->GetDictionary(i, &jwk)) {
DVLOG(1) << "Unable to access '" << kKeysTag << "'[" << i
<< "] in JWK Set";
return false;
}
KeyIdAndKeyPair key_pair;
if (!ConvertJwkToKeyPair(*jwk, &key_pair)) {
DVLOG(1) << "Error from '" << kKeysTag << "'[" << i << "]";
return false;
}
local_keys.push_back(key_pair);
}
keys->swap(local_keys);
return true;
}
}