TEA Implementation

B

Ben Chivers

I am having a few difficulties with implementing the tiny encryption
algorithm (TEA) source code into a c program. I am rather new to c
programming and have very little experience in it. I am confused in
the way you send data to the sub-routines to encrypt and decrypt data.
I was using the following source code to encrypt a 4 letter string,
by it does not work. I am completely confused in how you can encrypt
strings with the algorithm. Any help with this would be most
appreciated!


#include <stdio.h>
#include <stdlib.h>

int main()
{
unsigned long v[2], k[4];
char endp[5];

v[0] = strtoul(" the", endp, 2);
k[0] = strtoul("key ", endp, 2);

code(v,k);

return 0;
}

void code(long* v, long* k) {
unsigned long y=v[0],z=v[1], sum=0, /* set up */
delta=0x9e3779b9, n=32 ; /* a key schedule constant */
while (n-->0) { /* basic cycle start */
sum += delta ;
y += (z<<4)+k[0] ^ z+sum ^ (z>>5)+k[1] ;
z += (y<<4)+k[2] ^ y+sum ^ (y>>5)+k[3] ; /* end cycle */
}
v[0]=y ; v[1]=z ; }
 
M

Mark A. Odell

(e-mail address removed) (Ben Chivers) wrote in

I am having a few difficulties with implementing the tiny encryption
algorithm (TEA) source code into a c program. I am rather new to c

I couldn't even read this code, here it is reformatted for humans. Hope
this helps.

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
unsigned long v[2];
unsigned long k[4];
char endp[5];

v[0] = strtoul(" the", endp, 2);
k[0] = strtoul("key ", endp, 2);

code(v, k);

return 0;
}

void code(long *v, long *k)
{
/* set up a key schedule constant */
unsigned long y = v[0];
unsigned long z = v[1];
unsigned long sum = 0;
unsigned long delta = 0x9e3779b9;
unsigned long n = 32;

while (n-- > 0)
{
/* basic cycle start */
sum += delta ;
y += (z << 4) + k[0] ^ z + sum ^ (z >> 5) + k[1];
z += (y << 4) + k[2] ^ y + sum ^ (y >> 5) + k[3];
/* end cycle */
}

v[0] = y;
v[1] = z;
}
 
M

Malcolm

Ben Chivers said:
#include <stdio.h>
#include <stdlib.h>

int main()
{
unsigned long v[2], k[4];
char endp[5];

v[0] = strtoul(" the", endp, 2);
k[0] = strtoul("key ", endp, 2);
This is a misuse of strtol(). strtol is designed to convert human-readable
number strings to computer-readable binaries. By passing " the" you are not
giving strtol() a human-readable number to convert.
I think what you wnat to do is to convert text to some sort of 32-bit
integer, based on a coding scheme (maybe ASCII, maybe something else).
In C, char variables can be treated either as characters or as small
integers, so in a sense the coding is done for you. You just need to pack
the letters into a long.
v[0] = (' ' << 24) | ('t' << 16) | ('h' << 8) | 'e';
code(v,k);

return 0;
}

void code(long* v, long* k)

/* it makes code much more readbale if you declar one variable per line */
/*
do you know what you're doing mixing signed and unsigned here ?
*/
unsigned long y=v[0],z=v[1], sum=0, /* set up */
delta=0x9e3779b9, n=32 ; /* a key schedule constant */
while (n-->0) { /* basic cycle start */
sum += delta ;
/*
put parentheses in here to disambiguate.
*/
y += (z<<4)+k[0] ^ z+sum ^ (z>>5)+k[1] ;
z += (y<<4)+k[2] ^ y+sum ^ (y>>5)+k[3] ; /* end cycle */
}
v[0]=y ; v[1]=z ; }

I trust that this function is doing what you want.
 
A

Arthur J. O'Dwyer

(e-mail address removed) (Ben Chivers) wrote...

I couldn't even read this code, here it is reformatted for humans. Hope
this helps.

