1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.github.tonywasher.joceanus.gordianknot.impl.jca.sign;
18
19 import io.github.tonywasher.joceanus.gordianknot.api.base.GordianException;
20 import io.github.tonywasher.joceanus.gordianknot.api.digest.spec.GordianDigestType;
21 import io.github.tonywasher.joceanus.gordianknot.api.keypair.spec.GordianKeyPairType;
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.core.base.GordianBaseFactory;
25 import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianCryptoException;
26 import io.github.tonywasher.joceanus.gordianknot.impl.core.sign.GordianCoreSignature;
27 import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.keypair.GordianCoreKeyPairType;
28 import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.sign.GordianCoreSignatureSpec;
29 import io.github.tonywasher.joceanus.gordianknot.impl.jca.base.JcaProvider;
30 import io.github.tonywasher.joceanus.gordianknot.impl.jca.keypair.JcaKeyPair;
31 import org.bouncycastle.jcajce.spec.ContextParameterSpec;
32
33 import java.security.InvalidAlgorithmParameterException;
34 import java.security.InvalidKeyException;
35 import java.security.NoSuchAlgorithmException;
36 import java.security.Signature;
37 import java.security.SignatureException;
38
39
40
41
42 public abstract class JcaSignature
43 extends GordianCoreSignature {
44
45
46
47 private static final String SIG_ERROR = "Signature error";
48
49
50
51
52 private static final String RSA_PSSMGF1_ALGOBASE = "withRSAandMGF1";
53
54
55
56
57 private static final String RSA_PSS128_ALGOBASE = "withRSAandSHAKE128";
58
59
60
61
62 private static final String RSA_PSS256_ALGOBASE = "withRSAandSHAKE256";
63
64
65
66
67 private static final String RSA_PSSSHAKE_ALGOBASE = "withRSA/PSS";
68
69
70
71
72 private static final String RSA_X931_ALGOBASE = "withRSA/X9.31";
73
74
75
76
77 private static final String RSA_ISO9796D2_ALGOBASE = "withRSA/ISO9796-2";
78
79
80
81
82 private static final String RSA_PREHASH_ALGOBASE = "withRSAEncryption";
83
84
85
86
87 private static final String EC_DSA_ALGOBASE = "withECDSA";
88
89
90
91
92 private static final String EC_DDSA_ALGOBASE = "withECDDSA";
93
94
95
96
97 private static final String DSA_ALGOBASE = "withDSA";
98
99
100
101
102 private static final String DDSA_ALGOBASE = "withDDSA";
103
104
105
106
107 private static final String EC_NR_ALGOBASE = "withECNR";
108
109
110
111
112 private static final String EC_SM2_ALGOBASE = "WITHSM2";
113
114
115
116
117 static final String PQC_HASH_PFX = "HASH-";
118
119
120
121
122 private Signature theSigner;
123
124
125
126
127
128
129
130 JcaSignature(final GordianBaseFactory pFactory,
131 final GordianSignatureSpec pSpec) {
132 super(pFactory, pSpec);
133 }
134
135
136
137
138
139
140 protected void setSigner(final Signature pSigner) {
141 theSigner = pSigner;
142 }
143
144
145
146
147
148
149 protected Signature getSigner() {
150 return theSigner;
151 }
152
153 @Override
154 public void initForSigning(final GordianNewSignParams pParams) throws GordianException {
155
156 super.initForSigning(pParams);
157 final JcaKeyPair myPair = getKeyPair();
158 final byte[] myContext = getContext();
159 JcaKeyPair.checkKeyPair(myPair);
160
161
162 try {
163
164 final GordianCoreKeyPairType myType = GordianCoreKeyPairType.mapCoreType(getSignatureSpec().getKeyPairType());
165 final boolean useRandom = myType.useRandomForSignatures();
166
167
168 if (useRandom) {
169 getSigner().initSign(myPair.getPrivateKey().getPrivateKey(), getRandom());
170 } else {
171 getSigner().initSign(myPair.getPrivateKey().getPrivateKey());
172 }
173
174
175 if (getSignatureSpec().supportsContext()) {
176
177 final ContextParameterSpec mySpec = myContext == null ? null : new ContextParameterSpec(myContext);
178 getSigner().setParameter(mySpec);
179 }
180
181
182 } catch (InvalidKeyException
183 | InvalidAlgorithmParameterException e) {
184 throw new GordianCryptoException(SIG_ERROR, e);
185 }
186 }
187
188 @Override
189 public void initForVerify(final GordianNewSignParams pParams) throws GordianException {
190
191 super.initForVerify(pParams);
192 final JcaKeyPair myPair = getKeyPair();
193 final byte[] myContext = getContext();
194 JcaKeyPair.checkKeyPair(myPair);
195
196
197 try {
198
199 getSigner().initVerify(myPair.getPublicKey().getPublicKey());
200
201
202 if (getSignatureSpec().supportsContext()) {
203
204 final ContextParameterSpec mySpec = myContext == null ? null : new ContextParameterSpec(myContext);
205 getSigner().setParameter(mySpec);
206 }
207
208
209 } catch (InvalidKeyException
210 | InvalidAlgorithmParameterException e) {
211 throw new GordianCryptoException(SIG_ERROR, e);
212 }
213 }
214
215 @Override
216 public void update(final byte[] pBytes,
217 final int pOffset,
218 final int pLength) {
219 try {
220 theSigner.update(pBytes, pOffset, pLength);
221 } catch (SignatureException e) {
222 throw new IllegalArgumentException(e);
223 }
224 }
225
226 @Override
227 public void update(final byte pByte) {
228 try {
229 theSigner.update(pByte);
230 } catch (SignatureException e) {
231 throw new IllegalArgumentException(e);
232 }
233 }
234
235 @Override
236 public byte[] sign() throws GordianException {
237
238 checkMode(GordianSignatureMode.SIGN);
239
240
241 try {
242 return getSigner().sign();
243
244 } catch (SignatureException e) {
245 throw new GordianCryptoException(SIG_ERROR, e);
246 }
247 }
248
249 @Override
250 public boolean verify(final byte[] pSignature) throws GordianException {
251
252 checkMode(GordianSignatureMode.VERIFY);
253
254
255 try {
256 return getSigner().verify(pSignature);
257 } catch (SignatureException e) {
258 throw new GordianCryptoException(SIG_ERROR, e);
259 }
260 }
261
262 @Override
263 public void reset() {
264
265 }
266
267 @Override
268 protected JcaKeyPair getKeyPair() {
269 return (JcaKeyPair) super.getKeyPair();
270 }
271
272
273
274
275
276
277
278 static String getSignatureBase(final GordianSignatureSpec pSignatureSpec) {
279
280 if (GordianKeyPairType.SM2.equals(pSignatureSpec.getKeyPairType())) {
281 return EC_SM2_ALGOBASE;
282 }
283
284
285 final GordianCoreSignatureSpec mySpec = (GordianCoreSignatureSpec) pSignatureSpec;
286 final boolean isDSA = GordianKeyPairType.DSA.equals(pSignatureSpec.getKeyPairType());
287 final boolean isSHAKE = GordianDigestType.SHAKE.equals(mySpec.getDigestSpec().getDigestType());
288
289
290 return switch (pSignatureSpec.getSignatureType()) {
291 case PSSMGF1 -> RSA_PSSMGF1_ALGOBASE;
292 case PSS128 -> isSHAKE ? RSA_PSSSHAKE_ALGOBASE : RSA_PSS128_ALGOBASE;
293 case PSS256 -> isSHAKE ? RSA_PSSSHAKE_ALGOBASE : RSA_PSS256_ALGOBASE;
294 case X931 -> RSA_X931_ALGOBASE;
295 case ISO9796D2 -> RSA_ISO9796D2_ALGOBASE;
296 case PREHASH -> RSA_PREHASH_ALGOBASE;
297 case DSA -> isDSA
298 ? DSA_ALGOBASE
299 : EC_DSA_ALGOBASE;
300 case DDSA -> isDSA
301 ? DDSA_ALGOBASE
302 : EC_DDSA_ALGOBASE;
303 case NR -> EC_NR_ALGOBASE;
304 default -> null;
305 };
306 }
307
308
309
310
311
312
313
314
315
316 static Signature getJavaSignature(final String pAlgorithm,
317 final boolean postQuantum) throws GordianException {
318
319 try {
320
321 return Signature.getInstance(pAlgorithm, postQuantum
322 ? JcaProvider.BCPQPROV
323 : JcaProvider.BCPROV);
324
325
326 } catch (NoSuchAlgorithmException e) {
327
328 throw new GordianCryptoException("Failed to create Signature", e);
329 }
330 }
331 }