View Javadoc
1   /*
2    * GordianKnot: Security Suite
3    * Copyright 2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  
18  package io.github.tonywasher.joceanus.gordianknot.impl.bc.encrypt;
19  
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.encrypt.spec.GordianSM2EncryptionSpec;
23  import io.github.tonywasher.joceanus.gordianknot.api.encrypt.spec.GordianSM2EncryptionType;
24  import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianKeyPair;
25  import io.github.tonywasher.joceanus.gordianknot.impl.bc.digest.BouncyDigest;
26  import io.github.tonywasher.joceanus.gordianknot.impl.bc.keypair.BouncyKeyPair;
27  import io.github.tonywasher.joceanus.gordianknot.impl.bc.keypair.BouncyKeyPair.BouncyPrivateKey;
28  import io.github.tonywasher.joceanus.gordianknot.impl.bc.keypair.BouncyKeyPair.BouncyPublicKey;
29  import io.github.tonywasher.joceanus.gordianknot.impl.core.base.GordianBaseFactory;
30  import io.github.tonywasher.joceanus.gordianknot.impl.core.encrypt.GordianCoreEncryptor;
31  import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianCryptoException;
32  import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.encrypt.GordianCoreEncryptorSpec;
33  import org.bouncycastle.crypto.InvalidCipherTextException;
34  import org.bouncycastle.crypto.engines.SM2Engine;
35  import org.bouncycastle.crypto.engines.SM2Engine.Mode;
36  import org.bouncycastle.crypto.params.ParametersWithRandom;
37  
38  /**
39   * SM2 Encryptor.
40   */
41  public class BouncySM2Encryptor
42          extends GordianCoreEncryptor {
43      /**
44       * The underlying encryptor.
45       */
46      private final SM2Engine theEncryptor;
47  
48      /**
49       * Constructor.
50       *
51       * @param pFactory the factory
52       * @param pSpec    the encryptorSpec
53       * @throws GordianException on error
54       */
55      BouncySM2Encryptor(final GordianBaseFactory pFactory,
56                         final GordianCoreEncryptorSpec pSpec) throws GordianException {
57          /* Initialise underlying cipher */
58          super(pFactory, pSpec);
59          final GordianDigestFactory myFactory = pFactory.getDigestFactory();
60          final GordianSM2EncryptionSpec mySpec = pSpec.getSM2EncryptionSpec();
61          final BouncyDigest myDigest = (BouncyDigest) myFactory.createDigest(mySpec.getDigestSpec());
62          final Mode mySM2Mode = mySpec.getEncryptionType() == GordianSM2EncryptionType.C1C2C3
63                  ? Mode.C1C2C3 : Mode.C1C3C2;
64          theEncryptor = new SM2Engine(myDigest.getDigest(), mySM2Mode);
65      }
66  
67      @Override
68      protected BouncyPublicKey<?> getPublicKey() {
69          return (BouncyPublicKey<?>) super.getPublicKey();
70      }
71  
72      @Override
73      protected BouncyPrivateKey<?> getPrivateKey() {
74          return (BouncyPrivateKey<?>) super.getPrivateKey();
75      }
76  
77      @Override
78      public void initForEncrypt(final GordianKeyPair pKeyPair) throws GordianException {
79          /* Initialise underlying cipher */
80          BouncyKeyPair.checkKeyPair(pKeyPair);
81          super.initForEncrypt(pKeyPair);
82  
83          /* Initialise for encryption */
84          final ParametersWithRandom myParms = new ParametersWithRandom(getPublicKey().getPublicKey(), getRandom());
85          theEncryptor.init(true, myParms);
86      }
87  
88      @Override
89      public void initForDecrypt(final GordianKeyPair pKeyPair) throws GordianException {
90          /* Initialise underlying cipher */
91          BouncyKeyPair.checkKeyPair(pKeyPair);
92          super.initForDecrypt(pKeyPair);
93  
94          /* Initialise for decryption */
95          theEncryptor.init(false, getPrivateKey().getPrivateKey());
96      }
97  
98      @Override
99      public byte[] encrypt(final byte[] pBytes) throws GordianException {
100         try {
101             /* Check that we are in encryption mode */
102             checkMode(GordianEncryptMode.ENCRYPT);
103 
104             /* Encrypt the message */
105             return theEncryptor.processBlock(pBytes, 0, pBytes.length);
106         } catch (InvalidCipherTextException e) {
107             throw new GordianCryptoException("Failed to encrypt data", e);
108         }
109     }
110 
111     @Override
112     public byte[] decrypt(final byte[] pBytes) throws GordianException {
113         try {
114             /* Check that we are in decryption mode */
115             checkMode(GordianEncryptMode.DECRYPT);
116 
117             /* Decrypt the message */
118             return theEncryptor.processBlock(pBytes, 0, pBytes.length);
119         } catch (InvalidCipherTextException e) {
120             throw new GordianCryptoException("Failed to decrypt data", e);
121         }
122     }
123 }