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.sign;
19  
20  import io.github.tonywasher.joceanus.gordianknot.api.base.GordianException;
21  import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianKeyPair;
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.bc.keypair.BouncyKeyPair;
25  import io.github.tonywasher.joceanus.gordianknot.impl.bc.keypair.BouncyMLDSAKeyPair.BouncyMLDSAPrivateKey;
26  import io.github.tonywasher.joceanus.gordianknot.impl.bc.keypair.BouncyMLDSAKeyPair.BouncyMLDSAPublicKey;
27  import io.github.tonywasher.joceanus.gordianknot.impl.core.base.GordianBaseFactory;
28  import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianCryptoException;
29  import io.github.tonywasher.joceanus.gordianknot.impl.core.sign.GordianCoreSignature;
30  import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.keypair.GordianCoreKeyPairSpec;
31  import org.bouncycastle.crypto.CipherParameters;
32  import org.bouncycastle.crypto.CryptoException;
33  import org.bouncycastle.crypto.Signer;
34  import org.bouncycastle.crypto.params.ParametersWithContext;
35  import org.bouncycastle.crypto.params.ParametersWithRandom;
36  import org.bouncycastle.crypto.signers.HashMLDSASigner;
37  import org.bouncycastle.crypto.signers.MLDSASigner;
38  
39  /**
40   * MLDSA signer.
41   */
42  public class BouncyMLDSASignature
43          extends GordianCoreSignature {
44      /**
45       * The MLDSA Signer.
46       */
47      private Signer theSigner;
48  
49      /**
50       * Constructor.
51       *
52       * @param pFactory the factory
53       * @param pSpec    the signatureSpec.
54       */
55      BouncyMLDSASignature(final GordianBaseFactory pFactory,
56                           final GordianSignatureSpec pSpec) {
57          /* Initialise underlying class */
58          super(pFactory, pSpec);
59      }
60  
61      /**
62       * Create the signer according to the keyPair.
63       *
64       * @param pKeyPair the keyPair
65       * @return the signer
66       */
67      private static Signer createSigner(final GordianKeyPair pKeyPair) {
68          /* Determine whether this is a hashSigner */
69          final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeyPair.getKeyPairSpec();
70          final boolean isHash = myKeySpec.getMLDSASpec().isHash();
71  
72          /* Create the internal digests */
73          return isHash
74                  ? new HashMLDSASigner()
75                  : new MLDSASigner();
76      }
77  
78      @Override
79      public void initForSigning(final GordianNewSignParams pParams) throws GordianException {
80          /* Initialise detail */
81          super.initForSigning(pParams);
82          final BouncyKeyPair myPair = getKeyPair();
83          final byte[] myContext = getContext();
84          BouncyKeyPair.checkKeyPair(myPair);
85  
86          /* Initialise and set the signer */
87          theSigner = createSigner(myPair);
88          final BouncyMLDSAPrivateKey myPrivate = (BouncyMLDSAPrivateKey) myPair.getPrivateKey();
89          CipherParameters myParms = new ParametersWithRandom(myPrivate.getPrivateKey(), getRandom());
90          if (myContext != null) {
91              myParms = new ParametersWithContext(myParms, myContext);
92          }
93          theSigner.init(true, myParms);
94      }
95  
96      @Override
97      public void initForVerify(final GordianNewSignParams pParams) throws GordianException {
98          /* Initialise detail */
99          super.initForVerify(pParams);
100         final BouncyKeyPair myPair = getKeyPair();
101         final byte[] myContext = getContext();
102         BouncyKeyPair.checkKeyPair(myPair);
103 
104         /* Initialise and set the signer */
105         theSigner = createSigner(myPair);
106         final BouncyMLDSAPublicKey myPublic = (BouncyMLDSAPublicKey) myPair.getPublicKey();
107         CipherParameters myParms = myPublic.getPublicKey();
108         if (myContext != null) {
109             myParms = new ParametersWithContext(myParms, myContext);
110         }
111         theSigner.init(false, myParms);
112     }
113 
114     @Override
115     public void update(final byte[] pBytes,
116                        final int pOffset,
117                        final int pLength) {
118         theSigner.update(pBytes, pOffset, pLength);
119     }
120 
121     @Override
122     public void update(final byte pByte) {
123         theSigner.update(pByte);
124     }
125 
126     @Override
127     public void update(final byte[] pBytes) {
128         theSigner.update(pBytes, 0, pBytes.length);
129     }
130 
131     @Override
132     public void reset() {
133         theSigner.reset();
134     }
135 
136     @Override
137     protected BouncyKeyPair getKeyPair() {
138         return (BouncyKeyPair) super.getKeyPair();
139     }
140 
141     @Override
142     public byte[] sign() throws GordianException {
143         /* Check that we are in signing mode */
144         checkMode(GordianSignatureMode.SIGN);
145 
146         /* Sign the message */
147         try {
148             return theSigner.generateSignature();
149         } catch (CryptoException e) {
150             throw new GordianCryptoException("Failed to sign message", e);
151         }
152     }
153 
154     @Override
155     public boolean verify(final byte[] pSignature) throws GordianException {
156         /* Check that we are in verify mode */
157         checkMode(GordianSignatureMode.VERIFY);
158 
159         /* Verify the message */
160         return theSigner.verifySignature(pSignature);
161     }
162 }