paseto-0.1.0.0: test/Test/Crypto/Paseto/Protocol/V3.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TemplateHaskell #-}
module Test.Crypto.Paseto.Protocol.V3
( tests
) where
import Crypto.Paseto.Keys ( SigningKey (..), SymmetricKey (..), fromSigningKey )
import Crypto.Paseto.Mode ( Purpose (..), Version (..) )
import Crypto.Paseto.Protocol.V3 ( decrypt, encryptPure, signPure, verify )
import Crypto.Paseto.Token
( Footer (..), ImplicitAssertion, Payload (..), Token (..) )
import Crypto.Paseto.Token.Claims ( Claims )
import Data.ByteString ( ByteString )
import Hedgehog
( Property, checkParallel, discover, forAll, forAllWith, property, tripping )
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
import Prelude
import Test.Crypto.Paseto.Keys.Gen ( genSigningKeyV3, genSymmetricKeyV3 )
import Test.Crypto.Paseto.Keys.V3.Gen ( genScalarP384 )
import Test.Crypto.Paseto.Token.Claims.Gen ( genClaims )
import Test.Crypto.Paseto.Token.Gen ( genFooter, genImplicitAssertion )
import Test.Golden ( goldenTestPaseto )
tests :: IO Bool
tests = checkParallel $$(discover)
------------------------------------------------------------------------------
-- Properties
------------------------------------------------------------------------------
-- | Test that 'encryptPure' (a pure variant of 'encrypt') and 'decrypt' round
-- trip.
prop_roundTrip_encryptDecrypt :: Property
prop_roundTrip_encryptDecrypt = property $ do
n <- forAll $ Gen.bytes (Range.singleton 32)
k <- forAllWith unsafeRenderSymmetricKey genSymmetricKeyV3
claims <- forAll $ genClaims
f <- forAll $ Gen.maybe genFooter
i <- forAll $ Gen.maybe genImplicitAssertion
tripping claims (\cs -> unsafeEncryptPure n k cs f i) (\t -> decrypt k t f i)
where
unsafeEncryptPure
:: ByteString
-> SymmetricKey V3
-> Claims
-> Maybe Footer
-> Maybe ImplicitAssertion
-> Token V3 Local
unsafeEncryptPure n k cs f i =
case encryptPure n k cs f i of
Left err -> error $ "impossible: could not encrypt: " <> show err
Right encrypted -> encrypted
-- | Test that 'signPure' (a pure variant of 'sign') and 'verify' round trip.
prop_roundTrip_signVerify :: Property
prop_roundTrip_signVerify = property$ do
k <- forAll genScalarP384
sk <- forAllWith unsafeRenderSigningKey genSigningKeyV3
let vk = fromSigningKey sk
claims <- forAll $ genClaims
f <- forAll $ Gen.maybe genFooter
i <- forAll $ Gen.maybe genImplicitAssertion
tripping claims (\cs -> unsafeSignPure k sk cs f i) (\t -> verify vk t f i)
where
unsafeSignPure
:: Integer
-> SigningKey V3
-> Claims
-> Maybe Footer
-> Maybe ImplicitAssertion
-> Token V3 Public
unsafeSignPure k sk cs f i =
case signPure k sk cs f i of
Left err -> error $ "impossible: could not sign: " <> show err
Right signed -> signed
prop_golden_TokenV3Local :: Property
prop_golden_TokenV3Local = goldenTestPaseto goldenTokenV3Local "test/golden/paseto/v3-local/golden"
prop_golden_TokenV3Public :: Property
prop_golden_TokenV3Public = goldenTestPaseto goldenTokenV3Public "test/golden/paseto/v3-public/golden"
------------------------------------------------------------------------------
-- Golden examples
------------------------------------------------------------------------------
goldenTokenV3Local :: Token V3 Local
goldenTokenV3Local =
TokenV3Local
(Payload "&\247U3TH*\GS\145\212xF'\133K\141\166\184\EOT*yfR<+@N\141\187\231\247\242\240c\191/Bp\218\138\223\144\250\200\225\ETB\207\GS\ESC`t_\238\SI\220G1\CANy\252\195\&3\219N\186\142lxr\160\170c\203w0e\f\203v,\DC1\177\209\n\229 \239\151M\191\RS5\138%m\168\168c\SO@\153\146xC)\132E\135\139\vC(\151\237\131\141N\212_\aj\223\188\145\SI6d\128\f\SYN\169\&1\246\174U\145iqfG\189g3\SOHm\189\217\157\250")
(Just (Footer "{\"kid\":\"UbkK8Y6iv4GZhFp6Tx3IWLWLfNXSEvJcdT3zdR65YZxo\"}"))
goldenTokenV3Public :: Token V3 Public
goldenTokenV3Public =
TokenV3Public
(Payload "{\"data\":\"this is a signed message\",\"exp\":\"2022-01-01T00:00:00+00:00\"}\190\182\171OKA>\233\139\177Hy\136\145\131\f~\236\"C\228\213\245\188\DC2>\145\218?\188\140\RS\235\146@\137\200B\177p\195O'\152\203\186\179\239e,\209t\182\254!\175\216\217\133\218\189\142\251\197\178\243%\STXd\ETX\252\227%\230+w\201\150Cn(:\153-\179P\172\179u\218\239\135\&3\254=\192")
Nothing
------------------------------------------------------------------------------
-- Helpers
------------------------------------------------------------------------------
unsafeRenderSymmetricKey :: SymmetricKey v -> String
unsafeRenderSymmetricKey k =
case k of
SymmetricKeyV3 bs -> "SymmetricKeyV3 " <> show bs
SymmetricKeyV4 bs -> "SymmetricKeyV4 " <> show bs
unsafeRenderSigningKey :: SigningKey v -> String
unsafeRenderSigningKey sk =
case sk of
SigningKeyV3 k -> "SigningKeyV3 " <> show k
SigningKeyV4 bs -> "SigningKeyV4 " <> show bs