//Scrambler.h #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #ifndef Scramblerh #define Scramblerh #include "Rand.h" class __declspec(novtable) CScrambler { CScrambler() {} // Private Constructor: you shouldn't create one of these. protected: static CRand& Rand() { // static member would require a .cpp file so I use a method: static CRand Rand; // it is useful to be able to use the same PRNG outside of this class return Rand; } public: // Reverses the bits in the given DWORD. static DWORD ReverseBits(DWORD Bits) { register DWORD Result=0; for(int i=0; i<32; ++i) { Result<<=1; if(Bits & 1) Result|=1; Bits>>=1; } return Result; } /* Interleaves the Bits and returns the result. ABCDEFGH IJKLMNOP QRSTUVWX YZ123456 becomes: AIQYBJRZ CKS1DLT2 EMU3FNV4 GOW5HPX6 (Bits become separated by 3 Bits) */static DWORD Interleave(DWORD Bits) { DWORD Result=0; for(int i=0; i<32; ++i) Result|=((Bits>>(((i&3)<<3)+(i>>2)))&1)<>i)&1)<<(((i&3)<<3)+(i>>2)); return Result; } // DWORD to Base32 String: static CString long2txt(DWORD num) { CString Result; char* ptr=Result.GetBufferSetLength(7); for(int shift=0; shift<7*5; shift+=5) { char c=(char)((num>>shift) & 31); *ptr++=c+(c<6 ? '4' : 'A'-6); } Result.ReleaseBuffer(7); return Result; } // Base32 Text String to DWORD conversion: static DWORD txt2long(const char* ptr) { DWORD Result=0; for(int shift=0; shift<7*5; shift+=5) { char c=*ptr++; if(!isBase32(c)) return 0; Result |= ((c<'A') ? (c-'4') : (6+(c-'A')))<'9') && (c<'A')) || (c>'Z'));} /* Scramble and Unscramble are designed to work on Base32 encoded DWORDS. The Scrambled output is string consisting of groups of four, space-separated characters. Base32 encoded DWORDs are strings of 7 characters. The algorithm will cope with strings which are multiples of 7 characters. The Scrambled output also stores two seed bytes used in the scramble. To keep the string pretty random characters are appended to make the final string entirely composed of groups of four characters. If n DWORDS are in the Base32 encoded string: The number of data characters will be (7*n)+2 The number of space characters will be ((7*n)+2-1)>>2 The number of random characters appended will be 3-((7*n)+2-1)&3 The total number of characters will be ((7*n)+2)+(3-((7*n)+2-1)&3 The number of random characters appended will be (FinalLength-2)%7 Scrambles a Base32 string */ static CString Scramble(CString S) { // Uses the parameter as a temp variable ASSERT(S.GetLength()%7==0); const char* ptr=S; int seed1=0; int seed2=0; char c; while(c=*ptr++) { seed1+=c; seed2^=c; } S+=Scrambler(S, (seed1 % 26)+'A', (seed2 % 26)+'A'); //Append the seed to the string seed1=S.GetLength()-1; for(int n=(seed1>>2); n; S.Insert(n--<<2,' '));//Group the characters in fours separated with a space character for(int i=3-(seed1 & 3); i; --i) S+=char('A' + (++Rand() % 26)); //Make sure the last group is of four characters by appending junk if necessary: return S; } // Unscramble a Base32 string static CString Unscramble(CString S) { // Uses the parameter as a temp variable char* stt=S.GetBufferSetLength(S.GetLength()); char* dst=stt; // Begin by removing all spaces and capitalising it all; Convert to upper case and swap zero for O and one for I. char c; const char* src=S; while(c=*src++) { switch(c) { case '0': c='O'; break; case '1': c='I'; break; case '2': c='Z'; break; default: c=toupper(c); break; } if(isBase32(c)) *dst++=c; } *dst=0; dst-=(dst-stt-2)%7; //Ignore appended characters // Extract the random-number seed bytes to begin the unscramble process. int Seed2=*--dst; // High-byte of seed int Seed1=*--dst; // Low-byte of seed *dst=0; // Terminate here, and we're ready to unscramble. Scrambler(S, Seed1, Seed2); ASSERT(S.GetLength()%7==0); return S; } private: // Scrambles and unscrambles a string: static CString Scrambler(CString& S, int Seed1, int Seed2) { int Seed=Seed2*(Seed1+Seed2); for(Rand().Seed(376542); Seed--; ++Rand()); char* ptr=S.GetBuffer(0); unsigned char c; while(c=*ptr) { DWORD val=(c<'A' ? c-'4' : c-'A'+6) ^ (++Rand() & 31); // Fiddle with the 5-bit number *ptr++=(char)(val<6 ? val+'4' : val+'A'-6); // Convert to Base32 } S.ReleaseBuffer(); return CString((char)Seed1)+(char)Seed2; } }; #ifdef Assert static struct CScramblerTester : Tester, CScrambler { CScramblerTester() { InterleaveTester(); } void InterleaveTester() { Assert(Interleave(0x00000001)==0x00000001); Assert(Interleave(0x80000000)==0x80000000); Assert(Interleave(0x40000000)==0x08000000); Assert(Interleave(0x20000000)==0x00800000); Assert(Interleave(0x10000000)==0x00080000); Assert(Interleave(2454358)==56821046); Assert(Deinterleave(0x00000001)==0x00000001); Assert(Deinterleave(0x80000000)==0x80000000); Assert(Deinterleave(0x40000000)==0x00800000); Assert(Deinterleave(0x20000000)==0x00008000); Assert(Deinterleave(0x10000000)==0x00000080); Assert(Deinterleave(56821046)==2454358); } } CScramblerTester; #endif // def Assert #endif // Scramblerh