1 /**
2 * IF 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.if_algo;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_PUBLIC_KEY_CRYPTO):
15 
16 import botan.rng.rng;
17 public import botan.pubkey.pubkey;
18 import botan.math.bigint.bigint;
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.asn1.der_enc;
24 import botan.asn1.ber_dec;
25 
26 /**
27 * This class represents public keys
28 * of integer factorization based (IF) public key schemes.
29 */
30 class IFSchemePublicKey : PublicKey
31 {
32 public:
33     this(T)(in T options, in AlgorithmIdentifier, const ref SecureVector!ubyte key_bits)
34     {
35         decodeOptions(options);
36         BERDecoder(key_bits)
37                 .startCons(ASN1Tag.SEQUENCE)
38                 .decode(m_n)
39                 .decode(m_e)
40                 .verifyEnd()
41                 .endCons();
42     }
43 
44     this(T)(in T options, auto ref BigInt n, auto ref BigInt e)
45     {
46         decodeOptions(options);
47         m_n = n.move();
48         m_e = e.move(); 
49     }
50 
51     final void decodeOptions(T)(in T options) {
52         static if (__traits(hasMember, T, "checkKey"))
53             m_check_key = &options.checkKey;
54         static if (__traits(hasMember, T, "algoName"))
55             m_algo_name = options.algoName;
56         else static assert(false, "No algoName found in " ~ T.stringof);
57     }
58 
59 
60     /// Used for object casting to the right type in the factory.
61     final override @property string algoName() const {
62         return m_algo_name;
63     }
64 
65     /*
66     * Check IF Scheme Public Parameters
67     */
68     override bool checkKey(RandomNumberGenerator rng, bool strong) const
69     {
70         if (m_n < 35 || m_n.isEven() || m_e < 2)
71             return false;
72         return true;
73     }
74 
75 
76     final AlgorithmIdentifier algorithmIdentifier() const
77     {
78         return AlgorithmIdentifier(getOid(), AlgorithmIdentifierImpl.USE_NULL_PARAM);
79     }
80 
81     final Vector!ubyte x509SubjectPublicKey() const
82     {
83         auto der_enc = DEREncoder()
84                 .startCons(ASN1Tag.SEQUENCE)
85                 .encode(m_n)
86 				.encode(m_e);
87 		der_enc.endCons();
88 		return der_enc.getContentsUnlocked();
89     }
90 
91     /**
92     * Returns: public modulus
93     */
94     final ref const(BigInt) getN() const { return m_n; }
95 
96     /**
97     * Returns: public exponent
98     */
99     final ref const(BigInt) getE() const { return m_e; }
100 
101     final size_t maxInputBits() const { return (m_n.bits() - 1); }
102 
103     final override size_t messagePartSize() const {
104         return 0;
105     }
106 
107     final override size_t messageParts() const {
108         return 1;
109     }
110 
111     override final size_t estimatedStrength() const
112     {
113         return dlWorkFactor(m_n.bits());
114     }
115 
116 protected:
117     BigInt m_n, m_e;
118 
119     // options
120     string m_algo_name;
121     bool function(in IFSchemePrivateKey, RandomNumberGenerator, bool) m_check_key;
122 }
123 
124 /**
125 * This class represents public keys
126 * of integer factorization based (IF) public key schemes.
127 */
128 final class IFSchemePrivateKey : IFSchemePublicKey, PrivateKey
129 {
130 public:
131     this(T)(in T options, RandomNumberGenerator rng, 
132             in AlgorithmIdentifier aid, const ref SecureVector!ubyte key_bits)
133     {
134         BigInt n, e;
135         BERDecoder(key_bits).startCons(ASN1Tag.SEQUENCE)
136             .decodeAndCheck!size_t(0, "Unknown PKCS #1 key format version")
137             .decode(n)
138             .decode(e)
139             .decode(m_d)
140             .decode(m_p)
141             .decode(m_q)
142             .decode(m_d1)
143             .decode(m_d2)
144             .decode(m_c)
145             .endCons();
146         
147         super(options, n, e);
148 
149         loadCheck(rng);
150     }
151 
152     this(T)(in T options,
153             RandomNumberGenerator rng,
154             BigInt prime1,
155             BigInt prime2,
156             BigInt exp,
157             BigInt d_exp,
158             BigInt mod)
159     {
160         m_p = prime1.move();
161         m_q = prime2.move();
162         BigInt n = mod.isNonzero() ? mod.move() : m_p * m_q;
163         super(options, n.move(), exp.move()); // defines m_e and m_n
164 
165         m_d = d_exp.move();
166         
167         if (m_d == 0)
168         {
169             auto mp_minus_1 = m_p - 1;
170             auto mq_minus_1 = m_q - 1;
171             BigInt inv_for_d = lcm(&mp_minus_1, &mq_minus_1);
172             if (m_e.isEven())
173                 inv_for_d >>= 1;
174             
175             m_d = inverseMod(&m_e, &inv_for_d);
176         }
177         
178         m_d1 = m_d % (m_p - 1);
179         m_d2 = m_d % (m_q - 1);
180         m_c = inverseMod(&m_q, &m_p);
181 
182         loadCheck(rng);
183 
184     }
185 
186     override AlgorithmIdentifier pkcs8AlgorithmIdentifier() const { return super.algorithmIdentifier(); }
187 
188     /*
189     * Check IF Scheme Private Parameters
190     */
191     override bool checkKey(RandomNumberGenerator rng, bool strong) const
192     {
193         if (m_check_key) 
194             return m_check_key(this, rng, strong);
195         return checkKeyImpl(rng, strong);
196     }
197 
198     final bool checkKeyImpl(RandomNumberGenerator rng, bool strong) const 
199     {        
200 		auto p_q = m_p*m_q;
201         if (m_n < 35 || m_n.isEven() || m_e < 2 || m_d < 2 || m_p < 3 || m_q < 3 || p_q != m_n)
202             return false;
203         
204         if (m_d1 != m_d % (m_p - 1) || m_d2 != m_d % (m_q - 1) || m_c != inverseMod(&m_q, &m_p))
205             return false;
206         
207         const size_t prob = (strong) ? 56 : 12;
208         
209         if (!isPrime(&m_p, rng, prob) || !isPrime(&m_q, rng, prob))
210             return false;
211         return true;
212     }
213 
214     /**
215     * Get the first prime p.
216     * Returns: prime p
217     */
218     ref const(BigInt) getP() const { return m_p; }
219 
220     /**
221     * Get the second prime q.
222     * Returns: prime q
223     */
224     ref const(BigInt) getQ() const { return m_q; }
225 
226     /**
227     * Get d with exp * d = 1 mod (p - 1, q - 1).
228     * Returns: d
229     */
230     ref const(BigInt) getD() const { return m_d; }
231 
232     ref const(BigInt) getC() const { return m_c; }
233     ref const(BigInt) getD1() const { return m_d1; }
234     ref const(BigInt) getD2() const { return m_d2; }
235 
236     SecureVector!ubyte pkcs8PrivateKey() const
237     {
238         return DEREncoder()
239                 .startCons(ASN1Tag.SEQUENCE)
240                 .encode(cast(size_t)(0))
241                 .encode(m_n)
242                 .encode(m_e)
243                 .encode(m_d)
244                 .encode(m_p)
245                 .encode(m_q)
246                 .encode(m_d1)
247                 .encode(m_d2)
248                 .encode(m_c)
249                 .endCons()
250                 .getContents();
251     }
252 
253 protected:
254     BigInt m_d, m_p, m_q, m_d1, m_d2, m_c;
255 }