packages feed

cryptocipher 0.2.1 → 0.2.2

raw patch · 6 files changed

+195/−28 lines, 6 filesdep +cryptohashPVP ok

version bump matches the API change (PVP)

Dependencies added: cryptohash

API changes (from Hackage documentation)

+ Crypto.Cipher.DSA: InvalidSignature :: Error
+ Crypto.Cipher.DSA: PrivateKey :: Params -> Integer -> PrivateKey
+ Crypto.Cipher.DSA: PublicKey :: Params -> Integer -> PublicKey
+ Crypto.Cipher.DSA: RandomGenFailure :: GenError -> Error
+ Crypto.Cipher.DSA: data Error
+ Crypto.Cipher.DSA: data PrivateKey
+ Crypto.Cipher.DSA: data PublicKey
+ Crypto.Cipher.DSA: instance Eq Error
+ Crypto.Cipher.DSA: instance Show Error
+ Crypto.Cipher.DSA: instance Show PrivateKey
+ Crypto.Cipher.DSA: instance Show PublicKey
+ Crypto.Cipher.DSA: private_params :: PrivateKey -> Params
+ Crypto.Cipher.DSA: private_x :: PrivateKey -> Integer
+ Crypto.Cipher.DSA: public_params :: PublicKey -> Params
+ Crypto.Cipher.DSA: public_y :: PublicKey -> Integer
+ Crypto.Cipher.DSA: sign :: CryptoRandomGen g => g -> (ByteString -> ByteString) -> PrivateKey -> ByteString -> Either GenError (Signature, g)
+ Crypto.Cipher.DSA: type Params = (Integer, Integer, Integer)
+ Crypto.Cipher.DSA: type Signature = (Integer, Integer)
+ Crypto.Cipher.DSA: verify :: Signature -> (ByteString -> ByteString) -> PublicKey -> ByteString -> Either Error Bool

Files

