1 /**
2 * DL Scheme
3 * 
4 * Copyright:
5 * (C) 1999-2007 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.pubkey.algo.dl_algo;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_PUBLIC_KEY_CRYPTO):
15 
16 public import botan.pubkey.algo.dl_group;
17 public import botan.pubkey.pubkey;
18 import botan.utils.mem_ops;
19 import botan.pubkey.x509_key;
20 import botan.pubkey.pkcs8;
21 import botan.math.numbertheory.numthry;
22 import botan.pubkey.workfactor;
23 import botan.rng.rng;
24 import botan.asn1.der_enc;
25 import botan.asn1.ber_dec;
26 
27 /**
28 * This class represents discrete logarithm (DL) public keys.
29 */
30 class DLSchemePublicKey : PublicKey
31 {
32 public:
33     override bool checkKey(RandomNumberGenerator rng, bool strong) const
34     {    
35         return (cast(DLSchemePublicKey)this).checkKey(rng, strong);
36     }
37 
38     final bool checkKey(RandomNumberGenerator rng, bool strong)
39     {
40         if (m_y < 2 || m_y >= groupP())
41             return false;
42         if (!m_group.verifyGroup(rng, strong))
43             return false;
44         return true;
45     }
46 
47     final void decodeOptions(T)(in T options) {
48         static if (__traits(hasMember, T, "checkKey"))
49             m_check_key = &options.checkKey;
50         static if (__traits(hasMember, T, "msgParts"))
51             m_msg_parts = options.msgParts;
52 
53         static if (__traits(hasMember, T, "format"))
54             m_format = options.format;
55         else static assert(false, "No format found in " ~ T.stringof);
56     
57         static if (__traits(hasMember, T, "algoName"))
58             m_algo_name = options.algoName;
59         else static assert(false, "No algoName found in " ~ T.stringof);
60 
61     }
62 
63     /// Used for object casting to the right type in the factory.
64     final override @property string algoName() const {
65         return m_algo_name;
66     }
67 
68     final override size_t messageParts() const {
69         return m_msg_parts;
70     }
71 
72     final override size_t maxInputBits() const {
73         if (m_msg_parts == 1 && algoName != "DH" && algoName != "ElGamal") 
74             return 0;
75 
76         if (algoName == "NR" || algoName == "ElGamal")
77             return groupQ().bits() - 1;
78 
79         return groupQ().bits();
80     }
81 
82     final size_t messagePartSize() const { 
83         if (m_msg_parts == 1) return 0; 
84         return groupQ().bytes(); 
85     }
86 
87     final AlgorithmIdentifier algorithmIdentifier() const
88     {
89         return AlgorithmIdentifier(getOid(), m_group.DER_encode(m_format));
90     }
91 
92     final Vector!ubyte x509SubjectPublicKey() const
93     {
94         return DEREncoder().encode(m_y).getContentsUnlocked();
95     }
96 
97     /*
98     * Return the public value for key agreement
99     */
100     Vector!ubyte publicValue() const
101     {
102         return unlock(BigInt.encode1363(getY(), groupP().bytes()));
103     }
104 
105     /**
106     * Get the DL domain parameters of this key.
107     * Returns: DL domain parameters of this key
108     */
109     final ref const(DLGroup) getDomain() const { return m_group; }
110 
111     /**
112     * Get the public value m_y with m_y = g^m_x mod p where m_x is the secret key.
113     */
114     final ref const(BigInt) getY() const { return m_y; }
115 
116     /**
117     * Set the value m_y
118     */
119     final void setY(BigInt y) { m_y = y.move(); }
120 
121     /**
122     * Get the prime p of the underlying DL m_group.
123     * Returns: prime p
124     */
125     final ref const(BigInt) groupP() const { return m_group.getP(); }
126 
127     /**
128     * Get the prime q of the underlying DL m_group.
129     * Returns: prime q
130     */
131     final ref const(BigInt) groupQ() const { return m_group.getQ(); }
132 
133     /**
134     * Get the generator g of the underlying DL m_group.
135     * Returns: generator g
136     */
137     final ref const(BigInt) groupG() const { return m_group.getG(); }
138 
139     override final size_t estimatedStrength() const
140     {
141         return dlWorkFactor(m_group.getP().bits());
142     }
143 
144     this(T)(in T options,
145             in AlgorithmIdentifier alg_id, 
146             auto const ref SecureVector!ubyte key_bits)
147     {
148         decodeOptions(options);
149         m_group.BER_decode(alg_id.parameters, m_format);
150         BERDecoder(key_bits).decode(m_y);
151     }
152 
153     this(T)(in T options, DLGroup grp, BigInt y1)
154     {
155         decodeOptions(options);
156         m_group = grp.move;
157         m_y = y1.move;
158     }
159 
160 protected:
161     /**
162     * The DL public key
163     */
164     BigInt m_y;
165 
166     /**
167     * The DL group
168     */
169     DLGroup m_group;
170 
171     /// options
172     DLGroup.Format m_format;
173     string m_algo_name;
174     short m_msg_parts = 1;
175     bool function(in DLSchemePrivateKey, RandomNumberGenerator, bool) m_check_key;
176 }
177 
178 /**
179 * This class represents discrete logarithm (DL) private keys.
180 */
181 final class DLSchemePrivateKey : DLSchemePublicKey, PrivateKey, PKKeyAgreementKey
182 {
183 public:
184 
185     override AlgorithmIdentifier pkcs8AlgorithmIdentifier() const { return super.algorithmIdentifier(); }
186 
187     override bool checkKey(RandomNumberGenerator rng, bool strong) const
188     {
189         if (m_check_key)
190             return m_check_key(this, rng, strong);
191 
192         return checkKeyImpl(rng, strong);
193     }
194 
195     final bool checkKeyImpl(RandomNumberGenerator rng, bool strong) const 
196     {
197         const BigInt* p = &groupP();
198         const BigInt* g = &groupG();
199         if (m_y < 2 || m_y >= *p || m_x < 2 || m_x >= *p) {
200             return false;
201         }
202         if (!m_group.verifyGroup(rng, strong)) {
203             return false;
204         }
205         
206         if (!strong)
207             return true;
208         
209         if (m_y != powerMod(*g, m_x, *p)) 
210         {        
211             return false;
212         }
213         return true;
214     }
215 
216     /**
217     * Get the secret key m_x.
218     * Returns: secret key
219     */
220     ref const(BigInt) getX() const { return m_x; }
221 
222     SecureVector!ubyte pkcs8PrivateKey() const
223     {
224         return DEREncoder().encode(m_x).getContents();
225     }
226 
227     this(T)(in T options, in AlgorithmIdentifier alg_id,
228              const ref SecureVector!ubyte key_bits)
229     {
230         BERDecoder(key_bits).decode(m_x);
231         DLGroup grp;
232         grp.BER_decode(alg_id.parameters, options.format);
233         BigInt y = powerMod(grp.getG(), m_x, grp.getP());
234         super(options, grp.move, y.move);
235     }
236 
237     this(T)(in T options, 
238             DLGroup grp, 
239             BigInt y1, BigInt x_arg)
240     {
241         //logTrace("grp: ", grp.toString());
242         m_x = x_arg.move;
243         //logTrace("x: ", m_x.toString());
244         super(options, grp.move, y1.move);
245     }
246 
247     /*
248     * Return the public value for key agreement
249     */
250     override Vector!ubyte publicValue() const
251     {
252         return super.publicValue();
253     }
254 
255 
256 package:
257     /**
258     * The DL private key
259     */
260     BigInt m_x;
261 }