cryptocipher 0.2.8 → 0.2.9
raw patch · 9 files changed
+411/−62 lines, 9 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Crypto.Cipher.DH: data PrivateNumber
+ Crypto.Cipher.DH: data PublicNumber
+ Crypto.Cipher.DH: data SharedKey
+ Crypto.Cipher.DH: generatePublic :: Params -> PrivateNumber -> PublicNumber
+ Crypto.Cipher.DH: getShared :: Params -> PrivateNumber -> PublicNumber -> SharedKey
+ Crypto.Cipher.DH: instance Enum PrivateNumber
+ Crypto.Cipher.DH: instance Enum PublicNumber
+ Crypto.Cipher.DH: instance Enum SharedKey
+ Crypto.Cipher.DH: instance Eq PrivateNumber
+ Crypto.Cipher.DH: instance Eq PublicNumber
+ Crypto.Cipher.DH: instance Eq SharedKey
+ Crypto.Cipher.DH: instance Num PrivateNumber
+ Crypto.Cipher.DH: instance Num PublicNumber
+ Crypto.Cipher.DH: instance Num SharedKey
+ Crypto.Cipher.DH: instance Ord PrivateNumber
+ Crypto.Cipher.DH: instance Ord PublicNumber
+ Crypto.Cipher.DH: instance Ord SharedKey
+ Crypto.Cipher.DH: instance Read PrivateNumber
+ Crypto.Cipher.DH: instance Read PublicNumber
+ Crypto.Cipher.DH: instance Read SharedKey
+ Crypto.Cipher.DH: instance Real PrivateNumber
+ Crypto.Cipher.DH: instance Real PublicNumber
+ Crypto.Cipher.DH: instance Real SharedKey
+ Crypto.Cipher.DH: instance Show PrivateNumber
+ Crypto.Cipher.DH: instance Show PublicNumber
+ Crypto.Cipher.DH: instance Show SharedKey
+ Crypto.Cipher.DH: type Params = (Integer, Integer)
+ Crypto.Cipher.RSA: generate :: CryptoRandomGen g => g -> Int -> Integer -> Either GenError ((PublicKey, PrivateKey), g)
Files
- Crypto/Cipher/DH.hs +44/−0
- Crypto/Cipher/RSA.hs +38/−1
- LICENSE +1/−1
- Number/Basic.hs +81/−0
- Number/Generate.hs +24/−12
- Number/ModArithmetic.hs +2/−32
- Number/Prime.hs +147/−0
- Tests.hs +70/−15
- cryptocipher.cabal +4/−1
+ Crypto/Cipher/DH.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++-- |+-- Module : Crypto.Cipher.DH+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : Good+--+module Crypto.Cipher.DH+ ( Params+ , PublicNumber+ , PrivateNumber+ , SharedKey+ , generatePublic+ , getShared+ ) where++import Number.ModArithmetic (exponantiation_rtl_binary)+import Number.Prime+import Crypto.Random++type Params = (Integer,Integer) {- P prime, G generator -}++newtype PublicNumber = PublicNumber Integer {- Y -}+ deriving (Show,Read,Eq,Enum,Real,Num,Ord)++newtype PrivateNumber = PrivateNumber Integer {- X -}+ deriving (Show,Read,Eq,Enum,Real,Num,Ord)++newtype SharedKey = SharedKey Integer {- S -}+ deriving (Show,Read,Eq,Enum,Real,Num,Ord)++generateParams :: CryptoRandomGen g => g -> Params+generateParams = undefined++generatePrivate :: CryptoRandomGen g => g -> PrivateNumber+generatePrivate rng = undefined++generatePublic :: Params -> PrivateNumber -> PublicNumber+generatePublic (p,g) (PrivateNumber x) = PublicNumber $ exponantiation_rtl_binary g x p++getShared :: Params -> PrivateNumber -> PublicNumber -> SharedKey+getShared (p,_) (PrivateNumber x) (PublicNumber y) = SharedKey $ exponantiation_rtl_binary y x p
Crypto/Cipher/RSA.hs view
@@ -13,6 +13,7 @@ , PrivateKey(..) , HashF , HashASN1+ , generate , decrypt , encrypt , sign@@ -23,8 +24,10 @@ import Crypto.Random import Data.ByteString (ByteString) import qualified Data.ByteString as B-import Number.ModArithmetic (exponantiation_rtl_binary)+import Number.ModArithmetic (exponantiation_rtl_binary, inverse)+import Number.Prime (generatePrime) import Number.Serialize+import Data.Maybe (fromJust) data Error = MessageSizeIncorrect -- ^ the message to decrypt is not of the correct size (need to be == private_size)@@ -122,6 +125,40 @@ s <- makeSignature hash hashdesc (public_sz pk) m em <- i2ospOf (public_sz pk) $ expmod (os2ip sm) (public_e pk) (public_n pk) Right (s == em)++-- | generate a pair of (private, public) key of size in bytes.+generate :: CryptoRandomGen g => g -> Int -> Integer -> Either GenError ((PublicKey, PrivateKey), g)+generate rng size e = do+ ((p,q), rng') <- generatePQ rng+ let n = p * q+ let phi = (p-1)*(q-1)+ case inverse e phi of+ Nothing -> generate rng' size e+ Just d -> do+ let priv = PrivateKey+ { private_sz = size+ , private_n = n+ , private_d = d+ , private_p = p+ , private_q = q+ , private_dP = d `mod` (p-1)+ , private_dQ = d `mod` (q-1)+ , private_qinv = fromJust $ inverse q p -- q and p are coprime, so fromJust is safe.+ }+ let pub = PublicKey+ { public_sz = size+ , public_n = n+ , public_e = e+ }+ return ((pub, priv), rng')+ where+ generatePQ g = do+ (p, g') <- generatePrime g (8 * (size `div` 2))+ (q, g'') <- generateQ p g'+ return ((p,q), g'')+ generateQ p h = do+ (q, h') <- generatePrime h (8 * (size - (size `div` 2)))+ if p == q then generateQ p h' else return (q, h') {- makeSignature for sign and verify -} makeSignature :: HashF -> HashASN1 -> Int -> ByteString -> Either Error ByteString
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2010 Vincent Hanquez <vincent@snarc.org>+Copyright (c) 2010-2011 Vincent Hanquez <vincent@snarc.org> All rights reserved.
+ Number/Basic.hs view
@@ -0,0 +1,81 @@+{-# LANGUAGE BangPatterns #-}+module Number.Basic+ ( sqrti+ , gcde+ , gcde_binary+ , areEven+ ) where++import Data.Bits++-- | sqrti returns two integer (l,b) so that l <= sqrt i <= b+-- the implementation is quite naive, use an approximation for the first number+-- and use a dichotomy algorithm to compute the bound relatively efficiently.+sqrti :: Integer -> (Integer, Integer)+sqrti i+ | i < 0 = error "cannot compute negative square root"+ | i == 0 = (0,0)+ | i == 1 = (1,1)+ | i == 2 = (1,2)+ | otherwise = loop x0+ where+ nbdigits = length $ show i+ x0n = (if even nbdigits then nbdigits - 2 else nbdigits - 1) `div` 2+ x0 = if even nbdigits then 2 * 10 ^ x0n else 6 * 10 ^ x0n+ loop x = case compare (sq x) i of+ LT -> iterUp x+ EQ -> (x, x)+ GT -> iterDown x+ iterUp lb = if sq ub >= i then iter lb ub else iterUp ub+ where ub = lb * 2+ iterDown ub = if sq lb >= i then iterDown lb else iter lb ub+ where lb = ub `div` 2+ iter lb ub+ | lb == ub = (lb, ub)+ | lb+1 == ub = (lb, ub)+ | otherwise =+ let d = (ub - lb) `div` 2 in+ if sq (lb + d) >= i+ then iter lb (ub-d)+ else iter (lb+d) ub+ sq a = a * a++-- | get the extended GCD of two integer using integer divMod+gcde :: Integer -> Integer -> (Integer, Integer, Integer)+gcde a b = if d < 0 then (-x,-y,-d) else (x,y,d) where+ (d, x, y) = f (a,1,0) (b,0,1)+ f t (0, _, _) = t+ f (a', sa, ta) t@(b', sb, tb) =+ let (q, r) = a' `divMod` b' in+ f t (r, sa - (q * sb), ta - (q * tb))++-- | get the extended GCD of two integer using the extended binary algorithm (HAC 14.61)+-- get (x,y,d) where d = gcd(a,b) and x,y satisfying ax + by = d+gcde_binary :: Integer -> Integer -> (Integer, Integer, Integer)+gcde_binary a' b'+ | b' == 0 = (1,0,a')+ | a' >= b' = compute a' b'+ | otherwise = (\(x,y,d) -> (y,x,d)) $ compute b' a'+ where+ getEvenMultiplier !g !x !y+ | areEven [x,y] = getEvenMultiplier (g `shiftL` 1) (x `shiftR` 1) (y `shiftR` 1)+ | otherwise = (x,y,g)+ halfLoop !x !y !u !i !j+ | areEven [u,i,j] = halfLoop x y (u `shiftR` 1) (i `shiftR` 1) (j `shiftR` 1)+ | even u = halfLoop x y (u `shiftR` 1) ((i + y) `shiftR` 1) ((j - x) `shiftR` 1)+ | otherwise = (u, i, j)+ compute a b =+ let (x,y,g) = getEvenMultiplier 1 a b in+ loop g x y x y 1 0 0 1++ loop g _ _ 0 !v _ _ !c !d = (c, d, g * v)+ loop g x y !u !v !a !b !c !d =+ let (u2,a2,b2) = halfLoop x y u a b in+ let (v2,c2,d2) = halfLoop x y v c d in+ if u2 >= v2+ then loop g x y (u2 - v2) v2 (a2 - c2) (b2 - d2) c2 d2+ else loop g x y u2 (v2 - u2) a2 b2 (c2 - a2) (d2 - b2)++-- | check if a list of integer are all even+areEven :: [Integer] -> Bool+areEven = and . map even
Number/Generate.hs view
@@ -1,22 +1,34 @@ module Number.Generate ( generateMax+ , generateBetween+ , generateOfSize ) where import Number.Serialize import Crypto.Random+import qualified Data.ByteString as B+import Data.Bits ((.|.)) -{- a bit too simplitic and probably not very good. need to have a serious look- - on how to generate random integer. -}+-- | generate a positive integer between 0 and m.+-- using as many bytes as necessary to the same size as m, that are converted to integer. generateMax :: CryptoRandomGen g => g -> Integer -> Either GenError (Integer, g)-generateMax rng m =- let nbbytes = nbBytes m in- case genBytes nbbytes rng of- Left err -> Left err- Right (bs, rng') ->- let n = os2ip bs in- if n < m then Right (n, rng') else generateMax rng' m+generateMax rng m = genBytes (logiBytes m) rng >>= \(bs, rng') -> return (os2ip bs `mod` m, rng') -nbBytes :: Integer -> Int-nbBytes n+-- | generate a number between the inclusive bound [low,high].+generateBetween :: CryptoRandomGen g => g -> Integer -> Integer -> Either GenError (Integer, g)+generateBetween rng low high = generateMax rng rmax >>= \(v, rng') -> return (low + v, rng')+ where+ rmax = high - low + 1 -- relative maximum before being corrected by the low bound++-- | generate a positive integer of a specific size in bits.+-- the number of bits need to be multiple of 8. It will always returns+-- an integer that is close 2^(1+bits/8) by setting the 2 highest bits to 1.+generateOfSize :: CryptoRandomGen g => g -> Int -> Either GenError (Integer, g)+generateOfSize rng bits = case genBytes (bits `div` 8) rng of+ Left err -> Left err+ Right (bs, rng') -> Right (os2ip $ snd $ B.mapAccumL (\acc w -> (0, w .|. acc)) 0xc0 bs, rng')++logiBytes :: Integer -> Int+logiBytes n | n < 256 = 1- | otherwise = 1 + nbBytes (n `div` 256)+ | otherwise = 1 + logiBytes (n `div` 256)
Number/ModArithmetic.hs view
@@ -2,9 +2,9 @@ module Number.ModArithmetic ( exponantiation_rtl_binary , inverse- , gcde_binary ) where +import Number.Basic (gcde_binary) import Data.Bits -- note on exponantiation: 0^0 is treated as 1 for mimicking the standard library;@@ -23,35 +23,5 @@ -- | inverse computes the modular inverse as in g^(-1) mod m inverse :: Integer -> Integer -> Maybe Integer-inverse g m = if d > 1 then Nothing else Just x+inverse g m = if d > 1 then Nothing else Just (x `mod` m) where (x,_,d) = gcde_binary g m---- | get the extended GCD of two integer using the extended binary algorithm (HAC 14.61)--- get (x,y,d) where d = gcd(a,b) and x,y satisfying ax + by = d-gcde_binary :: Integer -> Integer -> (Integer, Integer, Integer)-gcde_binary a' b'- | b' == 0 = (1,0,a')- | a' >= b' = compute a' b'- | otherwise = (\(x,y,d) -> (y,x,d)) $ compute b' a'- where- getEvenMultiplier !g !x !y- | areEven [x,y] = getEvenMultiplier (g `shiftL` 1) (x `shiftR` 1) (y `shiftR` 1)- | otherwise = (x,y,g)- halfLoop !x !y !u !i !j- | areEven [u,i,j] = halfLoop x y (u `shiftR` 1) (i `shiftR` 1) (j `shiftR` 1)- | even u = halfLoop x y (u `shiftR` 1) ((i + y) `shiftR` 1) ((j - x) `shiftR` 1)- | otherwise = (u, i, j)- compute a b =- let (x,y,g) = getEvenMultiplier 1 a b in- loop g x y x y 1 0 0 1-- loop g _ _ 0 !v _ _ !c !d = (c, d, g * v)- loop g x y !u !v !a !b !c !d =- let (u2,a2,b2) = halfLoop x y u a b in- let (v2,c2,d2) = halfLoop x y v c d in- if u2 >= v2- then loop g x y (u2 - v2) v2 (a2 - c2) (b2 - d2) c2 d2- else loop g x y u2 (v2 - u2) a2 b2 (c2 - a2) (d2 - b2)--areEven :: [Integer] -> Bool-areEven = and . map even
+ Number/Prime.hs view
@@ -0,0 +1,147 @@+module Number.Prime+ ( generatePrime+ , isProbablyPrime+ , primalityTestNaive+ -- , primalityTestAKS+ , primalityTestMillerRabin+ , isCoprime+ ) where++import Crypto.Random+import Data.Bits+import Number.Generate+import Number.Basic (sqrti, gcde_binary)+import Number.ModArithmetic (exponantiation_rtl_binary)++-- | returns if the number is probably prime.+-- first a list of small primes are implicitely tested for divisibility,+-- then the Miller Rabin algorithm is used with an accuracy of 30 recursions+isProbablyPrime :: CryptoRandomGen g => g -> Integer -> Either GenError (Bool, g)+isProbablyPrime rng n+ | any (\p -> p `divides` n) (filter (< n) smallPrimes) = Right (False, rng)+ | otherwise = primalityTestMillerRabin rng 30 n++generatePrime :: CryptoRandomGen g => g -> Int -> Either GenError (Integer, g)+generatePrime rng bits = generateOfSize rng bits >>= \(sp, rng') -> findPrimeFrom rng' sp++findPrimeFrom :: CryptoRandomGen g => g -> Integer -> Either GenError (Integer, g)+findPrimeFrom rng n+ | even n = findPrimeFrom rng (n+1)+ | otherwise = isProbablyPrime rng n+ >>= \(isPPrime, rng') -> if isPPrime then return (n, rng') else findPrimeFrom rng' (n+2)++-- | Miller Rabin algorithm return if the number is probably prime or composite.+-- the tries parameter is the number of recursion, that determines the accuracy of the test.+primalityTestMillerRabin :: CryptoRandomGen g => g -> Int -> Integer -> Either GenError (Bool, g)+primalityTestMillerRabin rng tries n+ | n <= 3 = error "Miller-Rabin requires tested value to be > 3"+ | even n = Right (False, rng)+ | tries <= 0 = error "Miller-Rabin tries need to be > 0"+ | otherwise = loop rng (factorise 0 (n-1)) tries where+ -- factorise n-1 into the form 2^s*d+ factorise :: Integer -> Integer -> (Integer, Integer)+ factorise s v+ | v `testBit` 0 = (s, v)+ | otherwise = factorise (s+1) (v `shiftR` 1)+ expmod = exponantiation_rtl_binary+ -- when iteration reach zero, we have a probable prime+ loop g _ 0 = return (True, g)+ loop g (s,d) k = generateBetween g 2 (n-2) >>= \(a, g') ->+ let x = expmod a d n in+ if x == (1 :: Integer) || x == (n-1)+ then loop g' (s,d) (k-1)+ else loop' g' (s,d) (k-1) ((x*x) `mod` n) 1+ -- loop from 1 to s-1. if we reach the end then it's composite+ loop' g o@(s,_) km1 x2 r+ | r == s = Right (False, g)+ | x2 == 1 = Right (False, g)+ | x2 /= (n-1) = loop' g o km1 ((x2*x2) `mod` n) (r+1)+ | otherwise = loop g o km1+ +-- | AKS primality test return if the number is prime or composite+-- it uses the following algorithm:+-- Input: integer n > 1.+-- If n = ab for integers a > 0 and b > 1, output composite.+-- Find the smallest r such that o_r(n) > log2(n).+-- If 1 < gcd(a,n) < n for some a ≤ r, output composite.+-- If n <= r, output prime.+-- For a = 1 to lower-bound(sqrt(phi(n)) * log2(n)) do+-- if (X+a)n ≠ Xn+a (mod Xr − 1,n), output composite;+-- Output prime.+primalityTestAKS :: Integer -> Bool+primalityTestAKS n = undefined+ where+ -- for p prime, the euler totient (# of coprime to n) is clearly n -1+ totient = n-1+ ubound = (fst $ sqrti totient) * (logi n)+ logi n+ | n == 0 = 0+ | otherwise = 1 + logi (n `shiftR` 1)++-- | Test naively is integer is prime.+-- while naive, we skip even number and stop iteration at i > sqrt(n)+primalityTestNaive :: Integer -> Bool+primalityTestNaive n+ | n <= 1 = False+ | n == 2 = True+ | even n = False+ | otherwise = loop 3 where+ ubound = snd $ sqrti n+ loop i+ | i > ubound = True+ | i `divides` n = False+ | otherwise = loop (i+2)++-- | Test is two integer are coprime to each other+isCoprime :: Integer -> Integer -> Bool+isCoprime m n = case gcde_binary m n of (_,_,d) -> d == 1++-- | list of the first primes till 2903..+smallPrimes :: [Integer]+smallPrimes =+ [ 2 , 3 , 5 , 7 , 11 , 13 , 17 , 19 , 23 , 29+ , 31 , 37 , 41 , 43 , 47 , 53 , 59 , 61 , 67 , 71+ , 73 , 79 , 83 , 89 , 97 , 101 , 103 , 107 , 109 , 113+ , 127 , 131 , 137 , 139 , 149 , 151 , 157 , 163 , 167 , 173+ , 179 , 181 , 191 , 193 , 197 , 199 , 211 , 223 , 227 , 229+ , 233 , 239 , 241 , 251 , 257 , 263 , 269 , 271 , 277 , 281+ , 283 , 293 , 307 , 311 , 313 , 317 , 331 , 337 , 347 , 349+ , 353 , 359 , 367 , 373 , 379 , 383 , 389 , 397 , 401 , 409+ , 419 , 421 , 431 , 433 , 439 , 443 , 449 , 457 , 461 , 463+ , 467 , 479 , 487 , 491 , 499 , 503 , 509 , 521 , 523 , 541+ , 547 , 557 , 563 , 569 , 571 , 577 , 587 , 593 , 599 , 601+ , 607 , 613 , 617 , 619 , 631 , 641 , 643 , 647 , 653 , 659+ , 661 , 673 , 677 , 683 , 691 , 701 , 709 , 719 , 727 , 733+ , 739 , 743 , 751 , 757 , 761 , 769 , 773 , 787 , 797 , 809+ , 811 , 821 , 823 , 827 , 829 , 839 , 853 , 857 , 859 , 863+ , 877 , 881 , 883 , 887 , 907 , 911 , 919 , 929 , 937 , 941+ , 947 , 953 , 967 , 971 , 977 , 983 , 991 , 997 , 1009 , 1013+ , 1019 , 1021 , 1031 , 1033 , 1039 , 1049 , 1051 , 1061 , 1063 , 1069+ , 1087 , 1091 , 1093 , 1097 , 1103 , 1109 , 1117 , 1123 , 1129 , 1151+ , 1153 , 1163 , 1171 , 1181 , 1187 , 1193 , 1201 , 1213 , 1217 , 1223+ , 1229 , 1231 , 1237 , 1249 , 1259 , 1277 , 1279 , 1283 , 1289 , 1291+ , 1297 , 1301 , 1303 , 1307 , 1319 , 1321 , 1327 , 1361 , 1367 , 1373+ , 1381 , 1399 , 1409 , 1423 , 1427 , 1429 , 1433 , 1439 , 1447 , 1451+ , 1453 , 1459 , 1471 , 1481 , 1483 , 1487 , 1489 , 1493 , 1499 , 1511+ , 1523 , 1531 , 1543 , 1549 , 1553 , 1559 , 1567 , 1571 , 1579 , 1583+ , 1597 , 1601 , 1607 , 1609 , 1613 , 1619 , 1621 , 1627 , 1637 , 1657+ , 1663 , 1667 , 1669 , 1693 , 1697 , 1699 , 1709 , 1721 , 1723 , 1733+ , 1741 , 1747 , 1753 , 1759 , 1777 , 1783 , 1787 , 1789 , 1801 , 1811+ , 1823 , 1831 , 1847 , 1861 , 1867 , 1871 , 1873 , 1877 , 1879 , 1889+ , 1901 , 1907 , 1913 , 1931 , 1933 , 1949 , 1951 , 1973 , 1979 , 1987+ , 1993 , 1997 , 1999 , 2003 , 2011 , 2017 , 2027 , 2029 , 2039 , 2053+ , 2063 , 2069 , 2081 , 2083 , 2087 , 2089 , 2099 , 2111 , 2113 , 2129+ , 2131 , 2137 , 2141 , 2143 , 2153 , 2161 , 2179 , 2203 , 2207 , 2213+ , 2221 , 2237 , 2239 , 2243 , 2251 , 2267 , 2269 , 2273 , 2281 , 2287+ , 2293 , 2297 , 2309 , 2311 , 2333 , 2339 , 2341 , 2347 , 2351 , 2357+ , 2371 , 2377 , 2381 , 2383 , 2389 , 2393 , 2399 , 2411 , 2417 , 2423+ , 2437 , 2441 , 2447 , 2459 , 2467 , 2473 , 2477 , 2503 , 2521 , 2531+ , 2539 , 2543 , 2549 , 2551 , 2557 , 2579 , 2591 , 2593 , 2609 , 2617+ , 2621 , 2633 , 2647 , 2657 , 2659 , 2663 , 2671 , 2677 , 2683 , 2687+ , 2689 , 2693 , 2699 , 2707 , 2711 , 2713 , 2719 , 2729 , 2731 , 2741+ , 2749 , 2753 , 2767 , 2777 , 2789 , 2791 , 2797 , 2801 , 2803 , 2819+ , 2833 , 2837 , 2843 , 2851 , 2857 , 2861 , 2879 , 2887 , 2897 , 2903+ ]++{-# INLINE divides #-}+divides i n = n `mod` i == 0
Tests.hs view
@@ -9,6 +9,7 @@ import Control.Monad import Control.Arrow (first)+import Control.Applicative ((<$>)) import Data.List (intercalate) import Data.Char@@ -22,12 +23,16 @@ -- numbers import Number.ModArithmetic--- ciphers+import Number.Basic+import Number.Prime+import Number.Serialize+-- ciphers/Kexch import qualified Crypto.Cipher.AES as AES import qualified Crypto.Cipher.RC4 as RC4 import qualified Crypto.Cipher.Camellia as Camellia import qualified Crypto.Cipher.RSA as RSA import qualified Crypto.Cipher.DSA as DSA+import qualified Crypto.Cipher.DH as DH import Crypto.Random encryptStream fi fc key plaintext = B.unpack $ snd $ fc (fi key) plaintext@@ -242,25 +247,44 @@ {- end of units tests -} {- start of QuickCheck verification -} --- FIXME better to tweak the property to generate positive integer instead of this.--prop_gcde_binary_valid (a, b)- | a > 0 && b >= 0 =- let (x,y,v) = gcde_binary a b in- and [a*x + b*y == v, gcd a b == v]- | otherwise = True+prop_gcde_binary_valid (Positive a, Positive b) =+ let (x,y,v) = gcde_binary a b in+ let (x',y',v') = gcde a b in+ and [v==v', a*x' + b*y' == v', a*x + b*y == v, gcd a b == v] -prop_modexp_rtl_valid (a, b, m)- | m > 0 && a >= 0 && b >= 0 = exponantiation_rtl_binary a b m == ((a ^ b) `mod` m)- | otherwise = True+prop_modexp_rtl_valid (NonNegative a, NonNegative b, Positive m) =+ exponantiation_rtl_binary a b m == ((a ^ b) `mod` m) -prop_modinv_valid (a, m)- | m > 1 && a > 0 =+prop_modinv_valid (Positive a, Positive m)+ | m > 1 = case inverse a m of Just ainv -> (ainv * a) `mod` m == 1 Nothing -> True | otherwise = True +prop_sqrti_valid (Positive i) = l*l <= i && i <= u*u where (l, u) = sqrti i++prop_generate_prime_valid i =+ -- becuase of the next naive test, we can't generate easily number above 32 bits+ -- otherwise it slows down the tests to uselessness. when AKS or ECPP is implemented+ -- we can revisit the number here+ let p = withAleasInteger rng i (\g -> generatePrime g 32) in+ -- FIXME test if p is around 32 bits+ primalityTestNaive p++prop_miller_rabin_valid i+ | i <= 3 = True+ | otherwise =+ -- miller rabin only returns with certitude that the integer is composite.+ let b = withAleasInteger rng i (\g -> isProbablyPrime g i) in+ (b == False && primalityTestNaive i == False) || b == True++withAleasInteger rng i f = case reseed (i2osp (if i < 0 then -i else i)) rng of+ Left _ -> error "impossible"+ Right rng' -> case f rng' of+ Left _ -> error "impossible"+ Right v -> fst v+ newtype RSAMessage = RSAMessage B.ByteString deriving (Show, Eq) instance Arbitrary RSAMessage where@@ -275,7 +299,7 @@ getByte :: Rng -> (Word8, Rng) getByte (Rng (mz, mw)) = let mz2 = 36969 * (mz `mod` 65536) in- let mw2 = 18000 * (mw `mod` 65536) in+ let mw2 = 18070 * (mw `mod` 65536) in (fromIntegral (mz2 + mw2), Rng (mz2, mw2)) getBytes 0 rng = ([], rng)@@ -288,7 +312,9 @@ newGen _ = Right (Rng (2,3)) genSeedLength = 0 genBytes len g = Right $ first B.pack $ getBytes len g- reseed = undefined+ reseed bs (Rng (a,b)) = Right $ Rng (fromIntegral a', b) where+ a' = ((fromIntegral a) + i * 36969) `mod` 65536+ i = os2ip bs rng = Rng (1,2) @@ -296,6 +322,14 @@ {- testing RSA -} {-----------------------------------------------------------------------------------------------} +prop_rsa_generate_valid (Positive i, RSAMessage msgz) =+ let keysz = 64 in+ let (pub,priv) = withAleasInteger rng i (\g -> RSA.generate g keysz 65537) in+ let msg = B.take (keysz - 11) msgz in+ (RSA.private_p priv * RSA.private_q priv == RSA.private_n priv) &&+ ((RSA.private_d priv * RSA.public_e pub) `mod` ((RSA.private_p priv - 1) * (RSA.private_q priv - 1)) == 1) &&+ (either Left (RSA.decrypt priv . fst) $ RSA.encrypt rng pub msg) == Right msg+ prop_rsa_valid fast (RSAMessage msg) = (either Left (RSA.decrypt pk . fst) $ RSA.encrypt rng rsaPublickey msg) == Right msg where pk = if fast then rsaPrivatekey else rsaPrivatekey { RSA.private_p = 0, RSA.private_q = 0 }@@ -359,6 +393,20 @@ Right (signature, rng') = DSA.sign rng (SHA1.hash) dsaPrivatekey msg {-----------------------------------------------------------------------------------------------}+{- testing DH -}+{-----------------------------------------------------------------------------------------------}+instance Arbitrary DH.PrivateNumber where+ arbitrary = fromIntegral <$> (suchThat (arbitrary :: Gen Integer) (\x -> x >= 1))++prop_dh_valid (xa, xb) = sa == sb+ where+ sa = DH.getShared dhparams xa yb+ sb = DH.getShared dhparams xb ya+ yb = DH.generatePublic dhparams xb+ ya = DH.generatePublic dhparams xa+ dhparams = (11, 7)++{-----------------------------------------------------------------------------------------------} {- testing AES -} {-----------------------------------------------------------------------------------------------} data AES128Message = AES128Message B.ByteString B.ByteString B.ByteString deriving (Show, Eq)@@ -441,6 +489,9 @@ run_test "gcde binary valid" prop_gcde_binary_valid run_test "exponantiation RTL valid" prop_modexp_rtl_valid run_test "inverse valid" prop_modinv_valid+ run_test "sqrt integer valid" prop_sqrti_valid+ run_test "primality test Miller Rabin" prop_miller_rabin_valid+ run_test "Generate prime" prop_generate_prime_valid -- AES Tests run_test "AES128 (ECB) decrypt.encrypt = id" prop_aes128_ecb_valid@@ -452,7 +503,11 @@ run_test "AES256 (ECB) decrypt.encrypt = id" prop_aes256_ecb_valid run_test "AES256 (CBC) decrypt.encrypt = id" prop_aes256_cbc_valid + -- DH Tests+ run_test "DH test" prop_dh_valid+ -- RSA Tests+ run_test "RSA generate" prop_rsa_generate_valid run_test "RSA verify . sign(slow) = true" prop_rsa_sign_slow_valid run_test "RSA verify . sign(fast) = true" prop_rsa_sign_fast_valid
cryptocipher.cabal view
@@ -1,5 +1,5 @@ Name: cryptocipher-Version: 0.2.8+Version: 0.2.9 Description: Symmetrical Block, Stream and PubKey Ciphers License: BSD3 License-file: LICENSE@@ -33,9 +33,12 @@ Crypto.Cipher.Camellia Crypto.Cipher.RSA Crypto.Cipher.DSA+ Crypto.Cipher.DH other-modules: Number.ModArithmetic Number.Serialize Number.Generate+ Number.Basic+ Number.Prime ghc-options: -Wall Executable Tests