+ Crypto/Cipher/DSA.hs view
@@ -0,0 +1,79 @@+-- |+-- Module      : Crypto.Cipher.DSA+-- License     : BSD-style+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>+-- Stability   : experimental+-- Portability : Good+--++module Crypto.Cipher.DSA+	( Error(..)+	, Params+	, Signature+	, PublicKey(..)+	, PrivateKey(..)+	, sign+	, verify+	) where++import Crypto.Random+import Data.Maybe+import Data.ByteString (ByteString)+import Number.ModArithmetic (exponantiation_rtl_binary, inverse)+import Number.Serialize+import Number.Generate++data Error = +	  InvalidSignature          -- ^ signature is not valid r or s is not between the bound 0..q+	| RandomGenFailure GenError -- ^ the random generator returns an error. give the opportunity to reseed for example.+	deriving (Show,Eq)++type Params = (Integer,Integer,Integer) {- P, G, Q -}+type Signature = (Integer,Integer) {- R,S -}++data PublicKey = PublicKey+	{ public_params :: Params {- P, G, Q -}+	, public_y      :: Integer+	} deriving (Show)++data PrivateKey = PrivateKey+	{ private_params :: Params {- P, G, Q -}+	, private_x      :: Integer+	} deriving (Show)++{-| sign message using the private key. -}+sign :: CryptoRandomGen g => g -> (ByteString -> ByteString) -> PrivateKey -> ByteString -> Either GenError (Signature, g)+sign rng hash pk m =+	-- Recalculate the signature in the unlikely case that r = 0 or s = 0+	case generateMax rng q of+		Left err        -> Left err+		Right (k, rng') ->+			let kinv = fromJust $ inverse k q in+			let r    = expmod g k p `mod` q in+			let s    = (kinv * (hm + x * r)) `mod` q in+			if r == 0 || s == 0+				then sign rng' hash pk m+				else Right ((r, s), rng')+	where+		(p,g,q)   = private_params pk+		x         = private_x pk+		hm        = os2ip $ hash m++{- | verify a bytestring using the public key. -}+verify :: Signature -> (ByteString -> ByteString) -> PublicKey -> ByteString -> Either Error Bool+verify (r,s) hash pk m+	-- Reject the signature if either 0 < r <q or 0 < s < q is not satisfied.+	| r <= 0 || r >= q || s <= 0 || s >= q = Left InvalidSignature+	| otherwise                            = Right $ v == r+	where+		(p,g,q) = public_params pk+		y       = public_y pk+		hm      = os2ip $ hash m++		w       = fromJust $ inverse s q+		u1      = (hm*w) `mod` q+		u2      = (r*w) `mod` q+		v       = ((expmod g u1 p) * (expmod y u2 p)) `mod` p `mod` q++expmod :: Integer -> Integer -> Integer -> Integer+expmod = exponantiation_rtl_binary
Crypto/Cipher/RSA.hs view
@@ -17,10 +17,10 @@  import Control.Arrow (first) import Crypto.Random-import Data.Bits import Data.ByteString (ByteString) import qualified Data.ByteString as B import Number.ModArithmetic (exponantiation_rtl_binary)+import Number.Serialize  data Error = 	  MessageSizeIncorrect      -- ^ the message to decrypt is not of the correct size (need to be == private_size)@@ -124,17 +124,6 @@ 	where 		lenbytes = B.length bytes 		bytes    = i2osp m---- | os2ip converts a byte string into a positive integer-os2ip :: ByteString -> Integer-os2ip = B.foldl' (\a b -> (256 * a) .|. (fromIntegral b)) 0---- | i2osp converts a positive integer into a byte string-i2osp :: Integer -> ByteString-i2osp m = B.reverse $ B.unfoldr divMod256 m-	where-		divMod256 0 = Nothing-		divMod256 n = Just (fromIntegral a,b) where (b,a) = n `divMod` 256  expmod :: Integer -> Integer -> Integer -> Integer expmod = exponantiation_rtl_binary
+ Number/Generate.hs view
@@ -0,0 +1,22 @@+module Number.Generate+	( generateMax+	) where++import Number.Serialize+import Crypto.Random++{- a bit too simplitic and probably not very good. need to have a serious look+ - on how to generate random 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++nbBytes :: Integer -> Int+nbBytes n+	| n < 256   = 1+	| otherwise = 1 + nbBytes (n `div` 256)
+ Number/Serialize.hs view
@@ -0,0 +1,19 @@+module Number.Serialize+	( i2osp+	, os2ip+	) where++import Data.ByteString (ByteString)+import qualified Data.ByteString as B+import Data.Bits++-- | os2ip converts a byte string into a positive integer+os2ip :: ByteString -> Integer+os2ip = B.foldl' (\a b -> (256 * a) .|. (fromIntegral b)) 0++-- | i2osp converts a positive integer into a byte string+i2osp :: Integer -> ByteString+i2osp m = B.reverse $ B.unfoldr divMod256 m+	where+		divMod256 0 = Nothing+		divMod256 n = Just (fromIntegral a,b) where (b,a) = n `divMod` 256
Tests.hs view
@@ -8,6 +8,7 @@ import System.IO (hFlush, stdout)  import Control.Monad+import Control.Arrow (first)  import Data.List (intercalate) import Data.Char@@ -15,6 +16,8 @@ import Data.Word import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as BC+-- for DSA+import qualified Crypto.Hash.SHA1 as SHA1  -- numbers import Number.ModArithmetic@@ -22,6 +25,7 @@ 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 Crypto.Random  encryptStream fi fc key plaintext = B.unpack $ snd $ fc (fi key) plaintext@@ -108,23 +112,40 @@ 		ws <- replicateM sz (choose (0,255) :: Gen Int) 		return $ RSAMessage $ B.pack $ map fromIntegral ws -data Rng = Rng Int+{- this is a just test rng. this is absolutely not a serious RNG. DO NOT use elsewhere -}+data Rng = Rng (Int, Int) +getByte :: Rng -> (Word8, Rng)+getByte (Rng (mz, mw)) =+	let mz2 = 36969 * (mz `mod` 65536) in+	let mw2 = 18000 * (mw `mod` 65536) in+	(fromIntegral (mz2 + mw2), Rng (mz2, mw2))++getBytes 0 rng = ([], rng)+getBytes n rng =+	let (b, rng')  = getByte rng in+	let (l, rng'') = getBytes (n-1) rng' in+	(b:l, rng'')+ instance CryptoRandomGen Rng where-	newGen _       = Right (Rng 0)+	newGen _       = Right (Rng (2,3)) 	genSeedLength  = 0-	genBytes len g = Right (B.pack $ replicate len 0x2d, g)+	genBytes len g = Right $ first B.pack $ getBytes len g -rng = Rng 0+rng = Rng (1,2)  +{-----------------------------------------------------------------------------------------------}+{- testing RSA -}+{-----------------------------------------------------------------------------------------------}+ prop_rsa_fast_valid (RSAMessage msg) =-	(either Left (RSA.decrypt privatekey . fst) $ RSA.encrypt rng publickey msg) == Right msg+	(either Left (RSA.decrypt rsaPrivatekey . fst) $ RSA.encrypt rng rsaPublickey msg) == Right msg  prop_rsa_slow_valid (RSAMessage msg) =-	(either Left (RSA.decrypt pk . fst) $ RSA.encrypt rng publickey msg) == Right msg-	where pk = privatekey { RSA.private_p = 0, RSA.private_q = 0 }+	(either Left (RSA.decrypt pk . fst) $ RSA.encrypt rng rsaPublickey msg) == Right msg+	where pk = rsaPrivatekey { RSA.private_p = 0, RSA.private_q = 0 } -privatekey = RSA.PrivateKey+rsaPrivatekey = RSA.PrivateKey 	{ RSA.private_sz   = 128 	, RSA.private_n    = 140203425894164333410594309212077886844966070748523642084363106504571537866632850620326769291612455847330220940078873180639537021888802572151020701352955762744921926221566899281852945861389488419179600933178716009889963150132778947506523961974222282461654256451508762805133855866018054403911588630700228345151 	, RSA.private_d    = 133764127300370985476360382258931504810339098611363623122953018301285450176037234703101635770582297431466449863745848961134143024057267778947569638425565153896020107107895924597628599677345887446144410702679470631826418774397895304952287674790343620803686034122942606764275835668353720152078674967983573326257@@ -135,17 +156,49 @@ 	, RSA.private_qinv = 11136639099661288633118187183300604127717437440459572124866697429021958115062007251843236337586667012492941414990095176435990146486852255802952814505784196 	} -publickey = RSA.PublicKey+rsaPublickey = RSA.PublicKey 	{ RSA.public_sz = 128 	, RSA.public_n  = 140203425894164333410594309212077886844966070748523642084363106504571537866632850620326769291612455847330220940078873180639537021888802572151020701352955762744921926221566899281852945861389488419179600933178716009889963150132778947506523961974222282461654256451508762805133855866018054403911588630700228345151 	, RSA.public_e  = 65537 	} +{-----------------------------------------------------------------------------------------------}+{- testing DSA -}+{-----------------------------------------------------------------------------------------------}+++dsaParams = (p,g,q)+	where+		p = 0x00a8c44d7d0bbce69a39008948604b9c7b11951993a5a1a1fa995968da8bb27ad9101c5184bcde7c14fb79f7562a45791c3d80396cefb328e3e291932a17e22edd+		g = 0x0bf9fe6c75d2367b88912b2252d20fdcad06b3f3a234b92863a1e30a96a123afd8e8a4b1dd953e6f5583ef8e48fc7f47a6a1c8f24184c76dba577f0fec2fcd1c+		q = 0x0096674b70ef58beaaab6743d6af16bb862d18d119++dsaPrivatekey = DSA.PrivateKey+	{ DSA.private_params = dsaParams+	, DSA.private_x      = 0x229bac7aa1c7db8121bfc050a3426eceae23fae8+	}++dsaPublickey = DSA.PublicKey+	{ DSA.public_params = dsaParams+	, DSA.public_y      = 0x4fa505e86e32922f1fa1702a120abdba088bb4be801d4c44f7fc6b9094d85cd52c429cbc2b39514e30909b31e2e2e0752b0fc05c1a7d9c05c3e52e49e6edef4c+	}++prop_dsa_valid (RSAMessage msg) =+	case DSA.verify signature (SHA1.hash) dsaPublickey msg of+		Left err -> False+		Right b  -> b+	where+		Right (signature, rng') = DSA.sign rng (SHA1.hash) dsaPrivatekey msg++{-----------------------------------------------------------------------------------------------}+{- main -}+{-----------------------------------------------------------------------------------------------}+ args = stdArgs 	{ replay     = Nothing-	, maxSuccess = 1000-	, maxDiscard = 4000-	, maxSize    = 1000+	, maxSuccess = 200+	, maxDiscard = 1000+	, maxSize    = 200 	}  run_test n t = putStr ("  " ++ n ++ " ... ") >> hFlush stdout >> quickCheckWith args t@@ -159,3 +212,5 @@  	run_test "RSA decrypt(slow).encrypt = id" prop_rsa_slow_valid 	run_test "RSA decrypt(fast).encrypt = id" prop_rsa_fast_valid++	run_test "DSA verify . sign = valid" prop_dsa_valid
cryptocipher.cabal view
@@ -1,12 +1,12 @@ Name:                cryptocipher-Version:             0.2.1-Description:         Symmetrical Block and Stream Ciphers+Version:             0.2.2+Description:         Symmetrical Block, Stream and PubKey Ciphers License:             BSD3 License-file:        LICENSE Copyright:           Vincent Hanquez <vincent@snarc.org> Author:              Vincent Hanquez <vincent@snarc.org> Maintainer:          Vincent Hanquez <vincent@snarc.org>-Synopsis:            Symmetrical Block and Stream Ciphers+Synopsis:            Symmetrical Block, Stream and PubKey Ciphers Category:            Cryptography Build-Type:          Simple Homepage:            http://github.com/vincenthz/hs-cryptocipher@@ -21,14 +21,17 @@   Exposed-modules:   Crypto.Cipher.RC4                      Crypto.Cipher.Camellia                      Crypto.Cipher.RSA+                     Crypto.Cipher.DSA   other-modules:     Number.ModArithmetic+                     Number.Serialize+                     Number.Generate   ghc-options:       -Wall  Executable           Tests   Main-Is:           Tests.hs   if flag(test)     Buildable:       True-    Build-depends:   base >= 4 && < 7, HUnit, bytestring, QuickCheck >= 2+    Build-depends:   base >= 4 && < 7, HUnit, bytestring, cryptohash, QuickCheck >= 2   else     Buildable:       False