April 16, 2024, 10:56:35 AM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


128 bit wave encryption

Started by sapero, September 30, 2008, 07:13:55 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

sapero

September 30, 2008, 07:13:55 AM Last Edit: September 30, 2008, 05:57:36 PM by sapero
This is a little crypto application for wave files. It uses a GUID seed to encrypt/decrypt the PCM samples. The encryption is reversible because there is used an XOR, seeded by 128 bit linear shift register.
Even when a cracker finds the encryption key, he will need to know that there is used an linear shift register, lower bits are used for crypting, and the register rotates to 'left', without any bit-swapping or other modifications. All this gives more than 128 bits.

Compile and run. It will first copy chord.wav from windows media directory do temporary directory, and use the copy for crypting, every time you run this program.

#include "windows.inc"
#include "stdio.inc"


class LFSR128
{
// 128 bit linear feedback shift register
// Feedback bits: 127, 126, 125, 120

// initialize the register
declare Seed(wstring *pszGuid);
// shift the register by one bit
declare Clock(),BOOL;
// shift the register by 8 bits
declare Clock8(),UCHAR;
// shift the register by 16 bits
declare Clock16(),USHORT;
// shift the register by 32 bits
declare Clock32(),ULONG;

DWORD m_bufer[4]; // prohibited state: 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF
}


sub main()
{
dstring szSoundPath[MAX_PATH];

// pick a wave file from windows media directory
// copy it to temporary directory if not already copied
BOOL fCopied;
if (CreateSound(szSoundPath, "chord.wav", &fCopied))
{
sndPlaySound(szSoundPath, SND_SYNC);
Encode(szSoundPath, L"{76BFEBD2-94A7-4F21-911D-9CE3FBD796A0}");

if (fCopied) // first run
{
MessageBox(0, "Click OK to play encoded wave", "");
sndPlaySound(NULL, 0);
sndPlaySound(szSoundPath, SND_SYNC);

MessageBox(0, "Click OK to decode and play again", "");
Encode(szSoundPath, L"{76BFEBD2-94A7-4F21-911D-9CE3FBD796A0}");
sndPlaySound(NULL, 0);
sndPlaySound(szSoundPath, SND_SYNC);
}
}
}


// if you need to create a GUID...
sub CreateGuid()
{
GUID g;
wstring szGuid;

CoCreateGuid(&g);
StringFromCLSID2(&g, szGuid, 256);

print(w2s(szGuid));
}


// copy %WINDIR%\media\chord.wav to %TEMP%\chord.wav
// and return the destination path
sub CreateSound(string szSoundPath, string szWaveName, BOOL *pCopied),BOOL
{
dstring szWinDir[MAX_PATH];

*pCopied = false;
GetWindowsDirectory(szWinDir, MAX_PATH);
GetTempPath(MAX_PATH, szSoundPath);

sprintf(szWinDir, "%s\\media\\%s", szWinDir, szWaveName);
strcat(szSoundPath, szWaveName);

if (GetFileAttributes(szSoundPath) == INVALID_FILE_ATTRIBUTES)
{
if (GetFileAttributes(szWinDir) == INVALID_FILE_ATTRIBUTES)
{
MessageBox(0, "Failed to open " + szWinDir, "Error", MB_ICONSTOP);
return false;
}

if (!CopyFile(szWinDir, szSoundPath, false))
{
MessageBox(0, "Failed to open " + szWinDir + "\nto " + szSoundPath, "Error", MB_ICONSTOP);
return false;
}
*pCopied = true;
}
return true;
}


