|
Great article even today so many years after.
|
|
|
|
|
I don't think you need a strong password, how could I generate a random password each time the build process is run?
|
|
|
|
|
you could either write a script to insert a random password into the .CXR file before CXR runs, or you could modify the CXR tool itself.
if i was going to modify the CXR tool, i would have it generate a new password if the pwd in the .CXR file is "RANDOM".
so, in CXR.cpp ProcessFile(...)
csPassword = tokenizer.GetToken(3).csToken;
if (csPassword == "RANDOM")
{
csPassword = MakeRandomPassword();
}
And MakeRandomPassword would just assemble a random sequence of alpha-num characters. maybe 10 or 12 of them.
|
|
|
|
|
Great article. I have written my own version here: http://www.codeproject.com/Articles/502283/Strings-Obfuscation-System
|
|
|
|
|
I've found CXR to be quite useful, but its Windows-only MFC-dependencies are a blocker. I've removed the MFC dependencies (it now uses STL) and made it buildable cross-platform (using CMake).
This cross-platform branch of CXR is now up on Google Code here.
|
|
|
|
|
is it possible to do something like this:
void print(char* str);
print(_CXR("Encrypted"));
By this i mean to say, is it possible to encrypt the strings directly instead of adding them one by one to the .cxr file?
|
|
|
|
|
nope.
i think to do that, you'd need to do the encryption as part of the compiler's pre-processor step (when it processes all your macros and #includes), instead of as a pre-build step as CXR does. i don't if VC even allows that kind of integration.
but, see one of the comments below - the poster shows how to do a preproc encryption trick.
-- modified at 13:05 Friday 20th July, 2007
|
|
|
|
|
hi
i get some errors when i use this in the properties of the .cxr file(by right clicing on it in vs05):
cl /EP /C $(InputDir)$(InputFileName)>$(InputDir)$(InputName).i
$(InputDir)cxr.exe -i $(InputDir)$(InputName).i -o $(InputDir)$(InputName).cpp
del $(InputDir)$(InputName).i
These are the errors:
<br />
Performing Custom Build Step<br />
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86<br />
Copyright (C) Microsoft Corporation. All rights reserved.<br />
Documents<br />
and<br />
c1 : fatal error C1083: Cannot open source file: 'c:\Documents': Permission denied<br />
My<br />
c1 : fatal error C1083: Cannot open source file: 'and': No such file or directory<br />
c1 : fatal error C1083: Cannot open source file: 'Settings\-----.HOMIE\My': No such file or directory<br />
Visual<br />
Studio<br />
c1 : fatal error C1083: Cannot open source file: 'Documents\Visual': No such file or directory<br />
strings.cxr<br />
c1 : fatal error C1083: Cannot open source file: 'Studio': No such file or directory<br />
c1 : fatal error C1083: Cannot open source file: '2005\Projects\Dope\Dope\Encrypt\strings.cxr': No such file or directory<br />
and<br />
My<br />
c1 : fatal error C1083: Cannot open source file: 'and': No such file or directory<br />
Visual<br />
c1 : fatal error C1083: Cannot open source file: 'Settings\-----.HOMIE\My': No such file or directory<br />
c1 : fatal error C1083: Cannot open source file: 'Documents\Visual': No such file or directory<br />
Studio<br />
strings.i<br />
c1 : fatal error C1083: Cannot open source file: 'Studio': No such file or directory<br />
c1 : fatal error C1083: Cannot open source file: '2005\Projects\Dope\Dope\Encrypt\strings.i': No such file or directory<br />
'c:\Documents' is not recognized as an internal or external command,<br />
operable program or batch file.<br />
The system cannot find the path specified.<br />
Project : error PRJ0019: A tool returned an error code from "Performing Custom Build Step"
Could someone please help me to resolve this error?
Thanks
|
|
|
|
|
looks like you need some double quotes around $(InputDir)$(InputFileName).
|
|
|
|
|
Hi,
I like your idea, in fact I recently implemented the same thing myself in order to hide some Easter eggs in one of my tools to make it a little tougher to find.
There are however two problems I have with this implementation. First, I keep getting this error:
CPULED error PRJ0019: A tool returned an error code from "Performing Custom Build Step"
No matter what I do it won't work. (Yes, I've checked the command line arguments, yes I've changed it to $ProjectDir, and so on.) I can successfully run it from the command line but VS.NET always complains.
Second, and more importantly, it does not work for arrays, structs, and so on. It can (currently) only be used with standalone string variables like:
const char* pString1 = _CXR("Foo");
I tried to use it in an array:
const CString somestrings[]={
_CXR("Foo")
, _CXR("Bar")
, _CXR("Baz")
};
But that would not work because _CXR(Decrypt?) requires the terminating semi-colon. The resulting code does not compile.
I'm sure CXR is easy enough to make completely portable and even more useful than it is but for the time being (or until I can figure out how to get CXR working), I'll stick with mine.
Oh, and in reference to the proof of concept using the preprocessor to XOR encrypt strings, just today I was reading a text on computer security and not 10 minutes before I read that post, I read a chapter on encryption and how the old XOR against a fixed key method is just a bad idea (as mentioned in the post.)
My method is no more secure than either of these two presented here (besides, a resource-editor can still display the encrypted strings—or not! I just tried a couple with one of my encrypted apps and they did not show up in any of the strings tables. Weird! ) but obviosly for our uses they work well enough.
--
Synetech
-- modified at 11:16 Tuesday 23rd May, 2006
|
|
|
|
|
1.) In cxr_inc.h in order for CString to be declared, I added
#include "afx.h"
2.) In CXR project properties, changed /ZI to /Zi on the compiler command line (this is the same as changing "Program Database for Edit and Continue" to just "Program Database") since this setting is incompatible with having incremental linking OFF.
3.) Since the StdAfx.cpp was giving me this error: "WINVER not defined. Defaulting to 0x0501 (Windows XP and Windows .NET Server)". I looked up WINVER. Directions here say to do #define WINVER 0x0400 in StdAfx.h.
4.) Eliminated a "signed/unsigned" compiler warning in CmdLine.cpp by using static_cast on an int to change it to a "size_type". You'll know which line of code it is if you get this warning.
5.) Had to do static_cast on a bunch of stuff in CXR.cpp where an int needed to be a TCHAR.
-- modified at 16:48 Thursday 2nd March, 2006
6.) In the custom build step directions given by the author, I had to change $(ProjDir) to $(ProjectDir) (maybe this is a difference between VC6 and VC7.1).
-- modified at 17:55 Thursday 2nd March, 2006
Although the included "Test" app works, I can't get it to work in my code without some linker errors on AFX stuff. I am not trying to do MFC stuff in my code. I might have to rewrite CXR to use standard C++ <string> instead.
|
|
|
|
|
I rewrote all the source to use STL classes instead of MFC. I didn't want to use MFC, and it's not portable anyway. If anyone is interested, here is the source. I apologize in advance if the Code Project comment engine screws up any of the code as I try to post it.
CXR_standard.cpp:
<br />
<br />
#include "stdafx.h"<br />
#include <string><br />
#include <iostream><br />
#include <fstream><br />
#include <time.h><br />
#include "Tokenizer.h"<br />
#include "Stream.h"<br />
<br />
using namespace std;<br />
<br />
static bool ProcessFile(ifstream &in, const string &strInFilename, ofstream &out, const string &strOutFilename);<br />
static bool AddDecode(const string &strPassword, ofstream &out);<br />
static string Encrypt(const string &strIn, const char* pPass);<br />
static string Decrypt(const char* pIn, const char* pPass);<br />
static bool ExpandOctal(const string &strIn, string &strOut, int &iConsumed);<br />
static string TranslateString(const string &strIn);<br />
static bool ExpandHex(const string &strIn, string &strOut, int &iConsumed);<br />
static string EscapeString(const char* pIn);<br />
<br />
const int basechar1 = 128;<br />
const int basechar2 = 128;<br />
<br />
int _tmain(int argc, _TCHAR* argv[])<br />
{<br />
int nRetCode = 0;<br />
<br />
srand((unsigned int)time(NULL));<br />
<br />
cerr << _T("Starting CXR, the literal string encryptor. Copyright 2002, Smaller Animals Software Inc.") << endl;<br />
<br />
if ((basechar1 == 0) || (basechar2 == 0) || (basechar1 > 239) || (basechar2 > 239))<br />
{<br />
cerr << _T("CXR basechar values out of acceptable range. Aborting") << endl;<br />
nRetCode = 1;<br />
return nRetCode;<br />
}<br />
<br />
if (argc >= 2)<br />
{<br />
string strInFile = argv[2];<br />
string strOutFile = argv[4];<br />
<br />
if (!strInFile.empty() && !strOutFile.empty())<br />
{<br />
ifstream fileIn;<br />
<br />
ofstream fileOut;<br />
<br />
fileIn.open(strInFile.c_str(), ios::in);<br />
if(fileIn.is_open())<br />
{<br />
fileOut.open(strOutFile.c_str(), ios::trunc | ios::out);<br />
if(fileOut.is_open())<br />
{<br />
if (!ProcessFile(fileIn, strInFile, fileOut, strOutFile))<br />
{<br />
cerr << _T("CXR failed") << endl;<br />
nRetCode = 1;<br />
}<br />
}<br />
else<br />
{<br />
cerr << _T("Unable to open output file: ") << strOutFile << endl;<br />
nRetCode = 1;<br />
}<br />
}<br />
else<br />
{<br />
cerr << _T("Unable to open input file: ") << strInFile << endl;<br />
nRetCode = 1;<br />
}<br />
<br />
if (nRetCode==0)<br />
{<br />
cerr << _T("CXR created: ") << strOutFile << endl;<br />
}<br />
}<br />
else<br />
{<br />
cerr << _T("Not enough parameters.") << endl;<br />
cerr << _T("Usage: CXR -i [filename.cpp] -o [filename.cpp]") << endl;<br />
nRetCode = 1;<br />
}<br />
} <br />
else<br />
{<br />
cerr << _T("Not enough parameters.") << endl;<br />
cerr << _T("Usage: CXR -i [filename.cpp] -o [filename.cpp]") << endl;<br />
nRetCode = 1;<br />
}<br />
<br />
return nRetCode;<br />
}<br />
<br />
<br />
bool ProcessFile(ifstream &in, const string &strInFilename, ofstream &out, const string &strOutFilename)<br />
{<br />
<br />
enum {eStateWantPassword, eStateHavePassword, };<br />
<br />
int iState = eStateWantPassword;<br />
<br />
string strPassword;<br />
string strLine;<br />
<br />
char* pMetachars = "/\\=();'";<br />
char* pKeyWords[3] = {"//", "_CXR", "CXRP"};<br />
<br />
CTokenizer tokenizer(pKeyWords, 3, pMetachars, (int)strlen(pMetachars));<br />
int iErr = CTokenizer::eErrorNone;<br />
bool ok = true;<br />
<br />
out << "/////////////////////////////////////////////////////////////\n"<br />
<< "// "<br />
<< strOutFilename<br />
<< "\n//\n"<br />
<< "// This file was generated by CXR, the literal string encryptor.\n"<br />
<< "// CXR, Copyright 2002, Smaller Animals Software, Inc., all rights reserved.\n"<br />
<< "//\n"<br />
<< "// Please do not edit this file. Any changes here will be overwritten on the next compile.\n// If you wish to make changes to a string, please edit:\n// "<br />
<< strInFilename<br />
<<"\n//\n"<br />
<< "\n/////////////////////////////////////////////////////////////\n\n"<br />
<< "#include \"stdafx.h\"\n"<br />
<< "#include \"cxr_inc.h\"\n\n";<br />
<br />
bool bFoundCXR = false;<br />
<br />
do <br />
{<br />
if(in.eof())<br />
break;<br />
else<br />
getline(in, strLine);<br />
<br />
if (in.bad() || in.fail())<br />
break;<br />
<br />
switch (iState)<br />
{<br />
case eStateWantPassword:<br />
iErr = tokenizer.Tokenize(strLine.c_str());<br />
if (iErr == CTokenizer::eErrorNone)<br />
{<br />
if (tokenizer.GetTokenCount() >= 4)<br />
{<br />
if ((tokenizer.GetToken(0).strToken == "//") && <br />
(tokenizer.GetToken(1).strToken == "CXRP") && <br />
(tokenizer.GetToken(2).strToken == "=") && <br />
(tokenizer.GetToken(3).bIsQuotedString))<br />
{<br />
strPassword = tokenizer.GetToken(3).strToken;<br />
<br />
if (strPassword.empty())<br />
{<br />
cerr << _T("Invalid CXR password: \"") << strPassword.c_str() << _T("\"") << endl;
break;<br />
}<br />
<br />
iState = eStateHavePassword;<br />
continue;<br />
}<br />
}<br />
}<br />
break;<br />
case eStateHavePassword:<br />
bFoundCXR = false;<br />
iErr = tokenizer.Tokenize(strLine.c_str());<br />
if (iErr == CTokenizer::eErrorNone)<br />
{<br />
if (tokenizer.GetTokenCount() > 4)<br />
{<br />
for (int i=0; i < tokenizer.GetTokenCount() - 4; i++)<br />
{<br />
if ((tokenizer.GetToken(i).strToken == "_CXR") && !tokenizer.GetToken(i).bIsQuotedString &&<br />
(tokenizer.GetToken(i + 1).strToken == "(") && !tokenizer.GetToken(i + 1).bIsQuotedString &&<br />
(tokenizer.GetToken(i + 2).bIsQuotedString) &&<br />
(tokenizer.GetToken(i + 3).strToken == ")") && !tokenizer.GetToken(i + 3).bIsQuotedString)<br />
{<br />
string strTrans = TranslateString(tokenizer.GetToken(i + 2).strToken);<br />
string strEnc = Encrypt(strTrans, strPassword.c_str());<br />
<br />
out << "///////////////////////////\n#ifdef _USING_CXR\n";<br />
<br />
<br />
out << strLine.substr(0, tokenizer.GetToken(i).iStart);<br />
<br />
out << "\"" << strEnc << "\"";<br />
<br />
out << strLine.substr(tokenizer.GetToken(i + 4).iStop)<br />
<< "\n"<br />
<< "#else\n"<br />
<< strLine<br />
<< "\n#endif\n\n";<br />
<br />
bFoundCXR = true;<br />
<br />
break;<br />
}
}
}
}
<br />
if (bFoundCXR)<br />
{<br />
continue;<br />
}<br />
<br />
break;<br />
}
<br />
out << strLine << "\n";<br />
} while (1);<br />
<br />
if (iState == eStateWantPassword)<br />
{<br />
cerr << _T("No password line found in input file") << endl;<br />
return false;<br />
}<br />
<br />
<br />
AddDecode(strPassword, out);<br />
<br />
return true;<br />
}<br />
<br />
<br />
void AddEncByte(BYTE c, string &strOut)<br />
{<br />
char buf[4];<br />
<br />
BYTE b1 = c >> 4;<br />
BYTE b2 = c & 0x0f;<br />
<br />
_snprintf(buf, 3, "%x", b1 + basechar1);<br />
strOut += "\\x";<br />
strOut += buf;<br />
<br />
_snprintf(buf, 3, "%x", b2 + basechar1);<br />
strOut += "\\x";<br />
strOut += buf;<br />
}<br />
<br />
<br />
string Encrypt(const string &strIn, const char* pPass)<br />
{<br />
string strOut;<br />
<br />
CCXRIntEnc sap((const BYTE*)pPass, (int)strlen(pPass));<br />
<br />
<br />
<br />
BYTE seed = rand() % 256;<br />
BYTE c = sap.ProcessByte((BYTE)(seed));<br />
AddEncByte(c, strOut);<br />
<br />
for (int i=0; i < (int)strIn.length(); i++)<br />
{<br />
char temp = strIn.at(i);<br />
BYTE c = sap.ProcessByte((BYTE)(temp));<br />
AddEncByte(c, strOut);<br />
}<br />
<br />
return strOut;<br />
}<br />
<br />
<br />
string Decrypt(const TCHAR* pIn, const char* pPass)<br />
{<br />
string strOut;<br />
<br />
CCXRIntDec sap((const BYTE*)pPass, (int)strlen(pPass));<br />
<br />
int iLen = (int)strlen(pIn);<br />
<br />
if (iLen > 2)<br />
{<br />
int iBufLen = (int)strlen(pIn);<br />
if (iBufLen & 0x01)<br />
{<br />
cerr << _T("Illegal string length in Decrypt") << endl;<br />
return pIn;<br />
}<br />
<br />
iBufLen /= 2;<br />
<br />
for (int i=0; i < iBufLen; i++)<br />
{<br />
int b1 = pIn[i * 2] - basechar1;<br />
int b2 = pIn[i * 2 + 1] - basechar2;<br />
int c = (b1 << 4) | b2;<br />
<br />
BYTE bc = sap.ProcessByte((BYTE)(c));<br />
<br />
if (i>0)<br />
strOut += (char)bc;<br />
}<br />
}<br />
<br />
return strOut;<br />
}<br />
<br />
<br />
bool AddDecode(const string &strPassword, ofstream &out)<br />
{<br />
out << "\n\n/////////////////////////////////////////////////////////////\n"<br />
<< "// CXR-generated decoder follows\n\n"<br />
<< "#include <algorithm>\n"<br />
<< "const char * __pCXRPassword = \"";<br />
<br />
out << EscapeString(strPassword.c_str()) << "\";\n";<br />
<br />
out << "const int __iCXRDecBase1 = " << basechar1 << ";\nconst int __iCXRDecBase2 = " << basechar2 << ";\n\n";<br />
<br />
const char* szDecodingFunction = <br />
"string __CXRDecrypt(const char* pIn)\n"\<br />
"{\n"\<br />
" string x; char b[3]; b[2]=0;\n"\<br />
" CXRD sap((const BYTE*)__pCXRPassword, (int)strlen(__pCXRPassword));\n"\<br />
" int iLen = (int)strlen(pIn);\n"\<br />
" if (iLen > 2)\n"\<br />
" {\n"\<br />
" int ibl = (int)strlen(pIn);\n"\<br />
" if (ibl & 0x01)\n"\<br />
" {\n"\<br />
<br />
" return pIn;\n"\<br />
" }\n"\<br />
" ibl /= 2;\n"\<br />
" for (int i=0; i < ibl; i++)\n"\<br />
" {\n"\<br />
" int b1 = pIn[i*2] - __iCXRDecBase1; int b2 = pIn[i*2+1] - __iCXRDecBase2;\n"\<br />
" int c = (b1 << 4) | b2; char ch =(char)(sap.pb((BYTE)(c)));\n"\<br />
" if (i>0)\n"\<br />
" x += ch;\n"\<br />
" }\n"\<br />
" }\n"\<br />
" return x;\n"\<br />
"}\n";<br />
<br />
const char* szStreamCipherFunction =<br />
"class CCXR\n" \<br />
"{\n" \<br />
"protected:\n" \<br />
" CCXR(const BYTE* key, unsigned int ks)\n" \<br />
" {\n" \<br />
" int i;BYTE rs;unsigned kp;\n" \<br />
" for(i=0;i<256;i++)c[i]=i;kp=0;rs=0;for(i=255;i;i--)std::swap(c[i],c[kr(i,key,ks,&rs,&kp)]);r2=c[1];r1=c[3];av=c[5];lp=c[7];lc=c[rs];rs=0;kp=0;\n" \<br />
" }\n" \<br />
" inline void SC(){BYTE st=c[lc];r1+=c[r2++];c[lc]=c[r1];c[r1]=c[lp];c[lp]=c[r2];c[r2]=st;av+=c[st];}\n" \<br />
" BYTE c[256],r2,r1,av,lp,lc; \n" \<br />
"\n" \<br />
" BYTE kr(unsigned int lm, const BYTE *uk, BYTE ks, BYTE *rs, unsigned *kp)\n" \<br />
" {\n" \<br />
" unsigned rl=0,mk=1,u;while(mk<lm)mk=(mk<<1)+1;do{*rs=c[*rs]+uk[(*kp)++];if(*kp>=ks){*kp=0;*rs+=ks;}u=mk&*rs;if(++rl>11)u%=lm;}while(u>lm);return u;\n" \<br />
" }\n" \<br />
"};\n" \<br />
"struct CXRD:CCXR\n" \<br />
"{\n" \<br />
" CXRD(const BYTE *userKey, unsigned int keyLength=16) : CCXR(userKey, keyLength) {}\n" \<br />
" inline BYTE pb(BYTE b){SC();lp=b^c[(c[r1]+c[r2])&0xFF]^c[c[(c[lp]+c[lc]+c[av])&0xFF]];lc=b;return lp;}\n" \<br />
"};\n";<br />
<br />
out << szStreamCipherFunction;<br />
out << szDecodingFunction;<br />
<br />
return true;<br />
}<br />
<br />
<br />
string TranslateString(const string &strIn)<br />
{<br />
string strOut;<br />
<br />
for (int i=0; i < (int)strIn.length(); i++)<br />
{<br />
int c = strIn.at(i);
switch (c)<br />
{<br />
default:<br />
strOut += static_cast<char>(c);<br />
break;<br />
<br />
case '\\':<br />
if (i < (int)strIn.length() - 1)<br />
{<br />
c = strIn.at(i + 1);<br />
switch (c)<br />
{<br />
case 'n':<br />
strOut += '\n';<br />
break;<br />
case 't':<br />
strOut += '\t';<br />
break;<br />
case 'v':<br />
strOut += '\v';<br />
break;<br />
case 'b':<br />
strOut += '\b';<br />
break;<br />
case 'r':<br />
strOut += '\r';<br />
break;<br />
case 'f':<br />
strOut += '\f';<br />
break;<br />
case 'a':<br />
strOut += '\a';<br />
break;<br />
case '\\':<br />
strOut += '\\';<br />
break;<br />
case '?':<br />
strOut += '?';<br />
break;<br />
case '\'':<br />
strOut += '\'';<br />
break;<br />
case '\"':<br />
strOut += '\"';<br />
break;<br />
case '0':<br />
case '1':<br />
case '2':<br />
case '3':<br />
case '4':<br />
case '5':<br />
case '6':<br />
case '7':<br />
{<br />
int iConsumed = 0;<br />
if (!ExpandOctal(strIn.substr(i), strOut, iConsumed))<br />
{<br />
cerr << _T("Invalid octal sequence: ") << _T('\"') << strIn.c_str() << _T('\"') << endl;
strOut = strIn;<br />
break;<br />
}<br />
i += iConsumed - 1;<br />
}<br />
break;<br />
case 'x':<br />
{ <br />
int iConsumed = 0;<br />
if (!ExpandHex(strIn.substr(i), strOut, iConsumed))<br />
{<br />
cerr << _T("Invalid hex sequence: ") << _T('\"') << strIn.c_str() << _T('\"') << endl;
strOut = strIn;<br />
break;<br />
}<br />
i += iConsumed - 1;<br />
}<br />
break;<br />
}<br />
<br />
i++;<br />
continue;<br />
}<br />
else<br />
{<br />
cerr << _T("Invalid escape sequence: ") << _T('\"') << strIn.c_str() << _T('\"') << endl;
strOut = strIn;<br />
break;<br />
}<br />
break;<br />
}<br />
}<br />
<br />
return strOut;<br />
}<br />
<br />
<br />
bool ExpandOctal(const string &strIn, string &strOut, int &iConsumed)<br />
{<br />
if (strIn.length() < 2)<br />
return false;<br />
<br />
if (strIn.at(0) != '\\')<br />
return false;<br />
<br />
int iStart = 1;<br />
int iCur = iStart;<br />
<br />
string strDigits;<br />
int c = strIn.at(iCur);
while ((c >= '0') && (c <= '7'))<br />
{<br />
strDigits += static_cast<char>(c);<br />
<br />
if (iCur == 3)<br />
break;<br />
<br />
iCur++;<br />
c = strIn.at(iCur);<br />
}<br />
<br />
char* end;<br />
int octval = (char)strtol(strDigits.c_str(), &end, 8);<br />
<br />
iConsumed = (int)strDigits.length();<br />
<br />
strOut += static_cast<char>(octval);<br />
<br />
return true;<br />
}<br />
<br />
<br />
bool ExpandHex(const string &strIn, string &strOut, int &iConsumed)<br />
{<br />
if (strIn.length() < 3)<br />
return false;<br />
<br />
if ((strIn.at(0) != _T('\\')) || (strIn.at(1) != _T('x')))<br />
return false;<br />
<br />
int iStart = 2;<br />
int iCur = iStart;<br />
<br />
string strDigits;<br />
int c = strIn.at(iCur);<br />
while (_istxdigit(c))<br />
{<br />
strDigits += static_cast<char>(c);<br />
<br />
iCur++;<br />
c = strIn.at(iCur);<br />
}<br />
<br />
char* end;<br />
<br />
int hex = (char)strtol(strDigits.c_str(), &end, 16);<br />
<br />
iConsumed = (int)strDigits.length();<br />
<br />
iConsumed++;
<br />
strOut += static_cast<char>(hex);<br />
<br />
return true;<br />
}<br />
<br />
<br />
string EscapeString(const char* pIn)<br />
{<br />
string strOut;<br />
<br />
int iLen = (int)strlen(pIn);<br />
<br />
for (int i=0; i < iLen; i++)<br />
{<br />
strOut += pIn[i];<br />
<br />
if (pIn[i] == '\\')<br />
{<br />
strOut += '\\';<br />
}<br />
}<br />
<br />
return strOut;<br />
}<br />
Tokenizer.cpp:
<br />
<br />
<br />
<br />
#include "stdafx.h"<br />
#include "Tokenizer.h"<br />
<br />
#undef ALLOW_COMMENTS<br />
<br />
#undef RETURN_QUOTED_STRINGS<br />
<br />
#ifdef ALLOW_COMMENTS<br />
#define COMMENT_START "/*"<br />
#define COMMENT_STOP "*/"<br />
#endif<br />
<br />
CTokenizer::CTokenizer(char** pKeyWords, int iKeyWords, char* pMetaChars, int iMetaChars)<br />
{<br />
m_pKeyWords = pKeyWords;<br />
m_iKeyWords = iKeyWords;<br />
m_MetaChars = pMetaChars;<br />
m_iMetaChars = iMetaChars;<br />
}<br />
<br />
CTokenizer::~CTokenizer()<br />
{<br />
}<br />
<br />
<br />
void CTokenizer::Clear()<br />
{<br />
m_tokens.clear();<br />
}<br />
<br />
<br />
void CTokenizer::Init()<br />
{<br />
Clear();<br />
}<br />
<br />
<br />
int CTokenizer::Tokenize(const char* pInputLine)<br />
{<br />
int err = eErrorNone;<br />
<br />
Init();<br />
<br />
int iLen = (int)strlen(pInputLine);<br />
<br />
bool bInComment = false;<br />
<br />
for (int i=0; i < iLen; i++)<br />
{<br />
string curTokenString;<br />
bool bQuotedString = false;<br />
<br />
int iConsumed = GetToken(pInputLine + i, curTokenString, bQuotedString);<br />
<br />
if (iConsumed > 0)<br />
{<br />
{<br />
#ifdef ALLOW_COMMENTS<br />
if (curTokenString == COMMENT_START)<br />
{<br />
bInComment = true;<br />
i+=iConsumed;<br />
continue;<br />
}<br />
<br />
if (curTokenString == COMMENT_STOP)<br />
{<br />
if (!bInComment)<br />
{<br />
err = eErrorSyntax;<br />
break;<br />
}<br />
<br />
bInComment = false;<br />
<br />
i += iConsumed;<br />
continue;<br />
}<br />
#endif<br />
<br />
if (!bInComment)<br />
{<br />
int iStart = i;<br />
int iStop = i + iConsumed - 1;<br />
<br />
CSAToken curToken(curTokenString.c_str(), iStart, iStop, bQuotedString);<br />
<br />
m_tokens.push_back(curToken);<br />
}<br />
}<br />
<br />
i += iConsumed;<br />
<br />
i--;
continue;<br />
}<br />
else<br />
{<br />
if (IsMetaChar(*(pInputLine + i)))<br />
{<br />
if (!isspace(*(pInputLine + i)))<br />
{<br />
curTokenString.clear();<br />
curTokenString += *(pInputLine + i);<br />
<br />
CSAToken curToken(curTokenString.c_str(), i, (int)curTokenString.length() - 1, bQuotedString);<br />
<br />
m_tokens.push_back(curToken);<br />
}<br />
}<br />
}<br />
}<br />
<br />
return err;<br />
}<br />
<br />
<br />
bool CTokenizer::IsKeyWord(string &str)<br />
{<br />
return IsKeyWord((const char*)str.c_str());<br />
}<br />
<br />
<br />
bool CTokenizer::IsKeyWord(const char* pInput)<br />
{<br />
if (m_pKeyWords==NULL)<br />
{<br />
return false;<br />
}<br />
<br />
int iLen = (int)strlen(pInput);<br />
<br />
int iBestMatch = -1;<br />
<br />
for (int i=0; i < m_iKeyWords; i++)<br />
{<br />
int iCurKWLen = (int)strlen(m_pKeyWords[i]);<br />
<br />
if (iLen <= iCurKWLen)<br />
{<br />
if (strnicmp(m_pKeyWords[i], pInput, iCurKWLen)==0)<br />
{<br />
iBestMatch = i;<br />
}<br />
}<br />
}<br />
<br />
if (iBestMatch==-1)<br />
{<br />
#ifdef ALLOW_COMMENTS<br />
if (CSAScrUtil::sa_strnicmp(COMMENT_START, pInput, strlen(COMMENT_START))==0)<br />
{<br />
iBestMatch = m_iKeyWords + 1;<br />
}<br />
<br />
if (CSAScrUtil::sa_strnicmp(COMMENT_STOP, pInput, strlen(COMMENT_STOP))==0)<br />
{<br />
iBestMatch = m_iKeyWords + 2;<br />
}<br />
#endif<br />
}<br />
return (iBestMatch != -1);<br />
}<br />
<br />
<br />
int CTokenizer::GetToken(const char* pInput, string &out, bool &bQuotedString)<br />
{<br />
int iLen = (int)strlen(pInput);<br />
<br />
bool bFoundChars = false;<br />
<br />
bool bScanningMetaKW = false;<br />
<br />
bool bInQuotes = false;<br />
<br />
bQuotedString = false;<br />
<br />
char c;<br />
<br />
for (int iWS = 0; iWS < iLen; iWS++)<br />
{<br />
c = *(pInput + iWS);<br />
if (!isspace(c))<br />
break;<br />
if (!iscntrl(c))<br />
break;<br />
}<br />
<br />
for (int i=iWS; i<iLen; i++)<br />
{<br />
c = *(pInput + i);<br />
<br />
if ((c == '"') && !bInQuotes)<br />
{<br />
if (bFoundChars)<br />
{<br />
break;<br />
}<br />
<br />
bInQuotes = true;<br />
#ifdef RETURN_QUOTED_STRINGS<br />
out+=c;<br />
#endif<br />
continue;<br />
}<br />
<br />
if ((c == '"') && bInQuotes)<br />
{<br />
bInQuotes = false;<br />
#ifdef RETURN_QUOTED_STRINGS<br />
out += c;<br />
#endif<br />
i += 1;<br />
<br />
bQuotedString = true;<br />
break;<br />
}<br />
<br />
if (bInQuotes)<br />
{<br />
if (c == '\\')<br />
{<br />
if (i < iLen - 1)<br />
{<br />
switch (*(pInput + i + 1))<br />
{<br />
case '"':<br />
out += "\\\"";
i++;
continue;<br />
break;<br />
<br />
default:<br />
out += c;<br />
continue;<br />
break;<br />
}<br />
}<br />
}<br />
<br />
out += c;<br />
continue;<br />
}<br />
<br />
if (iscntrl(c) || isspace(c))<br />
{<br />
break;<br />
}<br />
<br />
if (IsMetaChar(c))<br />
{<br />
if (iscntrl(c) || isspace(c))<br />
{<br />
break;<br />
}<br />
<br />
if (!bFoundChars)<br />
{<br />
bScanningMetaKW = true;<br />
<br />
bFoundChars = true;<br />
<br />
if (i < iLen - 2)<br />
{<br />
char buf[3];<br />
buf[0] = c;<br />
buf[1] = *(pInput + i + 1);<br />
buf[2] = 0;<br />
<br />
if (IsKeyWord(buf))<br />
{<br />
out += c;<br />
out += *(pInput + i + 1);<br />
<br />
i += 2;<br />
<br />
break;<br />
}<br />
else<br />
{<br />
buf[1] = 0;<br />
if (IsKeyWord(buf))<br />
{<br />
out += c;<br />
<br />
i += 1;<br />
<br />
break;<br />
}<br />
}<br />
}<br />
<br />
out += c;<br />
}<br />
else<br />
{<br />
break;<br />
}<br />
}<br />
else<br />
{<br />
if (!bFoundChars)<br />
{<br />
bScanningMetaKW = false;<br />
<br />
bFoundChars = true;<br />
<br />
out += c;<br />
}<br />
else<br />
{<br />
if (bScanningMetaKW)<br />
{<br />
break;<br />
}<br />
else<br />
{<br />
out += c;<br />
}<br />
}<br />
}<br />
}<br />
<br />
return i;<br />
}<br />
<br />
<br />
bool CTokenizer::IsMetaChar(const char c)<br />
{<br />
for (int i=0; i < m_iMetaChars; i++)<br />
{<br />
if (c == m_MetaChars[i])<br />
return true;<br />
}<br />
<br />
return false;<br />
}<br />
<br />
<br />
bool CTokenizer::IsMetaChar(string &str)<br />
{<br />
if (str.length() > 1)<br />
return false;<br />
<br />
char c = str.at(0);<br />
<br />
for (int i=0; i < m_iMetaChars; i++)<br />
{<br />
if (c == m_MetaChars[i])<br />
return true;<br />
}<br />
<br />
return false;<br />
}<br />
<br />
<br />
void CTokenizer::Dump()<br />
{<br />
CSATokenVector::iterator theIterator;<br />
<br />
int i=0;<br />
for (theIterator = m_tokens.begin(); theIterator < m_tokens.end(); theIterator++)<br />
{<br />
}<br />
}<br />
<br />
<br />
bool operator < (const CSAToken &a, const CSAToken &b)<br />
{<br />
return (a.iStart < b.iStart);<br />
}<br />
<br />
bool operator == (const CSAToken &a, const CSAToken &b)<br />
{<br />
return (a.iStart == b.iStart);<br />
}<br />
cxr_inc.h:
<br />
<br />
#pragma once<br />
<br />
#include <string><br />
<br />
using namespace std;<br />
<br />
#define _USING_CXR<br />
<br />
#ifndef _USING_CXR<br />
#define _CXR(x) x<br />
#else<br />
#define _CXR(x) __CXRDecrypt(x)<br />
extern string __CXRDecrypt(const char* pIn);<br />
#endif<br />
stdafx.h:
<br />
<br />
#pragma once<br />
<br />
<br />
#include <iostream><br />
#include <tchar.h><br />
<br />
<br />
Stream.h:
<br />
<br />
<br />
<br />
<br />
<br />
#pragma once<br />
<br />
typedef unsigned char BYTE;<br />
<br />
class CCXRIntBase<br />
{<br />
protected:<br />
CCXRIntBase(const BYTE* key, unsigned int ks)<br />
{<br />
int i;BYTE rs;unsigned kp;<br />
for(i=0;i<256;i++)c[i]=i;kp=0;rs=0;for(i=255;i;i--)std::swap(c[i],c[kr(i,key,ks,&rs,&kp)]);r2=c[1];r1=c[3];av=c[5];lp=c[7];lc=c[rs];rs=0;kp=0;<br />
}<br />
inline void SC(){BYTE st=c[lc];r1+=c[r2++];c[lc]=c[r1];c[r1]=c[lp];c[lp]=c[r2];c[r2]=st;av+=c[st];}<br />
BYTE c[256],r2,r1,av,lp,lc; <br />
<br />
BYTE kr(unsigned int lm, const BYTE *uk, BYTE ks, BYTE *rs, unsigned *kp)<br />
{<br />
unsigned rl=0,mk=1,u;<br />
while(mk<lm)mk=(mk<<1)+1;<br />
do{*rs=c[*rs]+uk[(*kp)++];<br />
if(*kp>=ks){*kp=0;*rs+=ks;}u=mk&*rs;<br />
if(++rl>11)u%=lm;}while(u>lm);<br />
return u;<br />
}<br />
};<br />
<br />
<br />
struct CCXRIntDec:CCXRIntBase<br />
{<br />
CCXRIntDec(const BYTE *userKey, unsigned int keyLength=16) : CCXRIntBase(userKey, keyLength) {}<br />
inline BYTE ProcessByte(BYTE b){SC();lp=b^c[(c[r1]+c[r2])&0xFF]^c[c[(c[lp]+c[lc]+c[av])&0xFF]];lc=b;return lp;}<br />
};<br />
<br />
<br />
struct CCXRIntEnc:CCXRIntBase<br />
{<br />
CCXRIntEnc(const BYTE *userKey, unsigned int keyLength=16) : CCXRIntBase(userKey, keyLength) {}<br />
inline BYTE ProcessByte(BYTE b){SC();lc=b^c[(c[r1]+c[r2])&0xFF]^c[c[(c[lp]+c[lc]+c[av])&0xFF]];lp=b;return lc;}<br />
};<br />
Tokenizer.h:
<br />
<br />
<br />
#pragma once<br />
<br />
#include <vector><br />
#include <iterator><br />
<br />
#pragma warning(disable:4786)<br />
using namespace std ;<br />
using namespace std::rel_ops ;<br />
<br />
<br />
class CSAToken <br />
{<br />
public:<br />
CSAToken()<br />
{<br />
iStart = iStop = -1;<br />
bIsQuotedString = false;<br />
}<br />
<br />
CSAToken(const char* p, int x, int y, bool q)<br />
{<br />
strToken = p;<br />
iStart = x;<br />
iStop = y;<br />
<br />
bIsQuotedString = q;<br />
}<br />
<br />
string strToken;<br />
int iStart;<br />
int iStop;<br />
bool bIsQuotedString;<br />
};<br />
<br />
<br />
typedef vector<CSAToken> CSATokenVector;<br />
<br />
<br />
class CTokenizer <br />
{<br />
public:<br />
enum {eErrorNone, eErrorSyntax,}eError;<br />
<br />
CTokenizer(char** pKeyWords, int iKeyWords, char* pMetaChars, int iMetaChars);<br />
virtual ~CTokenizer();<br />
void Clear();<br />
void Init();<br />
<br />
int Tokenize(const char* pInputLine);<br />
<br />
bool IsKeyWord(string &str);<br />
bool IsKeyWord(const char* pInput);<br />
<br />
void Dump();<br />
<br />
bool IsMetaChar(const char c); <br />
bool IsMetaChar(string &str);<br />
<br />
_inline int GetTokenCount() {return (int)m_tokens.size();}<br />
_inline CSAToken GetToken(int i) {return m_tokens.at(i);}<br />
<br />
protected:<br />
int GetToken(const char* pInput, string &out, bool &bQuotedString);<br />
<br />
char** m_pKeyWords;<br />
int m_iKeyWords;<br />
char* m_MetaChars;<br />
int m_iMetaChars;<br />
<br />
CSATokenVector m_tokens;<br />
};<br />
<br />
<br />
extern bool operator < (const CSAToken &a, const CSAToken &b);<br />
extern bool operator == (const CSAToken &a, const CSAToken &b);<br />
|
|
|
|
|
stop posting errorcode, it's not fun to fix your ****.
|
|
|
|
|
Dear Sir,
Thanks for this utility, it did just what I wanted. I made a small improvements.
1. Added casts, because else VS.NET compiler complains.
2. I hate to write things twice, therefore I added generation of a header file with externs. I.e. for your demo project it generates
--strings.h---
extern const char* pString1 ;//blabal
extern const char* pString2 ;
Now one can just include this file into all project files.
3. I added
#define CXR_CPP
into the generated cpp file. So that one can customize cxr_inc.h, depending on whether it is now included in cxr generated cpp or other project files (sometimes usefull).
I share the changes with people in the hope, that it can be usefull for somebody else too.
----crx.cpp--
<code>
/*********************************************************************
Copyright (C) 2002 Smaller Animals Software, Inc.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
http://www.smalleranimals.com
smallest@smalleranimals.com
**********************************************************************/
// CXR.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "CXR.h"
#include "CmdLine.h"
#include "Tokenizer.h"
#include "Stream.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// The one and only application object
CWinApp theApp;
using namespace std;
/////////////////////////////////////////////////////////////////
static bool ProcessFile(CStdioFile &in, CStdioFile &out, CStdioFile &outh);
static bool AddDecode(const CString & csPassword, CStdioFile &out);
static CString Encrypt(const CString &csIn, const char *pPass);
static CString Decrypt(const char *pIn, const char *pPass);
static bool ExpandOctal(const CString &csIn, CString &csOut, int &iConsumed);
static CString TranslateCString(const CString &csIn);
static bool ExpandHex(const CString &csIn, CString &csOut, int &iConsumed);
static CString EscapeCString(const char *pIn);
// these can be adjusted in the range 1 to 239
const int basechar1 = 128;
const int basechar2 = 128;
/////////////////////////////////////////////////////////////////
int _tmain(int argc, char* argv[], char* envp[])
{
int nRetCode = 0;
srand(time(NULL));
// initialize MFC and print and error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
cerr << _T("Fatal Error: MFC initialization failed") << endl;
nRetCode = 1;
}
else
{
cerr << "Starting CXR, the literal string encryptor. Copyright 2002, Smaller Animals Software Inc.\n";
if ((basechar1 == 0) || (basechar2 == 0) || (basechar1 > 239) || (basechar2 > 239))
{
cerr << "CXR basechar values out of acceptable range. Aborting\n";
nRetCode = 1;
return nRetCode;
}
CCmdLine cmd;
if (cmd.SplitLine(argc, argv) >= 2)
{
CString csInFile = cmd.GetSafeArgument("-i", 0, "");
CString csOutFile = cmd.GetSafeArgument("-o", 0, "");
if (!csInFile.IsEmpty() && !csOutFile.IsEmpty())
{
// open the input file
CStdioFile fileIn;
// open the output file
CStdioFile fileOut;
CStdioFile fileOuth;
string _HeaderName=csOutFile;
string::size_type _dot=_HeaderName.find_last_of(".");
if ((_dot!=string::npos)&&(_dot>1)){
_HeaderName=_HeaderName.substr(0,_dot);
};
_HeaderName+=".h";
if (fileIn.Open(csInFile, CFile::modeRead | CFile::typeText))
{
if (fileOut.Open(csOutFile, CFile::modeCreate | CFile::modeWrite | CFile::typeText ))
{
if (fileOuth.Open(_HeaderName.c_str(), CFile::modeCreate | CFile::modeWrite | CFile::typeText ))
if (!ProcessFile(fileIn, fileOut,fileOuth))
{
cerr << "CXR failed\n";
nRetCode = 1;
}
}
else
{
cerr << _T("Unable to open output file: ") << (LPCTSTR)csOutFile << endl;
nRetCode = 1;
}
}
else
{
cerr << _T("Unable to open input file: ") << (LPCTSTR)csInFile << endl;
nRetCode = 1;
}
if (nRetCode==0)
{
cerr << "CXR created: " << (LPCTSTR)csOutFile << "\n";
}
}
else
{
cerr << _T("Not enough parameters") << endl;
nRetCode = 1;
}
}
else
{
cerr << _T("Not enough parameters") << endl;
nRetCode = 1;
}
}
return nRetCode;
}
/////////////////////////////////////////////////////////////////
bool ProcessFile(CStdioFile &in, CStdioFile &out,CStdioFile &outh)
{
enum
{
eStateWantPassword,
eStateHavePassword,
};
int iState = eStateWantPassword;
CString csPassword;
CString line;
char *pMetachars = _T("/\\=();'");
char *pKeyWords[3] = {_T("//"), _T("_CXR"), _T("CXRP")};
CTokenizer tokenizer(pKeyWords, 3, pMetachars, strlen(pMetachars));
int iErr = CTokenizer::eErrorNone;
bool ok = true;
out.WriteString(_T("/////////////////////////////////////////////////////////////\n"));
out.WriteString(_T("// "));
out.WriteString(out.GetFileName());
out.WriteString(_T("\n//\n"));
out.WriteString(_T("// This file was generated by CXR, the literal string encryptor.\n"));
out.WriteString(_T("// CXR, Copyright 2002, Smaller Animals Software, Inc., all rights reserved.\n"));
out.WriteString(_T("//\n"));
out.WriteString(_T("// Please do not edit this file. Any changes here will be overwritten on the next compile.\n// If you wish to make changes to a string, please edit:\n// "));
out.WriteString(in.GetFilePath());
out.WriteString(_T("\n//\n"));
out.WriteString(_T("\n/////////////////////////////////////////////////////////////\n\n"));
out.WriteString(_T("\n#define CXR_CPP\n\n"));
out.WriteString(_T("#include \"stdafx.h\"\n"));
out.WriteString(_T("#include \"cxr_inc.h\"\n\n"));
outh.WriteString(_T("// Please do not edit this file. Any changes here will be overwritten on the next compile.\n// If you wish to make changes to a string, please edit:\n// "));
outh.WriteString(in.GetFilePath());
outh.WriteString(_T("\n//\n"));
outh.WriteString(_T("#ifndef "));
CString _fn=outh.GetFileName();
_fn.Replace(".","_");
_fn.MakeUpper();
outh.WriteString(_fn);
outh.WriteString(_T("\n#define "));
outh.WriteString(_fn);
outh.WriteString(_T("\n"));
outh.WriteString(_T("#include \"cxr_inc.h\"\n\n"));
bool bFoundCXR = false;
do
{
if (!in.ReadString(line))
{
break;
}
switch (iState)
{
case eStateWantPassword:
iErr = tokenizer.Tokenize(line);
if (iErr == CTokenizer::eErrorNone)
{
if (tokenizer.GetTokenCount() >= 4)
{
// password declaration always looks like : // CXRP = "Password"
if ((tokenizer.GetToken(0).csToken == _T("//")) &&
(tokenizer.GetToken(1).csToken == _T("CXRP")) &&
(tokenizer.GetToken(2).csToken == _T("=")) &&
(tokenizer.GetToken(3).bIsQuotedString))
{
// we'll use the password from the file, literally. it's not treated as
// a C string-literal, just as a section of a text file. when we
// go to write the decoder, we'll have to fix it up to make sure
// the compiler gets the same text by adding any necessary escapes.
csPassword = tokenizer.GetToken(3).csToken;
if (csPassword.IsEmpty())
{
cerr << _T("Invalid CXR password: \"") << (LPCTSTR)csPassword << _T("\"") << endl;
ASSERT(0);
break;
}
iState = eStateHavePassword;
continue;
}
}
}
break;
case eStateHavePassword:
bFoundCXR = false;
iErr = tokenizer.Tokenize(line);
if (iErr == CTokenizer::eErrorNone)
{
if (tokenizer.GetTokenCount() > 4)
{
for (int i=0;i<tokenizer.GetTokenCount() - 4; i++)
{
// looking for _CXR ( "..." )
if (
(tokenizer.GetToken(i).csToken == _T("_CXR")) && !tokenizer.GetToken(i).bIsQuotedString &&
(tokenizer.GetToken(i + 1).csToken == _T("(")) && !tokenizer.GetToken(i + 1).bIsQuotedString &&
(tokenizer.GetToken(i + 2).bIsQuotedString) &&
(tokenizer.GetToken(i + 3).csToken == _T(")")) && !tokenizer.GetToken(i + 3).bIsQuotedString
)
{
CString csTrans = TranslateCString(tokenizer.GetToken(i + 2).csToken);
CString csEnc = Encrypt(csTrans, csPassword);
//CString csDec = Decrypt(csEnc, csPassword);
out.WriteString(_T("///////////////////////////\n#ifdef _USING_CXR\n"));
/*
out.WriteString("//");
out.WriteString(csDec);
out.WriteString("\n");
*/
// output up to _CXR
out.WriteString(line.Left(tokenizer.GetToken(i).iStart));
CString _newline=line.Left(tokenizer.GetToken(i).iStart);
_newline.Replace("=","");
_newline=_newline.Trim(" ");
// extern const char* ltrUnknown; //Unknown.
//Find last token in the string before = (i.e. variable name)
//and make #define lThisName _CRX(ThisName)
CString resToken;
CString TypeName;
int curPos=0;
resToken= _newline.Tokenize("% #*",curPos);
while (resToken != ""){
TypeName=resToken;
resToken= _newline.Tokenize("% #*",curPos);
};
_newline=" extern "+_newline;
outh.WriteString(_newline);
outh.WriteString(_T("; //")+csTrans+_T("\n"));
outh.WriteString(_T("#define l")+TypeName+ _T(" _CXR(")+TypeName+_T(").c_str()\n\n"));
// encrypted stuff
out.WriteString(_T("\""));
out.WriteString(csEnc);
out.WriteString(_T("\""));
// to the end of the line
out.WriteString(line.Mid(tokenizer.GetToken(i + 4).iStop));
out.WriteString(_T("\n"));
out.WriteString(_T("#else\n"));
out.WriteString(line);
out.WriteString(_T("\n#endif\n\n"));
bFoundCXR = true;
break;
} // found a good string ?
} // loop over tokens
} // > 4 tokens
} // tokenizer OK
if (bFoundCXR)
{
continue;
}
break; // switch
}
// done with it
out.WriteString(line);
out.WriteString("\n");
} while (1);
outh.WriteString(_T("\n\n#endif"));
if (iState == eStateWantPassword)
{
cerr << "No password line found in input file\n";
return false;
}
ASSERT(iState==eStateHavePassword);
// add the decoder functions
AddDecode(csPassword, out);
return true;
}
/////////////////////////////////////////////////////////////////
void AddEncByte(BYTE c, CString &csOut)
{
char buf[4];
BYTE b1 = c >> 4;
BYTE b2 = c & 0x0f;
_snprintf(buf, 3, "%x", b1 + basechar1);
csOut+="\\x";
csOut+=buf;
_snprintf(buf, 3, "%x", b2 + basechar1);
csOut+="\\x";
csOut+=buf;
}
/////////////////////////////////////////////////////////////////
CString Encrypt(const CString &csIn, const char *pPass)
{
CString csOut;
// initialize out
CCXRIntEnc sap((const BYTE*)pPass, strlen(pPass));
/*
start each string with a random char.
because this is a stream cipher, the ciphertext of a
string like "ABC" will be the same as the first 3 bytes
of the ciphertext for "ABCDEFG".
by starting with a random value, the cipher will be in a
different state (255:1) when it starts the real text. the
decoder will simply discard the first plaintext byte.
*/
BYTE seed = rand() % 256;
BYTE c = sap.ProcessByte((BYTE)(seed));
AddEncByte(c, csOut);
// encrypt and convert to hex string
for (int i=0; i < csIn.GetLength(); i++)
{
char t = csIn.GetAt(i);
BYTE c = sap.ProcessByte((BYTE)(t));
AddEncByte(c, csOut);
}
return csOut;
}
/////////////////////////////////////////////////////////////////
CString Decrypt(const char *pIn, const char *pPass)
{
CString csOut;
CCXRIntDec sap((const BYTE *)pPass, strlen(pPass));
int iLen = _tcslen(pIn);
if (iLen > 2)
{
int iBufLen = strlen(pIn);
if (iBufLen & 0x01)
{
cerr << "Illegal string length in Decrypt\n";
return pIn;
}
iBufLen/=2;
for (int i=0;i<iBufLen;i++)
{
int b1 = pIn[i * 2] - basechar1;
int b2 = pIn[i * 2 + 1] - basechar2;
int c = (b1 << 4) | b2;
BYTE bc = sap.ProcessByte((BYTE)(c));
if (i>0) csOut+=(char)bc;
}
}
return csOut;
}
/////////////////////////////////////////////////////////////////
bool AddDecode(const CString & csPassword, CStdioFile &out)
{
out.WriteString(_T("\n\n/////////////////////////////////////////////////////////////\n"));
out.WriteString(_T("// CXR-generated decoder follows\n\n"));
out.WriteString(_T("#include <algorithm>\n"));
out.WriteString(_T("const char * __pCXRPassword = \""));
// the password that encrypted the text used the literal text from the file (non-escaped \ chars).
// we need to make sure that compiler sees the same text when it gets the passowrd. so,
// we must double any "\" chars, to prevent them from becoming C-style escapes.
out.WriteString(EscapeCString(csPassword));
out.WriteString(_T("\";\n"));
CString t;
t.Format("const int __iCXRDecBase1 = %d;\nconst int __iCXRDecBase2 = %d;\n\n", basechar1, basechar2);
out.WriteString(t);
// the high-level decoding function
const char *pDec1 =
"CString __CXRDecrypt(const char *pIn)\n"\
"{\n"\
" CString x;char b[3];b[2]=0;\n"\
" CXRD sap((const BYTE*)__pCXRPassword, strlen(__pCXRPassword));\n"\
" int iLen = strlen(pIn);\n"\
" if (iLen > 2)\n"\
" {\n"\
" int ibl=strlen(pIn);\n"\
" if (ibl&0x01)\n"\
" {\n"\
" ASSERT(!\"Illegal string length in Decrypt\");\n"\
" return pIn;\n"\
" }\n"\
" ibl/=2;\n"\
" for (int i=0;i<ibl;i++)\n"\
" {\n"\
" int b1 =pIn[i*2]-__iCXRDecBase1;int b2=pIn[i*2+1]-__iCXRDecBase2;\n"\
" int c = (b1 << 4) | b2; char ch =(char)(sap.pb((BYTE)(c)));\n"\
" if (i>0) x+=ch;\n"\
" }\n"\
" }\n"\
" return x;\n"\
"}\n";
// the stream cipher
const char *pStr1 =
"class CCXR\n" \
"{\n" \
"protected:\n" \
" CCXR(const BYTE *key, unsigned int ks)\n" \
" {\n" \
" int i;BYTE rs;unsigned kp;\n" \
" for(i=0;i<256;i++)c[i]=i;kp=0;rs=0;for(i=255;i;i--)std::swap(c[i],c[kr(i,key,ks,&rs,&kp)]);r2=c[1];r1=c[3];av=c[5];lp=c[7];lc=c[rs];rs=0;kp=0;\n" \
" }\n" \
" inline void SC(){BYTE st=c[lc];r1+=c[r2++];c[lc]=c[r1];c[r1]=c[lp];c[lp]=c[r2];c[r2]=st;av+=c[st];}\n" \
" BYTE c[256],r2,r1,av,lp,lc; \n" \
"\n" \
" BYTE kr(unsigned int lm, const BYTE *uk, BYTE ks, BYTE *rs, unsigned *kp)\n" \
" {\n" \
" unsigned rl=0,mk=1,u;while(mk<lm)mk=(mk<<1)+1;do{*rs=c[*rs]+uk[(*kp)++];if(*kp>=ks){*kp=0;*rs+=ks;}u=mk&*rs;if(++rl>11)u%=lm;}while(u>lm);return u;\n" \
" }\n" \
"};\n" \
"struct CXRD:CCXR\n" \
"{\n" \
" CXRD(const BYTE *userKey, unsigned int keyLength=16) : CCXR(userKey, keyLength) {}\n" \
" inline BYTE pb(BYTE b){SC();lp=b^c[(c[r1]+c[r2])&0xFF]^c[c[(c[lp]+c[lc]+c[av])&0xFF]];lc=b;return lp;}\n" \
"};\n";
out.WriteString(pStr1);
out.WriteString(pDec1);
return true;
}
/////////////////////////////////////////////////////////////////
CString TranslateCString(const CString &csIn)
{
// translate C-style string escapes as documented in K&R 2nd, A2.5.2
CString csOut;
for (int i=0;i<csIn.GetLength(); i++)
{
int c = csIn.GetAt(i);
switch (c)
{
default:
// normal text
csOut+=static_cast<char>(c);
break;
// c-style escape
case _T('\\'):
if (i < csIn.GetLength() - 1)
{
c = csIn.GetAt(i + 1);
switch (c)
{
case _T('n'):
csOut+=_T('\n');
break;
case _T('t'):
csOut+=_T('\t');
break;
case _T('v'):
csOut+=_T('\v');
break;
case _T('b'):
csOut+=_T('\b');
break;
case _T('r'):
csOut+=_T('\r');
break;
case _T('f'):
csOut+=_T('\f');
break;
case _T('a'):
csOut+=_T('\a');
break;
case _T('\\'):
csOut+=_T('\\');
break;
case _T('?'):
csOut+=_T('?');
break;
case _T('\''):
csOut+=_T('\'');
break;
case _T('\"'):
csOut+=_T('\"');
break;
case _T('0'):
case _T('1'):
case _T('2'):
case _T('3'):
case _T('4'):
case _T('5'):
case _T('6'):
case _T('7'):
{
// expand octal
int iConsumed = 0;
if (!ExpandOctal(csIn.Mid(i), csOut, iConsumed))
{
cerr << _T("Invalid octal sequence: ") << _T('\"') << (LPCTSTR)csIn << _T('\"') << endl;
csOut = csIn;
break;
}
i+=iConsumed - 1;
}
break;
case _T('x'):
{
// expand hex
int iConsumed = 0;
if (!ExpandHex(csIn.Mid(i), csOut, iConsumed))
{
cerr << _T("Invalid hex sequence: ") << _T('\"') << (LPCTSTR)csIn << _T('\"') << endl;
csOut = csIn;
break;
}
i+=iConsumed - 1;
}
break;
}
i++;
continue;
}
else
{
cerr << _T("Invalid escape sequence: ") << _T('\"') << (LPCTSTR)csIn << _T('\"') << endl;
csOut = csIn;
break;
}
break;
}
}
return csOut;
}
/////////////////////////////////////////////////////////////////
bool ExpandOctal(const CString &csIn, CString &csOut, int &iConsumed)
{
// staring with the escape, we need at least one more char
if (csIn.GetLength() < 2)
{
return false;
}
if (csIn.GetAt(0) != _T('\\'))
{
return false;
}
int iStart = 1;
int iCur = iStart;
CString digits;
int c = csIn.GetAt(iCur);
while ((c >= _T('0')) && (c <= _T('7')))
{
digits+=static_cast<char>(c);
// an escape can't hold more that 3 octal digits (K&R 2nd A2.5.2)
if (iCur == 3)
{
break;
}
iCur++;
c = csIn.GetAt(iCur);
}
char *end;
int octval = (char)_tcstol(digits, &end, 8);
iConsumed = digits.GetLength();
csOut+=static_cast<char>(octval);
return true;
}
/////////////////////////////////////////////////////////////////
bool ExpandHex(const CString &csIn, CString &csOut, int &iConsumed)
{
// staring with the escape and the 'x', we need at least one more char
if (csIn.GetLength() < 3)
{
return false;
}
if ((csIn.GetAt(0) != _T('\\')) || (csIn.GetAt(1) != _T('x')))
{
return false;
}
int iStart = 2;
int iCur = iStart;
CString digits;
int c = csIn.GetAt(iCur);
while (_istxdigit(c))
{
digits+=static_cast<char>(c);
iCur++;
c = csIn.GetAt(iCur);
}
char *end;
// "There is no limit on the number of digits, but the behavior is undefined
// if the resulting character value exceeds that of the largest character"
// (K&R 2nd A2.5.2)
int hex = (char)_tcstol(digits, &end, 16);
iConsumed = digits.GetLength();
iConsumed++; // count the "x"
csOut+=static_cast<char>(hex);
return true;
}
/////////////////////////////////////////////////////////////////
CString EscapeCString(const char *pIn)
{
CString csOut;
int iLen = _tcslen(pIn);
for (int i=0;i<iLen;i++)
{
csOut+=pIn[i];
// double all "\" chars
if (pIn[i] == _T('\\'))
{
csOut+=_T('\\');
}
}
return csOut;
}
/////////////////////////////////////////////////////////////////
</code>
-- modified at 16:57 Thursday 2nd March, 2006
|
|
|
|
|
On many lines: 257, 466, 514, 713, ... your code got cut off or something.
<br />
for (int i=0;i<br />
And on line 437, I think there is something missing after "#include":
<br />
out.WriteString(_T("#include \n"));<br />
-- modified at 15:31 Thursday 2nd March, 2006
Update: Oh and also your static_cast statements lost their bracketed data type. I can guess what you meant though. You probably meant to cast the int to a TCHAR , right?
|
|
|
|
|
Hi,
Thanks for the tip.
all bracketed stuff went away I updated the code.Now it seems to be ok.
|
|
|
|
|
Thank you for the excellent tool.
We have CXR running in Visual C++ using MFC, but we ordinarily develop and build on Linux.
Does anyone have experience or suggestions on the best approach to get CXR to compile and run on Linux without MFC?
|
|
|
|
|
Yes. I made a comment post above -- in it I posted code that references STL classes in place of MFC. So now it's not dependent on any MFC code. It's still not 100% ready to compile under Linux, but it will probably require very little changing to make it work now.
|
|
|
|
|
fyi, I've posted a cross-platform branch of CXR on Google Code here.
|
|
|
|
|
|
Here's a proof of concept.
This will "encrypt" (scramble, rather) the strings at compile time and decrypt at runtime.
#ifndef SCRAMBLEH<br />
#define SCRAMBLEH<br />
<br />
<br />
<br />
<br />
#define STRING_SCRAMBLE(s00, s01, s02, s03, s04, s05, s06, s07, s08, s09, \<br />
s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, \<br />
s20, s21, s22, s23, s24, s25, s26, s27, s28, s29, \<br />
s30, s31) \<br />
{ \<br />
char(s00 ^ 0xa3), \<br />
char(s01 ^ 0x54), \<br />
char(s02 ^ 0xff), \<br />
char(s03 ^ 0x75), \<br />
char(s04 ^ 0xe7), \<br />
char(s05 ^ 0x44), \<br />
char(s06 ^ 0x4b), \<br />
char(s07 ^ 0x23), \<br />
char(s08 ^ 0xbf), \<br />
char(s09 ^ 0x45), \<br />
char(s10 ^ 0x3b), \<br />
char(s11 ^ 0x56), \<br />
char(s12 ^ 0xf8), \<br />
char(s13 ^ 0x98), \<br />
char(s14 ^ 0x5b), \<br />
char(s15 ^ 0xf4), \<br />
char(s16 ^ 0xb5), \<br />
char(s17 ^ 0x87), \<br />
char(s18 ^ 0x7b), \<br />
char(s19 ^ 0x0f), \<br />
char(s20 ^ 0xf4), \<br />
char(s21 ^ 0x76), \<br />
char(s22 ^ 0xb9), \<br />
char(s23 ^ 0x34), \<br />
char(s24 ^ 0xbf), \<br />
char(s25 ^ 0x1e), \<br />
char(s26 ^ 0xe7), \<br />
char(s27 ^ 0x78), \<br />
char(s28 ^ 0x98), \<br />
char(s29 ^ 0xe9), \<br />
char(s30 ^ 0x6f), \<br />
char(s31 ^ 0xb4), \<br />
'\0' \<br />
} <br />
<br />
#define LICENSE_STRING_CHECKSUM(s) \<br />
(s[ 0] << 0) ^ \<br />
(s[ 1] << 8) ^ \<br />
(s[ 2] << 16) ^ \<br />
(s[ 3] << 0) ^ \<br />
(s[ 4] << 8) ^ \<br />
(s[ 5] << 16) ^ \<br />
(s[ 6] << 24) ^ \<br />
(s[ 7] << 8) ^ \<br />
(s[ 8] << 0) ^ \<br />
(s[ 9] << 8) ^ \<br />
(s[10] << 16) ^ \<br />
(s[11] << 24) ^ \<br />
(s[12] << 0) ^ \<br />
(s[13] << 8) ^ \<br />
(s[14] << 16) ^ \<br />
(s[15] << 24) ^ \<br />
(s[16] << 0) ^ \<br />
(s[17] << 8) ^ \<br />
(s[18] << 16) ^ \<br />
(s[19] << 24) ^ \<br />
(s[20] << 0) ^ \<br />
(s[21] << 8) ^ \<br />
(s[22] << 16) ^ \<br />
(s[23] << 24) ^ \<br />
(s[24] << 0) ^ \<br />
(s[25] << 8) ^ \<br />
(s[26] << 16) ^ \<br />
(s[27] << 24) ^ \<br />
(s[28] << 0) ^ \<br />
(s[29] << 8) ^ \<br />
(s[30] << 16) ^ \<br />
(s[31] << 24)<br />
<br />
<br />
extern "C" void __cdecl exit(int);<br />
<br />
inline char* __STRING_UNSCRAMBLE(const char s[], char clear[32], <br />
unsigned compileTimeChksum) <br />
{ <br />
unsigned curChksum = STRING_CHECKSUM(s);<br />
<br />
if (compileTimeChksum != curChksum) <br />
exit(0);<br />
<br />
char temp[] =<br />
STRING_SCRAMBLE(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], <br />
s[10], s[11], s[12], s[13], s[14], s[15], s[16], s[17], s[18], s[19], <br />
s[20], s[21], s[22], s[23], s[24], s[25], s[26], s[27], s[28], s[29],<br />
s[30], s[31]);<br />
<br />
for (unsigned i = 0; i < 32; i++)<br />
clear[i] = temp[i];<br />
<br />
return (char*)clear; <br />
};<br />
<br />
<br />
#define STRING_DECL(NAME) \<br />
extern const char NAME ## _Scrambled[]; \<br />
extern char NAME ## _Clear[32]; \<br />
extern const unsigned NAME ## _CheckSum;<br />
<br />
#define STRING_UNSCRAMBLE(NAME) \<br />
__STRING_UNSCRAMBLE(NAME ## _Scrambled, NAME ## _Clear, NAME ## _CheckSum)<br />
<br />
#define STRING_DEF(NAME, VALUE) \<br />
const char NAME ## _Scrambled[] = STRING_SCRAMBLE VALUE; \<br />
char NAME ## _Clear[32]; \<br />
const unsigned NAME ## _CheckSum = STRING_CHECKSUM(NAME ## _Scrambled);<br />
<br />
<br />
#endif
(Obviously, change the encryption key...)
Downside: hardcoded 32-character length for strings (could perhaps be expanded), and all the downsides CXR has. Benefits: does not require extra build step.
|
|
|
|
|
This could be probably expanded into something more general using the for example the template capabilities of the C++ preprocessor. And I hear even the C preprocessor is Turing complete...
So, who makes the most elegant solution?
Bonus point for arbitrary length strings (not hard-coded to 32 chars), unicode support,
public key encryption (no secret key in the binary), compression...
|
|
|
|
|
Chris:
First of all thanks for sharing your code.
When I try to crypt the string "\\LocalMachine\\SOFTWARE\\Classes\\CLSID\\{8F99C758-2F07-495d-8533-D1F2C4522108}\\" it just doesn't work.
I took out the final \\ and presto!
Is this a bug or a feature?
Sheers
Martin Jimenez
|
|
|
|
|
mjimenez wrote:
Is this a bug or a feature?
bug
easy enough to fix, though.
in CTokenizer::GetToken, in the switch statement in the middle, make the following change:
switch (*(pInput + i + 1))
{
case _T('"'):
out+= _T("\\\"");
i++;
continue;
break;
default:
--->
---> out+=c;
--->
---> out+=*(pInput + i + 1);
--->
---> i++;
continue;
break;
}
Image Toolkits | Image Processing | Cleek
|
|
|
|
|
I see now that the strings contain characters above 0x7F. To be safe, I'd suggest generating \x escapes, instead of putting the characters directly in the CPP file. For example instead of "|||" , generate "\x8a\x8f\x86" .
--Mike--
Just released - 1ClickPicGrabber - Grab & organize pictures from your favorite web pages, with 1 click!
My really out-of-date homepage
Sonork-100.19012 Acid_Helm
|
|
|
|
|