1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package io.github.tonywasher.joceanus.gordianknot.impl.jca.encrypt;
19
20
21 import io.github.tonywasher.joceanus.gordianknot.api.base.GordianException;
22 import io.github.tonywasher.joceanus.gordianknot.api.base.GordianLength;
23 import io.github.tonywasher.joceanus.gordianknot.api.digest.spec.GordianDigestSpec;
24 import io.github.tonywasher.joceanus.gordianknot.api.digest.spec.GordianDigestType;
25 import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianKeyPair;
26 import io.github.tonywasher.joceanus.gordianknot.impl.core.base.GordianBaseFactory;
27 import io.github.tonywasher.joceanus.gordianknot.impl.core.encrypt.GordianCoreEncryptor;
28 import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianCryptoException;
29 import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.encrypt.GordianCoreEncryptorSpec;
30 import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.encrypt.GordianCoreSM2EncryptionSpec;
31 import io.github.tonywasher.joceanus.gordianknot.impl.jca.keypair.JcaKeyPair;
32 import io.github.tonywasher.joceanus.gordianknot.impl.jca.keypair.JcaKeyPair.JcaPrivateKey;
33 import io.github.tonywasher.joceanus.gordianknot.impl.jca.keypair.JcaKeyPair.JcaPublicKey;
34
35 import javax.crypto.BadPaddingException;
36 import javax.crypto.Cipher;
37 import javax.crypto.IllegalBlockSizeException;
38 import java.security.InvalidKeyException;
39
40
41
42
43 public class JcaHybridEncryptor
44 extends GordianCoreEncryptor {
45
46
47
48 private static final String ERROR_INIT = "Failed to initialise";
49
50
51
52
53 private final Cipher theEncryptor;
54
55
56
57
58
59
60
61
62 JcaHybridEncryptor(final GordianBaseFactory pFactory,
63 final GordianCoreEncryptorSpec pSpec) throws GordianException {
64
65 super(pFactory, pSpec);
66 theEncryptor = JcaEncryptor.getJavaEncryptor(getAlgorithmName(pSpec));
67 }
68
69 @Override
70 protected JcaPublicKey getPublicKey() {
71 return (JcaPublicKey) super.getPublicKey();
72 }
73
74 @Override
75 protected JcaPrivateKey getPrivateKey() {
76 return (JcaPrivateKey) super.getPrivateKey();
77 }
78
79 @Override
80 public void initForEncrypt(final GordianKeyPair pKeyPair) throws GordianException {
81 try {
82
83 JcaKeyPair.checkKeyPair(pKeyPair);
84 super.initForEncrypt(pKeyPair);
85
86
87 theEncryptor.init(Cipher.ENCRYPT_MODE, getPublicKey().getPublicKey(), getRandom());
88 } catch (InvalidKeyException e) {
89 throw new GordianCryptoException(ERROR_INIT, e);
90 }
91 }
92
93 @Override
94 public void initForDecrypt(final GordianKeyPair pKeyPair) throws GordianException {
95 try {
96
97 JcaKeyPair.checkKeyPair(pKeyPair);
98 super.initForDecrypt(pKeyPair);
99
100
101 theEncryptor.init(Cipher.DECRYPT_MODE, getPrivateKey().getPrivateKey());
102 } catch (InvalidKeyException e) {
103 throw new GordianCryptoException(ERROR_INIT, e);
104 }
105 }
106
107 @Override
108 public byte[] encrypt(final byte[] pBytes) throws GordianException {
109
110 checkMode(GordianEncryptMode.ENCRYPT);
111
112
113 return processData(pBytes);
114 }
115
116 @Override
117 public byte[] decrypt(final byte[] pBytes) throws GordianException {
118
119 checkMode(GordianEncryptMode.DECRYPT);
120
121
122 return processData(pBytes);
123 }
124
125
126
127
128
129
130
131
132 private byte[] processData(final byte[] pData) throws GordianException {
133 try {
134 return theEncryptor.doFinal(pData, 0, pData.length);
135 } catch (IllegalBlockSizeException
136 | BadPaddingException e) {
137 throw new GordianCryptoException("Failed to process data", e);
138 }
139 }
140
141
142
143
144
145
146
147 private static String getAlgorithmName(final GordianCoreEncryptorSpec pSpec) {
148
149 final GordianCoreSM2EncryptionSpec mySpec = pSpec.getSM2EncryptionSpec();
150 final GordianDigestSpec myDigestSpec = mySpec.getDigestSpec();
151 final GordianDigestType myDigestType = myDigestSpec.getDigestType();
152 return switch (myDigestType) {
153 case SHA2 -> "SM2withSHA" + myDigestSpec.getDigestLength();
154 case BLAKE2 -> "SM2withBlake2" + (GordianLength.LEN_512.equals(myDigestSpec.getDigestLength()) ? "b" : "s");
155 default -> "SM2with" + myDigestType;
156 };
157 }
158 }