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