diff --git a/.gitignore b/.gitignore index 33ee2ff..a213015 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ QA benchs/Bench benchs/Hash *.sublime-workspace +.cabal-sandbox/ +cabal.sandbox.config diff --git a/Crypto/Error/Types.hs b/Crypto/Error/Types.hs index 4aaf4e0..cb512d2 100644 --- a/Crypto/Error/Types.hs +++ b/Crypto/Error/Types.hs @@ -43,6 +43,8 @@ data CryptoError = -- Message authentification error | CryptoError_MacKeyInvalid | CryptoError_AuthenticationTagSizeInvalid + -- Prime generation error + | CryptoError_PrimeSizeInvalid deriving (Show,Eq,Enum,Data,Typeable) instance E.Exception CryptoError diff --git a/Crypto/Number/Prime.hs b/Crypto/Number/Prime.hs index 89a92da..c993648 100644 --- a/Crypto/Number/Prime.hs +++ b/Crypto/Number/Prime.hs @@ -27,6 +27,7 @@ import Crypto.Number.Basic (sqrti, gcde) import Crypto.Number.ModArithmetic (expSafe) import Crypto.Random.Types import Crypto.Random.Probabilistic +import Crypto.Error import Data.Bits @@ -40,22 +41,44 @@ isProbablyPrime !n | primalityTestFermat 50 (n`div`2) n = primalityTestMillerRabin 30 n | otherwise = False --- | generate a prime number of the required bitsize +-- | generate a prime number of the required bitsize (i.e. in the range +-- [2^(b-1)+2^(b-2), 2^b)). +-- +-- May throw a CryptoError_PrimeSizeInvalid if the requested size is less +-- than 5 bits, as the smallest prime meeting these conditions is 29. +-- This function requires that the two highest bits are set, so that when +-- multiplied with another prime to create a key, it is guaranteed to be of +-- the proper size. generatePrime :: MonadRandom m => Int -> m Integer generatePrime bits = do - sp <- generateParams bits (Just SetTwoHighest) True - return $ findPrimeFrom sp + if bits < 5 then + throwCryptoError $ CryptoFailed $ CryptoError_PrimeSizeInvalid + else do + sp <- generateParams bits (Just SetTwoHighest) True + let prime = findPrimeFrom sp + if prime < 1 `shiftL` bits then + return $ prime + else generatePrime bits -- | generate a prime number of the form 2p+1 where p is also prime. -- it is also knowed as a Sophie Germaine prime or safe prime. -- -- The number of safe prime is significantly smaller to the number of prime, -- as such it shouldn't be used if this number is supposed to be kept safe. +-- +-- May throw a CryptoError_PrimeSizeInvalid if the requested size is less than +-- 6 bits, as the smallest safe prime with the two highest bits set is 59. generateSafePrime :: MonadRandom m => Int -> m Integer generateSafePrime bits = do - sp <- generateParams bits (Just SetTwoHighest) True - let p = findPrimeFromWith (\i -> isProbablyPrime (2*i+1)) (sp `div` 2) - return (2*p+1) + if bits < 6 then + throwCryptoError $ CryptoFailed $ CryptoError_PrimeSizeInvalid + else do + sp <- generateParams bits (Just SetTwoHighest) True + let p = findPrimeFromWith (\i -> isProbablyPrime (2*i+1)) (sp `div` 2) + let val = 2 * p + 1 + if val < 1 `shiftL` bits then + return $ val + else generateSafePrime bits -- | find a prime from a starting point where the property hold. findPrimeFromWith :: (Integer -> Bool) -> Integer -> Integer diff --git a/cryptonite.cabal b/cryptonite.cabal index 1ea74f7..e82f1e5 100644 --- a/cryptonite.cabal +++ b/cryptonite.cabal @@ -205,7 +205,7 @@ Library , bytestring , memory >= 0.8 , ghc-prim - ghc-options: -Wall -fwarn-tabs -optc-O3 -fno-warn-unused-imports + ghc-options: -Wall -fwarn-tabs -optc-O3 -fno-warn-unused-imports -fobject-code default-language: Haskell2010 cc-options: -std=gnu99 if flag(old_toolchain_inliner)