Thanks, Mark. The OP should take note. Anyway, here's my take
on the original question...
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
unsigned long v[2];
unsigned long k[4];
char endp[5];

v[0] = strtoul(" the", endp, 2);
k[0] = strtoul("key ", endp, 2);

Misuse of 'strtoul'. 'strtoul' converts strings like "12345" into
numbers like 12345, not strings like " the" into numbers like
0x20716663. [I didn't bother looking up the real ASCII codes.]
code(v, k);

This implementation of TEA is obviously [to a good C programmer,
although certainly not to a novice] expecting you to pass it
pointers to the actual data. Like this:

code((long*)"the string to be encrypted", (long *)"the key");

Only a little bit worse than that; you see, the function is
designed to take only two longs' worth of data at a time (in
this case, it's obviously designed for 32-bit longs). So you
have to use a loop to do it [almost] right:

/* at the top of 'main' declare these */
char key[16] = "passwordpassword";
char plaintext[24] = "the text to be encrypted"; /* must be 8| */
char *p;
char *end = plaintext + sizeof plaintext;

for (p = plaintext; p < end; p += 2)
{
/* The casts are ugly, but required */
code((long*)p, (long*)key);
}
return 0;
}

void code(long *v, long *k)

This implementation of TEA is pretty awful, IMHO. It's poorly
named, takes parameters of the wrong type, doesn't even make a
pretense of being portable, and overwrites the plaintext with
the ciphertext rather than storing it in a new buffer. Also, it
has a hidden requirement: that the plaintext be exactly a multiple
of 8 bytes long [hence the cryptic comment next to plaintext[32]
above] -- otherwise it barfs.

The actual workings of TEA are "black magic" as far as I'm
concerned; all you need to know is that it wants you to pass it
4*4 = 16 bytes of keytext, and 2*4 = 8 bytes of plaintext, which
it will convert into 2*4 = 8 bytes of ciphertext and store
back in the plaintext buffer. And that it only works on systems
where 'long' is *exactly* 4 bytes long (and bytes are 8 bits wide).

Left in the rest of the code for the benefit of those who
come after me :), but no further comments.

-Arthur
{
/* set up a key schedule constant */
unsigned long y = v[0];
unsigned long z = v[1];
unsigned long sum = 0;
unsigned long delta = 0x9e3779b9;
unsigned long n = 32;

while (n-- > 0)
{
/* basic cycle start */
sum += delta ;
y += (z << 4) + k[0] ^ z + sum ^ (z >> 5) + k[1];
z += (y << 4) + k[2] ^ y + sum ^ (y >> 5) + k[3];
/* end cycle */
}

v[0] = y;
v[1] = z;
}
 
B

Ben Chivers

Arthur J. O'Dwyer said:
(e-mail address removed) (Ben Chivers) wrote...

I couldn't even read this code, here it is reformatted for humans. Hope
this helps.

Thanks, Mark. The OP should take note. Anyway, here's my take
on the original question...
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
unsigned long v[2];
unsigned long k[4];
char endp[5];

v[0] = strtoul(" the", endp, 2);
k[0] = strtoul("key ", endp, 2);

Misuse of 'strtoul'. 'strtoul' converts strings like "12345" into
numbers like 12345, not strings like " the" into numbers like
0x20716663. [I didn't bother looking up the real ASCII codes.]
code(v, k);

This implementation of TEA is obviously [to a good C programmer,
although certainly not to a novice] expecting you to pass it
pointers to the actual data. Like this:

code((long*)"the string to be encrypted", (long *)"the key");

Only a little bit worse than that; you see, the function is
designed to take only two longs' worth of data at a time (in
this case, it's obviously designed for 32-bit longs). So you
have to use a loop to do it [almost] right:

/* at the top of 'main' declare these */
char key[16] = "passwordpassword";
char plaintext[24] = "the text to be encrypted"; /* must be 8| */
char *p;
char *end = plaintext + sizeof plaintext;

for (p = plaintext; p < end; p += 2)
{
/* The casts are ugly, but required */
code((long*)p, (long*)key);
}
return 0;
}