// encode and decode wave data with 128 bit linear feedback shift register
// do not use {FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF} because this is
// prohibited register state
sub Encode(string path, string *pszGuidSeed),BOOL
{
LFSR128 lfsr;
lfsr.Seed(pszGuidSeed);

// map the file in memory
HANDLE hFile = OpenFile(path, MODE_READ | MODE_WRITE);
if (hFile)
{
DWORD sizeHI, sizeLO = GetFileSize(hFile, &sizeHI);

HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, sizeLO, NULL);
if (hMapping != INVALID_HANDLE_VALUE)
{
void *wave = MapViewOfFile(hMapping, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0);
if (wave)
{
void *pDataChunk = GetWaveDataChunk(wave, sizeLO);
if (pDataChunk)
{
int bytesleft = wave + sizeLO - pDataChunk;

// align pDataChunk to DWORD
while ((pDataChunk & 3) && bytesleft)
{
*(UCHAR)pDataChunk = lfsr.Clock8() xor *(UCHAR)pDataChunk;
bytesleft--;
pDataChunk++;
}
// encode all DWORDs
while (bytesleft > 3)
{
*(ULONG)pDataChunk = lfsr.Clock32() xor *(ULONG)pDataChunk;
bytesleft -= 4;
pDataChunk += 4;
}
// and data left
while (bytesleft > 0)
{
*(UCHAR)pDataChunk = lfsr.Clock8() xor *(UCHAR)pDataChunk;
bytesleft--;
pDataChunk++;
}
}
UnmapViewOfFile(wave);
}
CloseHandle(hMapping);
}
CloseHandle(hFile);
}
}



struct RIFFCHUNK
{
dstring name[4];
int     size;    // sizeof(data)
byte    data[0];
}

// this will return the address of PCM samples,
// or NULL if something is not valid
sub GetWaveDataChunk(RIFFCHUNK *pChunk, int bytesleft),void*
{
void *pDataChunk = NULL;

if ((bytesleft > 45) && !memcmp(pChunk->name, "RIFF", 4))
{
// get size of data inside RIFF
bytesleft = __min(bytesleft, pChunk->size);

BOOL isWave    = false; // pChunk "WAVE" present
BOOL hasFormat = false; // pChunk "fmt " present

// skip the first RIFF chunk
pChunk += sizeof(RIFFCHUNK);
// bytesleft is already updated

// loop until data chunk is found
while (memcmp(pChunk->name, "data", 4) && bytesleft)
{
if (!memcmp(pChunk->name, "WAVE", 4)) // pChunk has only 4 bytes
{
isWave     = true;
pChunk    += 4;
bytesleft -= 4;
}
else
{
int chunklen = pChunk->size + sizeof(RIFFCHUNK);

if (!memcmp(pChunk->name, "fmt ", 4) && isWave)
{
hasFormat = true;
}

bytesleft -= chunklen;
pChunk    += chunklen;
}
}
if ((bytesleft > sizeof(RIFFCHUNK)) && isWave && hasFormat
&& !memcmp(pChunk->name, "data", 4))
{
pDataChunk = pChunk + sizeof(RIFFCHUNK);
}
}

return pDataChunk;
}





LFSR128::Seed(wstring *pszGuid)
{
CLSIDFromString(pszGuid, &m_bufer);
}


LFSR128::Clock(),BOOL
{
__lfsr_128(&m_bufer);
return m_bufer[0] & 1;
}


LFSR128::Clock8(),UCHAR
{
// do 8 loops
for (int a=0; a<8; a++)
{
__lfsr_128(&m_bufer);
}
return m_bufer[0] & 0xFF;
}


LFSR128::Clock16(),USHORT
{
// do 16 loops
for (int a=0; a<16; a++)
{
__lfsr_128(&m_bufer);
}
return m_bufer[0] & 0xFFFF;
}


LFSR128::Clock32(),ULONG
{
// do 32 loops
for (int a=0; a<32; a++)
{
__lfsr_128(&m_bufer);
}
return m_bufer[0];
}


// this function does the actual shifting and xor'ing.
// returns the
sub __lfsr_128(byte *m_bufer),int
{
#asm
mov esi,[ebp+8] ; m_bufer
mov al,[esi+15] ; m_bufer[15]

; keep only bits for XOR
and al,11100001b
; now the parity flag is set if AL contains an even number of 1 bits
; this also gives us XNOR result of masked bits

; shift parity flag (PF; EFLAGS.2) to carry flag (CF; EFLAGS.0)
pushf
shr byte[esp],2
xor eax,eax
popf
; CY = XNOR

; shift the 128 bits
rcl dword [esi   ],1
rcl dword [esi+ 4],1
rcl dword [esi+ 8],1
rcl dword [esi+12],1
#endasm
}


EDIT: Fixed bug in CreateGuid function. Added GUI version in attachment.