Skip to content
Permalink
Browse files

Add decimal challenge option / add defaultKID in license request

  • Loading branch information...
peak3d committed Mar 16, 2018
1 parent 643a926 commit 9c5727fdbbdd466628ce5842e7948fef9349656a
Showing with 138 additions and 41 deletions.
  1. +2 −2 src/SSD_dll.h
  2. +29 −8 src/helpers.cpp
  3. +2 −0 src/helpers.h
  4. +1 −1 src/main.cpp
  5. +49 −14 wvdecrypter/wvdecrypter.cpp
  6. +55 −16 wvdecrypter/wvdecrypter_android.cpp
@@ -17,7 +17,7 @@ namespace SSD
OPTION_PROTOCOL,
OPTION_HEADER
};
static const uint32_t version = 8;
static const uint32_t version = 9;

virtual const char *GetLibraryPath() const = 0;
virtual const char *GetProfilePath() const = 0;
@@ -169,7 +169,7 @@ namespace SSD
// Return supported URN if type matches to capabilities, otherwise null
virtual const char *SelectKeySytem(const char* keySystem) = 0;
virtual bool OpenDRMSystem(const char *licenseURL, const AP4_DataBuffer &serverCertificate) = 0;
virtual AP4_CencSingleSampleDecrypter *CreateSingleSampleDecrypter(AP4_DataBuffer &pssh, const char *optionalKeyParameter) = 0;
virtual AP4_CencSingleSampleDecrypter *CreateSingleSampleDecrypter(AP4_DataBuffer &pssh, const char *optionalKeyParameter, const uint8_t *defaultkeyid) = 0;
virtual void DestroySingleSampleDecrypter(AP4_CencSingleSampleDecrypter* decrypter) = 0;

virtual void GetCapabilities(AP4_CencSingleSampleDecrypter* decrypter, const uint8_t *keyid, uint32_t media, SSD_DECRYPTER::SSD_CAPS &caps) = 0;
@@ -22,11 +22,25 @@
#include <stdlib.h>
#include "Ap4DataBuffer.h"
#include <map>
#include <sstream>

#ifndef BYTE
typedef unsigned char BYTE;
#endif

std::string ToDecimal(const uint8_t *data, size_t data_size)
{
std::stringstream ret;

if (data_size)
ret << data[0];

for (size_t i(1); i < data_size; ++i)
ret << ',' << static_cast<unsigned int>(data[i]);

return ret.str();
}

static const BYTE from_base64[] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 62, 255, 63,
@@ -325,6 +339,19 @@ void prkid2wvkid(const char *input, char *output)
output[i] = input[remap[i]];
}

