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.agree.GordianAgreementSpec;
20 import io.github.tonywasher.joceanus.gordianknot.api.base.GordianException;
21 import io.github.tonywasher.joceanus.gordianknot.api.digest.GordianDigestFactory;
22 import io.github.tonywasher.joceanus.gordianknot.api.digest.GordianDigestSpec;
23 import io.github.tonywasher.joceanus.gordianknot.api.digest.GordianDigestType;
24 import io.github.tonywasher.joceanus.gordianknot.api.encrypt.GordianEncryptorSpec;
25 import io.github.tonywasher.joceanus.gordianknot.api.encrypt.GordianSM2EncryptionSpec;
26 import io.github.tonywasher.joceanus.gordianknot.api.encrypt.GordianSM2EncryptionSpec.GordianSM2EncryptionType;
27 import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianKeyPair;
28 import io.github.tonywasher.joceanus.gordianknot.api.sign.GordianSignParams;
29 import io.github.tonywasher.joceanus.gordianknot.api.sign.GordianSignatureSpec;
30 import io.github.tonywasher.joceanus.gordianknot.impl.bc.BouncyEllipticKeyPair.BouncyECPrivateKey;
31 import io.github.tonywasher.joceanus.gordianknot.impl.bc.BouncyEllipticKeyPair.BouncyECPublicKey;
32 import io.github.tonywasher.joceanus.gordianknot.impl.bc.BouncyKeyPair.BouncyPrivateKey;
33 import io.github.tonywasher.joceanus.gordianknot.impl.bc.BouncyKeyPair.BouncyPublicKey;
34 import io.github.tonywasher.joceanus.gordianknot.impl.core.agree.GordianCoreAgreementFactory;
35 import io.github.tonywasher.joceanus.gordianknot.impl.core.base.GordianBaseFactory;
36 import io.github.tonywasher.joceanus.gordianknot.impl.core.encrypt.GordianCoreEncryptor;
37 import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianCryptoException;
38 import io.github.tonywasher.joceanus.gordianknot.impl.core.sign.GordianCoreSignature;
39 import org.bouncycastle.crypto.CryptoException;
40 import org.bouncycastle.crypto.InvalidCipherTextException;
41 import org.bouncycastle.crypto.agreement.SM2KeyExchange;
42 import org.bouncycastle.crypto.engines.SM2Engine;
43 import org.bouncycastle.crypto.engines.SM2Engine.Mode;
44 import org.bouncycastle.crypto.params.ParametersWithRandom;
45 import org.bouncycastle.crypto.params.SM2KeyExchangePrivateParameters;
46 import org.bouncycastle.crypto.params.SM2KeyExchangePublicParameters;
47 import org.bouncycastle.crypto.signers.SM2Signer;
48
49
50
51
52 public final class BouncySM2KeyPair {
53
54
55
56 private BouncySM2KeyPair() {
57 }
58
59
60
61
62 public static class BouncySM2Signature
63 extends GordianCoreSignature {
64
65
66
67 private final SM2Signer theSigner;
68
69
70
71
72
73
74
75
76 BouncySM2Signature(final GordianBaseFactory pFactory,
77 final GordianSignatureSpec pSpec) throws GordianException {
78
79 super(pFactory, pSpec);
80
81
82 final GordianDigestSpec mySpec = pSpec.getDigestSpec();
83 if (GordianDigestType.SM3.equals(mySpec.getDigestType())) {
84 theSigner = new SM2Signer();
85 } else {
86 final BouncyDigest myDigest = (BouncyDigest) pFactory.getDigestFactory().createDigest(mySpec);
87 theSigner = new SM2Signer(myDigest.getDigest());
88 }
89 }
90
91 @Override
92 public void update(final byte[] pBytes,
93 final int pOffset,
94 final int pLength) {
95 theSigner.update(pBytes, pOffset, pLength);
96 }
97
98 @Override
99 public void update(final byte pByte) {
100 theSigner.update(pByte);
101 }
102
103 @Override
104 public void update(final byte[] pBytes) {
105 theSigner.update(pBytes, 0, pBytes.length);
106 }
107
108 @Override
109 public void reset() {
110 theSigner.reset();
111 }
112
113 @Override
114 protected BouncyKeyPair getKeyPair() {
115 return (BouncyKeyPair) super.getKeyPair();
116 }
117
118 @Override
119 public void initForSigning(final GordianSignParams pParams) throws GordianException {
120
121 super.initForSigning(pParams);
122 final BouncyKeyPair myPair = getKeyPair();
123 BouncyKeyPair.checkKeyPair(myPair);
124
125
126 final BouncyECPrivateKey myPrivate = (BouncyECPrivateKey) myPair.getPrivateKey();
127 final ParametersWithRandom myParms = new ParametersWithRandom(myPrivate.getPrivateKey(), getRandom());
128 theSigner.init(true, myParms);
129 }
130
131 @Override
132 public void initForVerify(final GordianSignParams pParams) throws GordianException {
133
134 super.initForVerify(pParams);
135 final BouncyKeyPair myPair = getKeyPair();
136 BouncyKeyPair.checkKeyPair(myPair);
137
138
139 final BouncyECPublicKey myPublic = (BouncyECPublicKey) myPair.getPublicKey();
140 theSigner.init(false, myPublic.getPublicKey());
141 }
142
143 @Override
144 public byte[] sign() throws GordianException {
145
146 checkMode(GordianSignatureMode.SIGN);
147
148
149 try {
150 return theSigner.generateSignature();
151 } catch (CryptoException e) {
152 throw new GordianCryptoException(BouncySignature.ERROR_SIGGEN, e);
153 }
154 }
155
156 @Override
157 public boolean verify(final byte[] pSignature) throws GordianException {
158
159 checkMode(GordianSignatureMode.VERIFY);
160
161
162 return theSigner.verifySignature(pSignature);
163 }
164 }
165
166
167
168
169 public static class BouncySM2AgreementEngine
170 extends BouncyAgreementBase {
171
172
173
174 private static final int KEYLEN = 64;
175
176
177
178
179 private final SM2KeyExchange theAgreement;
180
181
182
183
184
185
186
187
188 BouncySM2AgreementEngine(final GordianCoreAgreementFactory pFactory,
189 final GordianAgreementSpec pSpec) throws GordianException {
190
191 super(pFactory, pSpec);
192
193
194 theAgreement = new SM2KeyExchange();
195 }
196
197 @Override
198 public void processClientHello() throws GordianException {
199
200 final BouncyECPublicKey myClientPublic = (BouncyECPublicKey) getPublicKey(getClientKeyPair());
201 final BouncyECPublicKey myClientEphPublic = (BouncyECPublicKey) getPublicKey(getClientEphemeral());
202 final BouncyECPrivateKey myPrivate = (BouncyECPrivateKey) getPrivateKey(getServerKeyPair());
203 final BouncyECPrivateKey myEphPrivate = (BouncyECPrivateKey) getPrivateKey(getServerEphemeral());
204
205
206 final SM2KeyExchangePrivateParameters myPrivParams = new SM2KeyExchangePrivateParameters(false,
207 myPrivate.getPrivateKey(), myEphPrivate.getPrivateKey());
208 theAgreement.init(myPrivParams);
209 final SM2KeyExchangePublicParameters myPubParams = new SM2KeyExchangePublicParameters(myClientPublic.getPublicKey(),
210 myClientEphPublic.getPublicKey());
211
212
213 if (Boolean.TRUE.equals(getSpec().withConfirm())) {
214
215 final byte[][] myResults = theAgreement.calculateKeyWithConfirmation(KEYLEN, null, myPubParams);
216
217
218 setServerConfirm(myResults[1]);
219 setClientConfirm(myResults[2]);
220
221
222 storeSecret(myResults[0]);
223
224
225 } else {
226
227 storeSecret(theAgreement.calculateKey(KEYLEN, myPubParams));
228 }
229 }
230
231 @Override
232 public void processServerHello() throws GordianException {
233
234 final BouncyECPublicKey myServerPublic = (BouncyECPublicKey) getPublicKey(getServerKeyPair());
235 final BouncyECPublicKey myServerEphPublic = (BouncyECPublicKey) getPublicKey(getServerEphemeral());
236 final BouncyECPrivateKey myPrivate = (BouncyECPrivateKey) getPrivateKey(getClientKeyPair());
237 final BouncyECPrivateKey myEphPrivate = (BouncyECPrivateKey) getPrivateKey(getClientEphemeral());
238
239
240 final SM2KeyExchangePrivateParameters myPrivParams = new SM2KeyExchangePrivateParameters(true,
241 myPrivate.getPrivateKey(), myEphPrivate.getPrivateKey());
242 theAgreement.init(myPrivParams);
243 final SM2KeyExchangePublicParameters myPubParams = new SM2KeyExchangePublicParameters(myServerPublic.getPublicKey(),
244 myServerEphPublic.getPublicKey());
245
246
247 if (Boolean.TRUE.equals(getSpec().withConfirm())) {
248
249 final byte[] myConfirm = getServerConfirm();
250
251
252 try {
253
254 final byte[][] myResults = theAgreement.calculateKeyWithConfirmation(KEYLEN, myConfirm, myPubParams);
255
256
257 if (setClientConfirm(myResults[1])) {
258
259 storeSecret(myResults[0]);
260 }
261
262
263 } catch (IllegalStateException e) {
264 getBuilder().setError("Server Confirmation failed");
265 }
266
267
268 } else {
269
270 storeSecret(theAgreement.calculateKey(KEYLEN, myPubParams));
271 }
272 }
273 }
274
275
276
277
278 public static class BouncySM2Encryptor
279 extends GordianCoreEncryptor {
280
281
282
283 private final SM2Engine theEncryptor;
284
285
286
287
288
289
290
291
292 BouncySM2Encryptor(final GordianBaseFactory pFactory,
293 final GordianEncryptorSpec pSpec) throws GordianException {
294
295 super(pFactory, pSpec);
296 final GordianDigestFactory myFactory = pFactory.getDigestFactory();
297 final GordianSM2EncryptionSpec mySpec = pSpec.getSM2EncryptionSpec();
298 final BouncyDigest myDigest = (BouncyDigest) myFactory.createDigest(mySpec.getDigestSpec());
299 final Mode mySM2Mode = mySpec.getEncryptionType() == GordianSM2EncryptionType.C1C2C3
300 ? Mode.C1C2C3 : Mode.C1C3C2;
301 theEncryptor = new SM2Engine(myDigest.getDigest(), mySM2Mode);
302 }
303
304 @Override
305 protected BouncyPublicKey<?> getPublicKey() {
306 return (BouncyPublicKey<?>) super.getPublicKey();
307 }
308
309 @Override
310 protected BouncyPrivateKey<?> getPrivateKey() {
311 return (BouncyPrivateKey<?>) super.getPrivateKey();
312 }
313
314 @Override
315 public void initForEncrypt(final GordianKeyPair pKeyPair) throws GordianException {
316
317 BouncyKeyPair.checkKeyPair(pKeyPair);
318 super.initForEncrypt(pKeyPair);
319
320
321 final ParametersWithRandom myParms = new ParametersWithRandom(getPublicKey().getPublicKey(), getRandom());
322 theEncryptor.init(true, myParms);
323 }
324
325 @Override
326 public void initForDecrypt(final GordianKeyPair pKeyPair) throws GordianException {
327
328 BouncyKeyPair.checkKeyPair(pKeyPair);
329 super.initForDecrypt(pKeyPair);
330
331
332 theEncryptor.init(false, getPrivateKey().getPrivateKey());
333 }
334
335 @Override
336 public byte[] encrypt(final byte[] pBytes) throws GordianException {
337 try {
338
339 checkMode(GordianEncryptMode.ENCRYPT);
340
341
342 return theEncryptor.processBlock(pBytes, 0, pBytes.length);
343 } catch (InvalidCipherTextException e) {
344 throw new GordianCryptoException("Failed to encrypt data", e);
345 }
346 }
347
348 @Override
349 public byte[] decrypt(final byte[] pBytes) throws GordianException {
350 try {
351
352 checkMode(GordianEncryptMode.DECRYPT);
353
354
355 return theEncryptor.processBlock(pBytes, 0, pBytes.length);
356 } catch (InvalidCipherTextException e) {
357 throw new GordianCryptoException("Failed to decrypt data", e);
358 }
359 }
360 }
361 }