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

org.xipki.security.util.GMUtil Maven / Gradle / Ivy

/*
 *
 * Copyright (c) 2013 - 2020 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.util;

import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECFieldElement;
import org.bouncycastle.util.BigIntegers;
import org.xipki.util.Hex;

import java.math.BigInteger;
import java.security.spec.EllipticCurve;

/**
 * Chinese GM/SM Util class.
 * @author Lijun Liao
 *
 */
public class GMUtil {

  private static final byte[] defaultIDA =
      new byte[]{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
          0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}; // the default value

  private static final byte[] sm2primev2A =
      Hex.decode("fffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc");
  private static final byte[] sm2primev2B =
      Hex.decode("28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93");
  private static final byte[] sm2primev2Gx =
      Hex.decode("32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7");
  private static final byte[] sm2primev2Gy =
      Hex.decode("bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0");
  private static final int sm2primev2FieldSize = 32;

  private static final BigInteger bnSm2primev2B = new BigInteger(1, sm2primev2B);

  private GMUtil() {
  }

  public static byte[] getSM2Z(ASN1ObjectIdentifier curveOid, BigInteger pubPointX, BigInteger pubPointY) {
    return getSM2Z(defaultIDA, curveOid, pubPointX, pubPointY);
  }

  public static byte[] getDefaultIDA() {
    return defaultIDA.clone();
  }

  public static byte[] getSM2Z(
      byte[] userID, ASN1ObjectIdentifier curveOid, BigInteger pubPointX, BigInteger pubPointY) {
    SM3Digest digest = new SM3Digest();

    addUserId(digest, userID == null ? defaultIDA : userID);

    int fieldSize;
    if (GMObjectIdentifiers.sm2p256v1.equals(curveOid)) {
      fieldSize = sm2primev2FieldSize;
      digest.update(sm2primev2A,  0, fieldSize);
      digest.update(sm2primev2B,  0, fieldSize);
      digest.update(sm2primev2Gx, 0, fieldSize);
      digest.update(sm2primev2Gy, 0, fieldSize);
    } else {
      X9ECParameters ecParams = GMNamedCurves.getByOID(curveOid);
      fieldSize = (ecParams.getCurve().getFieldSize() + 7) / 8;
      addFieldElement(digest, ecParams.getCurve().getA());
      addFieldElement(digest, ecParams.getCurve().getB());
      addFieldElement(digest, ecParams.getG().getAffineXCoord());
      addFieldElement(digest, ecParams.getG().getAffineYCoord());
    }

    digest.update(BigIntegers.asUnsignedByteArray(fieldSize, pubPointX), 0, fieldSize);
    digest.update(BigIntegers.asUnsignedByteArray(fieldSize, pubPointY), 0, fieldSize);

    byte[] result = new byte[digest.getDigestSize()];
    digest.doFinal(result, 0);
    return result;
  } // method getSM2Z

  private static void addUserId(Digest digest, byte[] userId) {
    int len = userId.length * 8;
    if (len > 0xFFFF) {
      throw new IllegalArgumentException("userId too long");
    }

    digest.update((byte)(len >> 8 & 0xFF));
    digest.update((byte)(len & 0xFF));
    digest.update(userId, 0, userId.length);
  }

  private static void addFieldElement(Digest digest, ECFieldElement element) {
    byte[] encoded = element.getEncoded();
    digest.update(encoded, 0, encoded.length);
  }

  public static boolean isSm2primev2Curve(EllipticCurve curve) {
    return curve.getB().equals(bnSm2primev2B);
  }

  public static boolean isSm2primev2Curve(ECCurve curve) {
    return curve.getB().toBigInteger().equals(bnSm2primev2B);
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy