summaryrefslogtreecommitdiff
path: root/Data/OpenPGP/Util/Gen.hs
blob: 713e9095754d0ea7d1771c829c7d3ffa1f632af2 (plain)
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
{-# LANGUAGE CPP #-}
module Data.OpenPGP.Util.Gen where

import Data.OpenPGP
import Data.Maybe
import Data.Word
import Control.Applicative
import qualified Data.ByteString.Lazy as B
import qualified Data.ByteString as S

import Crypto.Random as Vincent
import qualified Crypto.PubKey.DSA as Vincent.DSA
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
#endif

import Data.OpenPGP.Util.Base

data GenerateKeyParams = GenRSA Int -- keysize
                       | GenDSA (Maybe DSAParams)
                       | GenEd25519
                       | GenCv25519
 deriving (Eq,Ord,Show)

data DSAParams = DSAParams
                       { dsa_params_p :: Integer
                       , dsa_params_g :: Integer
                       , dsa_params_q :: Integer }
 deriving (Eq,Ord,Show)

genKeyAlg :: GenerateKeyParams -> KeyAlgorithm
genKeyAlg (GenRSA _)      = RSA
genKeyAlg (GenDSA _)      = DSA
genKeyAlg (GenEd25519 {}) = Ed25519
genKeyAlg (GenCv25519 {}) = ECC

-- | Generate a secret key pgp packet from system entropy.
generateKey :: GenerateKeyParams -> IO Packet
generateKey params = do
    now <- currentTime
    g <- makeGen Nothing
    let (fields,g') = generateKey' params g
    return $ buildPacket (genKeyAlg params) now fields

rsaFields priv = [ ('n', MPI $ Vincent.RSA.public_n (Vincent.RSA.private_pub priv))
                 , ('e', MPI $ Vincent.RSA.public_e (Vincent.RSA.private_pub priv))
                 , ('d', MPI $ Vincent.RSA.private_d priv)
                 , ('p', MPI $ Vincent.RSA.private_q priv)
                 , ('q', MPI $ Vincent.RSA.private_p priv)
                 , ('u', MPI $ Vincent.RSA.private_qinv priv)]

dsaFields priv = [ ('p', MPI p)
                 , ('q', MPI $ Vincent.DSA.params_q $ Vincent.DSA.private_params priv )
                 , ('g', MPI g)
                 , ('y', MPI $ g^x `mod` p)
                 , ('x', MPI x)]
 where
    x = Vincent.DSA.private_x priv
    g = Vincent.DSA.params_g $ Vincent.DSA.private_params priv
    p = Vincent.DSA.params_p $ Vincent.DSA.private_params priv


#if defined(VERSION_crypto_random)
type RNG = Vincent.SystemRNG

makeGen :: Maybe FilePath -> IO RNG
makeGen noisefile = do
    pool <- fromMaybe Vincent.createEntropyPool $ do
        path <- noisefile
        Just $ Vincent.createTestEntropyPool `fmap` S.readFile path
    return (Vincent.cprgCreate pool :: Vincent.SystemRNG)

generateKey' :: GenerateKeyParams -> RNG -> ([(Char,MPI)],RNG)
generateKey' (GenRSA keysize) g =
    let -- http://crypto.stackexchange.com/questions/3110/impacts-of-not-using-rsa-exponent-of-65537
        rsa_exponent = 65537
        ((pub,priv),g') = Vincent.RSA.generate g keysize rsa_exponent
    -- discarding private_dQ
    -- discarding private_dP
    in ( rsaFields priv, g' )
generateKey' (GenDSA mbparams) g =
    let dsa_params = fromMaybe defaultDSAParams $ fmap toVince mbparams
        toVince (DSAParams p g q) = Vincent.DSA.Params p g q
        (priv,g') = Vincent.DSA.generatePrivate g dsa_params
    -- public_key_fields DSA     = ['p', 'q', 'g', 'y']
    -- secret_key_fields DSA     = ['x']
    in ( dsaFields (Vincent.DSA.PrivateKey dsa_params priv), g' )

#else
newtype RNG = RNG (Either SystemDRG ChaChaDRG)
instance DRG RNG where
    randomBytesGenerate n (RNG g) =
        either (second (RNG . Left ) . randomBytesGenerate n)
               (second (RNG . Right) . randomBytesGenerate n) g

makeGen :: Maybe FilePath -> IO RNG
makeGen noisefile = do
    drg <- fromMaybe (Left <$> getSystemDRG) $ do
        path <- noisefile 
        Just $ Right . drgNewTest . decodeSeed <$> B.readFile path
    return $ RNG drg
 where
    decodeSeed :: B.ByteString -> (Word64, Word64, Word64, Word64, Word64)
    decodeSeed bs | B.null bs = (0,0,0,0,0)
                  | otherwise = decode $  B.cycle bs

generateKey' :: GenerateKeyParams -> RNG -> ([(Char,MPI)],RNG)
generateKey' (GenRSA keysize) g =
    let rsa_exponent = 65537
        ((_,priv),g') = withDRG g $ Vincent.RSA.generate keysize rsa_exponent
    in ( rsaFields priv, g' )
generateKey' (GenDSA mbparams) g =
    let dsa_params = maybe defaultDSAParams vincent mbparams
        vincent (DSAParams p g q) = Vincent.DSA.Params p g q
        (priv,g') = withDRG g $ Vincent.DSA.generatePrivate dsa_params
    in ( dsaFields (Vincent.DSA.PrivateKey dsa_params priv), g' )
generateKey' (GenEd25519 {}) g = withDRG g $ do
    k <- Ed25519.generateSecretKey
    return $ importSecretEd25519 k
generateKey' (GenCv25519 {}) g = withDRG g $ do
    k <- Cv25519.generateSecretKey
    return $ importSecretCv25519 SHA512 AES128 k


#endif



buildPacket :: KeyAlgorithm -> Word32 -> [(Char,MPI)] -> Packet
buildPacket alg stamp fields =
      SecretKeyPacket {
        timestamp = stamp                 :: Word32,
        version = 4                       :: Word8,
        key_algorithm = alg               :: KeyAlgorithm,
        key = fields                      :: [(Char,MPI)],
        s2k_useage = 0                    :: Word8,
        s2k = S2K 100 B.empty             :: S2K, -- Unencrypted so meaningless
        symmetric_algorithm = Unencrypted :: SymmetricAlgorithm,
        encrypted_data = B.empty          :: B.ByteString,
        is_subkey = True                  :: Bool
      }

defaultDSAParams :: Vincent.DSA.Params
defaultDSAParams = Vincent.DSA.Params
    { Vincent.DSA.params_p = 25016032990684888518988658620325126146216470517049479187156156734213376906219942961707957641401749519947125090638800516836972123148009221755073642581464845387235660414348889382008154731058786820730247996611955465863529460612040002991075529989397271247177642048614532123132310296005749599675664384673629073848636519328677230918100996732661901275340454155565768752980771336725651539837887289446847136557589393348919689634715419500097585479277479066450412377941277218532943901492329509956866134692951999522393506140918443671786722258878778178444946544570489542640773262151888089794659117142339310858339721084998689009113
    , Vincent.DSA.params_q = 24289205633892182261673754417007225086255920651423805093223058502897
    , Vincent.DSA.params_g = 14163516289631370671608698837927753143825670852934869718450850658283442975416133481761559479714034401583801628224741616560126187810551733284361046143315226067355563227860282174889634742169280269622671773116176523712230772457681507357681374615558206405969011913182779829876763280507794583263187213066680289675392841938777384288859684653238393939307768899246590677720387825052549466445990058620838747851535777836897369521109616233955046301358290724806298742875429454780763259982037236610786647541183309285037036036778584959871753945456209439667132114356168289377762491848873534919083413137563924214401854434599021748980
    }