AES.hs (3649B)
1 {-# LANGUAGE OverloadedStrings #-} 2 {-# LANGUAGE RecordWildCards #-} 3 4 module Main where 5 6 import Control.Applicative (optional) 7 import qualified Cryptopals.AES as AES 8 import qualified Data.ByteString.Base16 as B16 9 import qualified Data.Char as C 10 import qualified Data.Text as T 11 import qualified Data.Text.Encoding as TE 12 import qualified Data.Text.IO as TIO 13 import GHC.Word (Word64) 14 import qualified Options.Applicative as O 15 import qualified System.Exit as SE 16 import qualified System.IO as SIO 17 18 data Operation = 19 Encrypt 20 | Decrypt 21 22 data Mode = 23 ECB 24 | CBC 25 | CTR 26 27 data Args = Args { 28 argsOpr :: Operation 29 , argsMod :: Mode 30 , argsIv :: Maybe T.Text 31 , argsKey :: T.Text 32 , argsNonce :: Maybe Word64 33 , argsInp :: T.Text 34 } 35 36 ops :: O.Parser Args 37 ops = Args 38 <$> operationParser 39 <*> modeParser 40 <*> optional (O.strOption (O.long "iv" <> O.metavar "IV")) 41 <*> O.argument O.str (O.metavar "KEY") 42 <*> optional (O.option O.auto (O.long "nonce" <> O.metavar "NONCE")) 43 <*> O.argument O.str (O.metavar "INPUT") 44 45 operationParser :: O.Parser Operation 46 operationParser = O.argument op etc where 47 op = O.eitherReader $ \input -> case fmap C.toLower input of 48 "encrypt" -> pure Encrypt 49 "decrypt" -> pure Decrypt 50 _ -> Left ("invalid operation: " <> input) 51 52 etc = O.metavar "OPERATION" 53 <> O.help "{encrypt, decrypt}" 54 55 modeParser :: O.Parser Mode 56 modeParser = O.argument mode etc where 57 mode = O.eitherReader $ \input -> case fmap C.toLower input of 58 "ecb" -> pure ECB 59 "cbc" -> pure CBC 60 "ctr" -> pure CTR 61 _ -> Left ("invalid mode: " <> input) 62 63 etc = O.metavar "MODE" 64 <> O.help "{ecb, cbc}" 65 66 aes :: Args -> IO () 67 aes Args {..} = do 68 let args = do 69 k <- B16.decodeBase16 $ TE.encodeUtf8 argsKey 70 v <- B16.decodeBase16 $ TE.encodeUtf8 argsInp 71 pure (k, v) 72 73 out = TIO.putStrLn . TE.decodeUtf8 . B16.encodeBase16' 74 err = TIO.hPutStrLn SIO.stderr 75 76 case args of 77 Left e -> do 78 TIO.hPutStrLn SIO.stderr ("cryptopals: " <> e) 79 SE.exitFailure 80 81 Right (k, v) -> do 82 case argsOpr of 83 Encrypt -> case argsMod of 84 ECB -> out $ AES.encryptEcbAES128 k v 85 86 CBC -> case argsIv of 87 Nothing -> do 88 err $ "cryptopals: must provide IV" 89 SE.exitFailure 90 91 Just miv -> case B16.decodeBase16 (TE.encodeUtf8 miv) of 92 Left e -> do 93 err $ "cryptopals: " <> e 94 SE.exitFailure 95 96 Right iv -> 97 out $ AES.encryptCbcAES128 iv k v 98 99 CTR -> case argsNonce of 100 Nothing -> do 101 err $ "cryptopals: must provide nonce" 102 SE.exitFailure 103 104 Just n -> out $ AES.encryptCtrAES128 n k v 105 106 Decrypt -> case argsMod of 107 ECB -> out $ AES.decryptEcbAES128 k v 108 109 CBC -> case argsIv of 110 Nothing -> do 111 err $ "cryptopals: must provide IV" 112 SE.exitFailure 113 114 Just miv -> case B16.decodeBase16 (TE.encodeUtf8 miv) of 115 Left e -> do 116 err $ "cryptopals: " <> e 117 SE.exitFailure 118 119 Right iv -> 120 out $ AES.decryptCbcAES128 k (iv <> v) 121 122 CTR -> case argsNonce of 123 Nothing -> do 124 err $ "cryptopals: must provide nonce" 125 SE.exitFailure 126 127 Just n -> out $ AES.decryptCtrAES128 n k v 128 129 main :: IO () 130 main = do 131 let pars = O.info (O.helper <*> ops) $ 132 O.fullDesc 133 <> O.progDesc "AES encryption/decryption" 134 <> O.header "aes" 135 136 args <- O.execParser pars 137 138 aes args 139