* The Usage APIs return usage reports from either L1 or L3 (if available). * Correction to when usage reports are saved. In addition to other events they are now saved when keys are loaded, usage reports are released and soon after first decryption and periodically (60 seconds) after that, if decryption takes place. * Usage reports now get deleted on an unprovision request. * Policy timer is now started when offline licenses are restored. * Usage session is now released, when a usage response is received. * Usage tests ahev been enabled. * Added CDM extended duration (integration) tests to test usage reporting and querying. These need to be run manually as they take a while (currently half an hour). b/15592374 [ Merge of https://widevine-internal-review.googlesource.com/#/c/10800 from the Widevine CDM repo ] Change-Id: Ia817e03ebbe880e08ba7b4a235ecb82b3ff35fbf
206 lines
5.9 KiB
C++
206 lines
5.9 KiB
C++
// Copyright 2013 Google Inc. All Rights Reserved.
|
|
|
|
#include "string_conversions.h"
|
|
|
|
#include <arpa/inet.h>
|
|
#include <ctype.h>
|
|
#include <iostream>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <vector>
|
|
|
|
#include "log.h"
|
|
#include "modp_b64w.h"
|
|
|
|
namespace wvcdm {
|
|
|
|
static bool CharToDigit(char ch, unsigned char* digit) {
|
|
if (ch >= '0' && ch <= '9') {
|
|
*digit = ch - '0';
|
|
} else {
|
|
ch = tolower(ch);
|
|
if ((ch >= 'a') && (ch <= 'f')) {
|
|
*digit = ch - 'a' + 10;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// converts an ascii hex string(2 bytes per digit) into a decimal byte string
|
|
std::vector<uint8_t> a2b_hex(const std::string& byte) {
|
|
std::vector<uint8_t> array;
|
|
unsigned int count = byte.size();
|
|
if (count == 0 || (count % 2) != 0) {
|
|
LOGE("Invalid input size %u for string %s", count, byte.c_str());
|
|
return array;
|
|
}
|
|
|
|
for (unsigned int i = 0; i < count / 2; ++i) {
|
|
unsigned char msb = 0; // most significant 4 bits
|
|
unsigned char lsb = 0; // least significant 4 bits
|
|
if (!CharToDigit(byte[i * 2], &msb) ||
|
|
!CharToDigit(byte[i * 2 + 1], &lsb)) {
|
|
LOGE("Invalid hex value %c%c at index %d", byte[i*2], byte[i*2+1], i);
|
|
return array;
|
|
}
|
|
array.push_back((msb << 4) | lsb);
|
|
}
|
|
return array;
|
|
}
|
|
|
|
// converts an ascii hex string(2 bytes per digit) into a decimal byte string
|
|
// dump the string with the label.
|
|
std::vector<uint8_t> a2b_hex(const std::string& label, const std::string& byte) {
|
|
|
|
std::cout << std::endl << "[[DUMP: " << label << " ]= \"" << byte << "\"]"
|
|
<< std::endl << std::endl;
|
|
|
|
return a2b_hex(byte);
|
|
}
|
|
|
|
std::string a2bs_hex(const std::string& byte) {
|
|
std::vector<uint8_t> array = a2b_hex(byte);
|
|
return std::string(array.begin(), array.end());
|
|
}
|
|
|
|
std::string b2a_hex(const std::vector<uint8_t>& byte) {
|
|
return HexEncode(&byte[0], byte.size());
|
|
}
|
|
|
|
std::string b2a_hex(const std::string& byte) {
|
|
return HexEncode(reinterpret_cast<const uint8_t *>(byte.data()),
|
|
byte.length());
|
|
}
|
|
|
|
// Filename-friendly base64 encoding (RFC4648), commonly referred to
|
|
// as Base64WebSafeEncode.
|
|
//
|
|
// This is the encoding required to interface with the provisioning server, as
|
|
// well as for certain license server transactions. It is also used for logging
|
|
// certain strings. The difference between web safe encoding vs regular encoding
|
|
// is that the web safe version replaces '+' with '-' and '/' with '_'.
|
|
std::string Base64SafeEncode(const std::vector<uint8_t>& bin_input) {
|
|
if (bin_input.empty()) {
|
|
return std::string();
|
|
}
|
|
|
|
int in_size = bin_input.size();
|
|
std::string b64_output(modp_b64w_encode_len(in_size), 0);
|
|
|
|
int out_size = modp_b64w_encode(&b64_output[0],
|
|
reinterpret_cast<const char*>(&bin_input[0]),
|
|
in_size);
|
|
if (out_size == -1) {
|
|
LOGE("Base64SafeEncode failed");
|
|
return std::string();
|
|
}
|
|
|
|
b64_output.resize(out_size);
|
|
return b64_output;
|
|
}
|
|
|
|
std::string Base64SafeEncodeNoPad(const std::vector<uint8_t>& bin_input) {
|
|
std::string b64_output = Base64SafeEncode(bin_input);
|
|
// Output size: ceiling [ bin_input.size() * 4 / 3 ].
|
|
b64_output.resize((bin_input.size() * 4 + 2) / 3);
|
|
return b64_output;
|
|
}
|
|
|
|
// Decode for Filename-friendly base64 encoding (RFC4648), commonly referred
|
|
// as Base64WebSafeDecode.
|
|
std::vector<uint8_t> Base64SafeDecode(const std::string& b64_input) {
|
|
if (b64_input.empty()) {
|
|
return std::vector<uint8_t>();
|
|
}
|
|
|
|
int in_size = b64_input.size();
|
|
std::vector<uint8_t> bin_output(modp_b64w_decode_len(in_size), 0);
|
|
int out_size = modp_b64w_decode(reinterpret_cast<char*>(&bin_output[0]),
|
|
b64_input.data(),
|
|
in_size);
|
|
if (out_size == -1) {
|
|
LOGE("Base64SafeDecode failed");
|
|
return std::vector<uint8_t>(0);
|
|
}
|
|
|
|
bin_output.resize(out_size);
|
|
return bin_output;
|
|
}
|
|
|
|
std::string HexEncode(const uint8_t* in_buffer, unsigned int size) {
|
|
static const char kHexChars[] = "0123456789ABCDEF";
|
|
|
|
// Each input byte creates two output hex characters.
|
|
std::string out_buffer(size * 2, '\0');
|
|
|
|
for (unsigned int i = 0; i < size; ++i) {
|
|
char byte = in_buffer[i];
|
|
out_buffer[(i << 1)] = kHexChars[(byte >> 4) & 0xf];
|
|
out_buffer[(i << 1) + 1] = kHexChars[byte & 0xf];
|
|
}
|
|
return out_buffer;
|
|
}
|
|
|
|
std::string IntToString(int value) {
|
|
// log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
|
|
// So round up to allocate 3 output characters per byte, plus 1 for '-'.
|
|
const int kOutputBufSize = 3 * sizeof(int) + 1;
|
|
char buffer[kOutputBufSize];
|
|
memset(buffer, 0, kOutputBufSize);
|
|
snprintf(buffer, kOutputBufSize, "%d", value);
|
|
|
|
std::string out_string(buffer);
|
|
return out_string;
|
|
}
|
|
|
|
std::string UintToString(unsigned int value) {
|
|
// log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
|
|
// So round up to allocate 3 output characters per byte.
|
|
const int kOutputBufSize = 3 * sizeof(unsigned int);
|
|
char buffer[kOutputBufSize];
|
|
memset(buffer, 0, kOutputBufSize);
|
|
snprintf(buffer, kOutputBufSize, "%u", value);
|
|
|
|
std::string out_string(buffer);
|
|
return out_string;
|
|
}
|
|
|
|
int64_t htonll64(int64_t x) { // Convert to big endian (network-byte-order)
|
|
union {
|
|
uint32_t array[2];
|
|
int64_t number;
|
|
} mixed;
|
|
mixed.number = 1;
|
|
if (mixed.array[0] == 1) { // Little Endian.
|
|
mixed.number = x;
|
|
uint32_t temp = mixed.array[0];
|
|
mixed.array[0] = htonl(mixed.array[1]);
|
|
mixed.array[1] = htonl(temp);
|
|
return mixed.number;
|
|
} else { // Big Endian.
|
|
return x;
|
|
}
|
|
}
|
|
|
|
int64_t ntohll64(int64_t x) { // Convert from big endian (network-byte-order)
|
|
union {
|
|
uint32_t array[2];
|
|
int64_t number;
|
|
} mixed;
|
|
mixed.number = 1;
|
|
if (mixed.array[0] == 1) { // Little Endian.
|
|
mixed.number = x;
|
|
uint32_t temp = mixed.array[0];
|
|
mixed.array[0] = ntohl(mixed.array[1]);
|
|
mixed.array[1] = ntohl(temp);
|
|
return mixed.number;
|
|
} else { // Big Endian.
|
|
return x;
|
|
}
|
|
}
|
|
|
|
}; // namespace wvcdm
|