1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.github.tonywasher.joceanus.gordianknot.impl.bc;
18
19 import io.github.tonywasher.joceanus.gordianknot.api.base.GordianException;
20 import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianKeyPair;
21 import io.github.tonywasher.joceanus.gordianknot.api.keypair.spec.GordianKeyPairSpec;
22 import io.github.tonywasher.joceanus.gordianknot.api.sign.GordianNewSignParams;
23 import io.github.tonywasher.joceanus.gordianknot.api.sign.spec.GordianSignatureSpec;
24 import io.github.tonywasher.joceanus.gordianknot.impl.bc.BouncyKeyPair.BouncyPrivateKey;
25 import io.github.tonywasher.joceanus.gordianknot.impl.bc.BouncyKeyPair.BouncyPublicKey;
26 import io.github.tonywasher.joceanus.gordianknot.impl.bc.BouncySignature.BouncyDERCoder;
27 import io.github.tonywasher.joceanus.gordianknot.impl.bc.BouncySignature.BouncyDigestSignature;
28 import io.github.tonywasher.joceanus.gordianknot.impl.core.base.GordianBaseFactory;
29 import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianCryptoException;
30 import io.github.tonywasher.joceanus.gordianknot.impl.core.keypair.GordianKeyPairValidity;
31 import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.keypair.GordianCoreDSASpec;
32 import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.keypair.GordianCoreKeyPairSpec;
33 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
34 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
35 import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
36 import org.bouncycastle.crypto.DSA;
37 import org.bouncycastle.crypto.digests.SHA256Digest;
38 import org.bouncycastle.crypto.generators.DSAKeyPairGenerator;
39 import org.bouncycastle.crypto.generators.DSAParametersGenerator;
40 import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
41 import org.bouncycastle.crypto.params.DSAKeyGenerationParameters;
42 import org.bouncycastle.crypto.params.DSAParameterGenerationParameters;
43 import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
44 import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
45 import org.bouncycastle.crypto.params.ParametersWithRandom;
46 import org.bouncycastle.crypto.util.PrivateKeyFactory;
47 import org.bouncycastle.crypto.util.PrivateKeyInfoFactory;
48 import org.bouncycastle.crypto.util.PublicKeyFactory;
49 import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
50
51 import java.io.IOException;
52 import java.math.BigInteger;
53 import java.security.spec.PKCS8EncodedKeySpec;
54 import java.security.spec.X509EncodedKeySpec;
55
56
57
58
59 public final class BouncyDSAKeyPair {
60
61
62
63 private BouncyDSAKeyPair() {
64 }
65
66
67
68
69 public static class BouncyDSAPublicKey
70 extends BouncyPublicKey<DSAPublicKeyParameters> {
71
72
73
74
75
76
77 BouncyDSAPublicKey(final GordianKeyPairSpec pKeySpec,
78 final DSAPublicKeyParameters pPublicKey) {
79 super(pKeySpec, pPublicKey);
80 }
81
82 @Override
83 protected boolean matchKey(final AsymmetricKeyParameter pThat) {
84
85 final DSAPublicKeyParameters myThis = getPublicKey();
86 final DSAPublicKeyParameters myThat = (DSAPublicKeyParameters) pThat;
87
88
89 return compareKeys(myThis, myThat);
90 }
91
92
93
94
95
96
97
98 public boolean validPrivate(final BouncyDSAPrivateKey pPrivate) {
99 final DSAPrivateKeyParameters myPrivate = pPrivate.getPrivateKey();
100 return getPublicKey().getParameters().equals(myPrivate.getParameters());
101 }
102
103
104
105
106
107
108
109
110 private static boolean compareKeys(final DSAPublicKeyParameters pFirst,
111 final DSAPublicKeyParameters pSecond) {
112 return pFirst.getY().equals(pSecond.getY())
113 && pFirst.getParameters().equals(pSecond.getParameters());
114 }
115 }
116
117
118
119
120 public static class BouncyDSAPrivateKey
121 extends BouncyPrivateKey<DSAPrivateKeyParameters> {
122
123
124
125
126
127
128 BouncyDSAPrivateKey(final GordianKeyPairSpec pKeySpec,
129 final DSAPrivateKeyParameters pPrivateKey) {
130 super(pKeySpec, pPrivateKey);
131 }
132
133 @Override
134 protected boolean matchKey(final AsymmetricKeyParameter pThat) {
135
136 final DSAPrivateKeyParameters myThis = getPrivateKey();
137 final DSAPrivateKeyParameters myThat = (DSAPrivateKeyParameters) pThat;
138
139
140 return compareKeys(myThis, myThat);
141 }
142
143
144
145
146
147
148
149
150 private static boolean compareKeys(final DSAPrivateKeyParameters pFirst,
151 final DSAPrivateKeyParameters pSecond) {
152 return pFirst.getX().equals(pSecond.getX())
153 && pFirst.getParameters().equals(pSecond.getParameters());
154 }
155 }
156
157
158
159
160 public static class BouncyDSAKeyPairGenerator
161 extends BouncyKeyPairGenerator {
162
163
164
165 private final DSAKeyPairGenerator theGenerator;
166
167
168
169
170
171
172
173 BouncyDSAKeyPairGenerator(final GordianBaseFactory pFactory,
174 final GordianKeyPairSpec pKeySpec) {
175
176 super(pFactory, pKeySpec);
177
178
179 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
180 final GordianCoreDSASpec myKeyType = myKeySpec.getDSASpec();
181 final DSAParameterGenerationParameters myGenParms = new DSAParameterGenerationParameters(myKeyType.getKeySize(),
182 myKeyType.getHashSize(), PRIME_CERTAINTY, getRandom());
183 final DSAParametersGenerator myParmGenerator = new DSAParametersGenerator(new SHA256Digest());
184 myParmGenerator.init(myGenParms);
185
186
187 theGenerator = new DSAKeyPairGenerator();
188 final DSAKeyGenerationParameters myParams = new DSAKeyGenerationParameters(getRandom(), myParmGenerator.generateParameters());
189 theGenerator.init(myParams);
190 }
191
192 @Override
193 public BouncyKeyPair generateKeyPair() {
194
195 final AsymmetricCipherKeyPair myPair = theGenerator.generateKeyPair();
196 final BouncyDSAPublicKey myPublic = new BouncyDSAPublicKey(getKeySpec(), (DSAPublicKeyParameters) myPair.getPublic());
197 final BouncyDSAPrivateKey myPrivate = new BouncyDSAPrivateKey(getKeySpec(), (DSAPrivateKeyParameters) myPair.getPrivate());
198 return new BouncyKeyPair(myPublic, myPrivate);
199 }
200
201 @Override
202 public PKCS8EncodedKeySpec getPKCS8Encoding(final GordianKeyPair pKeyPair) throws GordianException {
203
204 try {
205
206 BouncyKeyPair.checkKeyPair(pKeyPair, getKeySpec());
207
208
209 final BouncyDSAPrivateKey myPrivateKey = (BouncyDSAPrivateKey) getPrivateKey(pKeyPair);
210 final DSAPrivateKeyParameters myParms = myPrivateKey.getPrivateKey();
211 final PrivateKeyInfo myInfo = PrivateKeyInfoFactory.createPrivateKeyInfo(myParms);
212 return new PKCS8EncodedKeySpec(myInfo.getEncoded());
213
214 } catch (IOException e) {
215 throw new GordianCryptoException(ERROR_PARSE, e);
216 }
217 }
218
219 @Override
220 public BouncyKeyPair deriveKeyPair(final X509EncodedKeySpec pPublicKey,
221 final PKCS8EncodedKeySpec pPrivateKey) throws GordianException {
222
223 try {
224
225 checkKeySpec(pPrivateKey);
226
227
228 final BouncyDSAPublicKey myPublic = derivePublicKey(pPublicKey);
229 final PrivateKeyInfo myInfo = PrivateKeyInfo.getInstance(pPrivateKey.getEncoded());
230 final DSAPrivateKeyParameters myParms = (DSAPrivateKeyParameters) PrivateKeyFactory.createKey(myInfo);
231 final BouncyDSAPrivateKey myPrivate = new BouncyDSAPrivateKey(getKeySpec(), myParms);
232 final BouncyKeyPair myPair = new BouncyKeyPair(myPublic, myPrivate);
233
234
235 GordianKeyPairValidity.checkValidity(getFactory(), myPair);
236
237
238 return myPair;
239
240 } catch (IOException e) {
241 throw new GordianCryptoException(ERROR_PARSE, e);
242 }
243 }
244
245 @Override
246 public X509EncodedKeySpec getX509Encoding(final GordianKeyPair pKeyPair) throws GordianException {
247
248 try {
249
250 BouncyKeyPair.checkKeyPair(pKeyPair, getKeySpec());
251
252
253 final BouncyDSAPublicKey myPublicKey = (BouncyDSAPublicKey) getPublicKey(pKeyPair);
254 final DSAPublicKeyParameters myParms = myPublicKey.getPublicKey();
255 final SubjectPublicKeyInfo myInfo = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(myParms);
256 return new X509EncodedKeySpec(myInfo.getEncoded());
257
258 } catch (IOException e) {
259 throw new GordianCryptoException(ERROR_PARSE, e);
260 }
261 }
262
263 @Override
264 public BouncyKeyPair derivePublicOnlyKeyPair(final X509EncodedKeySpec pEncodedKey) throws GordianException {
265 final BouncyDSAPublicKey myPublic = derivePublicKey(pEncodedKey);
266 return new BouncyKeyPair(myPublic);
267 }
268
269
270
271
272
273
274
275
276 private BouncyDSAPublicKey derivePublicKey(final X509EncodedKeySpec pEncodedKey) throws GordianException {
277
278 try {
279
280 checkKeySpec(pEncodedKey);
281
282
283 final SubjectPublicKeyInfo myInfo = SubjectPublicKeyInfo.getInstance(pEncodedKey.getEncoded());
284 final DSAPublicKeyParameters myParms = (DSAPublicKeyParameters) PublicKeyFactory.createKey(myInfo);
285 return new BouncyDSAPublicKey(getKeySpec(), myParms);
286
287 } catch (IOException e) {
288 throw new GordianCryptoException(ERROR_PARSE, e);
289 }
290 }
291 }
292
293
294
295
296 public static class BouncyDSASignature
297 extends BouncyDigestSignature {
298
299
300
301 private final DSA theSigner;
302
303
304
305
306 private final BouncyDERCoder theCoder;
307
308
309
310
311
312
313
314
315 BouncyDSASignature(final GordianBaseFactory pFactory,
316 final GordianSignatureSpec pSpec) throws GordianException {
317
318 super(pFactory, pSpec);
319
320
321 theSigner = BouncySignature.getDSASigner(pFactory, pSpec);
322 theCoder = new BouncyDERCoder();
323 }
324
325 @Override
326 public void initForSigning(final GordianNewSignParams pParams) throws GordianException {
327
328 super.initForSigning(pParams);
329 final BouncyKeyPair myPair = getKeyPair();
330 BouncyKeyPair.checkKeyPair(myPair);
331
332
333 final BouncyDSAPrivateKey myPrivate = (BouncyDSAPrivateKey) myPair.getPrivateKey();
334 final ParametersWithRandom myParms = new ParametersWithRandom(myPrivate.getPrivateKey(), getRandom());
335 theSigner.init(true, myParms);
336 }
337
338 @Override
339 public void initForVerify(final GordianNewSignParams pParams) throws GordianException {
340
341 super.initForVerify(pParams);
342 final BouncyKeyPair myPair = getKeyPair();
343 BouncyKeyPair.checkKeyPair(myPair);
344
345
346 final BouncyDSAPublicKey myPublic = (BouncyDSAPublicKey) myPair.getPublicKey();
347 theSigner.init(false, myPublic.getPublicKey());
348 }
349
350 @Override
351 public byte[] sign() throws GordianException {
352
353 checkMode(GordianSignatureMode.SIGN);
354
355
356 final BigInteger[] myValues = theSigner.generateSignature(getDigest());
357 return theCoder.dsaEncode(myValues[0], myValues[1]);
358 }
359
360 @Override
361 public boolean verify(final byte[] pSignature) throws GordianException {
362
363 checkMode(GordianSignatureMode.VERIFY);
364
365
366 final BigInteger[] myValues = theCoder.dsaDecode(pSignature);
367 return theSigner.verifySignature(getDigest(), myValues[0], myValues[1]);
368 }
369 }
370 }