module Crypto.Curve25519.Pure(
PrivateKey
, PublicKey
, importPublic, exportPublic
, importPrivate, exportPrivate
, generatePrivate
, generatePublic
, generateKeyPair
, makeShared
)
where
import Crypto.Random
import Data.Bits
import Data.ByteString(ByteString)
import qualified Data.ByteString as BS
import Data.ByteString.Unsafe
import Data.Word
import Foreign.C.Types
import Foreign.Marshal.Alloc
import Foreign.Ptr
import System.IO.Unsafe
import Data.Maybe (fromJust)
import Data.List (foldl')
newtype PrivateKey = Priv ByteString
newtype PublicKey = Pub ByteString
instance Show PrivateKey where
show :: PrivateKey -> String
show (Priv ByteString
x) = forall a. Show a => a -> String
show (ByteString -> Integer
buildNumber ByteString
x)
instance Show PublicKey where
show :: PublicKey -> String
show (Pub ByteString
x) = forall a. Show a => a -> String
show (ByteString -> Integer
buildNumber ByteString
x)
generatePrivate :: CryptoRandomGen g => g -> Either GenError (PrivateKey, g)
generatePrivate :: forall g. CryptoRandomGen g => g -> Either GenError (PrivateKey, g)
generatePrivate g
g =
case forall g.
CryptoRandomGen g =>
Int -> g -> Either GenError (ByteString, g)
genBytes Int
32 g
g of
Left GenError
e -> forall a b. a -> Either a b
Left GenError
e
Right (ByteString
bytesbs, g
g') -> forall a b. b -> Either a b
Right (forall a. HasCallStack => Maybe a -> a
fromJust (ByteString -> Maybe PrivateKey
importPrivate ByteString
bytesbs), g
g')
importPrivate :: ByteString -> Maybe PrivateKey
importPrivate :: ByteString -> Maybe PrivateKey
importPrivate ByteString
bstr
| ByteString -> Int
BS.length ByteString
bstr forall a. Eq a => a -> a -> Bool
/= Int
32 = forall a. Maybe a
Nothing
| Bool
otherwise =
let Just (Word8
b0, ByteString
b1_31) = ByteString -> Maybe (Word8, ByteString)
BS.uncons ByteString
bstr
Just (ByteString
b1_30, Word8
b31) = ByteString -> Maybe (ByteString, Word8)
BS.unsnoc ByteString
b1_31
b0' :: Word8
b0' = Word8
b0 forall a. Bits a => a -> a -> a
.&. Word8
248
b31' :: Word8
b31' = Word8
b31 forall a. Bits a => a -> a -> a
.&. Word8
127
b31'' :: Word8
b31'' = Word8
b31' forall a. Bits a => a -> a -> a
.|. Word8
64
bytes :: ByteString
bytes = (Word8
b0' Word8 -> ByteString -> ByteString
`BS.cons` ByteString
b1_30) ByteString -> Word8 -> ByteString
`BS.snoc` Word8
b31''
in forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ ByteString -> PrivateKey
Priv ByteString
bytes
exportPrivate :: PrivateKey -> ByteString
exportPrivate :: PrivateKey -> ByteString
exportPrivate (Priv ByteString
bstr) = ByteString
bstr
generatePublic :: PrivateKey -> PublicKey
generatePublic :: PrivateKey -> PublicKey
generatePublic (Priv ByteString
priv) = ByteString -> PublicKey
Pub (ByteString -> ByteString -> ByteString
curve25519 ByteString
priv ByteString
basePoint)
importPublic :: ByteString -> Maybe PublicKey
importPublic :: ByteString -> Maybe PublicKey
importPublic ByteString
bstr | ByteString -> Int
BS.length ByteString
bstr forall a. Eq a => a -> a -> Bool
== Int
32 = forall a. a -> Maybe a
Just (ByteString -> PublicKey
Pub ByteString
bstr)
| Bool
otherwise = forall a. Maybe a
Nothing
exportPublic :: PublicKey -> ByteString
exportPublic :: PublicKey -> ByteString
exportPublic (Pub ByteString
bstr) = ByteString
bstr
generateKeyPair :: CryptoRandomGen g =>
g ->
Either GenError (PrivateKey, PublicKey, g)
generateKeyPair :: forall g.
CryptoRandomGen g =>
g -> Either GenError (PrivateKey, PublicKey, g)
generateKeyPair g
g =
case forall g. CryptoRandomGen g => g -> Either GenError (PrivateKey, g)
generatePrivate g
g of
Left GenError
e -> forall a b. a -> Either a b
Left GenError
e
Right (PrivateKey
priv, g
g') -> forall a b. b -> Either a b
Right (PrivateKey
priv, PrivateKey -> PublicKey
generatePublic PrivateKey
priv, g
g')
makeShared :: PrivateKey -> PublicKey -> ByteString
makeShared :: PrivateKey -> PublicKey -> ByteString
makeShared (Priv ByteString
a) (Pub ByteString
b) = ByteString -> ByteString -> ByteString
curve25519 ByteString
a ByteString
b
curve25519 :: ByteString -> ByteString -> ByteString
curve25519 :: ByteString -> ByteString -> ByteString
curve25519 ByteString
a ByteString
b =
forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$
forall a. ByteString -> (CString -> IO a) -> IO a
unsafeUseAsCString ByteString
a forall a b. (a -> b) -> a -> b
$ \ CString
ptra ->
forall a. ByteString -> (CString -> IO a) -> IO a
unsafeUseAsCString ByteString
b forall a b. (a -> b) -> a -> b
$ \ CString
ptrb ->
do Ptr Word8
ptrc <- forall a. Int -> IO (Ptr a)
mallocBytes Int
32
Ptr Word8 -> CString -> CString -> IO ()
curve25519_donna Ptr Word8
ptrc CString
ptra CString
ptrb
Ptr Word8 -> Int -> IO () -> IO ByteString
unsafePackCStringFinalizer Ptr Word8
ptrc Int
32 (forall a. Ptr a -> IO ()
free Ptr Word8
ptrc)
basePoint :: ByteString
basePoint :: ByteString
basePoint = Word8 -> ByteString -> ByteString
BS.cons Word8
9 (Int -> Word8 -> ByteString
BS.replicate Int
31 Word8
0)
buildNumber :: ByteString -> Integer
buildNumber :: ByteString -> Integer
buildNumber ByteString
bstr = forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' forall {a} {a}. (Bits a, Integral a, Num a) => a -> a -> a
run Integer
0 (ByteString -> [Word8]
BS.unpack ByteString
bstr)
where
run :: a -> a -> a
run a
acc a
x = (a
acc forall a. Bits a => a -> Int -> a
`shiftL` Int
8) forall a. Num a => a -> a -> a
+ forall a b. (Integral a, Num b) => a -> b
fromIntegral a
x
foreign import ccall unsafe
curve25519_donna :: Ptr Word8 -> Ptr CChar -> Ptr CChar -> IO ()