commit ff01c61677c0e9206e7e0549fede3f3571b5c04c
parent 64357d513f00456eab1de95b0917fe73ba37aff2
Author: Jared Tobin <jared@jtobin.io>
Date: Wed, 2 Aug 2023 09:25:12 -0230
Fix some bit rot & add CTR mode to binaries.
Diffstat:
3 files changed, 34 insertions(+), 8 deletions(-)
diff --git a/docs/s3.md b/docs/s3.md
@@ -77,8 +77,6 @@ padding oracle attack (for arbitrary ciphertexts):
#### 3.18
-(FIXME, add binaries for these.)
-
CTR mode is trivial; the only thing to get right is really the specified
counter format. `Cryptopals.AES.decryptCtrAES128` (or its synonym,
`encryptCtrAES128`) can be used to retrieve our desired plaintext:
@@ -87,6 +85,14 @@ counter format. `Cryptopals.AES.decryptCtrAES128` (or its synonym,
> decryptCtrAES128 0 "YELLOW SUBMARINE" cip
"Yo, VIP Let's kick it Ice, Ice, baby Ice, Ice, baby "
+You can get at this from the command line via the 'ctr' arg to the 'aes'
+binary:
+
+ $ ct=$(echo "L77na/nrFsKvynd6HzOoG7GHTLXsTVu9qvY/2syLXzhPweyyMTJULu/6/kXX0KSvoOLSFQ==" | base64 -d | xxd -p | tr -d '\n')
+ $ key=$(echo -n "YELLOW SUBMARINE" | xxd -p)
+ $ aes decrypt ctr --nonce 0 "$key" "$ct" | xxd -r -p
+ Yo, VIP Let's kick it Ice, Ice, baby Ice, Ice, baby
+
#### 3.19 (and 3.20)
I used the same approach as was done in question 1.6, taking the
diff --git a/src/AES.hs b/src/AES.hs
@@ -10,6 +10,7 @@ import qualified Data.Char as C
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import qualified Data.Text.IO as TIO
+import GHC.Word (Word64)
import qualified Options.Applicative as O
import qualified System.Exit as SE
import qualified System.IO as SIO
@@ -21,13 +22,15 @@ data Operation =
data Mode =
ECB
| CBC
+ | CTR
data Args = Args {
- argsOpr :: Operation
- , argsMod :: Mode
- , argsIv :: Maybe T.Text
- , argsKey :: T.Text
- , argsInp :: T.Text
+ argsOpr :: Operation
+ , argsMod :: Mode
+ , argsIv :: Maybe T.Text
+ , argsKey :: T.Text
+ , argsNonce :: Maybe Word64
+ , argsInp :: T.Text
}
ops :: O.Parser Args
@@ -36,6 +39,7 @@ ops = Args
<*> modeParser
<*> optional (O.strOption (O.long "iv" <> O.metavar "IV"))
<*> O.argument O.str (O.metavar "KEY")
+ <*> optional (O.option O.auto (O.long "nonce" <> O.metavar "NONCE"))
<*> O.argument O.str (O.metavar "INPUT")
operationParser :: O.Parser Operation
@@ -53,6 +57,7 @@ modeParser = O.argument mode etc where
mode = O.eitherReader $ \input -> case fmap C.toLower input of
"ecb" -> pure ECB
"cbc" -> pure CBC
+ "ctr" -> pure CTR
_ -> Left ("invalid mode: " <> input)
etc = O.metavar "MODE"
@@ -91,6 +96,13 @@ aes Args {..} = do
Right iv ->
out $ AES.encryptCbcAES128 iv k v
+ CTR -> case argsNonce of
+ Nothing -> do
+ err $ "cryptopals: must provide nonce"
+ SE.exitFailure
+
+ Just n -> out $ AES.encryptCtrAES128 n k v
+
Decrypt -> case argsMod of
ECB -> out $ AES.decryptEcbAES128 k v
@@ -98,6 +110,7 @@ aes Args {..} = do
Nothing -> do
err $ "cryptopals: must provide IV"
SE.exitFailure
+
Just miv -> case B16.decodeBase16 (TE.encodeUtf8 miv) of
Left e -> do
err $ "cryptopals: " <> e
@@ -106,6 +119,13 @@ aes Args {..} = do
Right iv ->
out $ AES.decryptCbcAES128 k v
+ CTR -> case argsNonce of
+ Nothing -> do
+ err $ "cryptopals: must provide nonce"
+ SE.exitFailure
+
+ Just n -> out $ AES.decryptCtrAES128 n k v
+
main :: IO ()
main = do
let pars = O.info (O.helper <*> ops) $
diff --git a/src/MT19937.hs b/src/MT19937.hs
@@ -23,7 +23,7 @@ ops = Args
mt :: Args -> IO ()
mt Args {..} = do
let gen = MT.seed argsSeed
- (bytes, _) = MT.bytes (fromIntegral argsBytes) gen
+ (bytes, _) = MT.tap (fromIntegral argsBytes) gen
for_ bytes $ TIO.putStrLn . T.pack . show