crypton-1.0.2: Crypto/Cipher/DES/Primitive.hs
{-# LANGUAGE FlexibleInstances #-}
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- |
-- Module : Crypto.Cipher.DES.Primitive
-- License : BSD-style
--
-- This module is copy of DES module from Crypto package.
-- http://hackage.haskell.org/package/Crypto
module Crypto.Cipher.DES.Primitive (
encrypt,
decrypt,
Block (..),
) where
import Data.Bits
import Data.Word
-- | a DES block (64 bits)
newtype Block = Block {unBlock :: Word64}
type Rotation = Int
type Key = Word64
type Bits4 = [Bool]
type Bits6 = [Bool]
type Bits32 = [Bool]
type Bits48 = [Bool]
type Bits56 = [Bool]
type Bits64 = [Bool]
desXor :: [Bool] -> [Bool] -> [Bool]
desXor a b = zipWith (/=) a b
desRotate :: [Bool] -> Int -> [Bool]
desRotate bits rot = drop rot' bits ++ take rot' bits
where
rot' = rot `mod` length bits
bitify :: Word64 -> Bits64
bitify w = map (\b -> w .&. (shiftL 1 b) /= 0) [63, 62 .. 0]
unbitify :: Bits64 -> Word64
unbitify bs = foldl (\i b -> if b then 1 + shiftL i 1 else shiftL i 1) 0 bs
initial_permutation :: Bits64 -> Bits64
initial_permutation mb = map ((!!) mb) i
where
i =
[ 57
, 49
, 41
, 33
, 25
, 17
, 9
, 1
, 59
, 51
, 43
, 35
, 27
, 19
, 11
, 3
, 61
, 53
, 45
, 37
, 29
, 21
, 13
, 5
, 63
, 55
, 47
, 39
, 31
, 23
, 15
, 7
, 56
, 48
, 40
, 32
, 24
, 16
, 8
, 0
, 58
, 50
, 42
, 34
, 26
, 18
, 10
, 2
, 60
, 52
, 44
, 36
, 28
, 20
, 12
, 4
, 62
, 54
, 46
, 38
, 30
, 22
, 14
, 6
]
{-
"\x39\x31\x29\x21\x19\x11\x09\x01\x3b\x33\x2b\x23\x1b\x13\
\\x0b\x03\x3d\x35\x2d\x25\x1d\x15\x0d\x05\x3f\x37\x2f\x27\
\\x1f\x17\x0f\x07\x38\x30\x28\x20\x18\x10\x08\x00\x3a\x32\
\\x2a\x22\x1a\x12\x0a\x02\x3c\x34\x2c\x24\x1c\x14\x0c\x04\
\\x3e\x36\x2e\x26\x1e\x16\x0e\x06"
-}
key_transformation :: Bits64 -> Bits56
key_transformation kb = map ((!!) kb) i
where
i =
[ 56
, 48
, 40
, 32
, 24
, 16
, 8
, 0
, 57
, 49
, 41
, 33
, 25
, 17
, 9
, 1
, 58
, 50
, 42
, 34
, 26
, 18
, 10
, 2
, 59
, 51
, 43
, 35
, 62
, 54
, 46
, 38
, 30
, 22
, 14
, 6
, 61
, 53
, 45
, 37
, 29
, 21
, 13
, 5
, 60
, 52
, 44
, 36
, 28
, 20
, 12
, 4
, 27
, 19
, 11
, 3
]
{-
"\x38\x30\x28\x20\x18\x10\x08\x00\x39\x31\x29\x21\x19\x11\
\\x09\x01\x3a\x32\x2a\x22\x1a\x12\x0a\x02\x3b\x33\x2b\x23\
\\x3e\x36\x2e\x26\x1e\x16\x0e\x06\x3d\x35\x2d\x25\x1d\x15\
\\x0d\x05\x3c\x34\x2c\x24\x1c\x14\x0c\x04\x1b\x13\x0b\x03"
-}
des_enc :: Block -> Key -> Block
des_enc = do_des [1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28]
des_dec :: Block -> Key -> Block
des_dec = do_des [28, 27, 25, 23, 21, 19, 17, 15, 14, 12, 10, 8, 6, 4, 2, 1]
do_des :: [Rotation] -> Block -> Key -> Block
do_des rots (Block m) k = Block $ des_work rots (takeDrop 32 mb) kb
where
kb = key_transformation $ bitify k
mb = initial_permutation $ bitify m
des_work :: [Rotation] -> (Bits32, Bits32) -> Bits56 -> Word64
des_work [] (ml, mr) _ = unbitify $ final_perm $ (mr ++ ml)
des_work (r : rs) mb kb = des_work rs mb' kb
where
mb' = do_round r mb kb
do_round :: Rotation -> (Bits32, Bits32) -> Bits56 -> (Bits32, Bits32)
do_round r (ml, mr) kb = (mr, m')
where
kb' = get_key kb r
comp_kb = compression_permutation kb'
expa_mr = expansion_permutation mr
res = comp_kb `desXor` expa_mr
res' = drop 1 $ iterate (trans 6) ([], res)
trans n (_, b) = (take n b, drop n b)
res_s =
concat $
zipWith
(\f (x, _) -> f x)
[ s_box_1
, s_box_2
, s_box_3
, s_box_4
, s_box_5
, s_box_6
, s_box_7
, s_box_8
]
res'
res_p = p_box res_s
m' = res_p `desXor` ml
get_key :: Bits56 -> Rotation -> Bits56
get_key kb r = kb'
where
(kl, kr) = takeDrop 28 kb
kb' = desRotate kl r ++ desRotate kr r
compression_permutation :: Bits56 -> Bits48
compression_permutation kb = map ((!!) kb) i
where
i =
[ 13
, 16
, 10
, 23
, 0
, 4
, 2
, 27
, 14
, 5
, 20
, 9
, 22
, 18
, 11
, 3
, 25
, 7
, 15
, 6
, 26
, 19
, 12
, 1
, 40
, 51
, 30
, 36
, 46
, 54
, 29
, 39
, 50
, 44
, 32
, 47
, 43
, 48
, 38
, 55
, 33
, 52
, 45
, 41
, 49
, 35
, 28
, 31
]
expansion_permutation :: Bits32 -> Bits48
expansion_permutation mb = map ((!!) mb) i
where
i =
[ 31
, 0
, 1
, 2
, 3
, 4
, 3
, 4
, 5
, 6
, 7
, 8
, 7
, 8
, 9
, 10
, 11
, 12
, 11
, 12
, 13
, 14
, 15
, 16
, 15
, 16
, 17
, 18
, 19
, 20
, 19
, 20
, 21
, 22
, 23
, 24
, 23
, 24
, 25
, 26
, 27
, 28
, 27
, 28
, 29
, 30
, 31
, 0
]
s_box :: [[Word8]] -> Bits6 -> Bits4
s_box s [a, b, c, d, e, f] = to_bool 4 $ (s !! row) !! col
where
row = sum $ zipWith numericise [a, f] [1, 0]
col = sum $ zipWith numericise [b, c, d, e] [3, 2, 1, 0]
numericise :: Bool -> Int -> Int
numericise = (\x y -> if x then 2 ^ y else 0)
to_bool :: Int -> Word8 -> [Bool]
to_bool 0 _ = []
to_bool n i = ((i .&. 8) == 8) : to_bool (n - 1) (shiftL i 1)
s_box _ _ = error "DES: internal error bits6 more than 6 elements"
s_box_1 :: Bits6 -> Bits4
s_box_1 = s_box i
where
i =
[ [14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7]
, [0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8]
, [4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0]
, [15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13]
]
s_box_2 :: Bits6 -> Bits4
s_box_2 = s_box i
where
i =
[ [15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10]
, [3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5]
, [0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15]
, [13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9]
]
s_box_3 :: Bits6 -> Bits4
s_box_3 = s_box i
where
i =
[ [10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8]
, [13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1]
, [13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7]
, [1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12]
]
s_box_4 :: Bits6 -> Bits4
s_box_4 = s_box i
where
i =
[ [7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15]
, [13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9]
, [10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4]
, [3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14]
]
s_box_5 :: Bits6 -> Bits4
s_box_5 = s_box i
where
i =
[ [2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9]
, [14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6]
, [4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14]
, [11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3]
]
s_box_6 :: Bits6 -> Bits4
s_box_6 = s_box i
where
i =
[ [12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11]
, [10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8]
, [9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6]
, [4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13]
]
s_box_7 :: Bits6 -> Bits4
s_box_7 = s_box i
where
i =
[ [4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1]
, [13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6]
, [1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2]
, [6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12]
]
s_box_8 :: Bits6 -> Bits4
s_box_8 = s_box i
where
i =
[ [13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7]
, [1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2]
, [7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8]
, [2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11]
]
p_box :: Bits32 -> Bits32
p_box kb = map ((!!) kb) i
where
i =
[ 15
, 6
, 19
, 20
, 28
, 11
, 27
, 16
, 0
, 14
, 22
, 25
, 4
, 17
, 30
, 9
, 1
, 7
, 23
, 13
, 31
, 26
, 2
, 8
, 18
, 12
, 29
, 5
, 21
, 10
, 3
, 24
]
final_perm :: Bits64 -> Bits64
final_perm kb = map ((!!) kb) i
where
i =
[ 39
, 7
, 47
, 15
, 55
, 23
, 63
, 31
, 38
, 6
, 46
, 14
, 54
, 22
, 62
, 30
, 37
, 5
, 45
, 13
, 53
, 21
, 61
, 29
, 36
, 4
, 44
, 12
, 52
, 20
, 60
, 28
, 35
, 3
, 43
, 11
, 51
, 19
, 59
, 27
, 34
, 2
, 42
, 10
, 50
, 18
, 58
, 26
, 33
, 1
, 41
, 9
, 49
, 17
, 57
, 25
, 32
, 0
, 40
, 8
, 48
, 16
, 56
, 24
]
takeDrop :: Int -> [a] -> ([a], [a])
takeDrop _ [] = ([], [])
takeDrop 0 xs = ([], xs)
takeDrop n (x : xs) = (x : ys, zs)
where
(ys, zs) = takeDrop (n - 1) xs
-- | Basic DES encryption which takes a key and a block of plaintext
-- and returns the encrypted block of ciphertext according to the standard.
encrypt :: Word64 -> Block -> Block
encrypt = flip des_enc
-- | Basic DES decryption which takes a key and a block of ciphertext and
-- returns the decrypted block of plaintext according to the standard.
decrypt :: Word64 -> Block -> Block
decrypt = flip des_dec