void code(long *v, long *k)

This implementation of TEA is pretty awful, IMHO. It's poorly
named, takes parameters of the wrong type, doesn't even make a
pretense of being portable, and overwrites the plaintext with
the ciphertext rather than storing it in a new buffer. Also, it
has a hidden requirement: that the plaintext be exactly a multiple
of 8 bytes long [hence the cryptic comment next to plaintext[32]
above] -- otherwise it barfs.

The actual workings of TEA are "black magic" as far as I'm
concerned; all you need to know is that it wants you to pass it
4*4 = 16 bytes of keytext, and 2*4 = 8 bytes of plaintext, which
it will convert into 2*4 = 8 bytes of ciphertext and store
back in the plaintext buffer. And that it only works on systems
where 'long' is *exactly* 4 bytes long (and bytes are 8 bits wide).

Left in the rest of the code for the benefit of those who
come after me :), but no further comments.

-Arthur
{
/* set up a key schedule constant */
unsigned long y = v[0];
unsigned long z = v[1];
unsigned long sum = 0;
unsigned long delta = 0x9e3779b9;
unsigned long n = 32;

while (n-- > 0)
{
/* basic cycle start */
sum += delta ;
y += (z << 4) + k[0] ^ z + sum ^ (z >> 5) + k[1];
z += (y << 4) + k[2] ^ y + sum ^ (y >> 5) + k[3];
/* end cycle */
}

v[0] = y;
v[1] = z;
}

Heres my current code so far:

#include <stdio.h>
#include <stdlib.h>

void code(long* v, long* k);
void decode( long* v, long* k );

int main(char argc[], char *argv[])
{
char key[8] = "passwor";
char plaintext[24] = "the text to be encrypte"; /* must be 8| */
char *p, *d;
char *end = plaintext + sizeof(plaintext);

for (p = plaintext; p < end; p += 2)
{
/* The casts are ugly, but required */
code((long*)p, (long*)key);
}

printf("Encrypted String - %s\n", plaintext);

char *end2 = plaintext + sizeof(plaintext);

for (d = plaintext; d < end2; d += 2)
{
/* The casts are ugly, but required */
decode((long*)d, (long*)key);
}

printf("Decrypted String - %s\n", plaintext);
system("PAUSE");
return 0;
}

void code(long* v, long* k)
{
unsigned long y = v[0],
z = v[1],
sum = 0, /* set up */
delta = 0x9e3779b9,
n = 32; /* a key schedule constant */

while(n-- > 0) /* basic cycle start */
{ sum += delta;
y += (z << 4) + k[0] ^ z + sum ^ (z >> 5) + k[1];
z += (y << 4) + k[2] ^ y + sum ^ (y >> 5) + k[3];
} /* end cycle */

v[0] = y;
v[1] = z;
}

void decode( long* v, long* k )
{
unsigned long n = 32,
sum,
y = v[0],
z=v[1],
delta = 0x9e3779b9;

sum = delta << 5;
/* start cycle */
while(n-- > 0)
{ z -= (y << 4) + k[2] ^ y + sum ^ (y >> 5) + k[3];
y -= (z << 4) + k[0] ^ z + sum ^ (z >> 5) + k[1];
sum -= delta;
}
/* end cycle */
v[0] = y;
v[1] = z;
}

It compiles and runs fine. From what I know the string actual
encrypts fine, but when I try to decrypt the string which has just
been encrypted, it doesn't return as the original string.

I presume that the TEA function encrypts the variable plaintext and
returns the encrypted string to be stored in the same variable through
using pointers. Please remember I am only a beginner in this.

I appreciate the help so far.

Many Regards,
Ben Chivers
 
A

Arthur J. O'Dwyer

(e-mail address removed) (Ben Chivers) wrote...

I am having a few difficulties with implementing the tiny encryption
algorithm (TEA) source code into a c program. I am rather new to c

