module Data.CipherSaber2 (
ByteString, rc4, encrypt, decrypt,
toByteString, fromByteString, ivLength )
where
import Control.Monad
#if __GLASGOW_HASKELL__ < 710
import Control.Monad.ST.Safe
#else
import Control.Monad.ST
#endif
import Data.Array
import Data.Array.ST
import Data.Bits
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as BC
import Data.Word
ivLength :: Int
ivLength = 10
rc4 :: Int -> Int -> ByteString -> ByteString
rc4 scheduleReps keystreamLength key =
B.pack $ runST $ do
let nKey = fromIntegral $ B.length key :: Word8
let key' = listArray (0, fromIntegral (nKey 1)) $ B.unpack key ::
Array Word8 Word8
s <- newListArray (0, 255) [0..255] :: ST s (STUArray s Word8 Word8)
let schedStep j i = do
si <- readArray s i
let keyByte = key' ! (i `mod` nKey)
let j' = j + si + keyByte
sj <- readArray s j'
writeArray s i sj
writeArray s j' si
return j'
foldM_ schedStep 0 $ concat $ replicate scheduleReps [0..255]
let keystream 0 _ _ = return []
keystream n i j = do
let i' = i + 1
si <- readArray s i'
let j' = j + si
sj <- readArray s j'
writeArray s i' sj
writeArray s j' si
sk <- readArray s (si + sj)
ks <- keystream (n 1) i' j'
return $ sk : ks
keystream keystreamLength 0 0
toByteString :: String -> ByteString
toByteString s = BC.pack s
fromByteString :: ByteString -> String
fromByteString bs = BC.unpack bs
encrypt :: Int -> ByteString -> ByteString -> ByteString -> ByteString
encrypt scheduleReps key iv plaintext
| B.length iv == ivLength =
let keystream = rc4 scheduleReps
(B.length plaintext)
(B.append key iv) in
B.append iv $ B.pack $ B.zipWith xor keystream plaintext
| otherwise = error $ "expected IV length " ++ show ivLength
decrypt :: Int -> ByteString -> ByteString -> ByteString
decrypt scheduleReps key ciphertext0 =
let (iv, ciphertext) = B.splitAt ivLength ciphertext0
keystream = rc4 scheduleReps
(B.length ciphertext)
(B.append key iv) in
B.pack $ B.zipWith xor keystream ciphertext