cryptopals

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

commit dc9d806977074e3a8dffed3df9b0785ace902264
parent 1ef48519658f06f2e5bf400ded6cd04e8c7fcfb6
Author: Jared Tobin <jared@jtobin.io>
Date:   Wed, 31 May 2023 16:26:12 +0400

Add a few Haskell implementations.

Diffstat:
MREADME.md | 4++++
Mcryptopals.cabal | 26++++++++++++++++++--------
Rdata/s1/q2_input.txt -> data/s1/q2_input0.txt | 0
Rdata/s1/q2_against.txt -> data/s1/q2_input1.txt | 0
Mdocs/s1.md | 22+++++-----------------
Dlib/Cryptopals.hs | 4----
Alib/Cryptopals/Util.hs | 33+++++++++++++++++++++++++++++++++
Asrc/FixedXor.hs | 42++++++++++++++++++++++++++++++++++++++++++
8 files changed, 102 insertions(+), 29 deletions(-)

diff --git a/README.md b/README.md @@ -2,6 +2,10 @@ [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jtobin/cryptopals/blob/master/LICENSE) +Use e.g. `cabal build cryptopals:exec:fixed-xor` in a Nix shell +to build binaries. Use `cabal install` to (I think) dump them in +`$HOME/.cabal/bin`. + ## Problems * [Problem Set 1](docs/s1.md) diff --git a/cryptopals.cabal b/cryptopals.cabal @@ -12,18 +12,28 @@ cabal-version: >= 1.10 library default-language: Haskell2010 default-extensions: - DeriveFoldable - DeriveFunctor - DeriveTraversable LambdaCase - RankNTypes - ScopedTypeVariables - TypeFamilies - ViewPatterns + OverloadedStrings + RecordWildCards hs-source-dirs: lib exposed-modules: - Cryptopals + Cryptopals.Util build-depends: base + , base16 + , base64 + , bytestring + , text +executable fixed-xor + main-is: FixedXor.hs + ghc-options: -Wall -O2 + default-language: Haskell2010 + hs-source-dirs: src + build-depends: + base + , bytestring + , cryptopals + , optparse-applicative + , text diff --git a/data/s1/q2_input.txt b/data/s1/q2_input0.txt diff --git a/data/s1/q2_against.txt b/data/s1/q2_input1.txt diff --git a/docs/s1.md b/docs/s1.md @@ -28,9 +28,6 @@ equality: $ diff <(xxd -r -p data/s1/q1_input.txt | base64) data/s1/q1_output.txt -In Rust it's easy enough to just use the appropriate functionality from the -`hex` and `base64` crates. - #### 1.2 Fixed-xor just encrypts by xoring every bit with some corresponding bit. @@ -54,24 +51,15 @@ zero-padded: $ echo 'obase=16; ibase=2; 000011110000001000000111' | bc F0207 -The `fixed_xor` binary in `./bin` will perform the reverse task on the -zero-padded string here: +The `fixed_xor` executable included will perform the reverse task on the +zero-padded string: - $ ./bin/fixed_xor '0f0207' $(echo -n ICE | xxd -p) | xxd -r -p + $ fixed_xor '0f0207' $(echo -n ICE | xxd -p) | xxd -r -p FAB -The Rust implementation is trivial: - - fn fixed_xor(target: &[u8], partner: &[u8]) -> Vec<u8> { - target.iter() - .zip(partner) - .map(|(l, r)| l ^ r) - .collect() - } - -And running `fixed_xor` on the question input yields the following: +and running `fixed_xor` on the question input yields the following: - $ SOLUTION=$(./bin/fixed_xor $(< data/s1/q2_input.txt) $(< data/s1/q2_against.txt)) + $ SOLUTION=$(fixed_xor $(< data/s1/q2_input0.txt) $(< data/s1/q2_input1.txt)) 746865206b696420646f6e277420706c6179 The ASCII encoding is fun: diff --git a/lib/Cryptopals.hs b/lib/Cryptopals.hs @@ -1,4 +0,0 @@ - -module Cryptopals where - - diff --git a/lib/Cryptopals/Util.hs b/lib/Cryptopals/Util.hs @@ -0,0 +1,33 @@ +module Cryptopals.Util ( + Hex(..) + , Base64(..) + + , hexToB64 + , fixedXor + ) where + +import qualified Data.Bits as B +import qualified Data.ByteString as BS +import qualified Data.ByteString.Base16 as B16 +import qualified Data.ByteString.Base64 as B64 +import qualified Data.Text as T + +newtype Hex = Hex BS.ByteString + deriving (Eq, Show) + +newtype Base64 = Base64 BS.ByteString + deriving (Eq, Show) + +hexToB64 :: Hex -> Either T.Text Base64 +hexToB64 (Hex b) = do + b16 <- B16.decodeBase16 b + pure $ Base64 (B64.encodeBase64' b16) + +fixedXor :: Hex -> Hex -> Either T.Text Hex +fixedXor (Hex a) (Hex b) = do + l <- B16.decodeBase16 a + r <- B16.decodeBase16 b + if BS.length l /= BS.length r + then Left "fixedXor: unequal-length buffers" + else pure $ Hex (B16.encodeBase16' . BS.pack $ BS.zipWith B.xor l r) + diff --git a/src/FixedXor.hs b/src/FixedXor.hs @@ -0,0 +1,42 @@ +{-# LANGUAGE RecordWildCards #-} + +module Main where + +import Cryptopals.Util (Hex(..)) +import qualified Cryptopals.Util as CU +import qualified Data.Text as T +import qualified Data.Text.IO as TIO +import qualified Data.Text.Encoding as TE +import qualified Options.Applicative as O + +data Args = Args { + argsKey :: T.Text + , argsInp :: T.Text + } + +ops :: O.Parser Args +ops = Args + <$> O.argument O.str (O.metavar "KEY") + <*> O.argument O.str (O.metavar "INPUT") + +fxor :: Args -> IO () +fxor Args {..} = do + let k = Hex (TE.encodeUtf8 argsKey) + v = Hex (TE.encodeUtf8 argsInp) + r = CU.fixedXor k v + + case r of + Left e -> TIO.putStrLn e + Right (Hex b) -> TIO.putStrLn (TE.decodeUtf8 b) + +main :: IO () +main = do + let pars = O.info (O.helper <*> ops) $ + O.fullDesc + <> O.progDesc "compute fixed-xor KEY on INPUT" + <> O.header "fixed-xor" + + args <- O.execParser pars + + fxor args +