This implementation of TEA is pretty awful, IMHO. It's poorly
named, takes parameters of the wrong type, doesn't even make a
pretense of being portable, and overwrites the plaintext with
the ciphertext rather than storing it in a new buffer. Also, it
has a hidden requirement: that the plaintext be exactly a multiple
of 8 bytes long [hence the cryptic comment next to plaintext[32]
above] -- otherwise it barfs.

Okay, Ben, I've done my homework now, and I can safely say that
you've been misled by sloppy academic types. :) The original paper
on TEA, by Wheeler & Needham, is WRONG WRONG WRONG with respect to
the reference implementation they provide. They left out several
crucial pairs of parentheses, and both you and I were confused by
that. Rightly so.
The correct[ed?] code can be found at this site:
http://pandora.imt.uwm.edu/docs/tea.c
Note the extra parentheses in both functions.
Now, the C code that site adds on top of the corrected TEA code
is wrong, in that it doesn't check for strings that aren't of a
length evenly divisible by 32 bits. Also, if you watch their code
closely, you'll spot a rare idiocy hiding in the shadows:

datasize = 0 ? 1 : datasize;

Clever, eh? :)

Anyway, I've worked up a *COMPLETE* and hopefully *CORRECT*
implementation of TEA, and posted it on my website at
http://www.contrib.andrew.cmu.edu/~ajo/free-software/tea-example.c
Feel free to just grab and use that code as-is. But please watch
this newsgroup for the inevitable corrections that will follow. :)


Miscellaneous and hopefully moot comments:
Heres my current code so far:
char key[8] = "passwor";

You need a 16-byte key, not just 8 bytes.
char plaintext[24] = "the text to be encrypte"; /* must be 8| */

In the version I've posted to my site, I've patched that requirement.
You can now pass any length of data to the function, as long as you
accurately report its actual length.
char *p, *d;
char *end = plaintext + sizeof(plaintext);

for (p = plaintext; p < end; p += 2)

Should be 'p += 8', or alternatively declare 'p' as 'long *' to
begin with (or just use my version of the code ;).
y += (z << 4) + k[0] ^ z + sum ^ (z >> 5) + k[1];

Here's where the reference implementation is WRONG WRONG WRONG.
Change this line and the next one to match this outline:

y += (z << 4) + (k[0] ^ z) + (sum ^ (z >> 5)) + k[1];

Similarly in 'decode'.
I appreciate the help so far.

You're welcome. I'm quite pleased, actually -- I found out why
*my* TEA code wasn't working, too! :)

-Arthur
 
A

Arthur J. O'Dwyer

Anyway, I've worked up a *COMPLETE* and hopefully *CORRECT*
implementation of TEA, and posted it on my website at
http://www.contrib.andrew.cmu.edu/~ajo/free-software/tea-example.c
Feel free to just grab and use that code as-is. But please watch
this newsgroup for the inevitable corrections that will follow. :)

Aren't disclaimers wonderful? I should never, ever post code
without some rigorous testing! When I added the wrapper functions
that were supposed to let you encrypt any length of message, I
forgot that the encryption shuffles around bits within the blocks.
So I had worked it out so that (bad ASCII art)

n o r m a l m e s s a g e
|_|_|_|_|_|_|_|_I_|_|_|_|_|

would get silently padded to

n o r m a l m e s s a g e 0 0 0
|_|_|_|_|_|_|_|_I_|_|_|_|_|_|_|_|

(where '0' represents the null byte) and then encrypted to
something like

e n c r y p t e d m e s s a g e
|_|_|_|_|_|_|_|_I_|_|_|_|_|_|_|_|

but then would get stored back into the destination buffer
as a truncated version, like this:

e n c r y p t e d m e s s
|_|_|_|_|_|_|_|_I_|_|_|_|_|

which the decoding routine would pad out to

e n c r y p t e d m e s s 0 0 0
|_|_|_|_|_|_|_|_I_|_|_|_|_|_|_|_|

and then proceed to foul up the result. You'll get

