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             BigInt inv_for_d = lcm(m_p - 1, m_q - 1);
170             if (m_e.isEven())
171                 inv_for_d >>= 1;
172             
173             m_d = inverseMod(m_e, inv_for_d);
174         }
175         
176         m_d1 = m_d % (m_p - 1);
177         m_d2 = m_d % (m_q - 1);
178         m_c = inverseMod(m_q, m_p);
179 
180         loadCheck(rng);
181 
182     }
183 
184     override AlgorithmIdentifier pkcs8AlgorithmIdentifier() const { return super.algorithmIdentifier(); }
185 
186     /*
187     * Check IF Scheme Private Parameters
188     */
189     override bool checkKey(RandomNumberGenerator rng, bool strong) const
190     {
191         if (m_check_key) 
192             return m_check_key(this, rng, strong);
193         return checkKeyImpl(rng, strong);
194     }
195 
196     final bool checkKeyImpl(RandomNumberGenerator rng, bool strong) const 
197     {        
198 		auto p_q = m_p*m_q;
199         if (m_n < 35 || m_n.isEven() || m_e < 2 || m_d < 2 || m_p < 3 || m_q < 3 || p_q != m_n)
200             return false;
201         
202         if (m_d1 != m_d % (m_p - 1) || m_d2 != m_d % (m_q - 1) || m_c != inverseMod(m_q, m_p))
203             return false;
204         
205         const size_t prob = (strong) ? 56 : 12;
206         
207         if (!isPrime(m_p, rng, prob) || !isPrime(m_q, rng, prob))
208             return false;
209         return true;
210     }
211 
212     /**
213     * Get the first prime p.
214     * Returns: prime p
215     */
216     ref const(BigInt) getP() const { return m_p; }
217 
218     /**
219     * Get the second prime q.
220     * Returns: prime q
221     */
222     ref const(BigInt) getQ() const { return m_q; }
223 
224     /**
225     * Get d with exp * d = 1 mod (p - 1, q - 1).
226     * Returns: d
227     */
228     ref const(BigInt) getD() const { return m_d; }
229 
230     ref const(BigInt) getC() const { return m_c; }
231     ref const(BigInt) getD1() const { return m_d1; }
232     ref const(BigInt) getD2() const { return m_d2; }
233 
234     SecureVector!ubyte pkcs8PrivateKey() const
235     {
236         return DEREncoder()
237                 .startCons(ASN1Tag.SEQUENCE)
238                 .encode(cast(size_t)(0))
239                 .encode(m_n)
240                 .encode(m_e)
241                 .encode(m_d)
242                 .encode(m_p)
243                 .encode(m_q)
244                 .encode(m_d1)
245                 .encode(m_d2)
246                 .encode(m_c)
247                 .endCons()
248                 .getContents();
249     }
250 
251 protected:
252     BigInt m_d, m_p, m_q, m_d1, m_d2, m_c;
253 }