cryptopals

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

commit e6045d135be3962917e9fa53ede96a08fb1a17ec
parent 981c2bde42fda3d5de966e2bd7a72aa552234735
Author: Jared Tobin <jared@jtobin.io>
Date:   Sat, 26 Aug 2023 16:59:20 -0230

Add 6.44.

Diffstat:
Adata/s6/44.txt | 45+++++++++++++++++++++++++++++++++++++++++++++
Mdocs/s6.md | 42+++++++++++++++++++++++++++++++++++++-----
Mlib/Cryptopals/DSA.hs | 21+++++++++++++++++++++
Mlib/Cryptopals/DSA/Attacks.hs | 143++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
4 files changed, 242 insertions(+), 9 deletions(-)

diff --git a/data/s6/44.txt b/data/s6/44.txt @@ -0,0 +1,44 @@ +msg: Listen for me, you better listen for me now. +s: 1267396447369736888040262262183731677867615804316 +r: 1105520928110492191417703162650245113664610474875 +m: a4db3de27e2db3e5ef085ced2bced91b82e0df19 +msg: Listen for me, you better listen for me now. +s: 29097472083055673620219739525237952924429516683 +r: 51241962016175933742870323080382366896234169532 +m: a4db3de27e2db3e5ef085ced2bced91b82e0df19 +msg: When me rockin' the microphone me rock on steady, +s: 277954141006005142760672187124679727147013405915 +r: 228998983350752111397582948403934722619745721541 +m: 21194f72fe39a80c9c20689b8cf6ce9b0e7e52d4 +msg: Yes a Daddy me Snow me are de article dan. +s: 1013310051748123261520038320957902085950122277350 +r: 1099349585689717635654222811555852075108857446485 +m: 1d7aaaa05d2dee2f7dabdc6fa70b6ddab9c051c5 +msg: But in a in an' a out de dance em +s: 203941148183364719753516612269608665183595279549 +r: 425320991325990345751346113277224109611205133736 +m: 6bc188db6e9e6c7d796f7fdd7fa411776d7a9ff +msg: Aye say where you come from a, +s: 502033987625712840101435170279955665681605114553 +r: 486260321619055468276539425880393574698069264007 +m: 5ff4d4e8be2f8aae8a5bfaabf7408bd7628f43c9 +msg: People em say ya come from Jamaica, +s: 1133410958677785175751131958546453870649059955513 +r: 537050122560927032962561247064393639163940220795 +m: 7d9abd18bbecdaa93650ecc4da1b9fcae911412 +msg: But me born an' raised in the ghetto that I want yas to know, +s: 559339368782867010304266546527989050544914568162 +r: 826843595826780327326695197394862356805575316699 +m: 88b9e184393408b133efef59fcef85576d69e249 +msg: Pure black people mon is all I mon know. +s: 1021643638653719618255840562522049391608552714967 +r: 1105520928110492191417703162650245113664610474875 +m: d22804c4899b522b23eda34d2137cd8cc22b9ce8 +msg: Yeah me shoes a an tear up an' now me toes is a show a +s: 506591325247687166499867321330657300306462367256 +r: 51241962016175933742870323080382366896234169532 +m: bc7ec371d951977cba10381da08fe934dea80314 +msg: Where me a born in are de one Toronto, so +s: 458429062067186207052865988429747640462282138703 +r: 228998983350752111397582948403934722619745721541 +m: d6340bfcda59b6b75b59ca634813d572de800e8f +\ No newline at end of file diff --git a/docs/s6.md b/docs/s6.md @@ -128,19 +128,51 @@ fare; Cryptopals.DSA implements 'keygen', 'sign', and 'verify' functionality. As for the attack here, if one knows the subkey/nonce he can trivially -recover the private key via the relation given. Since the nonce is a -16-bit word, it can easily be brute-forced. The 'fromsub' and 'recover' -functions in Cryptopals.DSA.Attacks handle this: +recover the private key: + + s = k^{-1} (h + x r) (mod q) + s k = h + x r (mod q) + x r = s k - h (mod q) + x = r^{-1} (s k - h) (mod q) + +Since the nonce here is a 16-bit word, it can easily be brute-forced. +The 'fromsub' and 'recover' functions in Cryptopals.DSA.Attacks handle +this: > let sec@(Sec sk) = recover defaultParams rawmsg rawsig rawpub > CS.sha1 . BL.fromStrict . B16.encodeBase16' $ RSA.unroll sk 0954edd5e0afe5542a4adf012611a91912a3ec16 -We can log the nonce/subkey found and hardcode that in the 'sign' -function to check that we get the same signature as well (it's 16575): +We can log the nonce/subkey found (it's 16575) and hardcode that in the +'sign' function to check that we get the same signature as well: > sig <- sign defaultParams sec rawmsg gen > sig == rawsig True +#### 6.44 + +A reused nonce results in an identical 'r' in the DSA signature +produced, since 'r' depends only on the nonce and DSA domain parameters. +Then for two signatures s1 and s2, "integerized" digests h1 and h2, and +private key 'x', we have: + + s1 - s2 = k^{-1} (h1 + x r) - k^{-1} (h2 + x r) (mod q) + = k^{-1} (h1 + x r - h2 - x r) (mod q) + = k^{-1} (h1 - h2) (mod q) + k = (s1 - s2)^{-1} (h1 - h2) (mod q) + +There are a few pairs of messages here with identical 'r' values. Shove +any pair of them into the Cryptopals.DSA.Attacks.recoverNonce function +to recover the nonce used: + + > m1 + "Listen for me, you better listen for me now. " + > m2 + "Pure black people mon is all I mon know. " + > let k = recoverNonce defaultParams sig1 sig2 h1 h2 + 108994997653034620063305500641348549625 + > let Sec sk = fromsub defaultParams m1 sig1 k + > CS.sha1 . BL.fromStrict . B16.encodeBase16' $ RSA.unroll sk + ca8f6f7c66fa362d40760d135b763eb8527d3d52 diff --git a/lib/Cryptopals/DSA.hs b/lib/Cryptopals/DSA.hs @@ -8,6 +8,7 @@ module Cryptopals.DSA ( , Sig(..) , sign + , sign' , verify ) where @@ -83,6 +84,26 @@ sign ps@Params {..} key msg gen = case key of then sign ps key msg gen else pure (Sig r s) +-- sign with provided subkey/nonce +sign' + :: Params + -> Key + -> Natural + -> BS.ByteString + -> Sig +sign' ps@Params {..} key k msg = case key of + Pub {} -> error "sign: need secret key" + Sec x -> + let r = DH.modexp dsag k p `rem` dsaq + in if r == 0 + then error "sign': invalid nonce (r)" + else + let h = fi . CS.integerDigest . CS.sha1 $ BL.fromStrict msg + s = (RSA.modinv' k dsaq * (h + x * r)) `rem` dsaq + in if s == 0 + then error "sign': invalid nonce (s)" + else Sig r s + verify :: Params -> Key diff --git a/lib/Cryptopals/DSA/Attacks.hs b/lib/Cryptopals/DSA/Attacks.hs @@ -6,15 +6,21 @@ import qualified Cryptopals.Digest.Pure.SHA as CS import Cryptopals.DSA import qualified Cryptopals.RSA as RSA import qualified Data.ByteString as BS +import qualified Data.ByteString.Base16 as B16 import qualified Data.ByteString.Lazy as BL import GHC.Word (Word16) import Numeric.Natural import qualified System.Random.MWC as MWC +fi :: (Integral a, Num b) => a -> b +fi = fromIntegral + +-- key recovery from nonce ---------------------------------------------------- + -- recover private key given a subkey fromsub :: Params -> BS.ByteString -> Sig -> Natural -> Key fromsub Params {..} msg Sig {..} k = - let h = fromIntegral . CS.integerDigest . CS.sha1 $ BL.fromStrict msg + let h = fi . CS.integerDigest . CS.sha1 $ BL.fromStrict msg num = (sigs * k - h) `rem` dsaq den = RSA.modinv' sigr dsaq in Sec $ (num * den) `rem` dsaq @@ -30,7 +36,7 @@ recover ps@Params {..} msg sig pub = ST.runST $ do Pub pb -> pb loop :: forall s. Word16 -> MWC.Gen s -> ST.ST s Key loop k g = do - let sk@(Sec x) = fromsub ps msg sig (fromIntegral k) + let sk@(Sec x) = fromsub ps msg sig (fi k) sig' <- sign ps sk msg g if DH.modexp dsag x dsap == p && verify ps pub msg sig' then pure sk @@ -38,8 +44,8 @@ recover ps@Params {..} msg sig pub = ST.runST $ do rawmsg :: BS.ByteString rawmsg = mconcat [ - "For those that envy a MC it can be hazardous to your health\n" - , "So be friendly, a matter of life and death, just like a etch-a-sketch\n" + "For those that envy a MC it can be hazardous to your health " + , "So be friendly, a matter of life and death, just like a etch-a-sketch " ] rawpub :: Key @@ -51,3 +57,132 @@ rawsig = Sig { , sigs = 857042759984254168557880549501802188789837994940 } +-- nonce recovery from repeated nonce ----------------------------------------- + +recoverNonce :: Params -> Sig -> Sig -> Natural -> Natural -> Natural +recoverNonce Params {..} (Sig _ s1) (Sig _ s2) h1 h2 = + let num = (fi h1 - fi h2) `mod` (fi dsaq :: Integer) + den = (fi s1 - fi s2) `mod` (fi dsaq :: Integer) + in (fi num * RSA.modinv' (fi den) dsaq) `mod` dsaq + +tarpub :: Key +tarpub = Pub 0x2d026f4bf30195ede3a088da85e398ef869611d0f68f0713d51c9c1a3a26c95105d915e2d8cdf26d056b86b8a7b85519b1c23cc3ecdc6062650462e3063bd179c2a6581519f674a61f1d89a1fff27171ebc1b93d4dc57bceb7ae2430f98a6a4d83d8279ee65d71c1203d2c96d65ebbf7cce9d32971c3de5084cce04a2e147821 + +-- msg: Listen for me, you better listen for me now. +-- s: 1267396447369736888040262262183731677867615804316 +-- r: 1105520928110492191417703162650245113664610474875 +-- m: a4db3de27e2db3e5ef085ced2bced91b82e0df19 +r1 :: Natural +r1 = 1105520928110492191417703162650245113664610474875 + +s1 :: Natural +s1 = 1267396447369736888040262262183731677867615804316 + +m1 :: BS.ByteString +m1 = "Listen for me, you better listen for me now. " + +sig1 :: Sig +sig1 = Sig r1 s1 + +h1 :: Natural +h1 = 0xa4db3de27e2db3e5ef085ced2bced91b82e0df19 + +-- msg: Pure black people mon is all I mon know. +-- s: 1021643638653719618255840562522049391608552714967 +-- r: 1105520928110492191417703162650245113664610474875 +-- m: d22804c4899b522b23eda34d2137cd8cc22b9ce8 +r2 :: Natural +r2 = 1105520928110492191417703162650245113664610474875 + +s2 :: Natural +s2 = 1021643638653719618255840562522049391608552714967 + +m2 :: BS.ByteString +m2 = "Pure black people mon is all I mon know. " + +sig2 :: Sig +sig2 = Sig r2 s2 + +h2 :: Natural +h2 = 0xd22804c4899b522b23eda34d2137cd8cc22b9ce8 + +-- msg: Listen for me, you better listen for me now. +-- s: 29097472083055673620219739525237952924429516683 +-- r: 51241962016175933742870323080382366896234169532 +-- m: a4db3de27e2db3e5ef085ced2bced91b82e0df19 + +m3 :: BS.ByteString +m3 = "Listen for me, you better listen for me now. " + +s3 :: Natural +s3 = 29097472083055673620219739525237952924429516683 + +r3 :: Natural +r3 = 51241962016175933742870323080382366896234169532 + +sig3 :: Sig +sig3 = Sig r3 s3 + +h3 :: Natural +h3 = 0xa4db3de27e2db3e5ef085ced2bced91b82e0df19 + +-- msg: Yeah me shoes a an tear up an' now me toes is a show a +-- s: 506591325247687166499867321330657300306462367256 +-- r: 51241962016175933742870323080382366896234169532 +-- m: bc7ec371d951977cba10381da08fe934dea80314 + +m4 :: BS.ByteString +m4 = "Yeah me shoes a an tear up an' now me toes is a show a " + +s4 :: Natural +s4 = 506591325247687166499867321330657300306462367256 + +r4 :: Natural +r4 = 51241962016175933742870323080382366896234169532 + +sig4 :: Sig +sig4 = Sig r4 s4 + +h4 :: Natural +h4 = 0xbc7ec371d951977cba10381da08fe934dea80314 + +-- msg: When me rockin' the microphone me rock on steady, +-- s: 277954141006005142760672187124679727147013405915 +-- r: 228998983350752111397582948403934722619745721541 +-- m: 21194f72fe39a80c9c20689b8cf6ce9b0e7e52d4 + +m5 :: BS.ByteString +m5 = "When me rockin' the microphone me rock on steady, " + +s5 :: Natural +s5 = 277954141006005142760672187124679727147013405915 + +r5 :: Natural +r5 = 228998983350752111397582948403934722619745721541 + +sig5 :: Sig +sig5 = Sig r5 s5 + +h5 :: Natural +h5 = 0x21194f72fe39a80c9c20689b8cf6ce9b0e7e52d4 + +-- msg: Where me a born in are de one Toronto, so +-- s: 458429062067186207052865988429747640462282138703 +-- r: 228998983350752111397582948403934722619745721541 +-- m: d6340bfcda59b6b75b59ca634813d572de800e8f + +m6 :: BS.ByteString +m6 = "Where me a born in are de one Toronto, so " + +s6 :: Natural +s6 = 458429062067186207052865988429747640462282138703 + +r6 :: Natural +r6 = 228998983350752111397582948403934722619745721541 + +sig6 :: Sig +sig6 = Sig r6 s6 + +h6 :: Natural +h6 = 0xd6340bfcda59b6b75b59ca634813d572de800e8f +