n o r m a l m e g a r b a g e !
|_|_|_|_|_|_|_|_I_|_|_|_|_|_|_|_|

Whoops!
So the requirement for multiples of 8 bytes in encrypted
messages still applies. I guess there's no way around it.

HTH,
-Arthur
 
P

Peter Shaggy Haywood

Groovy hepcat Ben Chivers was jivin' on 23 Dec 2003 09:20:02 -0800 in
comp.lang.c.
TEA Implementation's a cool scene! Dig it!
I am having a few difficulties with implementing the tiny encryption
algorithm (TEA) source code into a c program. I am rather new to c
programming and have very little experience in it. I am confused in
the way you send data to the sub-routines to encrypt and decrypt data.
I was using the following source code to encrypt a 4 letter string,
by it does not work. I am completely confused in how you can encrypt
strings with the algorithm. Any help with this would be most
appreciated!

#include <stdio.h>
#include <stdlib.h>

int main()
{
unsigned long v[2], k[4];
char endp[5];

v[0] = strtoul(" the", endp, 2);

That's wrong. The second argument should be a pointer to pointer to
char. It should be the address of a pointer to char. But you are
passing an array of char (which converts to a pointer to char). This
is the wrong type, and makes no logical sense.
Also, the string in the first argument should contain digits at the
start, otherwise strtoul() will return 0 and set the pointer pointed
at by its second argument to point at the first character. Ovbiously
this is no good. It makes no sense. What are you trying to do,
exactly?
Only one array element is being used here. What do you need an array
for if you only use one element?
k[0] = strtoul("key ", endp, 2);

Same here.
code(v,k);

At this point code() is an undeclared function. A C90 compiler will
assume it returns an int, and will do no argument checking. A C99
compiler won't even accept it at all.
return 0;
}

