From 320186cdd1734c6fedbc73cccdf4d4202d725b9c Mon Sep 17 00:00:00 2001 From: John Galt Date: Sun, 15 Nov 2015 00:07:35 -0500 Subject: [PATCH 1/2] Fix endianness of incrementNonce function for ChaChaPoly1305 --- CHANGELOG.md | 1 + Crypto/Cipher/ChaChaPoly1305.hs | 42 +++++++++++++++++++++++---------- tests/ChaChaPoly1305.hs | 31 +++++++++++++++++------- 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f97df81..423a044 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Add missing documentation for various modules * Add a way to create Poly1305 Auth tag. * Added support for the BLAKE2 family of hash algorithms +* Fix endianness of incrementNonce function for ChaChaPoly1305 ## 0.8 diff --git a/Crypto/Cipher/ChaChaPoly1305.hs b/Crypto/Cipher/ChaChaPoly1305.hs index c464202..4bc622c 100644 --- a/Crypto/Cipher/ChaChaPoly1305.hs +++ b/Crypto/Cipher/ChaChaPoly1305.hs @@ -38,6 +38,7 @@ module Crypto.Cipher.ChaChaPoly1305 , finalize ) where +import Control.Monad (when) import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, Bytes, ScrubbedBytes) import qualified Crypto.Internal.ByteArray as B import Crypto.Internal.Imports @@ -60,8 +61,14 @@ data State = State !ChaCha.State -- | Valid Nonce for ChaChaPoly1305. -- -- It can be created with 'nonce8' or 'nonce12' -newtype Nonce = Nonce Bytes - deriving (ByteArrayAccess) +data Nonce = Nonce8 Bytes | Nonce12 Bytes + +instance ByteArrayAccess Nonce where + length (Nonce8 n) = B.length n + length (Nonce12 n) = B.length n + + withByteArray (Nonce8 n) = B.withByteArray n + withByteArray (Nonce12 n) = B.withByteArray n -- Based on the following pseudo code: -- @@ -86,8 +93,8 @@ pad16 n -- | Nonce smart constructor 12 bytes IV, nonce constructor nonce12 :: ByteArrayAccess iv => iv -> CryptoFailable Nonce nonce12 iv - | B.length iv /= 12 = CryptoFailed $ CryptoError_IvSizeInvalid - | otherwise = CryptoPassed $ Nonce (B.convert iv) + | B.length iv /= 12 = CryptoFailed CryptoError_IvSizeInvalid + | otherwise = CryptoPassed . Nonce12 . B.convert $ iv -- | 8 bytes IV, nonce constructor nonce8 :: ByteArrayAccess ba @@ -95,22 +102,26 @@ nonce8 :: ByteArrayAccess ba -> ba -- ^ 8 bytes IV -> CryptoFailable Nonce nonce8 constant iv - | B.length constant /= 4 = CryptoFailed $ CryptoError_IvSizeInvalid - | B.length iv /= 8 = CryptoFailed $ CryptoError_IvSizeInvalid - | otherwise = CryptoPassed $ Nonce $ B.concat [constant, iv] + | B.length constant /= 4 = CryptoFailed CryptoError_IvSizeInvalid + | B.length iv /= 8 = CryptoFailed CryptoError_IvSizeInvalid + | otherwise = CryptoPassed . Nonce8 . B.concat $ [constant, iv] -- | Increment a nonce incrementNonce :: Nonce -> Nonce -incrementNonce (Nonce n) = Nonce $ B.copyAndFreeze n $ \s -> - loop s $ s `plusPtr` ((B.length n) - 1) +incrementNonce (Nonce8 n) = Nonce8 $ incrementNonce' n 4 +incrementNonce (Nonce12 n) = Nonce12 $ incrementNonce' n 0 + +incrementNonce' :: Bytes -> Int -> Bytes +incrementNonce' b offset = B.copyAndFreeze b $ \s -> + loop s (s `plusPtr` offset) where loop :: Ptr Word8 -> Ptr Word8 -> IO () loop s p - | s == p = peek s >>= poke s . (+) 1 + | s == (p `plusPtr` (B.length b - offset - 1)) = peek s >>= poke s . (+) 1 | otherwise = do r <- (+) 1 <$> peek p poke p r - if r == 0 then loop s (p `plusPtr` (-1)) else return () + when (r == 0) $ loop s (p `plusPtr` 1) -- | Initialize a new ChaChaPoly1305 State -- @@ -118,8 +129,13 @@ incrementNonce (Nonce n) = Nonce $ B.copyAndFreeze n $ \s -> -- procured using either `nonce8` or `nonce12` initialize :: ByteArrayAccess key => key -> Nonce -> CryptoFailable State -initialize key (Nonce nonce) - | B.length key /= 32 = CryptoFailed $ CryptoError_KeySizeInvalid +initialize key (Nonce8 nonce) = initialize' key nonce +initialize key (Nonce12 nonce) = initialize' key nonce + +initialize' :: ByteArrayAccess key + => key -> Bytes -> CryptoFailable State +initialize' key nonce + | B.length key /= 32 = CryptoFailed CryptoError_KeySizeInvalid | otherwise = CryptoPassed $ State encState polyState 0 0 where rootState = ChaCha.initialize 20 key nonce diff --git a/tests/ChaChaPoly1305.hs b/tests/ChaChaPoly1305.hs index 39b455d..fab7330 100644 --- a/tests/ChaChaPoly1305.hs +++ b/tests/ChaChaPoly1305.hs @@ -9,7 +9,7 @@ import Poly1305 () import qualified Data.ByteString as B import qualified Data.ByteArray as B (convert) -plaintext, aad, key, iv, ciphertext, tag, nonce1, nonce2, nonce3 :: B.ByteString +plaintext, aad, key, iv, ciphertext, tag, nonce1, nonce2, nonce3, nonce4, nonce5, nonce6, nonce7, nonce8, nonce9, nonce10 :: B.ByteString plaintext = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it." aad = "\x50\x51\x52\x53\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" key = "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" @@ -17,9 +17,16 @@ iv = "\x40\x41\x42\x43\x44\x45\x46\x47" constant = "\x07\x00\x00\x00" ciphertext = "\xd3\x1a\x8d\x34\x64\x8e\x60\xdb\x7b\x86\xaf\xbc\x53\xef\x7e\xc2\xa4\xad\xed\x51\x29\x6e\x08\xfe\xa9\xe2\xb5\xa7\x36\xee\x62\xd6\x3d\xbe\xa4\x5e\x8c\xa9\x67\x12\x82\xfa\xfb\x69\xda\x92\x72\x8b\x1a\x71\xde\x0a\x9e\x06\x0b\x29\x05\xd6\xa5\xb6\x7e\xcd\x3b\x36\x92\xdd\xbd\x7f\x2d\x77\x8b\x8c\x98\x03\xae\xe3\x28\x09\x1b\x58\xfa\xb3\x24\xe4\xfa\xd6\x75\x94\x55\x85\x80\x8b\x48\x31\xd7\xbc\x3f\xf4\xde\xf0\x8e\x4b\x7a\x9d\xe5\x76\xd2\x65\x86\xce\xc6\x4b\x61\x16" tag = "\x1a\xe1\x0b\x59\x4f\x09\xe2\x6a\x7e\x90\x2e\xcb\xd0\x60\x06\x91" -nonce1 = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" -nonce2 = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" -nonce3 = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +nonce1 = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +nonce2 = "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +nonce3 = "\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +nonce4 = "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +nonce5 = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +nonce6 = "\x00\x00\x00\x00\x00\x00\x00\x00" +nonce7 = "\x01\x00\x00\x00\x00\x00\x00\x00" +nonce8 = "\xff\x00\x00\x00\x00\x00\x00\x00" +nonce9 = "\x00\x01\x00\x00\x00\x00\x00\x00" +nonce10 = "\xff\xff\xff\xff\xff\xff\xff\xff" tests = testGroup "ChaChaPoly1305" [ testCase "V1" runEncrypt @@ -45,8 +52,16 @@ tests = testGroup "ChaChaPoly1305" ] runNonceInc = - let n1 = throwCryptoError $ AEAD.nonce12 nonce1 - n3 = throwCryptoError $ AEAD.nonce12 nonce3 - in propertyHoldCase [ eqTest "nonce" nonce2 $ B.convert . AEAD.incrementNonce $ n1 - , eqTest "nonce" nonce1 $ B.convert . AEAD.incrementNonce $ n3 + let n1 = throwCryptoError . AEAD.nonce12 $ nonce1 + n3 = throwCryptoError . AEAD.nonce12 $ nonce3 + n5 = throwCryptoError . AEAD.nonce12 $ nonce5 + n6 = throwCryptoError . AEAD.nonce8 constant $ nonce6 + n8 = throwCryptoError . AEAD.nonce8 constant $ nonce8 + n10 = throwCryptoError . AEAD.nonce8 constant $ nonce10 + in propertyHoldCase [ eqTest "nonce12a" nonce2 $ B.convert . AEAD.incrementNonce $ n1 + , eqTest "nonce12b" nonce4 $ B.convert . AEAD.incrementNonce $ n3 + , eqTest "nonce12c" nonce1 $ B.convert . AEAD.incrementNonce $ n5 + , eqTest "nonce8a" (B.concat [constant, nonce7]) $ B.convert . AEAD.incrementNonce $ n6 + , eqTest "nonce8b" (B.concat [constant, nonce9]) $ B.convert . AEAD.incrementNonce $ n8 + , eqTest "nonce8c" (B.concat [constant, nonce6]) $ B.convert . AEAD.incrementNonce $ n10 ] From 53270f1ef67a0fc32ae83800e42b5bfed805acb1 Mon Sep 17 00:00:00 2001 From: John Galt Date: Mon, 16 Nov 2015 13:13:18 -0500 Subject: [PATCH 2/2] Removed unused language extension --- Crypto/Cipher/ChaChaPoly1305.hs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Crypto/Cipher/ChaChaPoly1305.hs b/Crypto/Cipher/ChaChaPoly1305.hs index 4bc622c..ed8b99e 100644 --- a/Crypto/Cipher/ChaChaPoly1305.hs +++ b/Crypto/Cipher/ChaChaPoly1305.hs @@ -1,5 +1,3 @@ -{-# LANGUAGE GeneralizedNewtypeDeriving #-} - -- | -- Module : Crypto.Cipher.ChaChaPoly1305 -- License : BSD-style