All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xipki.security.pkcs11.emulator.SM2Signer Maven / Gradle / Ivy

/*
 *
 * Copyright (c) 2013 - 2019 Lijun Liao
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.xipki.security.pkcs11.emulator;

import java.io.IOException;
import java.math.BigInteger;
import java.security.SecureRandom;

import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.signers.DSAKCalculator;
import org.bouncycastle.crypto.signers.RandomDSAKCalculator;
import org.bouncycastle.math.ec.ECConstants;
import org.bouncycastle.math.ec.ECMultiplier;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.math.ec.FixedPointCombMultiplier;
import org.xipki.security.HashAlgo;
import org.xipki.security.util.GMUtil;

/**
 * The RAW SM2 Digital Signature algorithm. The message is the hash value over the real message.
 *
 * @author Lijun Liao
 *
 */
class SM2Signer {
  // CHECKSTYLE:SKIP
  private final DSAKCalculator kCalculator = new RandomDSAKCalculator();

  private final Digest digest;

  private final ECDomainParameters ecParams;

  private final ECKeyParameters ecKey;

  private final ECPoint pubPoint;

  public SM2Signer(CipherParameters param) {
    if (param instanceof ParametersWithRandom) {
      ParametersWithRandom rdmParam = (ParametersWithRandom) param;

      ecKey = (ECKeyParameters)rdmParam.getParameters();
      ecParams = ecKey.getParameters();
      kCalculator.init(ecParams.getN(), rdmParam.getRandom());
    } else {
      ecKey = (ECKeyParameters) param;
      ecParams = ecKey.getParameters();
      kCalculator.init(ecParams.getN(), new SecureRandom());
    }

    if (!GMUtil.isSm2primev2Curve(ecKey.getParameters().getCurve())) {
      throw new IllegalArgumentException("Given EC key is not of the curve sm2primev2");
    }

    this.pubPoint = new FixedPointCombMultiplier().multiply(ecParams.getG(),
        ((ECPrivateKeyParameters)ecKey).getD()).normalize();

    this.digest = HashAlgo.SM3.createDigest();
  } // constructor

  public byte[] generateSignatureForMessage(byte[] userId, byte[] message) throws CryptoException {
    // CHECKSTYLE:SKIP
    byte[] z;
    if (userId == null) {
      // use default userId
      z = GMUtil.getSM2Z(GMObjectIdentifiers.sm2p256v1,
          pubPoint.getAffineXCoord().toBigInteger(),
          pubPoint.getAffineYCoord().toBigInteger());
    } else {
      z = GMUtil.getSM2Z(userId, GMObjectIdentifiers.sm2p256v1,
        pubPoint.getAffineXCoord().toBigInteger(),
        pubPoint.getAffineYCoord().toBigInteger());
    }
    digest.reset();
    digest.update(z, 0, z.length);
    digest.update(message, 0, message.length);
    byte[] hash = new byte[digest.getDigestSize()];
    digest.doFinal(hash, 0);
    return generateSignatureForHash(hash);
  } // method generateSignatureForMessage

  // CHECKSTYLE:SKIP
  public byte[] generateSignatureForHash(byte[] eHash) throws CryptoException {
    BigInteger n = ecParams.getN();
    BigInteger e = new BigInteger(1, eHash);
    BigInteger d = ((ECPrivateKeyParameters)ecKey).getD();

    BigInteger r;
    BigInteger s;

    ECMultiplier basePointMultiplier = new FixedPointCombMultiplier();

    // 5.2.1 Draft RFC:  SM2 Public Key Algorithms
    do { // generate s
      BigInteger k;
      do { // generate r
        // A3
        k = kCalculator.nextK();

        // A4
        ECPoint p = basePointMultiplier.multiply(ecParams.getG(), k).normalize();

        // A5
        r = e.add(p.getAffineXCoord().toBigInteger()).mod(n);
      } while (r.equals(ECConstants.ZERO) || r.add(k).equals(n));

      // A6
      // CHECKSTYLE:SKIP
      BigInteger dPlus1ModN = d.add(ECConstants.ONE).modInverse(n);

      s = k.subtract(r.multiply(d)).mod(n);
      s = dPlus1ModN.multiply(s).mod(n);
    } while (s.equals(ECConstants.ZERO));

    // A7
    try {
      ASN1EncodableVector v = new ASN1EncodableVector();
      v.add(new ASN1Integer(r));
      v.add(new ASN1Integer(s));
      return new DERSequence(v).getEncoded(ASN1Encoding.DER);
    } catch (IOException ex) {
      throw new CryptoException("unable to encode signature: " + ex.getMessage(), ex);
    }
  } // method generateSignatureForHash
  // CHECKSTYLE:ON

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy