{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Crypto.PubKey.Curve25519
( SecretKey
, PublicKey
, DhSecret
, dhSecret
, publicKey
, secretKey
, dh
, toPublic
, generateSecretKey
) where
import Data.Bits
import Data.Word
import Foreign.Ptr
import Foreign.Storable
import GHC.Ptr
import Crypto.Error
import Crypto.Internal.Compat
import Crypto.Internal.Imports
import Crypto.Internal.ByteArray (ByteArrayAccess, ScrubbedBytes, Bytes, withByteArray)
import qualified Crypto.Internal.ByteArray as B
import Crypto.Random
newtype SecretKey = SecretKey ScrubbedBytes
deriving (Int -> SecretKey -> ShowS
[SecretKey] -> ShowS
SecretKey -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SecretKey] -> ShowS
$cshowList :: [SecretKey] -> ShowS
show :: SecretKey -> String
$cshow :: SecretKey -> String
showsPrec :: Int -> SecretKey -> ShowS
$cshowsPrec :: Int -> SecretKey -> ShowS
Show,SecretKey -> SecretKey -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SecretKey -> SecretKey -> Bool
$c/= :: SecretKey -> SecretKey -> Bool
== :: SecretKey -> SecretKey -> Bool
$c== :: SecretKey -> SecretKey -> Bool
Eq,SecretKey -> Int
forall p. SecretKey -> Ptr p -> IO ()
forall ba.
(ba -> Int)
-> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
-> (forall p. ba -> Ptr p -> IO ())
-> ByteArrayAccess ba
forall p a. SecretKey -> (Ptr p -> IO a) -> IO a
copyByteArrayToPtr :: forall p. SecretKey -> Ptr p -> IO ()
$ccopyByteArrayToPtr :: forall p. SecretKey -> Ptr p -> IO ()
withByteArray :: forall p a. SecretKey -> (Ptr p -> IO a) -> IO a
$cwithByteArray :: forall p a. SecretKey -> (Ptr p -> IO a) -> IO a
length :: SecretKey -> Int
$clength :: SecretKey -> Int
ByteArrayAccess,SecretKey -> ()
forall a. (a -> ()) -> NFData a
rnf :: SecretKey -> ()
$crnf :: SecretKey -> ()
NFData)
newtype PublicKey = PublicKey Bytes
deriving (Int -> PublicKey -> ShowS
[PublicKey] -> ShowS
PublicKey -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PublicKey] -> ShowS
$cshowList :: [PublicKey] -> ShowS
show :: PublicKey -> String
$cshow :: PublicKey -> String
showsPrec :: Int -> PublicKey -> ShowS
$cshowsPrec :: Int -> PublicKey -> ShowS
Show,PublicKey -> PublicKey -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PublicKey -> PublicKey -> Bool
$c/= :: PublicKey -> PublicKey -> Bool
== :: PublicKey -> PublicKey -> Bool
$c== :: PublicKey -> PublicKey -> Bool
Eq,PublicKey -> Int
forall p. PublicKey -> Ptr p -> IO ()
forall ba.
(ba -> Int)
-> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
-> (forall p. ba -> Ptr p -> IO ())
-> ByteArrayAccess ba
forall p a. PublicKey -> (Ptr p -> IO a) -> IO a
copyByteArrayToPtr :: forall p. PublicKey -> Ptr p -> IO ()
$ccopyByteArrayToPtr :: forall p. PublicKey -> Ptr p -> IO ()
withByteArray :: forall p a. PublicKey -> (Ptr p -> IO a) -> IO a
$cwithByteArray :: forall p a. PublicKey -> (Ptr p -> IO a) -> IO a
length :: PublicKey -> Int
$clength :: PublicKey -> Int
ByteArrayAccess,PublicKey -> ()
forall a. (a -> ()) -> NFData a
rnf :: PublicKey -> ()
$crnf :: PublicKey -> ()
NFData)
newtype DhSecret = DhSecret ScrubbedBytes
deriving (Int -> DhSecret -> ShowS
[DhSecret] -> ShowS
DhSecret -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DhSecret] -> ShowS
$cshowList :: [DhSecret] -> ShowS
show :: DhSecret -> String
$cshow :: DhSecret -> String
showsPrec :: Int -> DhSecret -> ShowS
$cshowsPrec :: Int -> DhSecret -> ShowS
Show,DhSecret -> DhSecret -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DhSecret -> DhSecret -> Bool
$c/= :: DhSecret -> DhSecret -> Bool
== :: DhSecret -> DhSecret -> Bool
$c== :: DhSecret -> DhSecret -> Bool
Eq,DhSecret -> Int
forall p. DhSecret -> Ptr p -> IO ()
forall ba.
(ba -> Int)
-> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
-> (forall p. ba -> Ptr p -> IO ())
-> ByteArrayAccess ba
forall p a. DhSecret -> (Ptr p -> IO a) -> IO a
copyByteArrayToPtr :: forall p. DhSecret -> Ptr p -> IO ()
$ccopyByteArrayToPtr :: forall p. DhSecret -> Ptr p -> IO ()
withByteArray :: forall p a. DhSecret -> (Ptr p -> IO a) -> IO a
$cwithByteArray :: forall p a. DhSecret -> (Ptr p -> IO a) -> IO a
length :: DhSecret -> Int
$clength :: DhSecret -> Int
ByteArrayAccess,DhSecret -> ()
forall a. (a -> ()) -> NFData a
rnf :: DhSecret -> ()
$crnf :: DhSecret -> ()
NFData)
publicKey :: ByteArrayAccess bs => bs -> CryptoFailable PublicKey
publicKey :: forall bs. ByteArrayAccess bs => bs -> CryptoFailable PublicKey
publicKey bs
bs
| forall ba. ByteArrayAccess ba => ba -> Int
B.length bs
bs forall a. Eq a => a -> a -> Bool
== Int
32 = forall a. a -> CryptoFailable a
CryptoPassed forall a b. (a -> b) -> a -> b
$ Bytes -> PublicKey
PublicKey forall a b. (a -> b) -> a -> b
$ forall bs1 bs2 p.
(ByteArrayAccess bs1, ByteArray bs2) =>
bs1 -> (Ptr p -> IO ()) -> bs2
B.copyAndFreeze bs
bs (\Ptr Any
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return ())
| Bool
otherwise = forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_PublicKeySizeInvalid
secretKey :: ByteArrayAccess bs => bs -> CryptoFailable SecretKey
secretKey :: forall bs. ByteArrayAccess bs => bs -> CryptoFailable SecretKey
secretKey bs
bs
| forall ba. ByteArrayAccess ba => ba -> Int
B.length bs
bs forall a. Eq a => a -> a -> Bool
== Int
32 = forall a. IO a -> a
unsafeDoIO forall a b. (a -> b) -> a -> b
$ do
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bs
bs forall a b. (a -> b) -> a -> b
$ \Ptr Word8
inp -> do
Bool
valid <- Ptr Word8 -> IO Bool
isValidPtr Ptr Word8
inp
if Bool
valid
then (forall a. a -> CryptoFailable a
CryptoPassed forall b c a. (b -> c) -> (a -> b) -> a -> c
. ScrubbedBytes -> SecretKey
SecretKey) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall bs1 bs2 p.
(ByteArrayAccess bs1, ByteArray bs2) =>
bs1 -> (Ptr p -> IO ()) -> IO bs2
B.copy bs
bs (\Ptr Any
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return ())
else forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_SecretKeyStructureInvalid
| Bool
otherwise = forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_SecretKeySizeInvalid
where
isValidPtr :: Ptr Word8 -> IO Bool
isValidPtr :: Ptr Word8 -> IO Bool
isValidPtr Ptr Word8
_ = do
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
{-# NOINLINE secretKey #-}
dhSecret :: ByteArrayAccess b => b -> CryptoFailable DhSecret
dhSecret :: forall b. ByteArrayAccess b => b -> CryptoFailable DhSecret
dhSecret b
bs
| forall ba. ByteArrayAccess ba => ba -> Int
B.length b
bs forall a. Eq a => a -> a -> Bool
== Int
32 = forall a. a -> CryptoFailable a
CryptoPassed forall a b. (a -> b) -> a -> b
$ ScrubbedBytes -> DhSecret
DhSecret forall a b. (a -> b) -> a -> b
$ forall bs1 bs2 p.
(ByteArrayAccess bs1, ByteArray bs2) =>
bs1 -> (Ptr p -> IO ()) -> bs2
B.copyAndFreeze b
bs (\Ptr Any
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return ())
| Bool
otherwise = forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_SharedSecretSizeInvalid
dh :: PublicKey -> SecretKey -> DhSecret
dh :: PublicKey -> SecretKey -> DhSecret
dh (PublicKey Bytes
pub) (SecretKey ScrubbedBytes
sec) = ScrubbedBytes -> DhSecret
DhSecret forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
B.allocAndFreeze Int
32 forall a b. (a -> b) -> a -> b
$ \Ptr Word8
result ->
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray ScrubbedBytes
sec forall a b. (a -> b) -> a -> b
$ \Ptr Word8
psec ->
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray Bytes
pub forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ppub ->
Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO ()
ccrypton_curve25519 Ptr Word8
result Ptr Word8
psec Ptr Word8
ppub
{-# NOINLINE dh #-}
toPublic :: SecretKey -> PublicKey
toPublic :: SecretKey -> PublicKey
toPublic (SecretKey ScrubbedBytes
sec) = Bytes -> PublicKey
PublicKey forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
B.allocAndFreeze Int
32 forall a b. (a -> b) -> a -> b
$ \Ptr Word8
result ->
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray ScrubbedBytes
sec forall a b. (a -> b) -> a -> b
$ \Ptr Word8
psec ->
Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO ()
ccrypton_curve25519 Ptr Word8
result Ptr Word8
psec forall {a}. Ptr a
basePoint
where
basePoint :: Ptr a
basePoint = forall a. Addr# -> Ptr a
Ptr Addr#
"\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"#
{-# NOINLINE toPublic #-}
generateSecretKey :: MonadRandom m => m SecretKey
generateSecretKey :: forall (m :: * -> *). MonadRandom m => m SecretKey
generateSecretKey = ScrubbedBytes -> SecretKey
tweakToSecretKey forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) byteArray.
(MonadRandom m, ByteArray byteArray) =>
Int -> m byteArray
getRandomBytes Int
32
where
tweakToSecretKey :: ScrubbedBytes -> SecretKey
tweakToSecretKey :: ScrubbedBytes -> SecretKey
tweakToSecretKey ScrubbedBytes
bin = ScrubbedBytes -> SecretKey
SecretKey forall a b. (a -> b) -> a -> b
$ forall bs1 bs2 p.
(ByteArrayAccess bs1, ByteArray bs2) =>
bs1 -> (Ptr p -> IO ()) -> bs2
B.copyAndFreeze ScrubbedBytes
bin forall a b. (a -> b) -> a -> b
$ \Ptr Word8
inp -> do
Ptr Word8 -> Int -> (Word8 -> Word8) -> IO ()
modifyByte Ptr Word8
inp Int
0 (\Word8
e0 -> Word8
e0 forall a. Bits a => a -> a -> a
.&. Word8
0xf8)
Ptr Word8 -> Int -> (Word8 -> Word8) -> IO ()
modifyByte Ptr Word8
inp Int
31 (\Word8
e31 -> (Word8
e31 forall a. Bits a => a -> a -> a
.&. Word8
0x7f) forall a. Bits a => a -> a -> a
.|. Word8
0x40)
modifyByte :: Ptr Word8 -> Int -> (Word8 -> Word8) -> IO ()
modifyByte :: Ptr Word8 -> Int -> (Word8 -> Word8) -> IO ()
modifyByte Ptr Word8
p Int
n Word8 -> Word8
f = forall a b. Storable a => Ptr b -> Int -> IO a
peekByteOff Ptr Word8
p Int
n forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr Word8
p Int
n forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> Word8
f
foreign import ccall "crypton_curve25519_donna"
ccrypton_curve25519 :: Ptr Word8
-> Ptr Word8
-> Ptr Word8
-> IO ()