fedi/src/Fedi/Crypto.hs
2024-11-07 11:27:05 +02:00

65 lines
1.9 KiB
Haskell

{-# language RecordWildCards #-}
module Fedi.Crypto where
import Crypto.Hash qualified as Crypto
import Data.ByteArray qualified as BA
import Crypto.PubKey.RSA.PKCS15 qualified as Crypto
import Crypto.Store.X509 qualified as Crypto
import Crypto.Store.PKCS8 qualified as Crypto
import Data.X509 qualified as Crypto
import Fedi.Helpers
import Data.ByteString.Base64 qualified as Base64
import Data.Base64.Types qualified as Base64
import Data.Text qualified as T
verifyPub :: MonadThrow m => ByteString -> ByteString -> ByteString -> m Bool
verifyPub pubkeypem sig message = do
pubkey <-
case Crypto.readPubKeyFileFromMemory pubkeypem of
[Crypto.PubKeyRSA pubkey'] -> pure pubkey'
_ -> throw "failed to read pubkey pem"
pure $ Crypto.verify (Just Crypto.SHA256) pubkey message sig
sign :: FilePath -> ByteString -> IO Signed
sign privatePemFile message = do
-- get private key
privkeypem <- Crypto.readKeyFile privatePemFile
privateKey <- case privkeypem of
[Crypto.Unprotected (Crypto.PrivKeyRSA privkey)] -> pure privkey
_ -> throw $ "error reading local private key from '" <> privatePemFile <> "'."
-- sign message
signedMessage <-
Crypto.sign Nothing (Just Crypto.SHA256) privateKey message
& either (throw . show) pure
-- return
pure Signed{..}
newtype Signed
= Signed
{ signedMessage :: ByteString
}
deriving Show
ppSigned :: Signed -> String
ppSigned signed =
unlines
[ "Signature"
, "{ signedMessage = " <> encodeBase64String signed.signedMessage
, "}"
]
encodeBase64 :: ByteString -> ByteString
encodeBase64 = Base64.extractBase64 . Base64.encodeBase64'
encodeBase64String :: ByteString -> String
encodeBase64String = T.unpack . Base64.extractBase64 . Base64.encodeBase64
decodeBase64 :: ByteString -> ByteString
decodeBase64 = Base64.decodeBase64Lenient
makeDigest :: ByteString -> ByteString
makeDigest message =
BA.convert (Crypto.hash message :: Crypto.Digest Crypto.SHA256)