packages feed

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