-- | -- Module : Crypto.PubKey.Curve448 -- License : BSD-style -- Maintainer : John Galt -- Stability : experimental -- Portability : unknown -- -- Curve448 support -- -- Internally uses Decaf point compression to omit the cofactor -- and implementation by Mike Hamburg. Externally API and -- data types are compatible with the encoding specified in RFC 7748. -- {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MagicHash #-} module Crypto.PubKey.Curve448 ( SecretKey , PublicKey , DhSecret -- * Smart constructors , dhSecret , publicKey , secretKey -- * Methods , dh , toPublic , generateSecretKey ) where import Data.Word import Foreign.Ptr import GHC.Ptr import Crypto.Error import Crypto.Random import Crypto.Internal.Compat import Crypto.Internal.Imports import Crypto.Internal.ByteArray (ByteArrayAccess, ScrubbedBytes, Bytes, withByteArray) import qualified Crypto.Internal.ByteArray as B -- | A Curve448 Secret key newtype SecretKey = SecretKey ScrubbedBytes deriving (Show,Eq,ByteArrayAccess,NFData) -- | A Curve448 public key newtype PublicKey = PublicKey Bytes deriving (Show,Eq,ByteArrayAccess,NFData) -- | A Curve448 Diffie Hellman secret related to a -- public key and a secret key. newtype DhSecret = DhSecret ScrubbedBytes deriving (Show,Eq,ByteArrayAccess,NFData) -- | Try to build a public key from a bytearray publicKey :: ByteArrayAccess bs => bs -> CryptoFailable PublicKey publicKey bs | B.length bs == x448_bytes = CryptoPassed $ PublicKey $ B.copyAndFreeze bs (\_ -> return ()) | otherwise = CryptoFailed CryptoError_PublicKeySizeInvalid -- | Try to build a secret key from a bytearray secretKey :: ByteArrayAccess bs => bs -> CryptoFailable SecretKey secretKey bs | B.length bs == x448_bytes = unsafeDoIO $ withByteArray bs $ \inp -> do valid <- isValidPtr inp if valid then (CryptoPassed . SecretKey) <$> B.copy bs (\_ -> return ()) else return $ CryptoFailed CryptoError_SecretKeyStructureInvalid | otherwise = CryptoFailed CryptoError_SecretKeySizeInvalid where isValidPtr :: Ptr Word8 -> IO Bool isValidPtr _ = return True {-# NOINLINE secretKey #-} -- | Create a DhSecret from a bytearray object dhSecret :: ByteArrayAccess b => b -> CryptoFailable DhSecret dhSecret bs | B.length bs == x448_bytes = CryptoPassed $ DhSecret $ B.copyAndFreeze bs (\_ -> return ()) | otherwise = CryptoFailed CryptoError_SharedSecretSizeInvalid -- | Compute the Diffie Hellman secret from a public key and a secret key. -- -- This implementation may return an all-zero value as it does not check for -- the condition. dh :: PublicKey -> SecretKey -> DhSecret dh (PublicKey pub) (SecretKey sec) = DhSecret <$> B.allocAndFreeze x448_bytes $ \result -> withByteArray sec $ \psec -> withByteArray pub $ \ppub -> decaf_x448 result ppub psec {-# NOINLINE dh #-} -- | Create a public key from a secret key toPublic :: SecretKey -> PublicKey toPublic (SecretKey sec) = PublicKey <$> B.allocAndFreeze x448_bytes $ \result -> withByteArray sec $ \psec -> decaf_x448_derive_public_key result psec {-# NOINLINE toPublic #-} -- | Generate a secret key. generateSecretKey :: MonadRandom m => m SecretKey generateSecretKey = SecretKey <$> getRandomBytes x448_bytes x448_bytes :: Int x448_bytes = 448 `quot` 8 foreign import ccall "cryptonite_decaf_x448" decaf_x448 :: Ptr Word8 -- ^ public -> Ptr Word8 -- ^ basepoint -> Ptr Word8 -- ^ secret -> IO () foreign import ccall "cryptonite_decaf_x448_derive_public_key" decaf_x448_derive_public_key :: Ptr Word8 -- ^ public -> Ptr Word8 -- ^ secret -> IO ()