;;;; -*- coding:utf-8 -*-
;;;;**************************************************************************
;;;;FILE: tea.lisp
;;;;LANGUAGE: Common-Lisp
;;;;SYSTEM: Common-Lisp
;;;;USER-INTERFACE: NONE
;;;;DESCRIPTION
;;;;
;;;; Implementation of the TEA
;;;; Tiny Encryption Algorith
;;;;
;;;;
;;;;AUTHORS
;;;; Pascal Bourguignon
;;;;MODIFICATIONS
;;;; 2006-03-20 Created.
;;;;BUGS
;;;;TODO
;;;; Implement the new variant.
;;;;LEGAL
;;;; GPL
;;;;
;;;; Copyright Pascal Bourguignon 2006 - 2006
;;;;
;;;; This program is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU General Public License
;;;; as published by the Free Software Foundation; either version
;;;; 2 of the License, or (at your option) any later version.
;;;;
;;;; This program is distributed in the hope that it will be
;;;; useful, but WITHOUT ANY WARRANTY; without even the implied
;;;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
;;;; PURPOSE. See the GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public
;;;; License along with this program; if not, write to the Free
;;;; Software Foundation, Inc., 59 Temple Place, Suite 330,
;;;; Boston, MA 02111-1307 USA
;;;;**************************************************************************
(IN-PACKAGE "COMMON-LISP-USER")
(DEFPACKAGE "COM.INFORMATIMAGO.COMMON-LISP.TEA"
(:USE "COMMON-LISP")
(:EXPORT "TEA-DECIPHER" "TEA-ENCIPHER")
(:DOCUMENTATION
"This package imlements the TEA, Tiny Encryption Algorithm.
http://www.simonshepherd.supanet.com/tea.htm
Copyright Pascal J. Bourguignon 2006 - 2006
This package is provided under the GNU General Public License.
See the source file for details."))
(IN-PACKAGE "COM.INFORMATIMAGO.COMMON-LISP.TEA")
(eval-when (:compile-toplevel :load-toplevel :execute) (defconstant +n+ 32))
(defun op (x a b sum) (logxor (+ (ash x 4) a) (+ x sum) (+ (ash x -5) b)))
(declaim (inline op))
(defmacro ciploop ((v w k y z a b c d (sum init-sum) delta) &body body)
`(let ((,y (aref ,v 0)) (,z (aref ,v 1))
(,sum ,init-sum) (,delta #x9E3779B9)
(,a (aref ,k 0)) (,b (aref ,k 1))
(,c (aref ,k 2)) (,d (aref ,k 3)))
(loop repeat +n+ do ,@body finally (setf (aref ,w 0) ,y (aref ,w 1) ,z))))
(defmacro c-incf (var expr) `(setf ,var (mod (+ ,var ,expr) #x100000000)))
(defmacro c-decf (var expr) `(setf ,var (mod (- ,var ,expr) #x100000000)))
(defun tea-encipher (v w k)
(ciploop (v w k y z a b c d (sum 0) delta)
(c-incf sum delta) (c-incf y (op z a b sum)) (c-incf z (op y c d sum))))
(defun tea-decipher (v w k)
(ciploop (v w k y z a b c d (sum #.(mod (* +n+ #x9E3779B9) #x100000000)) delta)
(c-decf z (op y c d sum)) (c-decf y (op z a b sum)) (c-decf sum delta)))
#||
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;
}
||#
#||
ANSI C (New Variant)
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;
}
||#
(defun word (a b c d)
(dpb a (byte 8 24) (dpb b (byte 8 16) (dpb c (byte 8 8) d))))
(defun read-words (bits what)
(loop
for bytes = (progn (format t "Please enter ~D bits of ~A: "
bits what)
(let ((buffer (read-line *standard-input* nil nil)))
(when buffer
#+clisp
(ext:convert-string-to-bytes
buffer ext:*TERMINAL-ENCODING*)
#-clisp
(coerce (loop :for ch :in buffer
:collect (char-code ch)) 'vector))))
while (and bytes (< (* 8 (length bytes)) bits))
finally (return
(and bytes
(loop for i from 0 by 4 below (truncate (+ 7 bits) 8)
collect (word (aref bytes (+ i 0))
(aref bytes (+ i 1))
(aref bytes (+ i 2))
(aref bytes (+ i 3))) into words
finally (return (coerce words 'vector)))))))
(defun test ()
(loop
with code = (vector 0 0)
with decr = (vector 0 0)
for clear = (prog1 (read-words 64 "clear text") (terpri))
for key = (prog1 (read-words 128 "key") (terpri))
while (and clear key)
do (progn (tea-encipher clear code key)
(format t "(encipher ~S ~S)~% --> ~S~%" clear key code)
(tea-decipher code decr key)
(format t "(decipher ~S ~S)~% --> ~S~%" code key decr)
(unless (equalp clear decr) (format t "!!! ERROR !!!~%")))))
(defun auto-test ()
(with-input-from-string (*standard-input*
"Hello World!
John McCarthy invented LISP.
Big Unknown Secret.
Very very secret key. Forget it!
")
(test)))