void code(long* v, long* k) {
unsigned long y=v[0],z=v[1], sum=0, /* set up */

v[1] is uninitialised and, therefore, contains an indeterminate
value.
Set up what? This comment is useless. It doesn't do anithing to help
me understand the program. It does not explain the purpose of these
variables. All it does is clutter the code, making it harder to
understand.
delta=0x9e3779b9, n=32 ; /* a key schedule constant */

A what? Again, this comment really doesn't say much. It's slightly
more helpful that the previous one, but only because now I know that
either delta or n contains something called a key schedule constant
(whatever that is).
while (n-->0) { /* basic cycle start */

Ye gads! Seems like a rather confusing way of writing

for(n = 0; n < 32; n++)
{

Since the value of n is never used, except to control this loop, the
more usual form (as above) would be better.
And again, the comment is useless, and only clutters the code.
sum += delta ;
y += (z<<4)+k[0] ^ z+sum ^ (z>>5)+k[1] ;
z += (y<<4)+k[2] ^ y+sum ^ (y>>5)+k[3] ; /* end cycle */

k[1], k[2] and k[3] are uninitialised and, therefore, contain
indeterminate values. Since v[1] is uninitialised, z is based on an
indeterminate value and is, therefore, indeterminate itself.
And once again, the comment is useless. It is not clear how this
code is supposed to work, so a more useful comment that briefly,
succinctly describes what it is supposed to do would be in order.
}
v[0]=y ; v[1]=z ; }

The code is messy and inconsistently formatted, making it more
difficult to read. It contains utterly pointless comments that make
the situation even worse instead of making it easier to understand.
This dificulty is further exasperated by the lack of proper white
space and grouping of logically related statements. The way the code
is supposed to work is unclear, especially since you seem to be
seriously confused about C and have written the worst code I've seen
posted here in months! The program appears to have no input and no
output, unless I've missed something.
I know it seems like I'm being mean. I'm sorry! I don't mean to beat
you up. But look at this thing from our point of view. You post a
complete mess and tell us it doesn't work. You don't say how it's
supposed to work, nor even what "it does not work" means. (It won't
compile; compiles but crashes; compiles and runs but produces
incorrect output; what??? Be specific, please.)
I think you have chosen to write a program that is currently beyond
your C programming skills. You should probably write some simpler code
until you're more confident and compitent, and come back to this in a
few months.

--

Dig the even newer still, yet more improved, sig!

http://alphalink.com.au/~phaywood/
"Ain't I'm a dog?" - Ronny Self, Ain't I'm a Dog, written by G. Sherry & W. Walker.
I know it's not "technically correct" English; but since when was rock & roll "technically correct"?
 
A

Arthur J. O'Dwyer

The correct[ed?] code can be found at this site:
http://pandora.imt.uwm.edu/docs/tea.c

Does anyone have a simple way to read that link with correct line feeds on a
Windows machine? It is presented as one big line as I see it on my machine.

I use Netscape Navigator, which handles Unix-style linefeeds correctly.
That said, you can always try either
http://www.google.com/search?
q=cache:ufinmswLlXMJ:pandora.imt.uwm.edu/docs/tea.c
(which for some reason changes < to &lt;, & to &amp;, and so on),
or just download the file and view it in Word, Wordpad, or pretty
much any other smart editor. Notepad doesn't understand Unix-style
linefeeds, unfortunately.

HTH,
-Arthur
 
M

Mark A. Odell

Yeaaa! Works with Wordpad. All I needed was the motivation, the belief
that it might actually work with *something*. I still don't know what
"write" is, sounds like a Macintosh program to me.

It has come with Windows since v3.0 I believe.
 
K

Kevin Goodsell

Arthur said:
Arthur J. O'Dwyer writes:

The correct[ed?] code can be found at this site:
http://pandora.imt.uwm.edu/docs/tea.c

Does anyone have a simple way to read that link with correct line feeds on a
Windows machine? It is presented as one big line as I see it on my machine.


I use Netscape Navigator,

Oh, so *you're* the one. ;)

The file is being served as text/plain, which should be correct. What I
don't know is how text/plain resources are supposed to represent
newlines, and what, if any, translation is supposed to be done by the
client. Mozilla Firebird, Internet Explorer, and Links all seem to
display it correctly. IE converted the newlines on saving, Firebird
saved it as-is. I didn't try saving it in Links.
which handles Unix-style linefeeds correctly.
That said, you can always try either
http://www.google.com/search?
q=cache:ufinmswLlXMJ:pandora.imt.uwm.edu/docs/tea.c
(which for some reason changes < to &lt;, & to &amp;, and so on),
or just download the file and view it in Word, Wordpad, or pretty
much any other smart editor. Notepad doesn't understand Unix-style
linefeeds, unfortunately.

Yes, the answer to the question ("Does anyone have a simple way to read
that link with correct line feeds...") is "Use a decent editor" (or a
decent browser (Internet Explorer also works, apparently), depending one
what exactly was meant).

-Kevin
 
O

osmium

Mark said:
Loads perfectly in my Win32-based editor: CodeWright. Try reading the file
with write instead of notepad.

Yeaaa! Works with Wordpad. All I needed was the motivation, the belief
that it might actually work with *something*. I still don't know what
"write" is, sounds like a Macintosh program to me.
 
J

Joe Wright

Mark said:
It has come with Windows since v3.0 I believe.
I don't think so. write.exe got left behind with Windows 3.11. Windows
95 gave us Wordpad in its stead. Attempting to invoke write will get you
Wordpad. Opening a .wri file will get you Wordpad.
 
M

Mark A. Odell

I don't think so. write.exe got left behind with Windows 3.11. Windows
95 gave us Wordpad in its stead. Attempting to invoke write will get you
Wordpad. Opening a .wri file will get you Wordpad.

Yes! I was wrong and dating myself a bit. My memory fades as time goes on.
If you launch write.exe WordPad does, in fact, run. Nonetheless,
write/wordpad have the ability to handle LF EOLs and it's been around in
some form for quite some time.
 

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

No members online now.

Forum statistics

Threads
474,125
Messages
2,570,748
Members
47,302
Latest member
MitziWragg

Latest Threads

Top