{-|
Module      : Botan.PubKey
Description : Public key cryptography
Copyright   : (c) Leo D, 2023
License     : BSD-3-Clause
Maintainer  : leo@apotheca.io
Stability   : experimental
Portability : POSIX

Public key cryptography is a collection of techniques allowing
for encryption, signatures, and key agreement.
-}

module Botan.PubKey
(

-- * Thing
-- $introduction

-- * Usage
-- $usage

-- * Idiomatic interface

-- ** Data type
  PK(..)
-- TODO: Rename XMSSScheme
, XMSS(..)
, ECGroup(..)
, ecGroupName
, DLGroup(..)
, dlGroupName

-- ** Enumerations

-- , allPKs

-- ** Associated types

, PKExportFormat(..)
, pkExportFormatFlags
, PKCheckKeyFlags(..)
, PKPadding(..)
, pkPaddingName

-- * Private Keys

-- ** Wrapped private key
, PrivKey(..)

-- ** Destructor
, destroyPrivKey

-- ** Initializers
, newPrivKey

-- ** Accessors

, privKeyAlgo
, privKeyField

-- ** Accessory functions
, loadPrivKey
, exportPrivKey
, exportPrivKeyPubKey
, checkPrivKey

-- * Public Keys

, PubKey(..)

-- ** Destructor
, destroyPubKey

-- ** Accessors

, pubKeyAlgo
, pubKeyField
, estimatedPubKeyStrength
, pubKeyFingerprint

-- ** Accessory functions

, loadPubKey
, exportPubKey
, checkPubKey

--

, privKeyCreatePKIO

) where

import qualified Botan.Low.PubKey as Low
import Botan.Low.PubKey (PrivKey(..), PubKey(..))
import qualified Botan.Low.RNG as Low
import Botan.Low.MPI

import Botan.Hash
import Botan.Prelude
import Botan.RNG

import Data.Bool

{- $introduction

-}

{- $usage

-}

--
-- Idiomatic interface
--

-- Data type

-- data PK

-- Enumerations

-- allPKs = undefined

-- Accessory types

data PKExportFormat
    = PKExportDER
    | PKExportPEM

pkExportFormatFlags :: PKExportFormat -> Low.PrivKeyExportFlags
pkExportFormatFlags :: PKExportFormat -> Word32
pkExportFormatFlags PKExportFormat
PKExportDER = Word32
Low.PrivKeyExportDER
pkExportFormatFlags PKExportFormat
PKExportPEM = Word32
Low.PrivKeyExportPEM

--
-- Private Keys
--

-- Wrapped private key

-- data PrivKey
--     = PrivKey
--     { privKeyAlgo :: PK
--     , privKeyRef :: Low.PrivKey
--     }

-- Destructor

destroyPrivKey :: (MonadIO m) => PrivKey -> m ()
destroyPrivKey :: forall (m :: * -> *). MonadIO m => PrivKey -> m ()
destroyPrivKey = IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (PrivKey -> IO ()) -> PrivKey -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PrivKey -> IO ()
Low.privKeyDestroy

-- Initializers

newPrivKey :: (MonadRandomIO m) => PK -> m PrivKey
newPrivKey :: forall (m :: * -> *). MonadRandomIO m => PK -> m PrivKey
newPrivKey PK
pk = do
    RNG
rng <- m RNG
forall (m :: * -> *). MonadRandomIO m => m RNG
getRNG
    IO PrivKey -> m PrivKey
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO PrivKey -> m PrivKey) -> IO PrivKey -> m PrivKey
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> RNG -> IO PrivKey
Low.privKeyCreate (PK -> ByteString
pkName PK
pk) (PK -> ByteString
pkParams PK
pk) RNG
rng

-- Accessors

-- TODO: Parse Low.botan_privkey_algo -> PK
privKeyAlgo :: PrivKey -> PK
privKeyAlgo :: PrivKey -> PK
privKeyAlgo = PrivKey -> PK
forall a. HasCallStack => a
undefined

