-- Copyright © 2015 Bart Massey
-- [This work is licensed under the "MIT License"]
-- Please see the file LICENSE in the source
-- distribution of this software for license terms.
-- CipherSaber driver for UNIX-like systems with "/dev/random".
import Control.Monad
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BSC
import Data.CipherSaber2
import Data.Char
import Data.Word
import System.Console.ParseArgs
import System.IO
data ArgInd = ArgEncrypt | ArgDecrypt | ArgKey | ArgReps | ArgIV
deriving (Ord, Eq, Show)
argd :: [ Arg ArgInd ]
argd = [
Arg {
argIndex = ArgEncrypt,
argName = Just "encrypt",
argAbbr = Just 'e',
argData = Nothing,
argDesc = "Use decryption mode."
},
Arg {
argIndex = ArgDecrypt,
argName = Just "decrypt",
argAbbr = Just 'd',
argData = Nothing,
argDesc = "Use encryption mode."
},
Arg {
argIndex = ArgReps,
argName = Just "reps",
argAbbr = Just 'r',
argData = argDataDefaulted "number" ArgtypeInt 20,
argDesc = "Number of key scheduling reps " ++
"(use 1 for CipherSaber-1, default 20)."
},
Arg {
argIndex = ArgIV,
argName = Just "iv",
argAbbr = Just 'i',
argData = argDataOptional "hex-string" ArgtypeString,
argDesc = "IV as " ++ show (ivLength * 2) ++ " hex digits with" ++
" leading 0x, or " ++ show ivLength ++ " chars."
},
Arg {
argIndex = ArgKey,
argName = Nothing,
argAbbr = Nothing,
argData = argDataRequired "key" ArgtypeString,
argDesc = "Encryption or decryption key."
} ]
makeIV :: IO BS.ByteString
makeIV =
withBinaryFile "/dev/urandom" ReadMode $ \h ->
do
hSetBuffering h NoBuffering
BS.hGet h 10
main :: IO ()
main = do
hSetBinaryMode stdin True
hSetBinaryMode stdout True
argv <- parseArgsIO ArgsComplete argd
let k = toByteString $ getRequiredArg argv ArgKey
let e = gotArg argv ArgEncrypt
let d = gotArg argv ArgDecrypt
let r = getRequiredArg argv ArgReps :: Int
unless ((e && not d) || (d && not e)) $
usageError argv "Exactly one of -e or -d is required."
case e of
True -> do
iv <- case getArg argv ArgIV of
Nothing -> makeIV
Just ivString -> return (makeBS argv ivString)
BS.interact (encrypt r k iv)
False -> do
BS.interact (decrypt r k)
where
makeBS argv desc
| take 2 desc == "0x" && length desc == 2 * ivLength + 2 =
BS.pack $ reassembleIV $ drop 2 desc
| length desc == ivLength =
BSC.pack desc
| otherwise =
usageError argv $ "IV length must be " ++
show ivLength ++ " bytes."
where
reassembleIV :: String -> [Word8]
reassembleIV "" = []
reassembleIV (c1 : c2 : cs)
| isHexDigit c1 && isHexDigit c2 =
let aByte = 16 * digitToInt c1 + digitToInt c2 in
fromIntegral aByte : reassembleIV cs
reassembleIV _ = usageError argv "Bad IV string."