0%

Android 解析 WAPI 证书工具类

依赖

implementation("org.bouncycastle:bcprov-debug-jdk15on:1.64")

代码

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.asn1.x9.X9ECParametersHolder;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.*;

/**
 * 国家密码管理局无线局域网密钥工具类
 */
public class WAPIUtil {

    /**
     * 中国无线 LAN 标准 (GB 15629.11-2003)
     * http://www.chinabwips.org.cn/doc/101.pdf
     *
     * {@link GMObjectIdentifiers#wapip192v1}
     */
    public static final ASN1ObjectIdentifier china_wapip192v1 = new ASN1ObjectIdentifier("1.2.156.11235.1.1.2.1");

    /**
     * 国密算法: WAPI_P192_V1
     *
     * {@link WAPIUtil#china_wapip192v1}
     * {@link GMObjectIdentifiers#wapip192v1}
     * {@link GMNamedCurves#wapip192v1}
     */
    public static final String NAME_WAPI_P192_V1 = "wapip192v1";

    /**
     * 国密算法: SM2_P256_V1
     *
     * {@link GMObjectIdentifiers#sm2p256v1}
     * {@link GMNamedCurves#sm2p256v1}
     */
    public static final String NAME_SM2_P256_V1 = "sm2p256v1";

    private static final SecureRandom SECURE_RANDOM = new SecureRandom();

    static {
        try {
            Field field = GMNamedCurves.class.getDeclaredField(NAME_WAPI_P192_V1);
            field.setAccessible(true);
            X9ECParametersHolder holder = (X9ECParametersHolder) field.get(null);
            Method method = GMNamedCurves.class.getDeclaredMethod(
                    "defineCurve", String.class,
                    ASN1ObjectIdentifier.class, X9ECParametersHolder.class
            );
            method.setAccessible(true);
            method.invoke(null, NAME_WAPI_P192_V1, china_wapip192v1, holder);
        } catch (Exception e) {
            e.printStackTrace();
        }

        Security.addProvider(new BouncyCastleProvider());
    }



    public static byte[] encrypt(PublicKey publicKey, byte[] data) throws InvalidKeyException, InvalidCipherTextException {
        return processBlock(true, publicKey, data);
    }

    public static byte[] decrypt(PrivateKey privateKey, byte[] data) throws InvalidKeyException, InvalidCipherTextException {
        return processBlock(false, privateKey, data);
    }

    public static byte[] sign(PrivateKey privateKey, byte[] id, byte[] data) throws InvalidKeyException, CryptoException {
        SM2Signer sm2Signer = getSM2Signer(true, privateKey, id);
        sm2Signer.update(data, 0, data.length);
        return sm2Signer.generateSignature();
    }

    public static boolean verify(PublicKey publicKey, byte[] id, byte[] sign) throws InvalidKeyException {
        return getSM2Signer(false, publicKey, id) .verifySignature(sign);
    }

    public static List<X509Certificate> parseCertificate(String pem) throws GeneralSecurityException {
        List<byte[]> bytesList = parseObjectFromPem(pem, "CERTIFICATE");
        List<X509Certificate> result = new ArrayList<>();
        for (byte[] bytes : bytesList) {
            result.add(parseCertificate(bytes));
        }
        return result;
    }

    public static X509Certificate parseCertificate(byte[] bytes) throws GeneralSecurityException {
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
        return (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(bytes));
    }

    public static BCECPrivateKey parsePrivateKey(String pem) throws GeneralSecurityException {
        List<byte[]> bytesList = parseObjectFromPem(pem, "EC PRIVATE KEY");
        byte[] bytes = bytesList.get(0);
        return parsePrivateKey(NAME_SM2_P256_V1, bytes);
    }

    public static BCECPrivateKey parsePrivateKey(String name, byte[] bytes) throws GeneralSecurityException {
        X9ECParameters ecParameters = GMNamedCurves.getByName(name);
        ECParameterSpec ecParameterSpec = new ECParameterSpec(ecParameters.getCurve(), ecParameters.getG(), ecParameters.getN(), ecParameters.getH());
        BigInteger bigIntegerD = new BigInteger(bytes);
        KeyFactory keyFactory = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME);
        return (BCECPrivateKey) keyFactory.generatePrivate(new ECPrivateKeySpec(bigIntegerD, ecParameterSpec));
    }

    /**
     * 从 pem 文件解析密钥
     * @param pem
     * @param type "CERTIFICATE"/"EC PRIVATE KEY"
     * @return
     */
    public static List<byte[]> parseObjectFromPem(String pem, String type) throws InvalidKeyException {
        List<byte[]> result = new ArrayList<>();
        PemReader pemReader = new PemReader(new StringReader(pem));
        try {
            PemObject pemObject;
            while ((pemObject = pemReader.readPemObject()) != null) {
                if (Objects.equals(type, pemObject.getType())) {
                    result.add(pemObject.getContent());
                }
            }
        } catch (IOException e) {
            throw new InvalidKeyException("read key failed", e);
        }
        if (result.isEmpty()) {
            throw new InvalidKeyException("not found key");
        }
        return result;
    }

    private static byte[] processBlock(boolean forEncryption, Key key, byte[] data) throws InvalidKeyException, InvalidCipherTextException {
        CipherParameters cipherParameters;
        if (forEncryption) {
            PublicKey publicKey = (PublicKey) key;
            cipherParameters = new ParametersWithRandom(ECUtil.generatePublicKeyParameter(publicKey), SECURE_RANDOM);
        } else {
            PrivateKey privateKey = (PrivateKey) key;
            cipherParameters = ECUtil.generatePrivateKeyParameter(privateKey);
        }
        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(forEncryption, cipherParameters);
        return sm2Engine.processBlock(data, 0, data.length);
    }

    private static SM2Signer getSM2Signer(boolean forSigning, Key key, byte[] id) throws InvalidKeyException {
        CipherParameters cipherParameters;
        if (forSigning) {
            PrivateKey privateKey = (PrivateKey) key;
            cipherParameters = ECUtil.generatePrivateKeyParameter(privateKey);
        } else {
            PublicKey publicKey = (PublicKey) key;
            cipherParameters = ECUtil.generatePublicKeyParameter(publicKey);
        }
        SM2Signer sm2Signer = new SM2Signer();
        sm2Signer.init(forSigning, new ParametersWithID(new ParametersWithRandom(cipherParameters, SECURE_RANDOM), id));
        return sm2Signer;
    }
}
  • 本文作者: 6x
  • 本文链接: https://6xyun.cn/article/177
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-ND 许可协议。转载请注明出处!