cipher-rc5 0.1.0.1 → 0.1.0.2
raw patch · 2 files changed
+47/−45 lines, 2 filesdep ~basePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base
API changes (from Hackage documentation)
Files
- Crypto/Cipher/RC5.hs +45/−43
- cipher-rc5.cabal +2/−2
Crypto/Cipher/RC5.hs view
@@ -1,4 +1,4 @@--- | +-- | -- Module : Crypto.Cipher.RC5 -- License : BSD-style -- Maintainer : Finn Espen Gundersen <finn@gundersen.net> @@ -9,7 +9,7 @@ -- <http://en.wikipedia.org/wiki/RC5> -- -- You need to select a block size and number of rounds. --- If you are unsure, the most common settings are 32bit blocks with 12 rounds. +-- If you are unsure, the most common settings are 64bit blocks with 12 rounds. -- -- This implementation supports all the standard block lengths of 32, 64 & 128 bits. -- It also includes support for non-standard (not recommended) 16bit blocks. @@ -46,7 +46,7 @@ -- Encrypts the plaintext @[0xFE,0x13,0x37,0x00]@ with a blocksize of 64 bits, 12 rounds and key @[1,2,3,4]@ -- -- Maximum key length is 256. A common (and sufficient) length is 16 bytes. --- The length of the result is divisible by the block size (i.e. 2, 4, 8, 16) +-- The length of the result is divisible by the block size (i.e. 2, 4, 8, 16 bytes) -- On invalid input, the empty list is returned. encrypt :: Int -- ^ Blocksize in bits (16, 32, 64 or 128) @@ -56,12 +56,12 @@ -> [Word8] -- ^ Ciphertext encrypt blocksize rounds key plain | null key || null plain || length (take 257 key) == 257 || rounds > 256 || rounds < 0 = [] - | blocksize == 16 = crypt ws p8 q8 encryptblock rounds key plain - | blocksize == 32 = crypt ws p16 q16 encryptblock rounds key plain - | blocksize == 64 = crypt ws p32 q32 encryptblock rounds key plain - | blocksize == 128 = crypt ws p64 q64 encryptblock rounds key plain + | blocksize == 16 = concatMap (serialize ws) $ crypt ws encryptblock rounds (keyexpand ws p8 q8 key rounds) (splitAB ws plain) + | blocksize == 32 = concatMap (serialize ws) $ crypt ws encryptblock rounds (keyexpand ws p16 q16 key rounds) (splitAB ws plain) + | blocksize == 64 = concatMap (serialize ws) $ crypt ws encryptblock rounds (keyexpand ws p32 q32 key rounds) (splitAB ws plain) + | blocksize == 128 = concatMap (serialize ws) $ crypt ws encryptblock rounds (keyexpand ws p64 q64 key rounds) (splitAB ws plain) | otherwise = [] - where ws = shiftR blocksize 4 + where ws = shiftR blocksize 4 -- number of bytes in each word (two words per block) -- | RC5 decryption -- @@ -74,14 +74,15 @@ -> [Word8] -- ^ Ciphertext -> [Word8] -- ^ Recovered plaintext decrypt blocksize rounds key cipher - | length key > 256 || null key || null cipher || rounds > 256 || rounds < 0 = [] - | blocksize == 16 = crypt ws p8 q8 decryptblock rounds key cipher - | blocksize == 32 = crypt ws p16 q16 decryptblock rounds key cipher - | blocksize == 64 = crypt ws p32 q32 decryptblock rounds key cipher - | blocksize == 128 = crypt ws p64 q64 decryptblock rounds key cipher + | null key || null cipher || length (take 257 key) == 257 || rounds > 256 || rounds < 0 = [] + | blocksize == 16 = concatMap (serialize ws) $ crypt ws decryptblock rounds (keyexpand ws p8 q8 key rounds) (splitAB ws cipher) + | blocksize == 32 = concatMap (serialize ws) $ crypt ws decryptblock rounds (keyexpand ws p16 q16 key rounds) (splitAB ws cipher) + | blocksize == 64 = concatMap (serialize ws) $ crypt ws decryptblock rounds (keyexpand ws p32 q32 key rounds) (splitAB ws cipher) + | blocksize == 128 = concatMap (serialize ws) $ crypt ws decryptblock rounds (keyexpand ws p64 q64 key rounds) (splitAB ws cipher) | otherwise = [] where ws = shiftR blocksize 4 + -- Magic constants p8 = 0xb7 :: Word8 -- Two constants, Pw and Qw, are defined for q8 = 0x9f :: Word8 -- any word size W by the expressions: @@ -93,9 +94,9 @@ q64 = 0x9e3779b97f4a7c15 :: Word64 -- No real magic going on here. -- Example & selftest for RC5/32/12/16. From the appendix of the Rivest reference paper -key1 = take 16 $ repeat 0 :: [Word8] +key1 = replicate 16 0 :: [Word8] key2 = [0x91,0x5F,0x46,0x19,0xBE,0x41,0xB2,0x51,0x63,0x55,0xA5,0x01,0x10,0xA9,0xCE,0x91] :: [Word8] -plain1 = take 8 $ repeat 0 :: [Word8] +plain1 = replicate 8 0 :: [Word8] cipher1 = [0x21,0xA5,0xDB,0xEE,0x15,0x4B,0x8F,0x6D] :: [Word8] cipher1' = (0xEEDBA521,0x6D8F4B15) :: (Word32,Word32) @@ -109,34 +110,32 @@ selftest' key plain fasit | null fasit = [] - | otherwise = [((decrypt 64 12 key cipher) == plain) && (cipher == (head fasit))] ++ selftest' (nextkey cipher) cipher (tail fasit) + | otherwise = ((decrypt 64 12 key cipher == plain) && (cipher == head fasit)) : selftest' (nextkey cipher) cipher (tail fasit) where cipher = encrypt 64 12 key plain - nextkey cipher = map (\j -> fromIntegral (((bytes2word (take 4 cipher))::Word32) `mod` (255-j))) [0..15] + nextkey cipher = map (\j -> fromIntegral ((bytes2word (take 4 cipher) :: Word32) `mod` (255-j))) [0..15] -- Left rotate for encryption rotl :: Bits a => a -> Int -> Int -> a -rotl x s w = (shiftL x (s .&. (w-1))) .|. (shiftR x (w-(s .&. (w-1)))) +rotl x s w = shiftL x (s .&. (w-1)) .|. shiftR x (w-(s .&. (w-1))) -- Right rotate for decryption rotr :: Bits a => a -> Int -> Int -> a -rotr x s w = (shiftR x (s .&. (w-1))) .|. (shiftL x (w-(s .&. (w-1)))) - -crypt :: (Bits a, Integral a) => Int -> a -> a -> (Int -> [a] -> Int -> (a,a) -> [Word8]) -> Int -> [Word8] -> [Word8] -> [Word8] -crypt ws p q operation rounds key content = - concatMap (operation ws s rounds) ab - where ab = splitAB ws content - s = keyexpand ws p q key rounds +rotr x s w = shiftR x (s .&. (w-1)) .|. shiftL x (w-(s .&. (w-1))) -encryptblock :: (Bits a, Integral a) => Int -> [a] -> Int -> (a,a) -> [Word8] -encryptblock ws s rounds (a,b) = - word2bytes ws a' ++ word2bytes ws b' +crypt :: (Bits a, Integral a) => Int -> (Int -> [a] -> Int -> (a,a) -> (a,a)) -> Int -> [a] -> [(a,a)] -> [(a,a)] +crypt ws operation rounds s = map (operation ws s rounds) + +{-# ANN encryptblock "HLint: ignore" #-} +encryptblock :: (Bits a, Integral a) => Int -> [a] -> Int -> (a,a) -> (a,a) +encryptblock ws s rounds (a,b) = (a',b') where (a',b') = enc (ws*8) rounds 1 (a + (s!!0)) (b + (s!!1)) s -decryptblock :: (Bits a, Integral a) => Int -> [a] -> Int -> (a,a) -> [Word8] -decryptblock ws s rounds (a,b) = - word2bytes ws (a' - s!!0) ++ word2bytes ws (b' - s!!1) +{-# ANN decryptblock "HLint: ignore" #-} +decryptblock :: (Bits a, Integral a) => Int -> [a] -> Int -> (a,a) -> (a,a) +decryptblock ws s rounds (a,b) = (a' - s!!0, b' - s!!1) where (a',b') = dec (ws*8) rounds a b s +{-# ANN enc "HLint: ignore" #-} enc :: (Bits a, Integral a) => Int -> Int -> Int -> a -> a -> [a] -> (a,a) enc mask rounds i a b s | i > rounds = (a,b) @@ -151,6 +150,11 @@ where b' = (rotr (b - (s !! (2*i+1))) (fromIntegral a) mask) `xor` a a' = (rotr (a - (s !! (2*i))) (fromIntegral b') mask) `xor` b' +-- Converts output to bytelist +serialize :: (Bits a, Integral a) => Int -> (a,a) -> [Word8] +serialize ws (a,b) = word2bytes ws a ++ word2bytes ws b + +-- Deserializes input to wordpairs (==blocks) splitAB :: (Bits a, Integral a) => Int -> [Word8] -> [(a,a)] splitAB ws bs = map pair ab where chunks = chunksOf ws bs @@ -168,12 +172,12 @@ mixsecretkey :: (Bits a, Integral a) => Int -> [a] -> [a] -> [a] mixsecretkey bs s l = s' - where k = if ll > t then 3 * ll else 3 * t + where k = 3 * if ll > t then ll else t ll = length l t = length s (s',l') = mixS (bs*8) k 0 0 0 0 s l t ll --- Mixes S box with key. Paramter names may look cryptic, but matches those in standard +-- Mixes S box with key. Parameter names may look cryptic, but matches those in the original paper mixS :: (Bits a, Integral a) => Int -> Int -> a -> a -> Int -> Int -> [a] -> [a] -> Int -> Int -> ([a],[a]) mixS bs k a b i j s l t ll | k == 0 = (s,l) @@ -182,14 +186,13 @@ b' = rotl ((l !! j) + a' + b) (fromIntegral (a'+b)) bs i' = (i + 1) `mod` t j' = (j + 1) `mod` ll - s' = (take i s) ++ [a'] ++ (drop (i+1) s) - l' = (take j l) ++ [b'] ++ (drop (j+1) l) + s' = take i s ++ [a'] ++ drop (i+1) s + l' = take j l ++ [b'] ++ drop (j+1) l -- Creates S box. Could be precomputed for the most common variants. makeS :: Integral a => Int -> a -> a -> [a] -makeS t seed const - | t == 0 = [] - | otherwise = seed : makeS (t-1) (seed + const) const +makeS 0 _ _ = [] +makeS t seed const = seed : makeS (t-1) (seed + const) const makewordkey :: (Bits a, Integral a) => Int -> [Word8] -> [a] makewordkey ws key = map sum chunks @@ -197,13 +200,12 @@ chunks = chunksOf ws expokey bytes2word :: (Bits a, Integral a) => [Word8] -> a -bytes2word bs = bytes2word' 0 (fromIntegral 0) bs +bytes2word = bytes2word' 0 0 bytes2word' :: (Bits a, Integral a) => Int -> a -> [Word8] -> a -bytes2word' shft sofar [] = sofar +bytes2word' _ sofar [] = sofar bytes2word' shft sofar (x:xs) = bytes2word' (shft+8) (sofar + shiftL (fromIntegral x) shft) xs word2bytes :: (Bits a, Integral a) => Int -> a -> [Word8] -word2bytes ws w - | ws == 0 = [] - | otherwise = (fromIntegral (w .&. 0xFF)) : (word2bytes (ws-1) (shiftR w 8)) +word2bytes 0 _ = [] +word2bytes ws w = fromIntegral (w .&. 0xFF) : word2bytes (ws-1) (shiftR w 8)
cipher-rc5.cabal view
@@ -1,5 +1,5 @@ name: cipher-rc5 -version: 0.1.0.1 +version: 0.1.0.2 synopsis: Pure RC5 implementation description: Pure RC5 implementation homepage: http://github.com/fegu/cipher-rc5 @@ -14,4 +14,4 @@ library exposed-modules: Crypto.Cipher.RC5 - build-depends: base ==4.6.*, split ==0.2.*+ build-depends: base >=4.6 && <5, split ==0.2.*