From 713295a4ac808cc4bb1eb1f7be78d79d70dc6cd1 Mon Sep 17 00:00:00 2001 From: Joe Crayne Date: Thu, 14 Nov 2019 19:04:32 -0500 Subject: Enable generating cv25519 keys. --- Data/OpenPGP/Util/Cv25519.hs | 14 ++++++++- Data/OpenPGP/Util/Decrypt.hs | 53 +++++++++++++++++++++++++++++++++++ Data/OpenPGP/Util/DecryptSecretKey.hs | 40 +------------------------- Data/OpenPGP/Util/Gen.hs | 11 +++++--- openpgp-util.cabal | 1 + 5 files changed, 75 insertions(+), 44 deletions(-) create mode 100644 Data/OpenPGP/Util/Decrypt.hs diff --git a/Data/OpenPGP/Util/Cv25519.hs b/Data/OpenPGP/Util/Cv25519.hs index 4900b2f..d5ac641 100644 --- a/Data/OpenPGP/Util/Cv25519.hs +++ b/Data/OpenPGP/Util/Cv25519.hs @@ -26,7 +26,7 @@ import qualified Crypto.PubKey.Curve25519 as Cv25519 import Crypto.Error import Crypto.Cipher.AES import Crypto.Cipher.Types -import Data.OpenPGP.Util.DecryptSecretKey -- (withS2K, simpleUnCFB, Enciphered(..)) +import Data.OpenPGP.Util.Decrypt -- (withS2K, simpleUnCFB, Enciphered(..)) import Crypto.JOSE.AESKW @@ -229,3 +229,15 @@ decryptMessage ecdhkey asym encdta = do b1 = BL.drop (2 + fromIntegral blksize) b0 (_,_, Message ps) <- either (const Nothing) Just $ decodeOrFail b1 return ps + +importSecretCv25519 :: Cv25519.SecretKey -> [(Char,MPI)] +importSecretCv25519 k = + [ ('c', MPI oid_cv25519) + , ('l', MPI 128) + , ('n', MPI pub) + , ('f', MPI 0x40) + , ('d', MPI sec) + ] + where + pub = getBigNum $ BA.convert $ Cv25519.toPublic k + sec = getBigNumLE $ BA.convert k diff --git a/Data/OpenPGP/Util/Decrypt.hs b/Data/OpenPGP/Util/Decrypt.hs new file mode 100644 index 0000000..84bead5 --- /dev/null +++ b/Data/OpenPGP/Util/Decrypt.hs @@ -0,0 +1,53 @@ +{-# LANGUAGE RankNTypes, CPP #-} +module Data.OpenPGP.Util.Decrypt where + +import qualified Data.ByteString.Lazy as LZ +import Crypto.Error +import qualified Crypto.Cipher.AES as Vincent +import qualified Crypto.Cipher.Blowfish as Vincent +import qualified Crypto.Cipher.Types as Vincent +import Crypto.Cipher.Cast5 (CAST5_128) +import Crypto.Cipher.ThomasToVincent +import qualified Data.OpenPGP as OpenPGP +import Data.OpenPGP.Util.Base + + +-- decryption codec for withS2K +simpleUnCFB :: (Vincent.BlockCipher k) => k -> Vincent.IV k -> LZ.ByteString -> LZ.ByteString +simpleUnCFB k iv = padThenUnpad k (toLazyBS . Vincent.cfbDecrypt k iv . toStrictBS) + +withS2K' :: OpenPGP.SymmetricAlgorithm -> Maybe OpenPGP.S2K -> LZ.ByteString + -> (forall b. Vincent.BlockCipher b => b -> x) -> x +withS2K' OpenPGP.AES128 s2k s f = f (string2key s2k s :: Vincent.AES128) +withS2K' OpenPGP.AES192 s2k s f = f (string2key s2k s :: Vincent.AES192) +withS2K' OpenPGP.AES256 s2k s f = f (string2key s2k s :: Vincent.AES256) +withS2K' OpenPGP.Blowfish s2k s f = f (string2key s2k s :: Vincent.Blowfish128) +withS2K' OpenPGP.CAST5 s2k s f = f (string2key s2k s :: ThomasToVincent CAST5_128) + +string2key :: (Vincent.BlockCipher k) => Maybe OpenPGP.S2K -> LZ.ByteString -> k +string2key ms2k s = cipher + where +#if defined(VERSION_cryptonite) + CryptoPassed cipher = Vincent.cipherInit k + k = toStrictBS $ LZ.take ksize $ maybe s (\s2k -> OpenPGP.string2key hashBySymbol s2k s) ms2k +#else + cipher = Vincent.cipherInit k + Right k = Vincent.makeKey $ toStrictBS $ + LZ.take ksize $ maybe s (\s2k -> OpenPGP.string2key hashBySymbol s2k s) ms2k +#endif + ksize = case Vincent.cipherKeySize cipher of + Vincent.KeySizeFixed n -> fromIntegral n + Vincent.KeySizeEnum xs -> error $ "Unknown key size in string2key" + Vincent.KeySizeRange min max -> error $ "Unknown key size range in string2key" + +-- Apply a function f to a zero-padded bytestring s to a multiple +-- of the blocksize for cyper k. +-- Then drop the same number of bytes from the result of f. +padThenUnpad :: (Vincent.BlockCipher k) => k -> (LZ.ByteString -> LZ.ByteString) -> LZ.ByteString -> LZ.ByteString +padThenUnpad k f s = dropPadEnd (f padded) + where + dropPadEnd s = LZ.take (LZ.length s - padAmount) s + padded = s `LZ.append` LZ.replicate padAmount 0 + padAmount = blksize - (LZ.length s `mod` blksize) + blksize = fromIntegral $ Vincent.blockSize k + diff --git a/Data/OpenPGP/Util/DecryptSecretKey.hs b/Data/OpenPGP/Util/DecryptSecretKey.hs index a637b29..57dd8c3 100644 --- a/Data/OpenPGP/Util/DecryptSecretKey.hs +++ b/Data/OpenPGP/Util/DecryptSecretKey.hs @@ -27,6 +27,7 @@ import qualified Crypto.Cipher.AES as Vincent import qualified Crypto.Cipher.Blowfish as Vincent import qualified Crypto.Cipher.Types as Vincent +import Data.OpenPGP.Util.Decrypt #if defined(VERSION_cryptonite) import qualified Data.ByteArray as Bytes @@ -131,18 +132,6 @@ withS2K codec OpenPGP.Blowfish s2k s = withIV $ codec (string2key s2k s :: Vince withS2K codec OpenPGP.CAST5 s2k s = withIV $ codec (string2key s2k s :: ThomasToVincent CAST5_128) withS2K codec algo _ _ = error $ "Unsupported symmetric algorithm : " ++ show algo ++ " in Data.OpenPGP.CryptoAPI.withS2K" -withS2K' :: OpenPGP.SymmetricAlgorithm -> Maybe OpenPGP.S2K -> LZ.ByteString - -> (forall b. Vincent.BlockCipher b => b -> x) -> x -withS2K' OpenPGP.AES128 s2k s f = f (string2key s2k s :: Vincent.AES128) -withS2K' OpenPGP.AES192 s2k s f = f (string2key s2k s :: Vincent.AES192) -withS2K' OpenPGP.AES256 s2k s f = f (string2key s2k s :: Vincent.AES256) -withS2K' OpenPGP.Blowfish s2k s f = f (string2key s2k s :: Vincent.Blowfish128) -withS2K' OpenPGP.CAST5 s2k s f = f (string2key s2k s :: ThomasToVincent CAST5_128) - --- decryption codec for withS2K -simpleUnCFB :: (Vincent.BlockCipher k) => k -> Vincent.IV k -> LZ.ByteString -> LZ.ByteString -simpleUnCFB k iv = padThenUnpad k (toLazyBS . Vincent.cfbDecrypt k iv . toStrictBS) - simpleCFB :: forall k g. (Vincent.BlockCipher k, RG g) => g -> k -> LZ.ByteString -> (LZ.ByteString, g) simpleCFB g k bs = ( padThenUnpad k (LZ.fromChunks . (ivbs:) . (:[]) . Vincent.cfbEncrypt k iv . toStrictBS) bs , g' ) @@ -158,33 +147,6 @@ simpleCFB g k bs = ( padThenUnpad k (LZ.fromChunks . (ivbs:) . (:[]) . Vincent.c _ = Vincent.constEqBytes z iv #endif --- Apply a function f to a zero-padded bytestring s to a multiple --- of the blocksize for cyper k. --- Then drop the same number of bytes from the result of f. -padThenUnpad :: (Vincent.BlockCipher k) => k -> (LZ.ByteString -> LZ.ByteString) -> LZ.ByteString -> LZ.ByteString -padThenUnpad k f s = dropPadEnd (f padded) - where - dropPadEnd s = LZ.take (LZ.length s - padAmount) s - padded = s `LZ.append` LZ.replicate padAmount 0 - padAmount = blksize - (LZ.length s `mod` blksize) - blksize = fromIntegral $ Vincent.blockSize k - -string2key :: (Vincent.BlockCipher k) => Maybe OpenPGP.S2K -> LZ.ByteString -> k -string2key ms2k s = cipher - where -#if defined(VERSION_cryptonite) - CryptoPassed cipher = Vincent.cipherInit k - k = toStrictBS $ LZ.take ksize $ maybe s (\s2k -> OpenPGP.string2key hashBySymbol s2k s) ms2k -#else - cipher = Vincent.cipherInit k - Right k = Vincent.makeKey $ toStrictBS $ - LZ.take ksize $ maybe s (\s2k -> OpenPGP.string2key hashBySymbol s2k s) ms2k -#endif - ksize = case Vincent.cipherKeySize cipher of - Vincent.KeySizeFixed n -> fromIntegral n - Vincent.KeySizeEnum xs -> error $ "Unknown key size in string2key" - Vincent.KeySizeRange min max -> error $ "Unknown key size range in string2key" - catchIO_ :: IO a -> IO a -> IO a catchIO_ a h = Exception.catch a (\(_ :: IOException) -> h) diff --git a/Data/OpenPGP/Util/Gen.hs b/Data/OpenPGP/Util/Gen.hs index ca3c684..c33ef1e 100644 --- a/Data/OpenPGP/Util/Gen.hs +++ b/Data/OpenPGP/Util/Gen.hs @@ -14,7 +14,9 @@ import qualified Crypto.PubKey.RSA as Vincent.RSA import qualified Crypto.PubKey.RSA.PKCS15 as Vincent.RSA import qualified Crypto.PubKey.ECC.ECDSA as Vincent.ECDSA #if defined(VERSION_cryptonite) +import qualified Crypto.PubKey.Curve25519 as Cv25519 import qualified Crypto.PubKey.Ed25519 as Ed25519 +import Data.OpenPGP.Util.Cv25519 import Data.OpenPGP.Util.Ed25519 import Control.Arrow (second) import Data.Binary @@ -25,6 +27,7 @@ import Data.OpenPGP.Util.Base data GenerateKeyParams = GenRSA Int -- keysize | GenDSA (Maybe DSAParams) | GenEd25519 + | GenCv25519 deriving (Eq,Ord,Show) data DSAParams = DSAParams @@ -121,10 +124,10 @@ generateKey' (GenDSA mbparams) g = generateKey' (GenEd25519 {}) g = withDRG g $ do k <- Ed25519.generateSecretKey return $ importSecretEd25519 k - -- file:///usr/share/doc/libghc-cryptonite-doc/html/Crypto-PubKey-Ed25519.html#v:generateSecretKey - -- generateSecretKey :: MonadRandom m => m SecretKey - -- n = public key used to verify signatures. - -- public_key_fields Ed25519 = ['c','l','x', 'y', 'n', 'f'] +generateKey' (GenCv25519 {}) g = withDRG g $ do + k <- Cv25519.generateSecretKey + return $ importSecretCv25519 k + #endif diff --git a/openpgp-util.cabal b/openpgp-util.cabal index 132cb05..055dde7 100644 --- a/openpgp-util.cabal +++ b/openpgp-util.cabal @@ -139,6 +139,7 @@ library Data.OpenPGP.Util.Verify Data.OpenPGP.Util.Sign Data.OpenPGP.Util.Gen + Data.OpenPGP.Util.Decrypt Data.OpenPGP.Util.DecryptSecretKey Data.OpenPGP.Util.Ed25519 build-depends: -- cgit v1.2.3