encrypting with preprocessor

G

Gernot Frisch

cat tmp.c
#include <stdio.h>

#define CRYPT8(str) { CRYPT8_(str "\0\0\0\0\0\0\0\0") }
#define CRYPT8_(str) \
(str)[2],(str)[3],(str)[4],(str)[5],(str)[6],(str)[7],'\0'

int main(void)
{
const char str[] = CRYPT8("KungFu");
puts(strcmp(str,"ngFu") ? "KO" : "OK");
}
gcc tmp.c -o tmp
./tmp OK
strings ./tmp | grep "KungFu" | wc -l
0

the string "KungFu" is *not* in the binary. Impossible?


Now I've got it!!!!!! I have to provide the macro "CRYPT8_" for the
maximum characters used ever. So, longer strings will be trimmed right
side. If I use a max of 128, that will suffice for every line in my
code.
Excellent idea!
 
L

Laurent Deniau

Gernot said:
cat tmp.c

#include <stdio.h>

#define CRYPT8(str) { CRYPT8_(str "\0\0\0\0\0\0\0\0") }
#define CRYPT8_(str) \
(str)[2],(str)[3],(str)[4],(str)[5],(str)[6],(str)[7],'\0'

int main(void)
{
const char str[] = CRYPT8("KungFu");
puts(strcmp(str,"ngFu") ? "KO" : "OK");
}
gcc tmp.c -o tmp
./tmp
OK

strings ./tmp | grep "KungFu" | wc -l

0

the string "KungFu" is *not* in the binary. Impossible?



Now I've got it!!!!!! I have to provide the macro "CRYPT8_" for the
maximum characters used ever. So, longer strings will be trimmed right
side. If I use a max of 128, that will suffice for every line in my
code.
Excellent idea!

Note two small things, first I forgot to include string.h, second this
is c99 and not c89 since it uses array indexing which is not constant
(!), i.e. (str)[2] <=> *(str+2) and indirection cannot be computed at
compile time even if str is a literal string. Therefore the variable str
in the example above cannot have static storage class (e.g. static or
global). I hope that it is still what you were looking for.

a+, ld.
 
R

Rod Pemberton

Laurent Deniau said:
Rod said:
Hi,

I want to build a encryption macro set, that can crypt:

char secret[] = CRYPT("KungFu");

to anything unreadable, and then have a function:
char* DECRYPT(char* str)
{
...
}

I think it would be suffictient to encrypt a maximum of 16 characters.
Simple XOR would suffice, too. Any ideas of how that can be done?


I don't believe that using the preprocessor is the best solution, but here
is a simple solution:

#define _S(x) #x
#define _T(a,b,c,d,e,f) _S(a ## b ## c ## d ## e ## f)
#define CRYPT(a,b,c,d,e,f) _T(a,b,c,d,e,f)

/* define aliases for each letter, limited to _A-Za-z0-9 */
/* or you can use specific char's, say '!', directly in txt1 */
#define _CK A
#define _Cu z
#define _Cn y
#define _Cg q
#define _CF p

int main(void)
{

char txt1[]=CRYPT(_CK,_Cu,_Cn,_Cg,_CF,_Cu);

Why don't you concatenate the _C prefix in the CRYPT macro?

#define CRYPT(a,b,c,d,e,f) _T(_C##a,_C##b,_C##c,_C##d,_C##e,_C##f)

Because it doesn't work... at least with the compilers I use. If it works
for the OP's, great! It's another thing he can use.

This is the problem that occurs for me:
if a=K, _C##a will become _CK, but _CK won't be replaced with A.

You'll need to turn on preprocessing only with your compiler. For GCC,
it's -E option. For OpenWatcom, it's -p option. For others, you'll need to
check your documentation.
Then you can directly write:

char txt1[]=CRYPT(K,u,n,g,F,u);
char *secret=txt1;

}

That is probably about as much "encryption" as you would ever want to do
with the preprocessor. Anything further will be a nightmare to implement
properly.

Why?

