From 76bf7e08bccbb1a3a689068016b8a9c29d1e060e Mon Sep 17 00:00:00 2001 From: Joe Crayne Date: Sun, 10 Nov 2019 14:27:48 -0500 Subject: Ed25519 secret portion (create + sign). --- Data/OpenPGP/Util/Ed25519.hs | 116 +++++++++++++++++++++++++++++++------------ 1 file changed, 84 insertions(+), 32 deletions(-) (limited to 'Data/OpenPGP/Util/Ed25519.hs') diff --git a/Data/OpenPGP/Util/Ed25519.hs b/Data/OpenPGP/Util/Ed25519.hs index ed277c8..7504e7e 100644 --- a/Data/OpenPGP/Util/Ed25519.hs +++ b/Data/OpenPGP/Util/Ed25519.hs @@ -1,51 +1,103 @@ module Data.OpenPGP.Util.Ed25519 where +import Control.Monad import Crypto.Error import qualified Crypto.PubKey.Ed25519 as Ed25519 -import Data.OpenPGP.Internal -- (integerToBS,integerToLE,getBigNumLE) -import qualified Data.OpenPGP as OpenPGP -import Crypto.ECC.Edwards25519 +import Data.Bits +import qualified Data.ByteArray as BA +import qualified Data.ByteString as BS +import qualified Data.ByteString.Lazy as BL -import qualified Data.ByteArray as BA -import Control.Monad -import qualified Data.ByteString as BS -import qualified Data.ByteString.Lazy as BL -import Data.List -import Data.Int -import Data.Word +import qualified Data.OpenPGP as OpenPGP +import Data.OpenPGP (MPI(..)) +import Data.OpenPGP.Internal import Data.OpenPGP.Util.Base +-- import Crypto.ECC.Edwards25519 -import Text.Printf -import Numeric -import Data.Char -import System.IO +oid_ed25516 = 0x2B06010401DA470F01 -import Foreign.Ptr -import System.IO.Unsafe +zeroExtend :: Int -> BS.ByteString -> BS.ByteString +zeroExtend n bs = case compare (BS.length bs) n of + GT -> BS.take n bs + EQ -> bs + LT -> bs <> BS.replicate (n - BS.length bs) 0 -import Crypto.Cipher.SBox +zeroPad :: Int -> BS.ByteString -> BS.ByteString +zeroPad n bs = case compare (BS.length bs) n of + GT -> BS.take n bs + EQ -> bs + LT -> BS.replicate (n - BS.length bs) 0 <> bs ed25519Key :: OpenPGP.Packet -> Maybe Ed25519.PublicKey -ed25519Key k = case Ed25519.publicKey $ integerToBS $ keyParam 'n' k of - CryptoPassed ed25519 -> Just ed25519 - CryptoFailed err -> Nothing +ed25519Key k = + let n = case keyParam 'f' k of + 0x40 -> zeroPad 32 $ integerToBS $ keyParam 'n' k + _ -> + -- From Bernstein's "High-speed high-security signatures" + -- + -- An element (x, y) ∈ E is encoded as a b-bit string (x, y), namely the (b − + -- 1)- bit encoding of y followed by a sign bit; the sign bit is 1 iff x is + -- negative. This encoding immediately determines y, and it determines x via + -- the equation x = ± √(y² − 1)/(dy² + 1). + let y = keyParam 'y' k + x = keyParam 'x' k + ybs = zeroExtend 32 $ integerToLE y + lb = BS.last ybs + in if x < 0 then BS.take 31 ybs `BS.snoc` (lb .|. 1) + else BS.take 31 ybs `BS.snoc` (lb .&. 0xFE) + in case Ed25519.publicKey n of + CryptoPassed ed25519 -> Just ed25519 + CryptoFailed _ -> Nothing +ed25519sig :: OpenPGP.Packet -> Maybe Ed25519.Signature ed25519sig sig = - let [OpenPGP.MPI r,OpenPGP.MPI s] = OpenPGP.signature sig - -- rbs = BS.pack $ take 32 $ rbytes r ++ repeat 0 - -- sbs = BS.pack $ take 32 $ rbytes s ++ repeat 0 - rbs = let r' = integerToBS r in BS.replicate (32 - BS.length r') 0 <> r' - sbs = let s' = integerToBS s in BS.replicate (32 - BS.length s') 0 <> s' + let [MPI r,MPI s] = OpenPGP.signature sig + rbs = zeroPad 32 $ integerToBS r + sbs = zeroPad 32 $ integerToBS s in case Ed25519.signature (rbs <> sbs) of - CryptoPassed sig -> Just sig - CryptoFailed err -> Nothing + CryptoPassed sig25519 -> Just sig25519 + CryptoFailed _ -> Nothing + +privateEd25519Key :: OpenPGP.Packet -> Ed25519.SecretKey +privateEd25519Key k = case Ed25519.secretKey $ zeroExtend 32 $ integerToLE (keyParam 'd' k) of + CryptoPassed ed25519sec -> ed25519sec + CryptoFailed err -> error $ "Ed25519.secretKey: " ++ show err ed25519Verify :: OpenPGP.Packet -> BS.ByteString -> OpenPGP.Packet -> Maybe Bool ed25519Verify sig over k = do let hashbs = hashBySymbol (OpenPGP.hash_algorithm sig) $ BL.fromChunks [over] - guard $ 0x2B06010401DA470F01 == keyParam 'c' k -- Only Ed25519 curve. - k' <- ed25519Key k -- SecretKeyPacket ??? - sig' <- ed25519sig sig - let result = Ed25519.verify k' hashbs sig' - Just result + guard $ oid_ed25516 == keyParam 'c' k -- Only Ed25519 curve. + ek <- ed25519Key k + esig <- ed25519sig sig + Just $ Ed25519.verify ek hashbs esig + +ed25519Sign :: OpenPGP.Packet -> OpenPGP.HashAlgorithm -> BS.ByteString -> [Integer] +ed25519Sign k hsh dta = [ getBigNum rbs, getBigNum sbs ] + where + hashbs = hashBySymbol hsh $ BL.fromChunks [dta] + sec = privateEd25519Key k + Just pub = ed25519Key k + sig = Ed25519.sign sec pub hashbs + (rbs,sbs) = BS.splitAt 32 $ BA.convert sig + +importSecretEd25519 :: Ed25519.SecretKey -> [(Char,MPI)] +importSecretEd25519 k = + [ ('c', MPI oid_ed25516) + , ('l', MPI 128) + , ('n', MPI pub) + , ('f', MPI 0x40) + , ('d', MPI sec) + ] + where + pub = getBigNum $ BA.convert $ Ed25519.toPublic k + sec = getBigNumLE $ BA.convert k +importPublicEd25519 :: Ed25519.PublicKey -> [(Char,MPI)] +importPublicEd25519 k = + [ ('c', MPI oid_ed25516) + , ('l', MPI 128) + , ('n', MPI pub) + , ('f', MPI 0x40) + ] + where + pub = getBigNum $ BA.convert k -- cgit v1.2.3