module Test.Cardano.Crypto.Wallet.V2FormatSpec (tests) where
import qualified Codec.CBOR.Decoding as CBOR
import qualified Codec.CBOR.Read as CBOR
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import Test.Hspec
import Cardano.Crypto.WalletHD.Encrypted
testSeed :: BS.ByteString
testSeed :: ByteString
testSeed = Int -> Word8 -> ByteString
BS.replicate Int
32 Word8
0x02
testCC :: BS.ByteString
testCC :: ByteString
testCC = Int -> Word8 -> ByteString
BS.replicate Int
32 Word8
0xAB
testPass :: BS.ByteString
testPass :: ByteString
testPass = Int -> Word8 -> ByteString
BS.replicate Int
32 Word8
0x42
wrongPass :: BS.ByteString
wrongPass :: ByteString
wrongPass = Int -> Word8 -> ByteString
BS.replicate Int
32 Word8
0x00
expectedPublicKey :: BS.ByteString
expectedPublicKey :: ByteString
expectedPublicKey =
[Word8] -> ByteString
BS.pack
[ Word8
129
, Word8
57
, Word8
119
, Word8
14
, Word8
168
, Word8
125
, Word8
23
, Word8
95
, Word8
86
, Word8
163
, Word8
84
, Word8
102
, Word8
195
, Word8
76
, Word8
126
, Word8
204
, Word8
203
, Word8
141
, Word8
138
, Word8
145
, Word8
180
, Word8
238
, Word8
55
, Word8
162
, Word8
93
, Word8
246
, Word8
15
, Word8
91
, Word8
143
, Word8
201
, Word8
179
, Word8
148
]
tests :: Spec
tests :: Spec
tests = String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
"V2Format" (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
String -> IO () -> SpecWith (Arg (IO ()))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"encryptedCreate produces EnvelopeV2 format" (IO () -> SpecWith (Arg (IO ())))
-> IO () -> SpecWith (Arg (IO ()))
forall a b. (a -> b) -> a -> b
$ do
Either XPrvError EncryptedKey
res <- ByteString
-> ByteString -> ByteString -> IO (Either XPrvError EncryptedKey)
forall passphrase secret cc.
(ByteArrayAccess passphrase, ByteArrayAccess secret,
ByteArrayAccess cc) =>
secret -> passphrase -> cc -> IO (Either XPrvError EncryptedKey)
encryptedCreate ByteString
testSeed ByteString
testPass ByteString
testCC
case Either XPrvError EncryptedKey
res of
Left XPrvError
err -> HasCallStack => String -> IO ()
String -> IO ()
expectationFailure (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"encryptedCreate failed: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ XPrvError -> String
forall a. Show a => a -> String
show XPrvError
err
Right EncryptedKey
key -> EncryptedKey -> XPrvFormat
encryptedKeyFormat EncryptedKey
key XPrvFormat -> XPrvFormat -> IO ()
forall a. (HasCallStack, Show a, Eq a) => a -> a -> IO ()
`shouldBe` XPrvFormat
EnvelopeV2
String -> IO () -> SpecWith (Arg (IO ()))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"v2 key validates with correct passphrase" (IO () -> SpecWith (Arg (IO ())))
-> IO () -> SpecWith (Arg (IO ()))
forall a b. (a -> b) -> a -> b
$ do
Either XPrvError EncryptedKey
res <- ByteString
-> ByteString -> ByteString -> IO (Either XPrvError EncryptedKey)
forall passphrase secret cc.
(ByteArrayAccess passphrase, ByteArrayAccess secret,
ByteArrayAccess cc) =>
secret -> passphrase -> cc -> IO (Either XPrvError EncryptedKey)
encryptedCreate ByteString
testSeed ByteString
testPass ByteString
testCC
case Either XPrvError EncryptedKey
res of
Left XPrvError
err -> HasCallStack => String -> IO ()
String -> IO ()
expectationFailure (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"encryptedCreate failed: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ XPrvError -> String
forall a. Show a => a -> String
show XPrvError
err
Right EncryptedKey
key -> do
Either XPrvError ()
r <- EncryptedKey -> ByteString -> IO (Either XPrvError ())
forall passphrase.
ByteArrayAccess passphrase =>
EncryptedKey -> passphrase -> IO (Either XPrvError ())
encryptedValidatePassphrase EncryptedKey
key ByteString
testPass
Either XPrvError ()
r Either XPrvError () -> Either XPrvError () -> IO ()
forall a. (HasCallStack, Show a, Eq a) => a -> a -> IO ()
`shouldBe` () -> Either XPrvError ()
forall a b. b -> Either a b
Right ()
String -> IO () -> SpecWith (Arg (IO ()))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"v2 key rejects wrong passphrase with XPrvAuthenticationFailed" (IO () -> SpecWith (Arg (IO ())))
-> IO () -> SpecWith (Arg (IO ()))
forall a b. (a -> b) -> a -> b
$ do
Either XPrvError EncryptedKey
res <- ByteString
-> ByteString -> ByteString -> IO (Either XPrvError EncryptedKey)
forall passphrase secret cc.
(ByteArrayAccess passphrase, ByteArrayAccess secret,
ByteArrayAccess cc) =>
secret -> passphrase -> cc -> IO (Either XPrvError EncryptedKey)
encryptedCreate ByteString
testSeed ByteString
testPass ByteString
testCC
case Either XPrvError EncryptedKey
res of
Left XPrvError
err -> HasCallStack => String -> IO ()
String -> IO ()
expectationFailure (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"encryptedCreate failed: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ XPrvError -> String
forall a. Show a => a -> String
show XPrvError
err
Right EncryptedKey
key -> do
Either XPrvError ()
r <- EncryptedKey -> ByteString -> IO (Either XPrvError ())
forall passphrase.
ByteArrayAccess passphrase =>
EncryptedKey -> passphrase -> IO (Either XPrvError ())
encryptedValidatePassphrase EncryptedKey
key ByteString
wrongPass
Either XPrvError ()
r Either XPrvError () -> Either XPrvError () -> IO ()
forall a. (HasCallStack, Show a, Eq a) => a -> a -> IO ()
`shouldBe` XPrvError -> Either XPrvError ()
forall a b. a -> Either a b
Left XPrvError
XPrvAuthenticationFailed
String -> IO () -> SpecWith (Arg (IO ()))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"v2 envelope is a CBOR 9-element array" (IO () -> SpecWith (Arg (IO ())))
-> IO () -> SpecWith (Arg (IO ()))
forall a b. (a -> b) -> a -> b
$ do
Either XPrvError EncryptedKey
res <- ByteString
-> ByteString -> ByteString -> IO (Either XPrvError EncryptedKey)
forall passphrase secret cc.
(ByteArrayAccess passphrase, ByteArrayAccess secret,
ByteArrayAccess cc) =>
secret -> passphrase -> cc -> IO (Either XPrvError EncryptedKey)
encryptedCreate ByteString
testSeed ByteString
testPass ByteString
testCC
case Either XPrvError EncryptedKey
res of
Left XPrvError
err -> HasCallStack => String -> IO ()
String -> IO ()
expectationFailure (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"encryptedCreate failed: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ XPrvError -> String
forall a. Show a => a -> String
show XPrvError
err
Right EncryptedKey
key -> do
let bs :: ByteString
bs = EncryptedKey -> ByteString
unEncryptedKey EncryptedKey
key
case (forall s. Decoder s Int)
-> ByteString -> Either DeserialiseFailure (ByteString, Int)
forall a.
(forall s. Decoder s a)
-> ByteString -> Either DeserialiseFailure (ByteString, a)
CBOR.deserialiseFromBytes Decoder s Int
forall s. Decoder s Int
CBOR.decodeListLen (ByteString -> ByteString
BL.fromStrict ByteString
bs) of
Left DeserialiseFailure
e -> HasCallStack => String -> IO ()
String -> IO ()
expectationFailure (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"CBOR decode failed: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ DeserialiseFailure -> String
forall a. Show a => a -> String
show DeserialiseFailure
e
Right (ByteString
_, Int
9) -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Right (ByteString
_, Int
n) ->
HasCallStack => String -> IO ()
String -> IO ()
expectationFailure (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
String
"Expected 9-element CBOR array, got: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
n
String -> IO () -> SpecWith (Arg (IO ()))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"public key and chain code in envelope match accessors" (IO () -> SpecWith (Arg (IO ())))
-> IO () -> SpecWith (Arg (IO ()))
forall a b. (a -> b) -> a -> b
$ do
Either XPrvError EncryptedKey
res <- ByteString
-> ByteString -> ByteString -> IO (Either XPrvError EncryptedKey)
forall passphrase secret cc.
(ByteArrayAccess passphrase, ByteArrayAccess secret,
ByteArrayAccess cc) =>
secret -> passphrase -> cc -> IO (Either XPrvError EncryptedKey)
encryptedCreate ByteString
testSeed ByteString
testPass ByteString
testCC
case Either XPrvError EncryptedKey
res of
Left XPrvError
err -> HasCallStack => String -> IO ()
String -> IO ()
expectationFailure (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"encryptedCreate failed: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ XPrvError -> String
forall a. Show a => a -> String
show XPrvError
err
Right EncryptedKey
key -> do
let pub :: ByteString
pub = EncryptedKey -> ByteString
encryptedPublic EncryptedKey
key
cc :: ByteString
cc = EncryptedKey -> ByteString
encryptedChainCode EncryptedKey
key
case ByteString -> Either XPrvError EncryptedKey
encryptedKey (EncryptedKey -> ByteString
unEncryptedKey EncryptedKey
key) of
Left XPrvError
err -> HasCallStack => String -> IO ()
String -> IO ()
expectationFailure (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"re-parse failed: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ XPrvError -> String
forall a. Show a => a -> String
show XPrvError
err
Right EncryptedKey
key' -> do
EncryptedKey -> ByteString
encryptedPublic EncryptedKey
key' ByteString -> ByteString -> IO ()
forall a. (HasCallStack, Show a, Eq a) => a -> a -> IO ()
`shouldBe` ByteString
pub
EncryptedKey -> ByteString
encryptedChainCode EncryptedKey
key' ByteString -> ByteString -> IO ()
forall a. (HasCallStack, Show a, Eq a) => a -> a -> IO ()
`shouldBe` ByteString
cc
String -> IO () -> SpecWith (Arg (IO ()))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"presenting a v1 raw blob returns Left XPrvDecodeError" (IO () -> SpecWith (Arg (IO ())))
-> IO () -> SpecWith (Arg (IO ()))
forall a b. (a -> b) -> a -> b
$ do
let v1blob :: ByteString
v1blob = Int -> Word8 -> ByteString
BS.replicate Int
128 Word8
0x00
case ByteString -> Either XPrvError EncryptedKey
encryptedKey ByteString
v1blob of
Left XPrvError
err -> HasCallStack => String -> IO ()
String -> IO ()
expectationFailure (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"encryptedKey rejected v1 blob: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ XPrvError -> String
forall a. Show a => a -> String
show XPrvError
err
Right EncryptedKey
key -> do
Either XPrvError ()
r <- EncryptedKey -> ByteString -> IO (Either XPrvError ())
forall passphrase.
ByteArrayAccess passphrase =>
EncryptedKey -> passphrase -> IO (Either XPrvError ())
encryptedValidatePassphrase EncryptedKey
key ByteString
testPass
Either XPrvError ()
r Either XPrvError () -> Either XPrvError () -> IO ()
forall a. (HasCallStack, Show a, Eq a) => a -> a -> IO ()
`shouldBe` XPrvError -> Either XPrvError ()
forall a b. a -> Either a b
Left XPrvError
XPrvDecodeError
String -> IO () -> SpecWith (Arg (IO ()))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"truncated CBOR bytes return Left XPrvDecodeError" (IO () -> SpecWith (Arg (IO ())))
-> IO () -> SpecWith (Arg (IO ()))
forall a b. (a -> b) -> a -> b
$ do
Either XPrvError EncryptedKey
res <- ByteString
-> ByteString -> ByteString -> IO (Either XPrvError EncryptedKey)
forall passphrase secret cc.
(ByteArrayAccess passphrase, ByteArrayAccess secret,
ByteArrayAccess cc) =>
secret -> passphrase -> cc -> IO (Either XPrvError EncryptedKey)
encryptedCreate ByteString
testSeed ByteString
testPass ByteString
testCC
case Either XPrvError EncryptedKey
res of
Left XPrvError
err -> HasCallStack => String -> IO ()
String -> IO ()
expectationFailure (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"encryptedCreate failed: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ XPrvError -> String
forall a. Show a => a -> String
show XPrvError
err
Right EncryptedKey
key ->
ByteString -> Either XPrvError EncryptedKey
encryptedKey (Int -> ByteString -> ByteString
BS.take Int
10 (EncryptedKey -> ByteString
unEncryptedKey EncryptedKey
key))
Either XPrvError EncryptedKey
-> Either XPrvError EncryptedKey -> IO ()
forall a. (HasCallStack, Show a, Eq a) => a -> a -> IO ()
`shouldBe` XPrvError -> Either XPrvError EncryptedKey
forall a b. a -> Either a b
Left XPrvError
XPrvDecodeError
String -> IO () -> SpecWith (Arg (IO ()))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"encryptedChangePass re-randomizes envelope (different bytes, same public key)" (IO () -> SpecWith (Arg (IO ())))
-> IO () -> SpecWith (Arg (IO ()))
forall a b. (a -> b) -> a -> b
$ do
Either XPrvError EncryptedKey
res <- ByteString
-> ByteString -> ByteString -> IO (Either XPrvError EncryptedKey)
forall passphrase secret cc.
(ByteArrayAccess passphrase, ByteArrayAccess secret,
ByteArrayAccess cc) =>
secret -> passphrase -> cc -> IO (Either XPrvError EncryptedKey)
encryptedCreate ByteString
testSeed ByteString
testPass ByteString
testCC
case Either XPrvError EncryptedKey
res of
Left XPrvError
err -> HasCallStack => String -> IO ()
String -> IO ()
expectationFailure (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"encryptedCreate failed: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ XPrvError -> String
forall a. Show a => a -> String
show XPrvError
err
Right EncryptedKey
key -> do
Either XPrvError EncryptedKey
res' <- ByteString
-> ByteString -> EncryptedKey -> IO (Either XPrvError EncryptedKey)
forall oldPassPhrase newPassPhrase.
(ByteArrayAccess oldPassPhrase, ByteArrayAccess newPassPhrase) =>
oldPassPhrase
-> newPassPhrase
-> EncryptedKey
-> IO (Either XPrvError EncryptedKey)
encryptedChangePass ByteString
testPass ByteString
testPass EncryptedKey
key
case Either XPrvError EncryptedKey
res' of
Left XPrvError
err -> HasCallStack => String -> IO ()
String -> IO ()
expectationFailure (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"changePass failed: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ XPrvError -> String
forall a. Show a => a -> String
show XPrvError
err
Right EncryptedKey
key' -> do
EncryptedKey -> ByteString
encryptedPublic EncryptedKey
key ByteString -> ByteString -> IO ()
forall a. (HasCallStack, Show a, Eq a) => a -> a -> IO ()
`shouldBe` EncryptedKey -> ByteString
encryptedPublic EncryptedKey
key'
EncryptedKey -> ByteString
unEncryptedKey EncryptedKey
key ByteString -> ByteString -> IO ()
forall a. (HasCallStack, Show a, Eq a) => a -> a -> IO ()
`shouldNotBe` EncryptedKey -> ByteString
unEncryptedKey EncryptedKey
key'
String -> IO () -> SpecWith (Arg (IO ()))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"golden: public key matches deterministic ed25519 derivation from testSeed" (IO () -> SpecWith (Arg (IO ())))
-> IO () -> SpecWith (Arg (IO ()))
forall a b. (a -> b) -> a -> b
$ do
Either XPrvError EncryptedKey
res <- ByteString
-> ByteString -> ByteString -> IO (Either XPrvError EncryptedKey)
forall passphrase secret cc.
(ByteArrayAccess passphrase, ByteArrayAccess secret,
ByteArrayAccess cc) =>
secret -> passphrase -> cc -> IO (Either XPrvError EncryptedKey)
encryptedCreate ByteString
testSeed ByteString
testPass ByteString
testCC
case Either XPrvError EncryptedKey
res of
Left XPrvError
err -> HasCallStack => String -> IO ()
String -> IO ()
expectationFailure (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"encryptedCreate failed: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ XPrvError -> String
forall a. Show a => a -> String
show XPrvError
err
Right EncryptedKey
key -> EncryptedKey -> ByteString
encryptedPublic EncryptedKey
key ByteString -> ByteString -> IO ()
forall a. (HasCallStack, Show a, Eq a) => a -> a -> IO ()
`shouldBe` ByteString
expectedPublicKey