IMO, limitations of the preprocessor to do text replacement. It was very
difficult to come up with an example that worked the same way for both DJGPP
and OW. Things that worked on one didn't work on the other and vice versa.
The preprocessor isn't intended to be a full string library capable of doing
encryption. In a few lines of mostly non-preprocessor C code, he could do
everything he wants without much hassle.



Rod Pemberton
 
L

Laurent Deniau

Rod said:
Rod said:
is a simple solution:

#define _S(x) #x
#define _T(a,b,c,d,e,f) _S(a ## b ## c ## d ## e ## f)
#define CRYPT(a,b,c,d,e,f) _T(a,b,c,d,e,f)

/* define aliases for each letter, limited to _A-Za-z0-9 */
/* or you can use specific char's, say '!', directly in txt1 */
#define _CK A
#define _Cu z
#define _Cn y
#define _Cg q
#define _CF p

int main(void)
{

char txt1[]=CRYPT(_CK,_Cu,_Cn,_Cg,_CF,_Cu);

Why don't you concatenate the _C prefix in the CRYPT macro?

#define CRYPT(a,b,c,d,e,f) _T(_C##a,_C##b,_C##c,_C##d,_C##e,_C##f)


Because it doesn't work... at least with the compilers I use.

Oops. I forgot to add has the intermediate expansion macro:

#define _T0(a,b,c,d,e,f) _T(a,b,c,d,e,f)
#define CRYPT(a,b,c,d,e,f) _T0(_C##a,_C##b,_C##c,_C##d,_C##e,_C##f)

now this should work.

char txt1[]=CRYPT(K,u,n,g,F,u);
> gcc -P -E tmp.c
int main(void)
{
char txt1[]="Azyqpz";
}

Do you mean something like ;-) :

/* concatenate LIST1 and LIST2 */
#define cos_PPL_CAT(LIST1,LIST2) \
(cos_PP_ADD(cos_PP_LEN(LIST1),cos_PP_LEN(LIST2)), \
(cos_PP_IF(cos_PP_AND(cos_PP_LEN(LIST1),cos_PP_LEN(LIST2)), \
cos_PP_PAIR,cos_PP_CONS) \
(cos_PPL_TUPLE(LIST1),cos_PPL_TUPLE(LIST2))))

/* concatenate the LIST elements */
#define cos_PPL_ECAT(LIST) \
cos_PPL_APPLY(cos_PP_DECR(cos_PP_LEN(LIST)),cos_PPL_ECAT_,LIST)
#define cos_PPL_ECAT_(LIST) cos_PPL_CAT( \
(1, (cos_PP_CAT(cos_PPL_ELEM(0,LIST),cos_PPL_ELEM(1,LIST)))), \
cos_PPL_TAIL(cos_PP_SUB(cos_PP_LEN(LIST),2),LIST))
IMO, limitations of the preprocessor to do text replacement. It was very
difficult to come up with an example that worked the same way for both DJGPP
and OW. Things that worked on one didn't work on the other and vice versa.

It is clear that porting code to a non ISO C99 preprocessor can be a
nightmare. But in that case, I just throw away the cpp and take a
compliant one (e.g. ucpp).
The preprocessor isn't intended to be a full string library capable of doing
encryption. In a few lines of mostly non-preprocessor C code, he could do
everything he wants without much hassle.

Once you have a "user-friendly" package of macros to deal with lists of
tokens, much can be done easily, especially for generating C code.

a+, ld.
 
R

Rod Pemberton

Laurent Deniau said:
Rod said:
Rod Pemberton wrote:
is a simple solution:

#define _S(x) #x
#define _T(a,b,c,d,e,f) _S(a ## b ## c ## d ## e ## f)
#define CRYPT(a,b,c,d,e,f) _T(a,b,c,d,e,f)

/* define aliases for each letter, limited to _A-Za-z0-9 */
/* or you can use specific char's, say '!', directly in txt1 */
#define _CK A
#define _Cu z
#define _Cn y
#define _Cg q
#define _CF p