-- TODO: Return Integer instead?
privKeyField :: PrivKey -> ByteString -> Maybe MP
privKeyField :: PrivKey -> ByteString -> Maybe MP
privKeyField PrivKey
pk ByteString
field = IO (Maybe MP) -> Maybe MP
forall a. IO a -> a
unsafePerformIO (IO (Maybe MP) -> Maybe MP) -> IO (Maybe MP) -> Maybe MP
forall a b. (a -> b) -> a -> b
$ do
    MP
mp <- IO MP
mpInit
    -- TODO: Return nothing on catch error
    MP -> PrivKey -> ByteString -> IO ()
Low.privKeyGetField MP
mp PrivKey
pk ByteString
field
    Maybe MP -> IO (Maybe MP)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe MP -> IO (Maybe MP)) -> Maybe MP -> IO (Maybe MP)
forall a b. (a -> b) -> a -> b
$ MP -> Maybe MP
forall a. a -> Maybe a
Just MP
mp 
{-# NOINLINE privKeyField #-}

-- Accessory functions

-- NOTE: No way to recover the algo yet
-- TODO: Should be :: ByteString -> Maybe ByteString -> Maybe PrivKey
loadPrivKey :: ByteString -> ByteString -> Maybe PrivKey
loadPrivKey :: ByteString -> ByteString -> Maybe PrivKey
loadPrivKey ByteString
bits ByteString
password = IO (Maybe PrivKey) -> Maybe PrivKey
forall a. IO a -> a
unsafePerformIO (IO (Maybe PrivKey) -> Maybe PrivKey)
-> IO (Maybe PrivKey) -> Maybe PrivKey
forall a b. (a -> b) -> a -> b
$ do
    -- TODO: Return nothing on catch error
    PrivKey
pk <- ByteString -> ByteString -> IO PrivKey
Low.privKeyLoad ByteString
bits ByteString
password
    Maybe PrivKey -> IO (Maybe PrivKey)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe PrivKey -> IO (Maybe PrivKey))
