File: ElGamal.hs

package info (click to toggle)
haskell-cryptocipher 0.3.5-1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 256 kB
  • sloc: haskell: 2,916; ansic: 142; makefile: 3
file content (73 lines) | stat: -rw-r--r-- 2,370 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
-- |
-- Module      : Crypto.Cipher.ElGamal
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : experimental
-- Portability : Good
--
-- This module is a work in progress. do not use:
-- it might eat your dog, your data or even both.
--
-- TODO: provide a mapping between integer and ciphertext
--       generate numbers correctly
--
module Crypto.Cipher.ElGamal
	( Params
	, PublicNumber
	, PrivateNumber
	, SharedKey
    , generatePrivate
    , generatePublic
    , encryptWith
    , encrypt
    , decrypt
{-
    , sign
    , verify
-}
    ) where

import Number.ModArithmetic (exponantiation, inverse)
import Number.Generate (generateOfSize)
import Crypto.Types.PubKey.DH
import Crypto.Random
import Control.Arrow (first)
import Control.Applicative ((<$>))
import Data.Maybe (fromJust)

-- | generate a private number with no specific property
-- this number is usually called a.
-- 
-- FIXME replace generateOfSize by generateBetween [0, q-1]
generatePrivate :: CryptoRandomGen g => g -> Int -> Either GenError (PrivateNumber, g)
generatePrivate rng bits = either Left (Right . first PrivateNumber) $ generateOfSize rng bits

-- | generate a public number that is for the other party benefits.
-- this number is usually called h=g^a
generatePublic :: Params -> PrivateNumber -> PublicNumber
generatePublic (p,g) (PrivateNumber a) = PublicNumber $ exponantiation g a p

-- | encrypt with a specified ephemeral key
-- do not reuse ephemeral key.
encryptWith :: PrivateNumber -> Params -> PublicNumber -> Integer -> (Integer,Integer)
encryptWith (PrivateNumber b) (p,g) (PublicNumber h) m = (c1,c2)
    where s  = exponantiation h b p
          c1 = exponantiation g b p
          c2 = (s * m) `mod` p

-- | encrypt a message using params and public keys
-- will generate b (called the ephemeral key)
encrypt :: CryptoRandomGen g => g -> Params -> PublicNumber -> Integer -> Either GenError ((Integer,Integer), g)
encrypt rng params public m = (\(b,rng') -> (encryptWith b params public m,rng')) <$> generatePrivate rng 1024

-- | decrypt message
decrypt :: Params -> PrivateNumber -> (Integer, Integer) -> Integer
decrypt (p,_) (PrivateNumber a) (c1,c2) = (c2 * sm1) `mod` p
    where s   = exponantiation c1 a p
          sm1 = fromJust $ inverse s p -- always inversible in Zp

{-
sign = undefined

verify = undefined
-}