SM2加密解决java与iOS端加解密不配套问题

本文档详细介绍了在Java和iOS平台上,SM2加解密过程中遇到的兼容性问题。问题源于SM2加密结果在不同平台上的顺序差异。通过调整Java端的SM2代码,将加密结果顺序更改为C1C3C2,从而解决了iOS加密的Java无法解密的问题。文中提供了关键代码示例和相关依赖库。
摘要由CSDN通过智能技术生成

SM2加密解决java与iOS端加解密不配套问题

问题描述

使用java开发的SM2加解密,由java层生成SM2公私钥,iOS、Android(因和java层一致,暂忽略)层使用公钥做加密,java层做解密。

  1. java生成的公私钥在iOS和java层单独做加解密均可用。
  2. iOS层加密结果java层无法解密

问题判定

SM2非对称加密的结果由C1,C2,C3三部分组成。其中C1是生成随机数的计算出的椭圆曲线点,C2是密文数据,C3是SM3的摘要值。最开始的国密标准的结果是按C1C2C3顺序的,新标准的是按C1C3C2顺序存放的。java层SM2结果是C1C2C3,iOS(C)的结果是C1C3C2。

以下调整java层SM2代码为C1C3C2。

代码

使用方法:使用方法参考下方SM2Util中main方法。
使用jar包为:bcprov-jdk15on-1.65.jar
maven引入:

			 <sm2.version>1.65</sm2.version>
			<!--SM2加密-->
            <dependency>
                <groupId>org.bouncycastle</groupId>
                <artifactId>bcprov-jdk15on</artifactId>
                <version>${sm2.version}</version>
            </dependency>

SM2公私钥实体类SM2KeyPair :

/**
 *  SM2公私钥实体类
 */
public class SM2KeyPair {
   

    /** 公钥 */
    private String publicKeyStr;

    /** 私钥 */
    private String privateKeyStr;

    SM2KeyPair(String publicKeyStr, String privateKeyStr) {
   
        this.publicKeyStr = publicKeyStr;
        this.privateKeyStr = privateKeyStr;
    }

    public String getPublicKeyStr() {
   
        return publicKeyStr;
    }

    public String getPrivateKeyStr() {
   
        return privateKeyStr;
    }

}

SM2加减密实现类ZSM2Engine:

import java.io.IOException;
import java.math.BigInteger;
import java.security.SecureRandom;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.math.ec.ECFieldElement;
import org.bouncycastle.math.ec.ECMultiplier;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.math.ec.FixedPointCombMultiplier;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.Memoable;
import org.bouncycastle.util.Pack;
/**
 * SM2加解密实现类
 */
public class ZSM2Engine {
   

    public enum Mode {
   
        C1C2C3, C1C3C2;
    }

    private final Digest digest;
    private final Mode mode;

    private boolean forEncryption;
    private ECKeyParameters ecKey;
    private ECDomainParameters ecParams;
    private int curveLength;
    private SecureRandom random;
    /***
     * 默认采用国标:C1||C3||C2
     */
    public ZSM2Engine() {
   
        this(new SM3Digest(), Mode.C1C3C2);
    }

    public ZSM2Engine(Mode mode) {
   
        this(new SM3Digest(), mode);
    }

    public ZSM2Engine(Digest digest) {
   
        this(digest, Mode.C1C2C3);
    }

    public ZSM2Engine(Digest digest, Mode mode) {
   
        if (mode == null) {
   
            throw new IllegalArgumentException("mode cannot be NULL");
        }
        this.digest = digest;
        this.mode = mode;
    }

    /**
     * 初始化
     * @param forEncryption true-公钥加密, false-私钥解密
     * @param param 密码参数,从中获取公或私钥、及椭圆曲线相关参数
     */
    public void init(boolean forEncryption, CipherParameters param) {
   
        this.forEncryption = forEncryption;

        if (forEncryption) {
   
            ParametersWithRandom rParam = (ParametersWithRandom) param;

            ecKey = (ECKeyParameters) rParam.getParameters();
            ecParams = ecKey.getParameters();

            ECPoint s = ((ECPublicKeyParameters) ecKey).getQ().multiply(ecParams.getH());
            if (s.isInfinity()) {
   
                throw new IllegalArgumentException("invalid key: [h]Q at infinity");
            }

            random = rParam.getRandom();
        } else {
   
            ecKey = (ECKeyParameters) param;
            ecParams = ecKey.getParameters();
        }

        curveLength = (ecParams.getCurve().getFieldSize() + 7) / 8;
    }

    /**
     * 进行加密、或解密
     * @param in
     * @param inOff
     * @param inLen
     * @return
     * @throws InvalidCipherTextException
     */
    public byte[] processBlock(
            byte[] in,
            int inOff,
            int inLen)
            throws IOException, InvalidCipherTextException {
   
        if (forEncryption) {
   
            return encrypt(in, inOff, inLen);
        } else {
   
            return decrypt(in, inOff, inLen);
        }
    }

    public int getOutputSize(int inputLen) {
   
        return (1 + 2 * curveLength) + inputLen + digest.getDigestSize();
    }

    protected ECMultiplier createBasePointMultiplier() {
   
        return new FixedPointCombMultiplier();
    }

    private byte[] encrypt(byte[] in, int inOff, int inLen)
            throws IOException {
   
        byte[] c2 = new byte[inLen];

        System.arraycopy
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>