| ANSI C |
| Motorola PowerPC |
| Motorola 680x0 |
| New Variant (in ANSI C) |
| New Variant (in 16-bit x86 assembly language) |
Please feel free to use any of this code in your applications. The TEA algorithm (including new-variant TEA) has been placed in the public domain, as have my assembly language implementations.
void encipher(unsigned long *const v,unsigned long *const w,
const unsigned long *const k)
{
register unsigned long y=v[0],z=v[1],sum=0,delta=0x9E3779B9,
a=k[0],b=k[1],c=k[2],d=k[3],n=32;
while(n-->0)
{
sum += delta;
y += (z << 4)+a ^ z+sum ^ (z >> 5)+b;
z += (y << 4)+c ^ y+sum ^ (y >> 5)+d;
}
w[0]=y; w[1]=z;
}
void decipher(unsigned long *const v,unsigned long *const w,
const unsigned long *const k)
{
register unsigned long y=v[0],z=v[1],sum=0xC6EF3720,
delta=0x9E3779B9,a=k[0],b=k[1],
c=k[2],d=k[3],n=32;
/* sum = delta<<5, in general sum = delta * n */
while(n-->0)
{
z -= (y << 4)+c ^ y+sum ^ (y >> 5)+d;
y -= (z << 4)+a ^ z+sum ^ (z >> 5)+b;
sum -= delta;
}
w[0]=y; w[1]=z;
}
Motorola PowerPC (Metrowerks CodeWarrior Style)
asm void encipher(register const unsigned long * const v,
register unsigned long * const w,
register const unsigned long * const k)
{
// On entry, v = r3, w = r4, k = r5
// use r3 and r5 as scratch
// r0 = v[0]
// r6 = v[1]
// r7 - r10 = k[0] - k[3]
// r11 = sum
// r12 = delta
li r11,0 // sum = 0
li r12,0x79B9 // delta =0x9E3779B9
addis r12,r12,0x9E37
li r0,16 // loop counter into count register
mtctr r0
lwz r0,0(r3) // put the contents of v and k into the registers
lwz r6,4(r3)
lwz r7,0(r5)
lwz r8,4(r5)
lwz r9,8(r5)
lwz r10,12(r5)
loop: add r11,r11,r12 // sum += delta
slwi r5,r6,4 // z << 4
add r5,r5,r7 // (z << 4) + a
add r3,r6,r11 // z + sum
xor r3,r5,r3 // ((z << 4) + a) ^ (z + sum)
srwi r5,r6,5 // z >> 5
add r5,r5,r8 // (z >> 5) + b
xor r3,r5,r3 // ((z << 4)+a)^(z+sum)^((z >> 5)+b);
add r0,r0,r3 // y += result
slwi r5,r0,4 // y << 4
add r5,r5,r9 // (y << 4) +c
add r3,r0,r11 // y + sum
xor r3,r5,r3 // ((y << 4) +c) ^ (y + sum)
srwi r5,r0,5 // y >> 5
add r5,r5,r10 // (y >> 5) + d
xor r3,r5,r3 // ((y << 4)+c)^(y+sum)^((y >> 5)+d);
add r6,r6,r3 // z += result
bdnz+ loop // decrement CTR and branch
stw r0,0(r4) // store result back in w
stw r6,4(r4)
blr
}
asm void decipher(register const unsigned long * const v,
register unsigned long * const w,
register const unsigned long * const k)
{
// On entry, v = r3, w = r4, k = r5
// use r3 and r5 as scratch
// r0 = v[0]
// r6 = v[1]
// r7 - r10 = k[0] - k[3]
// r11 = sum
// r12 = delta
li r11,0x9B90; // sum =0xE3779B90
addis r11,r11,0xE378;
li r12,0x79B9 // delta =0x9E3779B9
addis r12,r12,0x9E37
li r0,16 // loop counter into count register
mtctr r0
lwz r0,0(r3) // put the contents of v and k into the registers
lwz r6,4(r3)
lwz r7,0(r5)
lwz r8,4(r5)
lwz r9,8(r5)
lwz r10,12(r5)
loop: slwi r5,r0,4 // y << 4
add r5,r5,r9 // (y << 4) + c
add r3,r0,r11 // y + sum
xor r3,r5,r3 // ((y << 4) + c) ^ (y + sum)
srwi r5,r0,5 // y >> 5
add r5,r5,r10 // (y >> 5) + d
xor r3,r5,r3 // ((y << 4)+c)^(y+sum)^((y >> 5)+d)
sub r6,r6,r3 // z -= result
slwi r5,r6,4 // z << 4
add r5,r5,r7 // (z << 4) + a
add r3,r6,r11 // z + sum
xor r3,r5,r3 // ((z << 4) + a) ^ (z + sum)
srwi r5,r6,5 // z >> 5
add r5,r5,r8 // (z >> 5) + b
xor r3,r5,r3 // ((z << 4)+a)^(z+sum)^((z >> 5)+b);
sub r0,r0,r3 // y -= result
sub r11,r11,r12 // sum -= delta
bdnz+ loop // decrement CTR and branch
stw r0,0(r4) // store result back in w
stw r6,4(r4)
blr
}
Motorola 680x0 (Metrowerks CodeWarrior style):
asm void encipher(const unsigned long* const v,unsigned long* const w,
const unsigned long* const k)
{
fralloc
movem.l d3-d7/a2,-(a7)
/* load initial registers
d0: y = v[0]
d1: z = v[1]
d2: a = k[0]
d3: b = k[1]
d4: c = k[2]
d5: loop counter (k[3] in a2)
d6: scratch register 1
d7: scratch register 2
a0: sum
a1: delta = 0x9E3779B9;
a2: d = k[3] */
move.l v,a0
move.l (a0),d0
move.l 4(a0),d1
move.l k,a0
move.l (a0),d2
move.l 4(a0),d3
move.l 8(a0),d4
move.l 12(a0),a2
move.l #0x9E3779B9,a0
move.l #0x9E3779B9,a1
moveq.l #15,d5 // sixteen rounds
// d6 = (z<<4)+a
loop: move.l d1,d6
lsl.l #4,d6
add.l d2,d6
// d7 = z+sum
move.l d1,d7
add.l a0,d7
// d7 = ((z<<4)+a)^(z+sum)
eor.l d6,d7
// d6 = (z>>5)+b
move.l d1,d6
lsr.l #5,d6
add.l d3,d6
// d7 = ((z<<4)+a)^(z+sum)^((z>>5)+b)
eor.l d6,d7
// add back into y
add.l d7,d0
// d6 = (y<<4)+c
move.l d0,d6
lsl.l #4,d6
add.l d4,d6
// d7 = y+sum
move.l d0,d7
add.l a0,d7
// d7 = ((y<<4)+c)^(y+sum)
eor.l d6,d7
// d6 = (y>>5)+d
move.l d0,d6
lsr.l #5,d6
add.l a2,d6
// d7 = ((y<<4)+c)^(y+sum)^((y>>5)+d)
eor.l d6,d7
// add back into z
add.l d7,d1
// sum+=delta
adda.l a1,a0
// branch back and do it again
dbra d5,loop
// place the result back into w
move.l w,a0
move.l d0,(a0)
move.l d1,4(a0)
movem.l (a7)+,d3-d7/a2
frfree
rts
}
asm void decipher(const unsigned long *const v,unsigned long *const w,
const unsigned long *const k)
{
fralloc
movem.l d3-d7/a2,-(a7)
/* load initial registers
d0: y = v[0]
d1: z = v[1]
d2: a = k[0]
d3: b = k[1]
d4: c = k[2]
d5: loop counter (k[3] in a2)
d6: scratch register 1
d7: scratch register 2
a0: sum = 0xE3779B90 (delta * 16)
a1: delta = 0x9E3779B9;
a2: d = k[3] */
move.l v,a0
move.l (a0),d0
move.l 4(a0),d1
move.l k,a0
move.l (a0),d2
move.l 4(a0),d3
move.l 8(a0),d4
move.l 12(a0),a2
move.l #0xE3779B90,a0
move.l #0x9E3779B9,a1
moveq.l #15,d5 // sixteen rounds
// d6 = (y<<4)+c
loop: move.l d0,d6
lsl.l #4,d6
add.l d4,d6
// d7 = y+sum
move.l d0,d7
add.l a0,d7
// d7 = ((y<<4)+c)^(y+sum)
eor.l d6,d7
// d6 = (y>>5)+d
move.l d0,d6
lsr.l #5,d6
add.l a2,d6
// d7 = ((y<<4)+c)^(y+sum)^((y>>5)+d)
eor.l d6,d7
// subtract from z
sub.l d7,d1
// d6 = (z<<4)+a
move.l d1,d6
lsl.l #4,d6
add.l d2,d6
// d7 = z+sum
move.l d1,d7
add.l a0,d7
// d7 = ((z<<4)+a)^(z+sum)
eor.l d6,d7
// d6 = (z>>5)+b
move.l d1,d6
lsr.l #5,d6
add.l d3,d6
// d7 = ((z<<4)+a)^(z+sum)^((z>>5)+b)
eor.l d6,d7
// subtract from y
sub.l d7,d0
// sum-=delta
suba.l a1,a0
// branch back and do it again
dbra d5,loop
// place the result back into w
move.l w,a0
move.l d0,(a0)
move.l d1,4(a0)
movem.l (a7)+,d3-d7/a2
frfree
rts
}
void encipher(const unsigned long *const v,unsigned long *const w,
const unsigned long * const k)
{
register unsigned long y=v[0],z=v[1],sum=0,delta=0x9E3779B9,n=32;
while(n-->0)
{
y += (z << 4 ^ z >> 5) + z ^ sum + k[sum&3];
sum += delta;
z += (y << 4 ^ y >> 5) + y ^ sum + k[sum>>11 & 3];
}
w[0]=y; w[1]=z;
}
void decipher(const unsigned long *const v,unsigned long *const w,
const unsigned long * const k)
{
register unsigned long y=v[0],z=v[1],sum=0xC6EF3720,
delta=0x9E3779B9,n=32;
/* sum = delta<<5, in general sum = delta * n */
while(n-->0)
{
z -= (y << 4 ^ y >> 5) + y ^ sum + k[sum>>11 & 3];
sum -= delta;
y -= (z << 4 ^ z >> 5) + z ^ sum + k[sum&3];
}
w[0]=y; w[1]=z;
}
Many thanks to Rafael R. Sevilla for contributing this version.
;; ;; An implementation of the XTEA algorithm in 16-bit 80x86 assembly ;; language. This should work on any processor in the 80x86 family ;; but works best with the 16-bit members of the family (80x86 for ;; x <= 2). This assembly language is suitable for use with linux-86 ;; and the as86 assembler, but should be fairly trivial to convert ;; so it will assemble with some other assembler easily. It has been ;; tested with 16-bit objects for Linux-8086 (ELKS), and should work ;; under DOS with the tiny and small memory models. To make it ;; work with the large and huge memory models, it will probably be ;; necessary to reset the parameters (bp+4 becomes bp+6 and so on), ;; and segment loads may need to be done as well (les and lds). ;; ;; Wasn't so easy to write because the number of registers available ;; on the 80x86 is kinda small...and they're 16-bit registers too! ;; ;; Placed in the Public Domain by Rafael R. Sevilla ;;;; .text export _xtea_encipher_asm _xtea_encipher_asm: push bp mov bp,sp sub sp,#14 ; space for y, z, sum, and n push si push di ;; bp+8 = pointer to key information ;; bp+6 = pointer to ciphertext to return to caller ;; bp+4 = pointer to plaintext ;; bp+2 = return address from caller ;; bp = pushed bp ;; bp-2 = y high word ;; bp-4 = y low word ;; bp-6 = z high word ;; bp-8 = z low word ;; bp-10 = sum high word ;; bp-12 = sum low word ;; bp-14 = n ;; bp-16 = pushed si ;; bp-18 = pushed di mov bx,[bp+4] ; get address of plaintext mov ax,[bx] ; low word of first dword of plaintext mov [bp-4],ax mov ax,[bx+2] ; high word mov [bp-2],ax mov ax,[bx+4] ; second dword of plaintext (low) mov [bp-8],ax mov ax,[bx+6] ; (high) mov [bp-6],ax xor ax,ax ; zero the sum initially mov [bp-10],ax mov [bp-12],ax mov byte ptr [bp-14],#32 ; set n (just 8 bits), # rounds ;; begin encryption encipher_rounds: ;; compute new y mov ax,[bp-8] ; low word z mov bx,[bp-6] ; high word z mov cx,ax ; copy to the rest of the registers mov dx,bx mov si,ax mov di,bx ;; (z<<4) ^ (z>>5) shl ax,#1 ; shift left once rcl bx,#1 shl ax,#1 ; shift twice rcl bx,#1 shl ax,#1 ; shift three times rcl bx,#1 shl ax,#1 ; shift four times rcl bx,#1 shr dx,#1 ; shift right once rcr cx,#1 shr dx,#1 ; shift right twice rcr cx,#1 shr dx,#1 ; shift right three times rcr cx,#1 shr dx,#1 ; shift right four times rcr cx,#1 shr dx,#1 ; shift right five times rcr cx,#1 xor ax,cx ; combine xor dx,bx ; dx:ax has result xor si,[bp-12] ; combine to sum xor di,[bp-10] add ax,si ; add them together adc dx,di mov bx,[bp-12] ; get low word of sum (all we need for this) and bx,#3 ; get low two bits (modulo 4) shl bx,#1 ; convert to dword offset shl bx,#1 add bx,[bp+8] ; add to base address of key info add ax,[bx] ; low word of key adc dx,[bx+2] ; high word of key add [bp-4],ax ; add back to y adc [bp-2],dx ;; update sum mov ax,#0x79b9 ; low word of delta add [bp-12],ax mov ax,#0x9e37 ; high word of delta adc [bp-10],ax ;; compute new z mov ax,[bp-4] ; low word of y mov bx,[bp-2] ; high word of y mov cx,ax ; copy to the rest of the registers mov dx,bx mov si,ax mov di,bx ;; (y<<4) ^ (y>>5) shl ax,#1 ; shift left once rcl bx,#1 shl ax,#1 ; shift twice rcl bx,#1 shl ax,#1 ; shift three times rcl bx,#1 shl ax,#1 ; shift four times rcl bx,#1 shr dx,#1 ; shift right once rcr cx,#1 shr dx,#1 ; shift right twice rcr cx,#1 shr dx,#1 ; shift right three times rcr cx,#1 shr dx,#1 ; shift right four times rcr cx,#1 shr dx,#1 ; shift right five times rcr cx,#1 xor ax,cx ; combine xor dx,bx ; dx:ax has result xor si,[bp-12] ; combine to sum xor di,[bp-10] add ax,si ; add them together adc dx,di mov bx,[bp-12] ; get sum low word mov cx,[bp-10] ; get sum high word shr cx,#1 ; shift right once rcr bx,#1 shr cx,#1 ; shift right twice rcr bx,#1 shr cx,#1 ; shift right three times rcr bx,#1 shr cx,#1 ; shift right four times rcr bx,#1 shr cx,#1 ; shift right five times rcr bx,#1 shr cx,#1 ; shift right six times rcr bx,#1 shr cx,#1 ; shift right seven times rcr bx,#1 shr cx,#1 ; shift right eight times rcr bx,#1 shr cx,#1 ; shift right nine times rcr bx,#1 shr cx,#1 ; shift right ten times rcr bx,#1 shr cx,#1 ; shift right eleven times rcr bx,#1 and bx,#3 shl bx,#1 ; convert to dword offset shl bx,#1 add bx,[bp+8] ; add to base address of key add ax,[bx] ; low word of key adc dx,[bx+2] ; high word of key add [bp-8],ax ; add back to z adc [bp-6],dx dec byte ptr [bp-14] ; decrement rounds counter jz finish_encipher jmp near encipher_rounds finish_encipher: mov bx,[bp+6] ; get address of ciphertext storage mov ax,[bp-4] ; y, low word mov [bx],ax mov ax,[bp-2] ; y, high word mov [bx+2],ax mov ax,[bp-8] ; z, low word mov [bx+4],ax mov ax,[bp-6] ; z, high word mov [bx+6],ax pop di pop si add sp,#14 ; discard local vars pop bp ret export _xtea_decipher_asm _xtea_decipher_asm: push bp mov bp,sp sub sp,#14 ; space for y, z, sum, and n push si push di ;; bp+8 = pointer to key information ;; bp+6 = pointer to plaintext to return to caller ;; bp+4 = pointer to ciphertext ;; bp+2 = return address from caller ;; bp = pushed bp ;; bp-2 = y high word ;; bp-4 = y low word ;; bp-6 = z high word ;; bp-8 = z low word ;; bp-10 = sum high word ;; bp-12 = sum low word ;; bp-14 = n ;; bp-16 = pushed si ;; bp-18 = pushed di mov bx,[bp+4] ; get address of ciphertext mov ax,[bx] ; low word of first dword of ciphertext mov [bp-4],ax mov ax,[bx+2] ; high word mov [bp-2],ax mov ax,[bx+4] ; second dword of ciphertext (low) mov [bp-8],ax mov ax,[bx+6] ; (high) mov [bp-6],ax mov ax,#0x3720 ; low word of initial sum mov [bp-12],ax mov ax,#0xc6ef mov [bp-10],ax mov byte ptr [bp-14],#32 ; set n (just 8 bits), # rounds ;; begin decryption decipher_rounds: mov ax,[bp-4] ; low word of y mov bx,[bp-2] ; high word of y mov cx,ax ; copy to the rest of the registers mov dx,bx mov si,ax mov di,bx ;; (y<<4) ^ (y>>5) shl ax,#1 ; shift left once rcl bx,#1 shl ax,#1 ; shift twice rcl bx,#1 shl ax,#1 ; shift three times rcl bx,#1 shl ax,#1 ; shift four times rcl bx,#1 shr dx,#1 ; shift right once rcr cx,#1 shr dx,#1 ; shift right twice rcr cx,#1 shr dx,#1 ; shift right three times rcr cx,#1 shr dx,#1 ; shift right four times rcr cx,#1 shr dx,#1 ; shift right five times rcr cx,#1 xor ax,cx ; combine xor dx,bx ; dx:ax has result xor si,[bp-12] ; combine to sum xor di,[bp-10] add ax,si ; add them together adc dx,di mov bx,[bp-12] ; get sum low word mov cx,[bp-10] ; get sum high word shr cx,#1 ; shift right once rcr bx,#1 shr cx,#1 ; shift right twice rcr bx,#1 shr cx,#1 ; shift right three times rcr bx,#1 shr cx,#1 ; shift right four times rcr bx,#1 shr cx,#1 ; shift right five times rcr bx,#1 shr cx,#1 ; shift right six times rcr bx,#1 shr cx,#1 ; shift right seven times rcr bx,#1 shr cx,#1 ; shift right eight times rcr bx,#1 shr cx,#1 ; shift right nine times rcr bx,#1 shr cx,#1 ; shift right ten times rcr bx,#1 shr cx,#1 ; shift right eleven times rcr bx,#1 and bx,#3 shl bx,#1 ; convert to dword offset shl bx,#1 add bx,[bp+8] ; add to base address of key add ax,[bx] ; low word of key adc dx,[bx+2] ; high word of key sub [bp-8],ax ; subtract from z sbb [bp-6],dx ;; update sum mov ax,#0x79b9 ; low word of delta sub [bp-12],ax mov ax,#0x9e37 ; high word of delta sbb [bp-10],ax ;; compute new y mov ax,[bp-8] ; low word z mov bx,[bp-6] ; high word z mov cx,ax ; copy to the rest of the registers mov dx,bx mov si,ax mov di,bx ;; (z<<4) ^ (z>>5) shl ax,#1 ; shift left once rcl bx,#1 shl ax,#1 ; shift twice rcl bx,#1 shl ax,#1 ; shift three times rcl bx,#1 shl ax,#1 ; shift four times rcl bx,#1 shr dx,#1 ; shift right once rcr cx,#1 shr dx,#1 ; shift right twice rcr cx,#1 shr dx,#1 ; shift right three times rcr cx,#1 shr dx,#1 ; shift right four times rcr cx,#1 shr dx,#1 ; shift right five times rcr cx,#1 xor ax,cx ; combine xor dx,bx ; dx:ax has result xor si,[bp-12] ; combine to sum xor di,[bp-10] add ax,si ; add them together adc dx,di mov bx,[bp-12] ; get low word of sum (all we need for this) and bx,#3 ; get low two bits (modulo 4) shl bx,#1 ; convert to dword offset shl bx,#1 add bx,[bp+8] ; add to base address of key info add ax,[bx] ; low word of key adc dx,[bx+2] ; high word of key sub [bp-4],ax ; subtract from y sbb [bp-2],dx dec byte ptr [bp-14] ; decrement rounds counter jz finish_decipher jmp near decipher_rounds finish_decipher: mov bx,[bp+6] ; get address of ciphertext storage mov ax,[bp-4] ; y, low word mov [bx],ax mov ax,[bp-2] ; y, high word mov [bx+2],ax mov ax,[bp-8] ; z, low word mov [bx+4],ax mov ax,[bp-6] ; z, high word mov [bx+6],ax pop di pop si add sp,#14 ; discard local vars pop bp ret