-> Maybe PrivKey -> IO (Maybe PrivKey)
forall a b. (a -> b) -> a -> b
$ PrivKey -> Maybe PrivKey
forall a. a -> Maybe a
Just PrivKey
pk
{-# NOINLINE loadPrivKey #-}

-- NOTE: Is including trailing \0 in PEM format?
exportPrivKey :: PrivKey -> PKExportFormat -> ByteString
exportPrivKey :: PrivKey -> PKExportFormat -> ByteString
exportPrivKey PrivKey
pk PKExportFormat
fmt = IO ByteString -> ByteString
forall a. IO a -> a
unsafePerformIO (IO ByteString -> ByteString) -> IO ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ PrivKey -> Word32 -> IO ByteString
Low.privKeyExport PrivKey
pk (PKExportFormat -> Word32
pkExportFormatFlags PKExportFormat
fmt)
{-# NOINLINE exportPrivKey #-}

exportPrivKeyPubKey :: PrivKey -> PubKey
exportPrivKeyPubKey :: PrivKey -> PubKey
exportPrivKeyPubKey PrivKey
pk = IO PubKey -> PubKey
forall a. IO a -> a
unsafePerformIO (IO PubKey -> PubKey) -> IO PubKey -> PubKey
forall a b. (a -> b) -> a -> b
$ PrivKey -> IO PubKey
Low.privKeyExportPubKey PrivKey
pk 
{-# NOINLINE exportPrivKeyPubKey #-}

checkPrivKey :: (MonadRandomIO m) => PrivKey -> Bool -> m Bool
checkPrivKey :: forall (m :: * -> *). MonadRandomIO m => PrivKey -> Bool -> m Bool
checkPrivKey PrivKey
pk Bool
expensive = do
    RNG
rng <- m RNG
forall (m :: * -> *). MonadRandomIO m => m RNG
getRNG
    -- TODO: Return false on catch error
    IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ PrivKey -> RNG -> Word32 -> IO ()
Low.privKeyCheckKey PrivKey
pk RNG
rng (Word32 -> Word32 -> Bool -> Word32
forall a. a -> a -> Bool -> a
bool Word32
Low.CheckKeyNormalTests Word32
Low.CheckKeyExpensiveTests Bool
expensive)
    Bool -> m Bool
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True

--
-- Public Keys
--

-- data PubKey
--     = PubKey
--     { pubKeyAlgo :: PK
--     , pubKeyRef :: Low.PubKey
--     }

-- Destructor

destroyPubKey :: (MonadIO m) => PubKey -> m ()
destroyPubKey :: forall (m :: * -> *). MonadIO m => PubKey -> m ()
destroyPubKey = IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (PubKey -> IO ()) -> PubKey -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PubKey -> IO ()
Low.pubKeyDestroy

-- Accessors

-- TODO: Parse Low.botan_pubkey_algo -> PK
pubKeyAlgo :: PubKey -> PK
pubKeyAlgo :: PubKey -> PK
pubKeyAlgo = PubKey -> PK
forall a. HasCallStack => a
undefined

-- TODO: Return Integer instead?
pubKeyField :: PubKey -> ByteString -> Maybe MP
pubKeyField :: PubKey -> ByteString -> Maybe MP
pubKeyField PubKey
pk ByteString
field = IO (Maybe MP) -> Maybe MP
forall a. IO a -> a
unsafePerformIO (IO (Maybe MP) -> Maybe MP) -> IO (Maybe MP) -> Maybe MP
forall a b. (a -> b) -> a -> b
$ do
    MP
mp <- IO MP
mpInit
    -- TODO: Return nothing on catch error
    MP -> PubKey -> ByteString -> IO ()
Low.pubKeyGetField MP
mp PubKey
pk ByteString
field
    Maybe MP -> IO (Maybe MP)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe MP -> IO (Maybe MP)) -> Maybe MP -> IO (Maybe MP)
forall a b. (a -> b) -> a -> b
$ MP -> Maybe MP
forall a. a -> Maybe a
Just MP
mp 
{-# NOINLINE pubKeyField #-}

estimatedPubKeyStrength :: PubKey -> Int
estimatedPubKeyStrength :: PubKey -> Int
estimatedPubKeyStrength = IO Int -> Int
forall a. IO a -> a
unsafePerformIO (IO Int -> Int) -> (PubKey -> IO Int) -> PubKey -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PubKey -> IO Int
Low.pubKeyEstimatedStrength
{-# NOINLINE estimatedPubKeyStrength #-}

pubKeyFingerprint :: PubKey -> Hash -> ByteString
pubKeyFingerprint :: PubKey -> Hash -> ByteString
pubKeyFingerprint PubKey
pk Hash
h = IO ByteString -> ByteString
forall a. IO a -> a
unsafePerformIO (IO ByteString -> ByteString) -> IO ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ PubKey -> ByteString -> IO ByteString
Low.pubKeyFingerprint PubKey
pk (Hash -> ByteString
hashName Hash
h)
{-# NOINLINE pubKeyFingerprint #-}

-- Accessory functions

-- NOTE: No way to recover the algo yet
loadPubKey :: ByteString -> Maybe PubKey
loadPubKey :: ByteString -> Maybe PubKey
loadPubKey ByteString
bits = IO (Maybe PubKey) -> Maybe PubKey
forall a. IO a -> a
unsafePerformIO (IO (Maybe PubKey) -> Maybe PubKey)
-> IO (Maybe PubKey) -> Maybe PubKey
forall a b. (a -> b) -> a -> b
$ do
    -- TODO: Return nothing on catch error
    PubKey
pk <- ByteString -> IO PubKey
Low.pubKeyLoad ByteString
bits
    Maybe PubKey -> IO (Maybe PubKey)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe PubKey -> IO (Maybe PubKey))
-> Maybe PubKey -> IO (Maybe PubKey)
forall a b. (a -> b) -> a -> b
$ PubKey -> Maybe PubKey
forall a. a -> Maybe a
Just PubKey
pk
{-# NOINLINE loadPubKey #-}

-- NOTE: Is including trailing \0 in PEM format?
exportPubKey :: PubKey -> PKExportFormat -> ByteString
exportPubKey :: PubKey -> PKExportFormat -> ByteString
exportPubKey PubKey
pk PKExportFormat
fmt = IO ByteString -> ByteString
forall a. IO a -> a
unsafePerformIO (IO ByteString -> ByteString) -> IO ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ PubKey -> Word32 -> IO ByteString
Low.pubKeyExport PubKey
pk (PKExportFormat -> Word32
pkExportFormatFlags PKExportFormat
fmt)
{-# NOINLINE exportPubKey #-}

checkPubKey :: (MonadRandomIO m) => PubKey -> Bool -> m Bool
checkPubKey :: forall (m :: * -> *). MonadRandomIO m => PubKey -> Bool -> m Bool
checkPubKey PubKey
pk Bool
expensive = do
    RNG
rng <- m RNG
forall (m :: * -> *). MonadRandomIO m => m RNG
getRNG
    -- TODO: Return false on catch error
    IO Bool -> m Bool
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> m Bool) -> IO Bool -> m Bool
forall a b. (a -> b) -> a -> b
$ PubKey -> RNG -> Word32 -> IO Bool
Low.pubKeyCheckKey PubKey
pk RNG
rng (Word32 -> Word32 -> Bool -> Word32
forall a. a -> a -> Bool -> a
bool Word32
Low.CheckKeyNormalTests Word32
Low.CheckKeyExpensiveTests Bool
expensive)
    Bool -> m Bool
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True





--
-- OG BELOW
--





-- TODO: Dig into Key agreement (KA) vs key exchange (KE / KX) vs key encapsulation mechanism (KEM)
-- NOTE: libsodium uses kx for key exchange
-- ALG SOURCES: https://github.com/randombit/botan/blob/a303f4af1504e7ac349dd798190924ea08ead9b7/src/lib/pubkey/pk_algs.cpp
-- NOTE: Testing shows SM2 is broken or at least finnicky
data PK                     -- NOTE: PQ = post-quantum, NS = national standard
    = RSA Word32            -- Encryption, signing, key encapsulation
    | SM2 ECGroup           -- NS, Encryption, signing -- NOTE: Accepts SM2_Sig and SM2_Enc as names too
    | ElGamal DLGroup       -- Encryption
    | DSA DLGroup           -- Signing
    | ECDSA ECGroup         -- Signing
    | ECKCDSA ECGroup       -- NS, Signing
    | ECGDSA ECGroup        -- NS, Signing
    | GOST_34_10 ECGroup    -- NS, Signing -- NOTE: Accepts "" as param too, alternate names "GOST-34.10-2012-256" and "GOST-34.10-2012-512"
    | Ed25519               -- Signing; TODO: Variant (Prehashed, Pure)
    | XMSS XMSS             -- PQ, signing
    | DH DLGroup            -- Key exchange
    | ECDH ECGroup          -- Key exchange
    | Curve25519            -- Key exchange, aka X25519
    -- New in 3.x?
    | Dilithium         -- PQ, signing, unknown parameters
    | Kyber             -- PQ, key encapsulation, unknown parameters
    -- | SPHINCSPlus    -- PQ, signing, unknown parameters, possibly unavailable because brew botan is 3.0
    | McEliece          -- PQ, key encapsulation, unknown parameters

-- TODO: SKey, KXKey, KAKey, KEMKey

type PKName = ByteString
type PKParams = ByteString

pkName :: PK -> PKName
pkName :: PK -> ByteString
pkName (RSA Word32
_)          = ByteString
Low.RSA           -- "RSA"
pkName (SM2 ECGroup
_)          = ByteString
Low.SM2           -- "SM2"
pkName (ElGamal DLGroup
_)      = ByteString
Low.ElGamal       -- "ElGamal"
pkName (DSA DLGroup
_)          = ByteString
Low.DSA           -- "DSA"
pkName (ECDSA ECGroup
_)        = ByteString
Low.ECDSA         -- "ECDSA"
pkName (ECKCDSA ECGroup
_)      = ByteString
Low.ECKCDSA       -- "ECKCDSA"
pkName (ECGDSA ECGroup
_)       = ByteString
Low.ECGDSA        -- "ECGDSA"
pkName (GOST_34_10 ECGroup
_)   = ByteString
Low.GOST_34_10    -- "GOST-34.10"
pkName PK
Ed25519          = ByteString
Low.Ed25519       -- "Ed25519"
pkName (XMSS XMSS
_)         = ByteString
Low.XMSS          -- "XMSS"
pkName (DH DLGroup
_)           = ByteString
Low.DH            -- "DH"
pkName (ECDH ECGroup
_)         = ByteString
Low.ECDH          -- "ECDH"
pkName PK
Curve25519       = ByteString
Low.Curve25519    -- "Curve25519"
-- New in 3.x?
pkName PK
Dilithium        = ByteString
Low.Dilithium   -- "Dilithium-6x5-r3"   -- TODO: Find full listing in doxygen 
pkName PK
Kyber            = ByteString
Low.Kyber       -- "Kyber-1024-r3"      -- TODO: Find full listing in doxygen 
-- pkName SPHINCSPlus      = "SPHINCS+"  -- Doesn't work :/      -- TODO: Find full listing in doxygen 
pkName PK
McEliece         = ByteString
Low.McEliece

pkParams :: PK -> PKParams
pkParams :: PK -> ByteString
pkParams (RSA Word32
bits)       = Word32 -> ByteString
forall a. Show a => a -> ByteString
showBytes Word32
bits
pkParams (SM2 ECGroup
grp)        = ECGroup -> ByteString
ecGroupName ECGroup
grp
pkParams (ElGamal DLGroup
grp)    = DLGroup -> ByteString
dlGroupName DLGroup
grp
pkParams (DSA DLGroup
grp)        = DLGroup -> ByteString
dlGroupName DLGroup
grp
pkParams (ECDSA ECGroup
grp)      = ECGroup -> ByteString
ecGroupName ECGroup
grp
pkParams (ECKCDSA ECGroup
grp)    = ECGroup -> ByteString
ecGroupName ECGroup
grp
pkParams (ECGDSA ECGroup
grp)     = ECGroup -> ByteString
ecGroupName ECGroup
grp
pkParams (GOST_34_10 ECGroup
grp) = ECGroup -> ByteString
ecGroupName ECGroup
grp
pkParams PK
Ed25519          = ByteString
""
pkParams (XMSS XMSS
xmss)      = XMSS -> ByteString
xmssName XMSS
xmss
pkParams (DH DLGroup
grp)         = DLGroup -> ByteString
dlGroupName DLGroup
grp
pkParams (ECDH ECGroup
grp)       = ECGroup -> ByteString
ecGroupName ECGroup
grp
pkParams PK
Curve25519       = ByteString
""
-- New in 3.x? Unknown params!
pkParams PK
Dilithium        = ByteString
""
pkParams PK
Kyber            = ByteString
""
-- pkParams SPHINCSPlus      = ""
pkParams PK
McEliece         = ByteString
""

data XMSS
    = XMSS_SHA2_10_256
    | XMSS_SHA2_16_256
    | XMSS_SHA2_20_256
    | XMSS_SHA2_10_512
    | XMSS_SHA2_16_512
    | XMSS_SHA2_20_512
    | XMSS_SHAKE_10_256
    | XMSS_SHAKE_16_256
    | XMSS_SHAKE_20_256
    | XMSS_SHAKE_10_512
    | XMSS_SHAKE_16_512
    | XMSS_SHAKE_20_512

type XMSSName = ByteString

xmssName :: XMSS -> XMSSName
xmssName :: XMSS -> ByteString
xmssName XMSS
XMSS_SHA2_10_256   = ByteString
Low.XMSS_SHA2_10_256
xmssName XMSS
XMSS_SHA2_16_256   = ByteString
Low.XMSS_SHA2_16_256
xmssName XMSS
XMSS_SHA2_20_256   = ByteString
Low.XMSS_SHA2_20_256
xmssName XMSS
XMSS_SHA2_10_512   = ByteString
Low.XMSS_SHA2_10_512
xmssName XMSS
XMSS_SHA2_16_512   = ByteString
Low.XMSS_SHA2_16_512
xmssName XMSS
XMSS_SHA2_20_512   = ByteString
Low.XMSS_SHA2_20_512
xmssName XMSS
XMSS_SHAKE_10_256  = ByteString
Low.XMSS_SHAKE_10_256
xmssName XMSS
XMSS_SHAKE_16_256  = ByteString
Low.XMSS_SHAKE_16_256
xmssName XMSS
XMSS_SHAKE_20_256  = ByteString
Low.XMSS_SHAKE_20_256
xmssName XMSS
XMSS_SHAKE_10_512  = ByteString
Low.XMSS_SHAKE_10_512
xmssName XMSS
XMSS_SHAKE_16_512  = ByteString
Low.XMSS_SHAKE_16_512
xmssName XMSS
XMSS_SHAKE_20_512  = ByteString
Low.XMSS_SHAKE_20_512

data ECGroup
    = Secp160k1
    | Secp160r1
    | Secp160r2
    | Secp192k1
    | Secp192r1
    | Secp224k1
    | Secp224r1
    | Secp256k1
    | Secp256r1
    | Secp384r1
    | Secp521r1
    | Brainpool160r1
    | Brainpool192r1
    | Brainpool224r1
    | Brainpool256r1
    | Brainpool320r1
    | Brainpool384r1
    | Brainpool512r1
    | X962_p192v2
    | X962_p192v3
    | X962_p239v1
    | X962_p239v2
    | X962_p239v3
    | Gost_256A
    | Gost_512A
    | Frp256v1
    | Sm2p256v1

type ECGroupName = ByteString

ecGroupName :: ECGroup -> ECGroupName
ecGroupName :: ECGroup -> ByteString
ecGroupName ECGroup
Secp160k1       = ByteString
Low.Secp160k1
ecGroupName ECGroup
Secp160r1       = ByteString
Low.Secp160r1
ecGroupName ECGroup
Secp160r2       = ByteString
Low.Secp160r2
ecGroupName ECGroup
Secp192k1       = ByteString
Low.Secp192k1
ecGroupName ECGroup
Secp192r1       = ByteString
Low.Secp192r1
ecGroupName ECGroup
Secp224k1       = ByteString
Low.Secp224k1
ecGroupName ECGroup
Secp224r1       = ByteString
Low.Secp224r1
ecGroupName ECGroup
Secp256k1       = ByteString
Low.Secp256k1
ecGroupName ECGroup
Secp256r1       = ByteString
Low.Secp256r1
ecGroupName ECGroup
Secp384r1       = ByteString
Low.Secp384r1
ecGroupName ECGroup
Secp521r1       = ByteString
Low.Secp521r1
ecGroupName ECGroup
Brainpool160r1  = ByteString
Low.Brainpool160r1
ecGroupName ECGroup
Brainpool192r1  = ByteString
Low.Brainpool192r1
ecGroupName ECGroup
Brainpool224r1  = ByteString
Low.Brainpool224r1
ecGroupName ECGroup
Brainpool256r1  = ByteString
Low.Brainpool256r1
ecGroupName ECGroup
Brainpool320r1  = ByteString
Low.Brainpool320r1
ecGroupName ECGroup
Brainpool384r1  = ByteString
Low.Brainpool384r1
ecGroupName ECGroup
Brainpool512r1  = ByteString
Low.Brainpool512r1
ecGroupName ECGroup
X962_p192v2     = ByteString
Low.X962_p192v2
ecGroupName ECGroup
X962_p192v3     = ByteString
Low.X962_p192v3
ecGroupName ECGroup
X962_p239v1     = ByteString
Low.X962_p239v1
ecGroupName ECGroup
X962_p239v2     = ByteString
Low.X962_p239v2
ecGroupName ECGroup
X962_p239v3     = ByteString
Low.X962_p239v3
ecGroupName ECGroup
Gost_256A       = ByteString
Low.Gost_256A
ecGroupName ECGroup
Gost_512A       = ByteString
Low.Gost_512A
ecGroupName ECGroup
Frp256v1        = ByteString
Low.Frp256v1
ecGroupName ECGroup
Sm2p256v1       = ByteString
Low.Sm2p256v1

data DLGroup
    -- = FFDHE FFDHE
    -- | MODP MODP
    -- | DSA DSA
    = FFDHE_IETF_2048
    | FFDHE_IETF_3072
    | FFDHE_IETF_4096
    | FFDHE_IETF_6144
    | FFDHE_IETF_8192
    | MODP_IETF_1024
    | MODP_IETF_1536
    | MODP_IETF_2048
    | MODP_IETF_3072
    | MODP_IETF_4096
    | MODP_IETF_6144
    | MODP_IETF_8192
    | MODP_SRP_1024
    | MODP_SRP_1536
    | MODP_SRP_2048
    | MODP_SRP_3072
    | MODP_SRP_4096
    | MODP_SRP_6144
    | MODP_SRP_8192
    | DSA_JCE_1024
    | DSA_BOTAN_2048
    | DSA_BOTAN_3072

type DLGroupName = ByteString

dlGroupName :: DLGroup -> DLGroupName
dlGroupName :: DLGroup -> ByteString
dlGroupName DLGroup
FFDHE_IETF_2048 = ByteString
Low.FFDHE_IETF_2048
dlGroupName DLGroup
FFDHE_IETF_3072 = ByteString
Low.FFDHE_IETF_3072
dlGroupName DLGroup
FFDHE_IETF_4096 = ByteString
Low.FFDHE_IETF_4096
dlGroupName DLGroup
FFDHE_IETF_6144 = ByteString
Low.FFDHE_IETF_6144
dlGroupName DLGroup
FFDHE_IETF_8192 = ByteString
Low.FFDHE_IETF_8192
dlGroupName DLGroup
MODP_IETF_1024  = ByteString
Low.MODP_IETF_1024
dlGroupName DLGroup
MODP_IETF_1536  = ByteString
Low.MODP_IETF_1536
dlGroupName DLGroup
MODP_IETF_2048  = ByteString
Low.MODP_IETF_2048
dlGroupName DLGroup
MODP_IETF_3072  = ByteString
Low.MODP_IETF_3072
dlGroupName DLGroup
MODP_IETF_4096  = ByteString
Low.MODP_IETF_4096
dlGroupName DLGroup
MODP_IETF_6144  = ByteString
Low.MODP_IETF_6144
dlGroupName DLGroup
MODP_IETF_8192  = ByteString
Low.MODP_IETF_8192
dlGroupName DLGroup
MODP_SRP_1024   = ByteString
Low.MODP_SRP_1024
dlGroupName DLGroup
MODP_SRP_1536   = ByteString
Low.MODP_SRP_1536
dlGroupName DLGroup
MODP_SRP_2048   = ByteString
Low.MODP_SRP_2048
dlGroupName DLGroup
MODP_SRP_3072   = ByteString
Low.MODP_SRP_3072
dlGroupName DLGroup
MODP_SRP_4096   = ByteString
Low.MODP_SRP_4096
dlGroupName DLGroup
MODP_SRP_6144   = ByteString
Low.MODP_SRP_6144
dlGroupName DLGroup
MODP_SRP_8192   = ByteString
Low.MODP_SRP_8192
dlGroupName DLGroup
DSA_JCE_1024    = ByteString
Low.DSA_JCE_1024
dlGroupName DLGroup
DSA_BOTAN_2048  = ByteString
Low.DSA_BOTAN_2048
dlGroupName DLGroup
DSA_BOTAN_3072  = ByteString
Low.DSA_BOTAN_3072

privKeyCreatePKIO :: PK -> Low.RNG -> IO PrivKey
privKeyCreatePKIO :: PK -> RNG -> IO PrivKey
privKeyCreatePKIO PK
pk = ByteString -> ByteString -> RNG -> IO PrivKey
Low.privKeyCreate (PK -> ByteString
pkName PK
pk) (PK -> ByteString
pkParams PK
pk)

-- data PKExportFlags
--     = PKExportDER   -- BOTAN_PRIVKEY_EXPORT_FLAG_DER
--     | PKExportPEM   -- BOTAN_PRIVKEY_EXPORT_FLAG_PEM

data PKCheckKeyFlags
    = PKCheckKeyNone            -- BOTAN_CHECK_KEY_NONE
    | PKCheckKeyExpensiveTests  -- BOTAN_CHECK_KEY_EXPENSIVE_TESTS

-- NOTE: Need to confirm  that this is all EME (encryption) padding
data PKPadding
    = EME_RAW
    | EME_PKCS1
    | EME_OAEP Hash (Maybe Hash) (Maybe ByteString)    -- Hash, mask gen hash, label
    | SM2EncParam Hash  -- NOTE: Why SM2 specific? Why not just PKPaddingHash Hash?

pkPaddingName :: PKPadding -> ByteString
pkPaddingName :: PKPadding -> ByteString
pkPaddingName PKPadding
EME_RAW     = ByteString
"Raw"
pkPaddingName PKPadding
EME_PKCS1   = ByteString
"PKCS1v15"  -- "PKCS1v15" -- Why not "EME-PKCS1-v1_5"? See C++ docs
pkPaddingName (EME_OAEP Hash
h Maybe Hash
m Maybe ByteString
l) = case (Maybe Hash
m,Maybe ByteString
l) of
    (Maybe Hash
Nothing, Maybe ByteString
Nothing) -> ByteString
"OAEP(" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Hash -> ByteString
hashName Hash
h ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
",MGF1)"
    (Maybe Hash
Nothing, Just ByteString
l') -> ByteString
"OAEP(" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Hash -> ByteString
hashName Hash
h ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
",MGF1," ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
l' ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
")"
    (Just Hash
m', Maybe ByteString
Nothing) -> ByteString
"OAEP(" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Hash -> ByteString
hashName Hash
h ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
",MGF1(" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Hash -> ByteString
hashName Hash
m' ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
"))"
    (Just Hash
m', Just ByteString
l') -> ByteString
"OAEP(" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Hash -> ByteString
hashName Hash
h ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
",MGF1(" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Hash -> ByteString
hashName Hash
m' ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
")," ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
l' ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
")"
pkPaddingName (SM2EncParam Hash
h)  = Hash -> ByteString
hashName Hash
h

defaultPKPadding :: String
defaultPKPadding = String
"OAEP(SHA-256)" -- C++ docs tell us more about this

-- SEE: C++ Docs on more types, eg MGF1:
--  MGF1: https://botan.randombit.net/doxygen/mgf1_8h_source.html
--  pk_pad: https://botan.randombit.net/doxygen/dir_63563f8eb148fb3139a10bc08bfb3f55.html
-- Note that there are:
--  EME (Encoding Method for Encryption) - padding algo for encryption
--  EMSA (Encoding Method for Signature with Appendix) - padding algo for signing
--  MGF1
-- and others