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 }