cryptopals

Matasano's cryptopals challenges (cryptopals.com).
Log | Files | Refs | README | LICENSE

commit 1092b0928bfa398fbedcf7278e4baa278d5a4c52
parent 88dd2825e002d0a1e81b5657a10dbba1a2f5afaf
Author: Jared Tobin <jared@jtobin.io>
Date:   Fri, 28 Jul 2023 16:19:12 -0230

Add CTR mode for AES128.

Diffstat:
Mcryptopals.cabal | 1+
Mdocs/s3.md | 11+++++++++++
Mlib/Cryptopals/AES.hs | 29+++++++++++++++++++++++++++--
3 files changed, 39 insertions(+), 2 deletions(-)

diff --git a/cryptopals.cabal b/cryptopals.cabal @@ -30,6 +30,7 @@ library base , base16 , base64 + , binary , bytestring , containers , cryptonite diff --git a/docs/s3.md b/docs/s3.md @@ -75,3 +75,14 @@ padding oracle attack (for arbitrary ciphertexts): "000003Cooking MC's like a pound of bacon" "000004Burning 'em, if you ain't quick and nimble" +#### 3.18 + +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: + + > let Right cip = B64.decodeBase64 "L77na/nrFsKvynd6HzOoG7GHTLXsTVu9qvY/2syLXzhPweyyMTJULu/6/kXX0KSvoOLSFQ==" + > decryptCtrAES128 0 "YELLOW SUBMARINE" cip + "Yo, VIP Let's kick it Ice, Ice, baby Ice, Ice, baby " + + diff --git a/lib/Cryptopals/AES.hs b/lib/Cryptopals/AES.hs @@ -1,15 +1,23 @@ module Cryptopals.AES ( encryptCbcAES128 , encryptEcbAES128 + , decryptCbcAES128 , decryptEcbAES128 + + , encryptCtrAES128 + , decryptCtrAES128 ) where -import qualified Data.ByteString as BS -import qualified Cryptopals.Util as CU import qualified Crypto.Cipher.AES as CAES import qualified Crypto.Cipher.Types as CT import qualified Crypto.Error as CE +import qualified Cryptopals.Util as CU +import qualified Data.Binary.Get as BG +import qualified Data.Binary.Put as BP +import qualified Data.ByteString as BS +import qualified Data.ByteString.Lazy as BSL +import GHC.Word (Word64) initAES128 :: BS.ByteString -> CAES.AES128 initAES128 = CE.throwCryptoError . CT.cipherInit @@ -46,3 +54,20 @@ decryptCbcAES128 key ciphertext = then nacc else loop b nacc (BS.splitAt 16 bs) +encryptCtrAES128 :: Word64 -> BS.ByteString -> BS.ByteString -> BS.ByteString +encryptCtrAES128 nonce key plaintext = loop mempty 0 bs where + bs = CU.chunks 16 plaintext + iv = BS.replicate 16 0 + no = BP.runPut (BP.putWord64le nonce) + + loop !acc !ctr cs = case cs of + [] -> acc + (h:t) -> + let bc = BP.runPut (BP.putWord64le ctr) + pt = BSL.toStrict (no <> bc) + ks = BS.drop 16 $ encryptCbcAES128 iv key pt + in loop (acc <> CU.fixedXor h ks) (ctr + 1) t + +decryptCtrAES128 :: Word64 -> BS.ByteString -> BS.ByteString -> BS.ByteString +decryptCtrAES128 = encryptCtrAES128 +