{-# LANGUAGE FlexibleInstances    #-}
{-# LANGUAGE TypeSynonymInstances #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Codec.Encryption.AES
-- Copyright   :  (c) Dominic Steinitz 2004
-- License     :  BSD-style (see the file ReadMe.tex)
--
-- Stability   :  experimental
-- Portability :  portable
--
-- Takes the AES module supplied by Lukasz Anforowicz and wraps it so it can
-- used with the standard modes.
--
-----------------------------------------------------------------------------

module Codec.Encryption.AES (
   -- * Function Types
   encrypt, decrypt, AESKey) where

import           Codec.Encryption.AESAux
import           Codec.Utils
import           Data.Bits
import           Data.LargeWord
import           Data.Word

class (Bits a, Integral a) => AESKeyIndirection a
class AESKeyIndirection a => AESKey a

instance AESKeyIndirection Word128
instance AESKeyIndirection Word192
instance AESKeyIndirection Word256

instance AESKey Word128
instance AESKey Word192
instance AESKey Word256

-- | Basic AES encryption which takes a key and a block of plaintext
-- and returns the encrypted block of ciphertext according to the standard.

encrypt :: AESKey a => a -> Word128 -> Word128
encrypt :: forall a. AESKey a => a -> Word128 -> Word128
encrypt a
k Word128
p =
   case forall a. Bits a => a -> Int
bitSize a
k of
      Int
128 -> forall {a} {a} {b}.
(Bits a, Bits a, Integral a, Integral a, Num b) =>
([Octet] -> [Octet] -> [Octet]) -> a -> a -> b
f [Octet] -> [Octet] -> [Octet]
aes128Encrypt a
k Word128
p
      Int
192 -> forall {a} {a} {b}.
(Bits a, Bits a, Integral a, Integral a, Num b) =>
([Octet] -> [Octet] -> [Octet]) -> a -> a -> b
f [Octet] -> [Octet] -> [Octet]
aes192Encrypt a
k Word128
p
      Int
256 -> forall {a} {a} {b}.
(Bits a, Bits a, Integral a, Integral a, Num b) =>
([Octet] -> [Octet] -> [Octet]) -> a -> a -> b
f [Octet] -> [Octet] -> [Octet]
aes256Encrypt a
k Word128
p

f :: ([Octet] -> [Octet] -> [Octet]) -> a -> a -> b
f [Octet] -> [Octet] -> [Octet]
g a
k a
p =
   forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Integral b) => a -> [Octet] -> b
fromOctets Integer
256 forall a b. (a -> b) -> a -> b
$
      [Octet] -> [Octet] -> [Octet]
g (forall a. Integral a => Int -> a -> [Octet]
i2osp (forall a. Bits a => a -> Int
bitSize a
k forall a. Integral a => a -> a -> a
`div` forall a. Bits a => a -> Int
bitSize (Octet
0::Octet)) forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral a
k)
        (forall a. Integral a => Int -> a -> [Octet]
i2osp (forall a. Bits a => a -> Int
bitSize a
p forall a. Integral a => a -> a -> a
`div` forall a. Bits a => a -> Int
bitSize (Octet
0::Octet)) forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral a
p)

-- | Basic AES decryption which takes a key and a block of ciphertext and
-- returns the decrypted block of plaintext according to the standard.

decrypt :: AESKey a => a -> Word128 -> Word128
decrypt :: forall a. AESKey a => a -> Word128 -> Word128
decrypt a
k Word128
p =
   case forall a. Bits a => a -> Int
bitSize a
k of
      Int
128 -> forall {a} {a} {b}.
(Bits a, Bits a, Integral a, Integral a, Num b) =>
([Octet] -> [Octet] -> [Octet]) -> a -> a -> b
f [Octet] -> [Octet] -> [Octet]
aes128Decrypt a
k Word128
p
      Int
192 -> forall {a} {a} {b}.
(Bits a, Bits a, Integral a, Integral a, Num b) =>
([Octet] -> [Octet] -> [Octet]) -> a -> a -> b
f [Octet] -> [Octet] -> [Octet]
aes192Decrypt a
k Word128
p
      Int
256 -> forall {a} {a} {b}.
(Bits a, Bits a, Integral a, Integral a, Num b) =>
([Octet] -> [Octet] -> [Octet]) -> a -> a -> b
f [Octet] -> [Octet] -> [Octet]
aes256Decrypt a
k Word128
p