----------------------------------------------------------------------------- -- | -- Module : Codec.Encryption.TEA -- Copyright : (c) John Meacham 2008 -- License : BSD-style (see the file ReadMe.tex) -- -- Maintainer : john@repetae.net (http://repetae.net/) -- Stability : experimental -- Portability : portable -- -- Implementation of the TEA tiny encryption algorithm -- ----------------------------------------------------------------------------- module Codec.Encryption.TEA( TEAKey(TEAKey), encrypt, decrypt ) where import Data.Bits import Data.Word -- We don't use LargeKey for both efficiency and practical reasons. data TEAKey = TEAKey {-# UNPACK #-} !Word32 {-# UNPACK #-} !Word32 {-# UNPACK #-} !Word32 {-# UNPACK #-} !Word32 delta :: Word32 delta = 0x9e3779b9 rounds = 32 encrypt :: TEAKey -> Word64 -> Word64 encrypt (TEAKey k0 k1 k2 k3) v = f rounds 0 v0 v1 where v0,v1 :: Word32 v0 = fromIntegral v v1 = fromIntegral $ v `shiftR` 32 f a b c d | a `seq` b `seq` c `seq` d `seq` False = undefined f 0 _ v0 v1 = (fromIntegral v1 `shiftL` 32) .|. (fromIntegral v0 .&. 0xffffffff) f n sum v0 v1 = f (n - 1) sum' v0' v1' where sum' = sum + delta v0' = (v0 + (((v1 `shiftL` 4) + k0) `xor` (v1 + sum') `xor` ((v1 `shiftR` 5) + k1))) v1' = (v1 + (((v0' `shiftL` 4) + k2) `xor` (v0' + sum') `xor` ((v0' `shiftR` 5) + k3))) decrypt :: TEAKey -> Word64 -> Word64 decrypt (TEAKey k0 k1 k2 k3) v = f rounds 0xC6EF3720 v0 v1 where v0,v1 :: Word32 v0 = fromIntegral v v1 = fromIntegral $ v `shiftR` 32 f a b c d | a `seq` b `seq` c `seq` d `seq` False = undefined f 0 _ v0 v1 = (fromIntegral v1 `shiftL` 32) .|. (fromIntegral v0 .&. 0xFFFFFFFF) f n sum v0 v1 = f (n - 1) (sum - delta) v0' v1' where v1' = (v1 - (((v0 `shiftL` 4) + k2) `xor` (v0 + sum) `xor` ((v0 `shiftR` 5) + k3))) v0' = (v0 - (((v1' `shiftL` 4) + k0) `xor` (v1' + sum) `xor` ((v1' `shiftR` 5) + k1))) {- void encrypt (unsigned long* v, unsigned long* k) { unsigned long v0=v[0], v1=v[1], sum=0, i; /* set up */ unsigned long delta=0x9e3779b9; /* a key schedule constant */ unsigned long k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */ for (i=0; i < 32; i++) { /* basic cycle start */ sum += delta; v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1); v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3); /* end cycle */ } v[0]=v0; v[1]=v1; } void decrypt (unsigned long* v, unsigned long* k) { unsigned long v0=v[0], v1=v[1], sum=0xC6EF3720, i; /* set up */ unsigned long delta=0x9e3779b9; /* a key schedule constant */ unsigned long k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */ for (i=0; i<32; i++) { /* basic cycle start */ v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3); v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1); sum -= delta; /* end cycle */ } v[0]=v0; v[1]=v1; } -}