You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
5.3 KiB
153 lines
5.3 KiB
#include "drmkPCH.h"
|
|
#include "CryptoHelpers.h"
|
|
#include "KList.h"
|
|
#include "../DRMKMain/StreamMgr.h"
|
|
#include "AudioDescrambler.h"
|
|
//------------------------------------------------------------------------------
|
|
// When doing noise addition, we only decryptt the low bits. These constants define
|
|
// the number of bits encrypted.
|
|
// If you change this, change the contants in DRMKMain, too.
|
|
WORD mask16=(WORD) 0x3FFF;
|
|
char mask8=(char) 0x7F;
|
|
//------------------------------------------------------------------------------
|
|
DRM_STATUS DescrambleBlock(WAVEFORMATEX* Wfx, DWORD StreamId,
|
|
BYTE* Dest, DWORD DestSize, DWORD* DestUsed,
|
|
BYTE* Src, DWORD SrcSize, DWORD* SrcUsed,
|
|
BOOL InitKey, STREAMKEY* streamKey,
|
|
DWORD FrameSize){
|
|
if(StreamId==0){
|
|
// StreamId==0 is a dummy debugging stream that is unencrypted
|
|
DWORD NumBytes=min(SrcSize, DestSize);
|
|
memcpy(Dest, Src, NumBytes);
|
|
*SrcUsed=NumBytes;
|
|
*DestUsed=NumBytes;
|
|
return DRM_OK;
|
|
};
|
|
|
|
*SrcUsed=0;
|
|
*DestUsed=0;
|
|
DWORD blockLen=min(SrcSize, DestSize);
|
|
blockLen=blockLen/FrameSize*FrameSize;
|
|
if(blockLen==0){
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("Not enough data"));
|
|
return DRM_DATALENGTH;
|
|
};
|
|
static bool firstTime=true;
|
|
if(firstTime){
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("Descramble: streamId=%d, isPCM=%d, (bits=%d, mono=%d), FrameSize=%d\n",
|
|
StreamId, Wfx->wFormatTag, (int) Wfx->wBitsPerSample, (int) Wfx->nChannels, FrameSize));
|
|
firstTime=false;
|
|
};
|
|
|
|
if(InitKey){
|
|
if(TheStreamMgr!=NULL){
|
|
STREAMKEY* theStreamKey;
|
|
DRM_STATUS stat=TheStreamMgr->getKey(StreamId, theStreamKey);
|
|
// note, we keep a local copy. If you call an encryption fucntion on this
|
|
// key, state in streamManager will NOT be updated.
|
|
if(stat!=KRM_OK){
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("Can't get key for stream: %x", StreamId));
|
|
return stat;
|
|
};
|
|
*streamKey= *theStreamKey;
|
|
} else {
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("TheStreamMgr not initted"));
|
|
return KRM_SYSERR;
|
|
};
|
|
};
|
|
|
|
DWORD bitsPerSample=Wfx->wBitsPerSample;
|
|
DWORD numChannels=Wfx->nChannels;
|
|
bool isPcm=(Wfx->wFormatTag==WAVE_FORMAT_PCM);
|
|
|
|
// for non-pcm, we scramble al but the msb in each byte.
|
|
DWORD effectiveBitsPerSample=bitsPerSample;
|
|
if(!isPcm)effectiveBitsPerSample=8;
|
|
|
|
// We deal with data in FrameSize lumps
|
|
DWORD numLumps=blockLen/FrameSize;
|
|
for(DWORD k=0;k<numLumps;k++){
|
|
|
|
BYTE* inData=Src+k*FrameSize;
|
|
BYTE* outData=Dest+k*FrameSize;
|
|
memcpy(outData, inData, FrameSize);
|
|
|
|
// If the frame is all zeros, pass it unscrambled (the audio system inserts
|
|
// blank frames. These will not necessarily have been scrambled. we take
|
|
// a frame of zeros as a special case and do not unscramble).
|
|
DWORD* inBuffer=reinterpret_cast<DWORD*> (inData);
|
|
DWORD numDwordsPerFrame=FrameSize/4;
|
|
bool isBlankFrame=true;
|
|
for(DWORD kk=0;kk<numDwordsPerFrame;kk++){
|
|
if(inBuffer[kk]!=0){
|
|
isBlankFrame=false;
|
|
break;
|
|
};
|
|
};
|
|
if(isBlankFrame){
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("Blank buffer"));
|
|
continue;
|
|
};
|
|
|
|
// we seed the packet sample key with some MSBs from the data stream
|
|
// (these are not encrypted). We take bits from the first 64 samples.
|
|
// We could tune this for speed/security.
|
|
int samplesForSeed=64;
|
|
__int64 seed=0;
|
|
if(effectiveBitsPerSample==8){
|
|
// grab MSBs
|
|
for(int j=0;j<samplesForSeed; j++){
|
|
BYTE c=inData[j] & ~mask8;
|
|
c >>= 7;
|
|
seed = (seed << 1) + c;
|
|
};
|
|
} else {
|
|
for(int j=0;j<samplesForSeed; j++){
|
|
WORD& w= (WORD&) *((WORD*) &inData[j*2]);
|
|
WORD m=w & ~mask16;
|
|
|
|
m >>= 14;
|
|
seed = (seed << 1) + m;
|
|
};
|
|
};
|
|
// MAC the seed using the main stream key. Generate the packet key from the mac.
|
|
// (user mode performs identical operations to generate the scrmabling key)
|
|
CBCKey macKey;
|
|
CBCState macState;
|
|
DRM_STATUS stat=CryptoHelpers::InitMac(macKey, macState, (BYTE*) streamKey, sizeof(STREAMKEY));
|
|
DRMDIGEST mac;
|
|
stat=CryptoHelpers::Mac(macKey, (BYTE*) &seed, sizeof(seed), mac);
|
|
STREAMKEY packetKey;
|
|
bv4_key_C(&packetKey, sizeof(mac),(BYTE*) &mac);
|
|
|
|
// If there has been a fatal error (usually out-of-memory somewhere)
|
|
// we do not descramble (an alternative would be to return silence).
|
|
if(TheStreamMgr->getFatalError()==DRM_OK){
|
|
// We have already copied the inBlock to the outBlock, now we can decrypt it
|
|
CryptoHelpers::Xcrypt(packetKey, outData, FrameSize);
|
|
// We know about noise addition on 8 and 16 bit PCM audio. Other
|
|
// audio formats get treated like 8 bit audio.
|
|
DWORD numSamples=FrameSize/(effectiveBitsPerSample/8);
|
|
if(effectiveBitsPerSample==16){
|
|
WORD* in=(WORD*) inData;
|
|
WORD* out=(WORD*) outData;
|
|
for(DWORD j=0;j<numSamples;j++){
|
|
out[j]=(out[j] & mask16) | (in[j] & ~mask16);
|
|
};
|
|
}
|
|
if(effectiveBitsPerSample==8){
|
|
char* in=(char*) inData;
|
|
char* out=(char*) outData;
|
|
for(DWORD j=0;j<numSamples;j++){
|
|
out[j]=(out[j] & mask8) | (in[j] & ~mask8);
|
|
};
|
|
};
|
|
};
|
|
}; // of loop over blocks
|
|
|
|
*SrcUsed=blockLen;
|
|
*DestUsed=blockLen;
|
|
|
|
return DRM_OK;
|
|
};
|
|
//------------------------------------------------------------------------------
|