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