module Crypto.Cipher.AES ( Key , encrypt , decrypt , initKey128 -- * those key sizes are not actually working right now. , initKey192 , initKey256 ) where import Data.Word import Data.Vector.Unboxed (Vector, (//)) import qualified Data.Vector.Unboxed as V import Data.List (foldl') import Data.Bits import Data.ByteString (ByteString) import qualified Data.ByteString as B import qualified Data.ByteString.Unsafe as B newtype Key = Key (Vector Word8) deriving (Show,Eq) type AESState = Vector Word8 {- | encrypt with the key a bytestring and returns the encrypted bytestring -} encrypt :: Key -> B.ByteString -> B.ByteString encrypt key b | B.length b `mod` 16 == 0 = B.concat $ doChunks (coreEncrypt key) b | otherwise = error "wrong length" {- | decrypt with the key a bytestring and returns the encrypted bytestring -} decrypt :: Key -> B.ByteString -> B.ByteString decrypt key b | B.length b `mod` 16 == 0 = B.concat $ doChunks (coreDecrypt key) b | otherwise = error "wrong length" doChunks :: (B.ByteString -> B.ByteString) -> B.ByteString -> [B.ByteString] doChunks f b = let (x, rest) = B.splitAt 16 b in if B.length rest >= 16 then f x : doChunks f rest else [ f x ] coreEncrypt :: Key -> ByteString -> ByteString coreEncrypt key input = swapBlockInv $ aesMain 10 key $ swapBlock input coreDecrypt :: Key -> ByteString -> ByteString coreDecrypt key input = swapBlockInv $ aesMainInv 10 key $ swapBlock input initKey128 :: ByteString -> Either String Key initKey128 = initKey 16 10 initKey192 :: ByteString -> Either String Key initKey192 = initKey 24 12 initKey256 :: ByteString -> Either String Key initKey256 = initKey 32 14 initKey :: Int -> Int -> ByteString -> Either String Key initKey sz nbr b | B.length b == sz = Right $ coreExpandKey nbr (V.generate sz $ B.unsafeIndex b) | otherwise = Left "wrong key size" aesMain :: Int -> Key -> AESState -> AESState aesMain nbr key block = addRoundKey key nbr $! shiftRows $! mrounds $! addRoundKey key 0 block where mrounds b = foldl' (\bk i -> addRoundKey key i $! mixColumns $! shiftRows bk) b [1..nbr-1] aesMainInv :: Int -> Key -> AESState -> AESState aesMainInv nbr key block = addRoundKey key 0 $! shiftRowsInv $! mrounds $! addRoundKey key nbr block where mrounds b = foldl' (\bk i -> mixColumnsInv $! addRoundKey key i $! shiftRowsInv bk) b (reverse [1..nbr-1]) {- 0 -> 0, 1 -> 4, ... -} swapIndexes :: Vector Int swapIndexes = V.fromList [ 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 ] swapIndex :: Int -> Int swapIndex i = V.unsafeIndex swapIndexes i coreExpandKey :: Int -> Vector Word8 -> Key coreExpandKey nbr vkey = Key (V.concat (ek0 : ekN)) where ek0 = vkey ekN = reverse $ snd $ foldl generateFold (ek0, []) [1..nbr] generateFold (prevk, accK) it = let nk = generate prevk it in (nk, nk : accK) generate prevk it = let v0 = cR0 it (V.unsafeIndex prevk 12) (V.unsafeIndex prevk 13) (V.unsafeIndex prevk 14) (V.unsafeIndex prevk 15) in let (e0,e1,e2,e3) = xorVector prevk 0 v0 in let (e4,e5,e6,e7) = xorVector prevk 4 (e0,e1,e2,e3) in let (e8,e9,e10,e11) = xorVector prevk 8 (e4,e5,e6,e7) in let (e12,e13,e14,e15) = xorVector prevk 12 (e8,e9,e10,e11) in V.fromList [e0,e1,e2,e3,e4,e5,e6,e7,e8,e9,e10,e11,e12,e13,e14,e15] xorVector k i (t0,t1,t2,t3) = ( V.unsafeIndex k (i+0) `xor` t0 , V.unsafeIndex k (i+1) `xor` t1 , V.unsafeIndex k (i+2) `xor` t2 , V.unsafeIndex k (i+3) `xor` t3 ) cR0 it r0 r1 r2 r3 = (mSbox r1 `xor` mRcon it, mSbox r2, mSbox r3, mSbox r0) shiftRows :: AESState -> AESState shiftRows ost = let st = V.map mSbox ost in st // [ (7, V.unsafeIndex st 4), (4, V.unsafeIndex st 5), (5, V.unsafeIndex st 6), (6, V.unsafeIndex st 7) , (10, V.unsafeIndex st 8), (11, V.unsafeIndex st 9), (8, V.unsafeIndex st 10), (9, V.unsafeIndex st 11) , (13, V.unsafeIndex st 12), (14, V.unsafeIndex st 13), (15, V.unsafeIndex st 14), (12, V.unsafeIndex st 15) ] addRoundKey :: Key -> Int -> AESState -> AESState addRoundKey (Key key) i = V.zipWith (\v1 v2 -> v1 `xor` v2) rk where rk = V.generate 16 (\n -> V.unsafeIndex key (16 * i + swapIndex n)) mixColumns :: AESState -> AESState mixColumns state = let (state0, state4, state8, state12) = pr 0 in let (state1, state5, state9, state13) = pr 1 in let (state2, state6, state10, state14) = pr 2 in let (state3, state7, state11, state15) = pr 3 in state // [ (0,state0), (1,state1), (2,state2), (3,state3) , (4,state4), (5,state5), (6,state6), (7,state7) , (8,state8), (9,state9), (10,state10), (11,state11) , (12,state12), (13,state13), (14,state14), (15,state15) ] where pr i = let cpy0 = V.unsafeIndex state (0 * 4 + i) in let cpy1 = V.unsafeIndex state (1 * 4 + i) in let cpy2 = V.unsafeIndex state (2 * 4 + i) in let cpy3 = V.unsafeIndex state (3 * 4 + i) in (gm2 cpy0 `xor` gm1 cpy3 `xor` gm1 cpy2 `xor` gm3 cpy1 ,gm2 cpy1 `xor` gm1 cpy0 `xor` gm1 cpy3 `xor` gm3 cpy2 ,gm2 cpy2 `xor` gm1 cpy1 `xor` gm1 cpy0 `xor` gm3 cpy3 ,gm2 cpy3 `xor` gm1 cpy2 `xor` gm1 cpy1 `xor` gm3 cpy0) gm1 a = a gm2 a = V.unsafeIndex gmtab2 $ fromIntegral a gm3 a = V.unsafeIndex gmtab3 $ fromIntegral a shiftRowsInv :: AESState -> AESState shiftRowsInv st = let nst = st // [ (5, V.unsafeIndex st 4), (6, V.unsafeIndex st 5), (7, V.unsafeIndex st 6), (4, V.unsafeIndex st 7) , (10, V.unsafeIndex st 8), (11, V.unsafeIndex st 9), (8, V.unsafeIndex st 10), (9, V.unsafeIndex st 11) , (15, V.unsafeIndex st 12), (12, V.unsafeIndex st 13), (13, V.unsafeIndex st 14), (14, V.unsafeIndex st 15) ] in V.map mRsbox nst mixColumnsInv :: AESState -> AESState mixColumnsInv state = let (state0, state4, state8, state12) = pr 0 in let (state1, state5, state9, state13) = pr 1 in let (state2, state6, state10, state14) = pr 2 in let (state3, state7, state11, state15) = pr 3 in state // [ (0,state0), (1,state1), (2,state2), (3,state3) , (4,state4), (5,state5), (6,state6), (7,state7) , (8,state8), (9,state9), (10,state10), (11,state11) , (12,state12), (13,state13), (14,state14), (15,state15) ] where pr i = let cpy0 = V.unsafeIndex state (0 * 4 + i) in let cpy1 = V.unsafeIndex state (1 * 4 + i) in let cpy2 = V.unsafeIndex state (2 * 4 + i) in let cpy3 = V.unsafeIndex state (3 * 4 + i) in (gm14 cpy0 `xor` gm9 cpy3 `xor` gm13 cpy2 `xor` gm11 cpy1 ,gm14 cpy1 `xor` gm9 cpy0 `xor` gm13 cpy3 `xor` gm11 cpy2 ,gm14 cpy2 `xor` gm9 cpy1 `xor` gm13 cpy0 `xor` gm11 cpy3 ,gm14 cpy3 `xor` gm9 cpy2 `xor` gm13 cpy1 `xor` gm11 cpy0) gm14 a = V.unsafeIndex gmtab14 $ fromIntegral a gm13 a = V.unsafeIndex gmtab13 $ fromIntegral a gm11 a = V.unsafeIndex gmtab11 $ fromIntegral a gm9 a = V.unsafeIndex gmtab9 $ fromIntegral a swapBlock :: ByteString -> AESState swapBlock b = V.generate 16 (\i -> B.unsafeIndex b $ swapIndex i) swapBlockInv :: AESState -> ByteString swapBlockInv v = B.pack $ map (V.unsafeIndex v . swapIndex) [0..15] mSbox :: Word8 -> Word8 mSbox = V.unsafeIndex sbox . fromIntegral mRsbox :: Word8 -> Word8 mRsbox = V.unsafeIndex rsbox . fromIntegral mRcon :: Int -> Word8 mRcon i = V.unsafeIndex rcon (i `mod` len) where len = V.length rcon sbox :: Vector Word8 sbox = V.fromList [ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5 , 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76 , 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0 , 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0 , 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc , 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15 , 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a , 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75 , 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0 , 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84 , 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b , 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf , 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85 , 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8 , 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5 , 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2 , 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17 , 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73 , 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88 , 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb , 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c , 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79 , 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9 , 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08 , 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6 , 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a , 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e , 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e , 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94 , 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf , 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68 , 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ] rsbox :: Vector Word8 rsbox = V.fromList [ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38 , 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb , 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87 , 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb , 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d , 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e , 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2 , 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 , 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16 , 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 , 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda , 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 , 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a , 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 , 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02 , 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b , 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea , 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 , 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85 , 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e , 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89 , 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b , 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20 , 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 , 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31 , 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f , 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d , 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef , 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0 , 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 , 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26 , 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d ] rcon :: Vector Word8 rcon = V.fromList [ 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40 , 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a , 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a , 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39 , 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25 , 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a , 0x74, 0xe8, 0xcb ] gmtab2, gmtab3, gmtab9, gmtab11, gmtab13, gmtab14 :: Vector Word8 gmtab2 = V.fromList [ 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e , 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e , 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e , 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e , 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e , 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e , 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e , 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e , 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e , 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e , 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae , 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe , 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce , 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde , 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee , 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe , 0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15 , 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05 , 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35 , 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25 , 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55 , 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45 , 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75 , 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65 , 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95 , 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85 , 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5 , 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5 , 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5 , 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5 , 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5 , 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5 ] gmtab3 = V.fromList [ 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09 , 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11 , 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39 , 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21 , 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69 , 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71 , 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59 , 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41 , 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9 , 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1 , 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9 , 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1 , 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9 , 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1 , 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99 , 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81 , 0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92 , 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a , 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2 , 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba , 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2 , 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea , 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2 , 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda , 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52 , 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a , 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62 , 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a , 0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32 , 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a , 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02 , 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a ] gmtab9 = V.fromList [ 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f , 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77 , 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf , 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7 , 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04 , 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c , 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94 , 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc , 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49 , 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01 , 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9 , 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91 , 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72 , 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a , 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2 , 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa , 0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3 , 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b , 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43 , 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b , 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8 , 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0 , 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78 , 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30 , 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5 , 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed , 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35 , 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d , 0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e , 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6 , 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e , 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46 ] gmtab11 = V.fromList [ 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31 , 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69 , 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81 , 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9 , 0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a , 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12 , 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa , 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2 , 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7 , 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f , 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77 , 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f , 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc , 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4 , 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c , 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54 , 0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6 , 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e , 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76 , 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e , 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd , 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5 , 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d , 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55 , 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30 , 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68 , 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80 , 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8 , 0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b , 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13 , 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb , 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3 ] gmtab13 = V.fromList [ 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23 , 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b , 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3 , 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b , 0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98 , 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0 , 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48 , 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20 , 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e , 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26 , 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e , 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6 , 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5 , 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d , 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25 , 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d , 0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9 , 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91 , 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29 , 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41 , 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42 , 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a , 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92 , 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa , 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94 , 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc , 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44 , 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c , 0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f , 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47 , 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff , 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97 ] gmtab14 = V.fromList [ 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a , 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a , 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca , 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba , 0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1 , 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81 , 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11 , 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61 , 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87 , 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7 , 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67 , 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17 , 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c , 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c , 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc , 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc , 0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b , 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b , 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b , 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb , 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0 , 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0 , 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50 , 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20 , 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6 , 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6 , 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26 , 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56 , 0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d , 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d , 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd , 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d ]