int main(void)
{

char txt1[]=CRYPT(_CK,_Cu,_Cn,_Cg,_CF,_Cu);

Why don't you concatenate the _C prefix in the CRYPT macro?

#define CRYPT(a,b,c,d,e,f) _T(_C##a,_C##b,_C##c,_C##d,_C##e,_C##f)


Because it doesn't work... at least with the compilers I use.

Oops. I forgot to add has the intermediate expansion macro:

#define _T0(a,b,c,d,e,f) _T(a,b,c,d,e,f)
#define CRYPT(a,b,c,d,e,f) _T0(_C##a,_C##b,_C##c,_C##d,_C##e,_C##f)

now this should work.

char txt1[]=CRYPT(K,u,n,g,F,u);
gcc -P -E tmp.c
int main(void)
{
char txt1[]="Azyqpz";
}

Yes, and no for me. It works for me with OWv1.3. It fails with DJGPP's gcc
v3.4.1 and gcc v4.1.0. Is DJGPP's preprocessor broken?
Do you mean something like ;-) :

/* concatenate LIST1 and LIST2 */
#define cos_PPL_CAT(LIST1,LIST2) \
(cos_PP_ADD(cos_PP_LEN(LIST1),cos_PP_LEN(LIST2)), \
(cos_PP_IF(cos_PP_AND(cos_PP_LEN(LIST1),cos_PP_LEN(LIST2)), \
cos_PP_PAIR,cos_PP_CONS) \
(cos_PPL_TUPLE(LIST1),cos_PPL_TUPLE(LIST2))))

/* concatenate the LIST elements */
#define cos_PPL_ECAT(LIST) \
cos_PPL_APPLY(cos_PP_DECR(cos_PP_LEN(LIST)),cos_PPL_ECAT_,LIST)
#define cos_PPL_ECAT_(LIST) cos_PPL_CAT( \
(1, (cos_PP_CAT(cos_PPL_ELEM(0,LIST),cos_PPL_ELEM(1,LIST)))), \
cos_PPL_TAIL(cos_PP_SUB(cos_PP_LEN(LIST),2),LIST))

Any pointers for "taming the nightmare"? I could use them.
versa.

It is clear that porting code to a non ISO C99 preprocessor can be a
nightmare. But in that case, I just throw away the cpp and take a
compliant one (e.g. ucpp).

Nice. I don't recall seeing that one. Thanks, here's the link for others:
http://pornin.nerim.net/ucpp/
Once you have a "user-friendly" package of macros to deal with lists of
tokens, much can be done easily, especially for generating C code.

Later,

Rod Pemberton
 
L

Laurent Deniau

Rod said:
Yes, and no for me. It works for me with OWv1.3. It fails with DJGPP's gcc
v3.4.1 and gcc v4.1.0. Is DJGPP's preprocessor broken?

It works with 4.0.3 but I suspect that gcc4.1.0 to be more compliant
because according to 6.10.3.1-1, I suspect the ## operator to be applied
before parameter substitution. But anyway it is easy to force the
parameter substitution by delaying the action of ## by one level:

#define _S(x) #x
#define _C(x) _C##x
#define _T(a,b,c,d,e,f) _S(a ## b ## c ## d ## e ## f)
#define _T0(a,b,c,d,e,f) _T(a,b,c,d,e,f)
#define CRYPT(a,b,c,d,e,f) _T0(_C(a),_C(b),_C(c),_C(d),_C(e),_C(f))

#define _CK A
#define _Cu z
#define _Cn y
#define _Cg q
#define _CF p

int main(void)
{
char txt1[]=CRYPT(K,u,n,g,F,u);
}
Any pointers for "taming the nightmare"? I could use them.

No, as I said, I have a cpp (c99) "package" to manipulate list of tokens
and the macros above are just a small part of this "package". No doc, no
warranty but I can provide a tarball on request. The advantage of macros
is that they do not need makefile, just a -I directive ;-)
Nice. I don't recall seeing that one. Thanks, here's the link for others:
http://pornin.nerim.net/ucpp/

Yes, that is why for portability issue I use c99cpp + c89core since I
always can rely on this level ;-) I find the variadic macros very useful
(one of the best thing introduced by c99).

a+, ld.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top