uint8_t* KIDtoUUID(const uint8_t* kid, uint8_t* dst)
{
static const uint8_t hexmap[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
for (unsigned int i(0); i < 16; ++i)
{
if (i == 4 || i == 6 || i == 8 || i == 10)
*dst++ = '-';
*dst++ = hexmap[(uint8_t)(kid[i]) >> 4];
*dst++ = hexmap[(uint8_t)(kid[i]) & 15];
}
return dst;
}

bool create_ism_license(std::string key, std::string license_data, AP4_DataBuffer &init_data)
{
if (key.size() != 16 || license_data.empty())
@@ -375,17 +402,11 @@ bool create_ism_license(std::string key, std::string license_data, AP4_DataBuffe
} while (1);
if (uuid)
{
static const uint8_t hexmap[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
memcpy(protoptr, kid, uuid - kid);
protoptr += uuid - kid;

for (unsigned int i(0); i < 16; ++i)
{
if(i == 4 || i == 6 || i == 8 || i == 10)
*protoptr++ = '-';
*protoptr++ = hexmap[(uint8_t)(key.data()[i]) >> 4];
*protoptr++ = hexmap[(uint8_t)(key.data()[i]) & 15];
}
protoptr = KIDtoUUID((const uint8_t*)key.data(), protoptr);

unsigned int sizeleft = ld_size - ((uuid - kid) + 6);
memcpy(protoptr, uuid + 6, sizeleft);
protoptr += sizeleft;
@@ -27,6 +27,7 @@ class AP4_DataBuffer;

bool b64_decode(const char *in, unsigned int in_len, uint8_t *out, unsigned int &out_len);

std::string ToDecimal(const uint8_t *data, size_t data_size);
std::string b64_encode(unsigned char const* in, unsigned int in_len, bool urlEncode);

std::vector<std::string> split(const std::string& s, char seperator);
@@ -41,5 +42,6 @@ std::string avc_to_annexb(const std::string &avc);
unsigned char HexNibble(char c);

void prkid2wvkid(const char *input, char *output);
uint8_t* KIDtoUUID(const uint8_t* kid, uint8_t* dst);
bool create_ism_license(std::string key, std::string license_data, AP4_DataBuffer &init_data);
void parseheader(std::map<std::string, std::string> &headerMap, const char* headerString);
@@ -1921,7 +1921,7 @@ bool Session::initialize()
}

if (decrypter_ && init_data.GetDataSize() >= 4 && (session.single_sample_decryptor_
|| (session.single_sample_decryptor_ = decrypter_->CreateSingleSampleDecrypter(init_data, optionalKeyParameter)) != 0))
|| (session.single_sample_decryptor_ = decrypter_->CreateSingleSampleDecrypter(init_data, optionalKeyParameter, (const uint8_t *)defkid)) != 0))
{

decrypter_->GetCapabilities(
@@ -240,7 +240,7 @@ class WV_CencSingleSampleDecrypter : public AP4_CencSingleSampleDecrypter
{
public:
// methods
WV_CencSingleSampleDecrypter(WV_DRM &drm, AP4_DataBuffer &pssh);
WV_CencSingleSampleDecrypter(WV_DRM &drm, AP4_DataBuffer &pssh, const uint8_t *defaultKeyId);
virtual ~WV_CencSingleSampleDecrypter();

void GetCapabilities(const uint8_t* key, uint32_t media, SSD_DECRYPTER::SSD_CAPS &caps);
@@ -295,6 +295,7 @@ class WV_CencSingleSampleDecrypter : public AP4_CencSingleSampleDecrypter
WV_DRM &drm_;
std::string session_;
AP4_DataBuffer pssh_, challenge_;
uint8_t defaultKeyId_[16];
struct WVSKEY
{
bool operator == (WVSKEY const &other) const { return keyid == other.keyid; };
@@ -465,7 +466,7 @@ void WV_DRM::OnCDMMessage(const char* session, uint32_t session_size, CDMADPMSG
| WV_CencSingleSampleDecrypter::WV_CencSingleSampleDecrypter
+---------------------------------------------------------------------*/

WV_CencSingleSampleDecrypter::WV_CencSingleSampleDecrypter(WV_DRM &drm, AP4_DataBuffer &pssh)
WV_CencSingleSampleDecrypter::WV_CencSingleSampleDecrypter(WV_DRM &drm, AP4_DataBuffer &pssh, const uint8_t *defaultKeyId)
: AP4_CencSingleSampleDecrypter(0)
, drm_(drm)
, pssh_(pssh)
@@ -488,6 +489,11 @@ WV_CencSingleSampleDecrypter::WV_CencSingleSampleDecrypter(WV_DRM &drm, AP4_Data

drm_.insertssd(this);

if (defaultKeyId)
memcpy(defaultKeyId_, defaultKeyId, 16);
else
memset(defaultKeyId_, 0, 16);

#ifdef LOCLICENSE
std::string strDbg = host->GetProfilePath();
strDbg += "EDEF8BA9-79D6-4ACE-A3C8-27DCD51D21ED.init";
@@ -694,19 +700,28 @@ bool WV_CencSingleSampleDecrypter::SendSessionMessage()
insPos = blocks[2].find("{SSM}");
if (insPos != std::string::npos)
{
std::string::size_type sidSearchPos(insPos);
std::string::size_type sidPos(blocks[2].find("{SID}"));
std::string::size_type kidPos(blocks[2].find("{KID}"));
size_t size_written(0);

if (insPos > 0)
{
if (blocks[2][insPos - 1] == 'B' || blocks[2][insPos - 1] == 'b')
{
std::string msgEncoded = b64_encode(challenge_.GetData(), challenge_.GetDataSize(), blocks[2][insPos - 1] == 'B');
blocks[2].replace(insPos - 1, 6, msgEncoded);
sidSearchPos += msgEncoded.size();
size_written = msgEncoded.size();
}
else if (blocks[2][insPos - 1] == 'D')
{
std::string msgEncoded = ToDecimal(challenge_.GetData(), challenge_.GetDataSize());
blocks[2].replace(insPos - 1, 6, msgEncoded);
size_written = msgEncoded.size();
}
else
{
blocks[2].replace(insPos - 1, 6, reinterpret_cast<const char*>(challenge_.GetData()), challenge_.GetDataSize());
sidSearchPos += challenge_.GetDataSize();
size_written = challenge_.GetDataSize();
}
}
else
@@ -715,25 +730,45 @@ bool WV_CencSingleSampleDecrypter::SendSessionMessage()
goto SSMFAIL;
}

insPos = blocks[2].find("{SID}", sidSearchPos);
if (insPos != std::string::npos)
if (sidPos != std::string::npos && insPos < sidPos)
sidPos += size_written, sidPos -= 6;

if (kidPos != std::string::npos && insPos < kidPos)
kidPos += size_written, sidPos -= 6;

size_written = 0;

if (sidPos != std::string::npos)
{
if (insPos > 0)
if (sidPos > 0)
{
if (blocks[2][insPos - 1] == 'B' || blocks[2][insPos - 1] == 'b')
if (blocks[2][sidPos - 1] == 'B' || blocks[2][sidPos - 1] == 'b')
{
std::string msgEncoded = b64_encode(reinterpret_cast<const unsigned char*>(session_.data()),session_.size(), blocks[2][insPos - 1] == 'B');
blocks[2].replace(insPos - 1, 6, msgEncoded);
std::string msgEncoded = b64_encode(reinterpret_cast<const unsigned char*>(session_.data()),session_.size(), blocks[2][sidPos - 1] == 'B');
blocks[2].replace(sidPos - 1, 6, msgEncoded);
size_written = msgEncoded.size();
}
else
blocks[2].replace(insPos - 1, 6, session_.data(), session_.size());
{
blocks[2].replace(sidPos - 1, 6, session_.data(), session_.size());
size_written = session_.size();
}
}
else
{
Log(SSD_HOST::LL_ERROR, "Unsupported License request template (body / ?{SID})");
goto SSMFAIL;
}
}

if (kidPos != std::string::npos)
{
if (sidPos < kidPos)
kidPos += size_written, kidPos -= 6;
uint8_t uuid[36];
KIDtoUUID(defaultKeyId_, uuid);
blocks[2].replace(kidPos, 5, (const char*)uuid, 32);
}
}
std::string decoded = b64_encode(reinterpret_cast<const unsigned char*>(blocks[2].data()), blocks[2].size(), false);
host->CURLAddOption(file, SSD_HOST::OPTION_PROTOCOL, "postdata", decoded.c_str());
@@ -1297,9 +1332,9 @@ class WVDecrypter : public SSD_DECRYPTER
return cdmsession_->GetCdmAdapter() != nullptr;
}

virtual AP4_CencSingleSampleDecrypter *CreateSingleSampleDecrypter(AP4_DataBuffer &pssh, const char *optionalKeyParameter) override
virtual AP4_CencSingleSampleDecrypter *CreateSingleSampleDecrypter(AP4_DataBuffer &pssh, const char *optionalKeyParameter, const uint8_t *defaultkeyid) override
{
WV_CencSingleSampleDecrypter *decrypter = new WV_CencSingleSampleDecrypter(*cdmsession_, pssh);
WV_CencSingleSampleDecrypter *decrypter = new WV_CencSingleSampleDecrypter(*cdmsession_, pssh, defaultkeyid);
if (!decrypter->GetSessionId())
{
delete decrypter;
@@ -168,7 +168,7 @@ class WV_CencSingleSampleDecrypter : public AP4_CencSingleSampleDecrypter
{
public:
// methods
WV_CencSingleSampleDecrypter(WV_DRM &drm, AP4_DataBuffer &pssh, const char *optionalKeyParameter);
WV_CencSingleSampleDecrypter(WV_DRM &drm, AP4_DataBuffer &pssh, const char *optionalKeyParameter, const uint8_t* defaultKeyId);
~WV_CencSingleSampleDecrypter();

size_t CreateSession(AP4_DataBuffer &pssh);
@@ -210,6 +210,7 @@ class WV_CencSingleSampleDecrypter : public AP4_CencSingleSampleDecrypter

const uint8_t *key_request_;
size_t key_request_size_;
uint8_t defaultKeyId_[16];

struct FINFO
{
@@ -227,7 +228,7 @@ class WV_CencSingleSampleDecrypter : public AP4_CencSingleSampleDecrypter
| WV_CencSingleSampleDecrypter::WV_CencSingleSampleDecrypter
+---------------------------------------------------------------------*/

WV_CencSingleSampleDecrypter::WV_CencSingleSampleDecrypter(WV_DRM &drm, AP4_DataBuffer &pssh, const char *optionalKeyParameter)
WV_CencSingleSampleDecrypter::WV_CencSingleSampleDecrypter(WV_DRM &drm, AP4_DataBuffer &pssh, const char *optionalKeyParameter, const uint8_t* defaultKeyId)
: AP4_CencSingleSampleDecrypter(0)
, media_drm_(drm)
, key_request_(nullptr)
@@ -269,6 +270,11 @@ WV_CencSingleSampleDecrypter::WV_CencSingleSampleDecrypter(WV_DRM &drm, AP4_Data
pssh_[sizeof(atom) - 2] = static_cast<uint8_t>((pssh_.size() - sizeof(atom)) >> 8);
}

if (defaultKeyId)
memcpy(defaultKeyId_, defaultKeyId, 16);
else
memset(defaultKeyId_, 0, 16);

media_status_t status;

bool retry(false);
@@ -469,42 +475,75 @@ bool WV_CencSingleSampleDecrypter::SendSessionMessage(AMediaDrmByteArray &sessio
insPos = blocks[2].find("{SSM}");
if (insPos != std::string::npos)
{
std::string::size_type sidSearchPos(insPos);
std::string::size_type sidPos(blocks[2].find("{SID}"));
std::string::size_type kidPos(blocks[2].find("{KID}"));
size_t size_written(0);

if (insPos > 0)
{
if (blocks[2][insPos - 1] == 'B' || blocks[2][insPos - 1] == 'b')
{
std::string msgEncoded = b64_encode(key_request, key_request_size, blocks[2][insPos - 1] == 'B');
std::string msgEncoded = b64_encode(challenge_.GetData(), challenge_.GetDataSize(), blocks[2][insPos - 1] == 'B');

This comment has been minimized.

Copy link
@Rechi

Rechi Mar 17, 2018

Contributor

error: use of undeclared identifier 'challenge_'

This comment has been minimized.

Copy link
@peak3d

peak3d Mar 17, 2018

Author Owner

thx

blocks[2].replace(insPos - 1, 6, msgEncoded);
size_written = msgEncoded.size();
}
else if (blocks[2][insPos - 1] == 'D')
{
std::string msgEncoded = ToDecimal(challenge_.GetData(), challenge_.GetDataSize());
blocks[2].replace(insPos - 1, 6, msgEncoded);
size_written = msgEncoded.size();
}
else
blocks[2].replace(insPos - 1, 6, reinterpret_cast<const char*>(key_request), key_request_size);
{
blocks[2].replace(insPos - 1, 6, reinterpret_cast<const char*>(challenge_.GetData()), challenge_.GetDataSize());
size_written = challenge_.GetDataSize();
}
}
else
{
Log(SSD_HOST::LL_ERROR, "Unsupported License request template (body)");
Log(SSD_HOST::LL_ERROR, "Unsupported License request template (body / ?{SSM})");
goto SSMFAIL;
}

insPos = blocks[2].find("{SID}", sidSearchPos);
if (insPos != std::string::npos)
if (sidPos != std::string::npos && insPos < sidPos)
sidPos += size_written, sidPos -= 6;

if (kidPos != std::string::npos && insPos < kidPos)
kidPos += size_written, sidPos -= 6;

size_written = 0;

if (sidPos != std::string::npos)
{
if (insPos > 0)
if (sidPos > 0)
{
if (blocks[2][insPos - 1] == 'B' || blocks[2][insPos - 1] == 'b')
if (blocks[2][sidPos - 1] == 'B' || blocks[2][sidPos - 1] == 'b')
{
std::string msgEncoded = b64_encode(session_id.ptr, session_id.length, blocks[2][insPos - 1] == 'B');
blocks[2].replace(insPos - 1, 6, msgEncoded);
std::string msgEncoded = b64_encode(reinterpret_cast<const unsigned char*>(session_.data()), session_.size(), blocks[2][sidPos - 1] == 'B');

This comment has been minimized.

Copy link
@Rechi

Rechi Mar 17, 2018

Contributor

error: use of undeclared identifier 'session_'

This comment has been minimized.

Copy link
@peak3d

peak3d Mar 17, 2018

Author Owner

thx!

blocks[2].replace(sidPos - 1, 6, msgEncoded);
size_written = msgEncoded.size();
}
else
blocks[2].replace(insPos - 1, 6, reinterpret_cast<const char*>(session_id.ptr), session_id.length);
{
blocks[2].replace(sidPos - 1, 6, session_.data(), session_.size());
size_written = session_.size();
}
}
else
{
Log(SSD_HOST::LL_ERROR, "Unsupported License request template (body)");
Log(SSD_HOST::LL_ERROR, "Unsupported License request template (body / ?{SID})");
goto SSMFAIL;
}
}

if (kidPos != std::string::npos)
{
if (sidPos < kidPos)
kidPos += size_written, kidPos -= 6;
uint8_t uuid[36];
KIDtoUUID(defaultKeyId_, uuid);
blocks[2].replace(kidPos, 5, (const char*)uuid, 32);
}
}
std::string decoded = b64_encode(reinterpret_cast<const unsigned char*>(blocks[2].data()), blocks[2].size(), false);
host->CURLAddOption(file, SSD_HOST::OPTION_PROTOCOL, "postdata", decoded.c_str());
@@ -816,9 +855,9 @@ class WVDecrypter : public SSD_DECRYPTER
return cdmsession_->GetMediaDrm();
}

virtual AP4_CencSingleSampleDecrypter *CreateSingleSampleDecrypter(AP4_DataBuffer &pssh, const char *optionalKeyParameter) override
virtual AP4_CencSingleSampleDecrypter *CreateSingleSampleDecrypter(AP4_DataBuffer &pssh, const char *optionalKeyParameter, const uint8_t *defaultkeyid) override
{
WV_CencSingleSampleDecrypter *decrypter = new WV_CencSingleSampleDecrypter(*cdmsession_, pssh, optionalKeyParameter);
WV_CencSingleSampleDecrypter *decrypter = new WV_CencSingleSampleDecrypter(*cdmsession_, pssh, optionalKeyParameter, defaultkeyid);
if (!decrypter->GetSessionId())
{
delete decrypter;

0 comments on commit 9c5727f

Please sign in to comment.
You can’t perform that action at this time.