module Network.LibP2P.Crypto.SignedEnvelope
( SignedEnvelope (..)
, createEnvelope
, verifyEnvelope
, encodeSignedEnvelope
, decodeSignedEnvelope
, buildSigningContent
) where
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import Data.Word (Word64)
import Network.LibP2P.Core.Varint (encodeUvarint)
import Network.LibP2P.Crypto.Key (PublicKey (..), PrivateKey, sign, verify)
import Network.LibP2P.Crypto.Protobuf (encodePublicKey, decodePublicKey)
import qualified Proto3.Wire.Decode as Decode
import Proto3.Wire.Decode (Parser, RawMessage, at, one, parse)
import qualified Proto3.Wire.Encode as Encode
import Proto3.Wire.Types (FieldNumber (..))
data SignedEnvelope = SignedEnvelope
{ SignedEnvelope -> PublicKey
sePublicKey :: !PublicKey
, SignedEnvelope -> ByteString
seDomain :: !ByteString
, SignedEnvelope -> ByteString
sePayloadType :: !ByteString
, SignedEnvelope -> ByteString
sePayload :: !ByteString
, SignedEnvelope -> ByteString
seSignature :: !ByteString
} deriving (Int -> SignedEnvelope -> ShowS
[SignedEnvelope] -> ShowS
SignedEnvelope -> [Char]
(Int -> SignedEnvelope -> ShowS)
-> (SignedEnvelope -> [Char])
-> ([SignedEnvelope] -> ShowS)
-> Show SignedEnvelope
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SignedEnvelope -> ShowS
showsPrec :: Int -> SignedEnvelope -> ShowS
$cshow :: SignedEnvelope -> [Char]
show :: SignedEnvelope -> [Char]
$cshowList :: [SignedEnvelope] -> ShowS
showList :: [SignedEnvelope] -> ShowS
Show, SignedEnvelope -> SignedEnvelope -> Bool
(SignedEnvelope -> SignedEnvelope -> Bool)
-> (SignedEnvelope -> SignedEnvelope -> Bool) -> Eq SignedEnvelope
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SignedEnvelope -> SignedEnvelope -> Bool
== :: SignedEnvelope -> SignedEnvelope -> Bool
$c/= :: SignedEnvelope -> SignedEnvelope -> Bool
/= :: SignedEnvelope -> SignedEnvelope -> Bool
Eq)
buildSigningContent :: ByteString -> ByteString -> ByteString -> ByteString
buildSigningContent :: ByteString -> ByteString -> ByteString -> ByteString
buildSigningContent ByteString
domain ByteString
payloadType ByteString
payload =
let lenPrefix :: ByteString -> ByteString
lenPrefix ByteString
bs = Word64 -> ByteString
encodeUvarint (Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int
BS.length ByteString
bs) :: Word64) ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
bs
in ByteString -> ByteString
lenPrefix ByteString
domain ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString -> ByteString
lenPrefix ByteString
payloadType ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString -> ByteString
lenPrefix ByteString
payload
createEnvelope :: PrivateKey -> PublicKey -> ByteString -> ByteString -> ByteString -> Either String SignedEnvelope
createEnvelope :: PrivateKey
-> PublicKey
-> ByteString
-> ByteString
-> ByteString
-> Either [Char] SignedEnvelope
createEnvelope PrivateKey
privKey PublicKey
pubKey ByteString
domain ByteString
payloadType ByteString
payload = do
let content :: ByteString
content = ByteString -> ByteString -> ByteString -> ByteString
buildSigningContent ByteString
domain ByteString
payloadType ByteString
payload
sig <- PrivateKey -> ByteString -> Either [Char] ByteString
sign PrivateKey
privKey ByteString
content
Right SignedEnvelope
{ sePublicKey = pubKey
, seDomain = domain
, sePayloadType = payloadType
, sePayload = payload
, seSignature = sig
}
verifyEnvelope :: SignedEnvelope -> ByteString -> Bool
verifyEnvelope :: SignedEnvelope -> ByteString -> Bool
verifyEnvelope SignedEnvelope
env ByteString
expectedDomain =
let content :: ByteString
content = ByteString -> ByteString -> ByteString -> ByteString
buildSigningContent ByteString
expectedDomain (SignedEnvelope -> ByteString
sePayloadType SignedEnvelope
env) (SignedEnvelope -> ByteString
sePayload SignedEnvelope
env)
in PublicKey -> ByteString -> ByteString -> Bool
verify (SignedEnvelope -> PublicKey
sePublicKey SignedEnvelope
env) ByteString
content (SignedEnvelope -> ByteString
seSignature SignedEnvelope
env)
encodeSignedEnvelope :: SignedEnvelope -> ByteString
encodeSignedEnvelope :: SignedEnvelope -> ByteString
encodeSignedEnvelope SignedEnvelope
env = LazyByteString -> ByteString
BL.toStrict (LazyByteString -> ByteString) -> LazyByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ MessageBuilder -> LazyByteString
Encode.toLazyByteString (MessageBuilder -> LazyByteString)
-> MessageBuilder -> LazyByteString
forall a b. (a -> b) -> a -> b
$
FieldNumber -> ByteString -> MessageBuilder
Encode.byteString (Word64 -> FieldNumber
FieldNumber Word64
1) (PublicKey -> ByteString
encodePublicKey (SignedEnvelope -> PublicKey
sePublicKey SignedEnvelope
env))
MessageBuilder -> MessageBuilder -> MessageBuilder
forall a. Semigroup a => a -> a -> a
<> FieldNumber -> ByteString -> MessageBuilder
Encode.byteString (Word64 -> FieldNumber
FieldNumber Word64
2) (SignedEnvelope -> ByteString
sePayloadType SignedEnvelope
env)
MessageBuilder -> MessageBuilder -> MessageBuilder
forall a. Semigroup a => a -> a -> a
<> FieldNumber -> ByteString -> MessageBuilder
Encode.byteString (Word64 -> FieldNumber
FieldNumber Word64
3) (SignedEnvelope -> ByteString
sePayload SignedEnvelope
env)
MessageBuilder -> MessageBuilder -> MessageBuilder
forall a. Semigroup a => a -> a -> a
<> FieldNumber -> ByteString -> MessageBuilder
Encode.byteString (Word64 -> FieldNumber
FieldNumber Word64
5) (SignedEnvelope -> ByteString
seSignature SignedEnvelope
env)
decodeSignedEnvelope :: ByteString -> Either String SignedEnvelope
decodeSignedEnvelope :: ByteString -> Either [Char] SignedEnvelope
decodeSignedEnvelope ByteString
bs =
case Parser RawMessage (ByteString, ByteString, ByteString, ByteString)
-> ByteString
-> Either
ParseError (ByteString, ByteString, ByteString, ByteString)
forall a. Parser RawMessage a -> ByteString -> Either ParseError a
parse Parser RawMessage (ByteString, ByteString, ByteString, ByteString)
signedEnvelopeParser ByteString
bs of
Left ParseError
err -> [Char] -> Either [Char] SignedEnvelope
forall a b. a -> Either a b
Left ([Char] -> Either [Char] SignedEnvelope)
-> [Char] -> Either [Char] SignedEnvelope
forall a b. (a -> b) -> a -> b
$ [Char]
"SignedEnvelope decode error: " [Char] -> ShowS
forall a. [a] -> [a] -> [a]
++ ParseError -> [Char]
forall a. Show a => a -> [Char]
show ParseError
err
Right (ByteString
pkBytes, ByteString
ptBytes, ByteString
payload, ByteString
sig) -> do
pk <- ByteString -> Either [Char] PublicKey
decodePublicKey ByteString
pkBytes
Right SignedEnvelope
{ sePublicKey = pk
, seDomain = BS.empty
, sePayloadType = ptBytes
, sePayload = payload
, seSignature = sig
}
signedEnvelopeParser :: Parser RawMessage (ByteString, ByteString, ByteString, ByteString)
signedEnvelopeParser :: Parser RawMessage (ByteString, ByteString, ByteString, ByteString)
signedEnvelopeParser = (,,,)
(ByteString
-> ByteString
-> ByteString
-> ByteString
-> (ByteString, ByteString, ByteString, ByteString))
-> Parser RawMessage ByteString
-> Parser
RawMessage
(ByteString
-> ByteString
-> ByteString
-> (ByteString, ByteString, ByteString, ByteString))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser RawField ByteString
-> FieldNumber -> Parser RawMessage ByteString
forall a. Parser RawField a -> FieldNumber -> Parser RawMessage a
at (Parser RawPrimitive ByteString
-> ByteString -> Parser RawField ByteString
forall a. Parser RawPrimitive a -> a -> Parser RawField a
one Parser RawPrimitive ByteString
Decode.byteString ByteString
BS.empty) (Word64 -> FieldNumber
FieldNumber Word64
1)
Parser
RawMessage
(ByteString
-> ByteString
-> ByteString
-> (ByteString, ByteString, ByteString, ByteString))
-> Parser RawMessage ByteString
-> Parser
RawMessage
(ByteString
-> ByteString -> (ByteString, ByteString, ByteString, ByteString))
forall a b.
Parser RawMessage (a -> b)
-> Parser RawMessage a -> Parser RawMessage b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser RawField ByteString
-> FieldNumber -> Parser RawMessage ByteString
forall a. Parser RawField a -> FieldNumber -> Parser RawMessage a
at (Parser RawPrimitive ByteString
-> ByteString -> Parser RawField ByteString
forall a. Parser RawPrimitive a -> a -> Parser RawField a
one Parser RawPrimitive ByteString
Decode.byteString ByteString
BS.empty) (Word64 -> FieldNumber
FieldNumber Word64
2)
Parser
RawMessage
(ByteString
-> ByteString -> (ByteString, ByteString, ByteString, ByteString))
-> Parser RawMessage ByteString
-> Parser
RawMessage
(ByteString -> (ByteString, ByteString, ByteString, ByteString))
forall a b.
Parser RawMessage (a -> b)
-> Parser RawMessage a -> Parser RawMessage b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser RawField ByteString
-> FieldNumber -> Parser RawMessage ByteString
forall a. Parser RawField a -> FieldNumber -> Parser RawMessage a
at (Parser RawPrimitive ByteString
-> ByteString -> Parser RawField ByteString
forall a. Parser RawPrimitive a -> a -> Parser RawField a
one Parser RawPrimitive ByteString
Decode.byteString ByteString
BS.empty) (Word64 -> FieldNumber
FieldNumber Word64
3)
Parser
RawMessage
(ByteString -> (ByteString, ByteString, ByteString, ByteString))
-> Parser RawMessage ByteString
-> Parser
RawMessage (ByteString, ByteString, ByteString, ByteString)
forall a b.
Parser RawMessage (a -> b)
-> Parser RawMessage a -> Parser RawMessage b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Parser RawField ByteString
-> FieldNumber -> Parser RawMessage ByteString
forall a. Parser RawField a -> FieldNumber -> Parser RawMessage a
at (Parser RawPrimitive ByteString
-> ByteString -> Parser RawField ByteString
forall a. Parser RawPrimitive a -> a -> Parser RawField a
one Parser RawPrimitive ByteString
Decode.byteString ByteString
BS.empty) (Word64 -> FieldNumber
FieldNumber Word64
5)