JAVA中的提供的第三方jar包(比如BouncyCastle), 对于SM2加密的大都是c1c2c3格式。在Java体系内互相认证,问题不大,但如果与其他语言对接时, 就需要按照最新的国家标准, 将其转换成c1c3c2的asn1格式。

BouncyCastle 提供了一些类辅助,例如:

private static final int C1_LEN = 65;
private static final int C3_LEN = 32;
/**
     * 将c1c3c2转成标准的ASN1格式
     *
     * @param c1c3c2
     * @return
     * @throws IOException
     */
    public static byte[] changeC1C3C2ToAsn1(byte[] c1c3c2) throws IOException {
        byte[] c1 = Arrays.copyOfRange(c1c3c2, 0, C1_LEN);
        byte[] c3 = Arrays.copyOfRange(c1c3c2, C1_LEN, C1_LEN + C3_LEN);
        byte[] c2 = Arrays.copyOfRange(c1c3c2, C1_LEN + C3_LEN, c1c3c2.length);
        byte[] c1X = Arrays.copyOfRange(c1, 1, 33);
        byte[] c1Y = Arrays.copyOfRange(c1, 33, 65);
        ASN1Integer x = new ASN1Integer(c1X);
        ASN1Integer y = new ASN1Integer(c1Y);
        DEROctetString derDig = new DEROctetString(c3);
        DEROctetString derEnc = new DEROctetString(c2);
        ASN1EncodableVector v = new ASN1EncodableVector();
        v.add(x);
        v.add(y);
        v.add(derDig);
        v.add(derEnc);
        DERSequence seq = new DERSequence(v);
        return seq.getEncoded();
    }

    /**
     * 将ASN1格式转成c1c3c2
     *
     * @param asn1
     * @return
     * @throws IOException
     */
    public static byte[] changeAsn1ToC1C3C2(byte[] asn1) throws IOException {
        ASN1InputStream aIn = new ASN1InputStream(asn1);
        ASN1Sequence seq = (ASN1Sequence) aIn.readObject();
        BigInteger x = ASN1Integer.getInstance(seq.getObjectAt(0)).getValue();
        BigInteger y = ASN1Integer.getInstance(seq.getObjectAt(1)).getValue();
        byte[] c3 = ASN1OctetString.getInstance(seq.getObjectAt(2)).getOctets();
        byte[] c2 = ASN1OctetString.getInstance(seq.getObjectAt(3)).getOctets();
        // 不压缩
        ECPoint c1Point = x9ECParameters.getCurve().createPoint(x, y, false);
        byte[] c1 = c1Point.getEncoded();

        return ByteUtils.join(c1, c3, c2);
    }

但 BouncyCastle 各版本可能存在冲突,也不希望为了一个转换引入第三方包。这里我写了一个基于JDK的c1c3c2和asn1的转换。

其实,了解清楚asn1的格式就不难转换了:

ASN.1 = 48,len-bts,c1_asn1,c3_asn1(4,length_c3,c3),c2_asn1(4,len-bts,c2)
说明:
48:SEQUENCE(0x10) | CONSTRUCTED(0x20) 说明是有预定格式的序列
len-bts:数据内容的长度,就是后面字节长度,可能是多个字节(长度字节大小,长度字节)
c1_asn1:c1的Asn1格式(2,len_x,[0],byte_x,2,len_y,[0],byte_y)
c2_asn1len-bts是c2的数据内容的长度 ,可能是多个字节(长度字节大小,长度字节) 

具体代码如下:BigIntegers.java

public final class BigIntegers {
    /**
     * Return the passed in value as an unsigned byte array.
     *
     * @param value value to be converted.
     * @return a byte array without a leading zero byte if present in the signed encoding.
     */
    public static byte[] asUnsignedByteArray(BigInteger value) {
        byte[] bytes = value.toByteArray();

        if (bytes[0] == 0) {
            byte[] tmp = new byte[bytes.length - 1];

            System.arraycopy(bytes, 1, tmp, 0, tmp.length);

            return tmp;
        }

        return bytes;
    }

    /**
     * Return the passed in value as an unsigned byte array.
     *
     * @param value value to be converted.
     * @return a byte array without a leading zero byte if present in the signed encoding.
     */
    public static byte[] asUnsignedByteArray(int length, BigInteger value) {
        byte[] bytes = value.toByteArray();
        if (bytes.length == length) {
            return bytes;
        }

        int start = bytes[0] == 0 ? 1 : 0;
        int count = bytes.length - start;

        if (count > length) {
            throw new IllegalArgumentException("standard length exceeded for value");
        }

        byte[] tmp = new byte[length];
        System.arraycopy(bytes, start, tmp, tmp.length - count, count);
        return tmp;
    }

    public static BigInteger fromUnsignedByteArray(byte[] buf) {
        return new BigInteger(1, buf);
    }

    public static BigInteger fromUnsignedByteArray(byte[] buf, int off, int length) {
        byte[] mag = buf;
        if (off != 0 || length != buf.length) {
            mag = new byte[length];
            System.arraycopy(buf, off, mag, 0, length);
        }
        return new BigInteger(1, mag);
    }
}

Asn1Point.java

/**
 * ASN1
 * 格式: 2,len_x,[0],byte_x,2,len_y,[0],byte_y
 */
public static class Asn1Point {
    private static final byte PREFIX = 2;
    private byte[] x;
    private byte[] y;
    private boolean negativeR;
    private boolean negativeS;

    public static Asn1Point of(byte[] x, byte[] y) {
        Asn1Point asn1 = new Asn1Point();
        asn1.x = x;
        asn1.y = y;
        asn1.negativeR = x[0] < 0;
        asn1.negativeS = y[0] < 0;
        return asn1;
    }

    public static Asn1Point of(byte[] asn1) {
        int lenX = asn1[1];
        int lenY = asn1[lenX + 3];
        int idxX = 2;
        int idxY = asn1.length - lenY;
        byte[] r = new byte[lenX];
        byte[] s = new byte[lenY];
        //获取R
        System.arraycopy(asn1, idxX, r, 0, lenX);
        // 判断第一个是否是正负符号
        if (r[0] == 0 && r[1] < 0) {
            r = Arrays.copyOfRange(r, 1, lenX);
        }
        //获取S
        System.arraycopy(asn1, idxY, s, 0, lenY);
        if (s[0] == 0 && s[1] < 0) {
            s = Arrays.copyOfRange(s, 1, lenY);
        }
        //返回
        return of(r, s);
    }

    public byte[] getX() {
        return x;
    }

    public byte[] getY() {
        return y;
    }

    public byte[] toXY() {
        int lenR = x.length;
        int lenS = y.length;
        byte[] rs = new byte[lenR + lenS];
        //获取R
        System.arraycopy(x, 0, rs, 0, lenR);
        //获取S
        System.arraycopy(y, 0, rs, lenR, lenS);
        return rs;
    }

    public byte[] toAsn1() {
        // 计算长度
        int lenR = x.length;
        int lenS = y.length;
        if (negativeR) {
            lenR += 1;
        }
        if (negativeS) {
            lenS += 1;
        }
        int len = lenR + lenS + 4;

        byte[] asn1 = new byte[len];
        int idx = 0;
        // x
        asn1[idx++] = PREFIX;
        asn1[idx++] = (byte) lenR;
        if (negativeR) {
            asn1[idx++] = 0;
        }
        System.arraycopy(x, 0, asn1, idx, x.length);
        idx += x.length;
        // y
        asn1[idx++] = PREFIX;
        asn1[idx++] = (byte) lenS;
        if (negativeS) {
            asn1[idx++] = 0;
        }
        System.arraycopy(y, 0, asn1, idx, y.length);

        return asn1;
    }
}

EncryptAsn1.java

/**
     * ASN1
     * 格式: 48,len-c1c3c2_asn1,c1_asn1,c3_asn1(4,len,c3),c2_asn1(4,len-bts,c3)
     */
    public static class EncryptAsn1 {
        private static final byte PREFIX = SEQUENCE | CONSTRUCTED; // 48
        private static final byte PREFIX_C = 4;
        /**
         * sm2p256v1的这个固定65。可看GMNamedCurves、ECCurve代码
         * (x9ECParameters.getCurve().getFieldSize() + 7) / 8 * 2 + 1
         */
        private static final int C1_LEN = 65;
        /**
         * new SM3Digest().getDigestSize()
         */
        private static final int C3_LEN = 32;
        private byte[] c1;
        private byte[] c2;
        private byte[] c3;
        private Asn1Point c1Point;

        public static EncryptAsn1 ofC1C2C3(byte[] c1c2c3) {
            EncryptAsn1 asn1 = new EncryptAsn1();

            asn1.c1 = Arrays.copyOfRange(c1c2c3, 0, C1_LEN);
            asn1.c2 = Arrays.copyOfRange(c1c2c3, C1_LEN, c1c2c3.length - C3_LEN);
            asn1.c3 = Arrays.copyOfRange(c1c2c3, c1c2c3.length - C3_LEN, c1c2c3.length);
            asn1.c1Point = Asn1Point.of(getX(asn1.c1), getY(asn1.c1));

            return asn1;
        }

        public static EncryptAsn1 ofC1C3C2(byte[] c1c3c2) {
            EncryptAsn1 asn1 = new EncryptAsn1();

            asn1.c1 = Arrays.copyOfRange(c1c3c2, 0, C1_LEN);
            asn1.c3 = Arrays.copyOfRange(c1c3c2, C1_LEN, C1_LEN + C3_LEN);
            asn1.c2 = Arrays.copyOfRange(c1c3c2, C1_LEN + C3_LEN, c1c3c2.length);
            asn1.c1Point = Asn1Point.of(getX(asn1.c1), getY(asn1.c1));

            return asn1;

        }

        public static EncryptAsn1 ofAsn1(byte[] asn1Bts) {
            EncryptAsn1 asn1 = new EncryptAsn1();

            // 计算c1c3c2Len
            byte[] lenBts = getUnSignedLengthByte(asn1Bts, 1);
            int c1c3c2Len = BigIntegers.fromUnsignedByteArray(lenBts).intValue();

            // 取c1_asn1
            int c1Idx = 1 + lenBts.length;
            if (c1c3c2Len > 127) {
                c1Idx++;
            }
            int c1XLen = asn1Bts[c1Idx + 1];
            int c1YLen = asn1Bts[c1Idx + 2 + c1XLen + 1];
            int c1Len = c1XLen + c1YLen + 4;
            byte[] c1Asn1 = Arrays.copyOfRange(asn1Bts, c1Idx, c1Idx + c1Len);
            asn1.c1Point = Asn1Point.of(c1Asn1);
            asn1.c1 = new byte[C1_LEN];
            asn1.c1[0] = PREFIX_C;
            System.arraycopy(asn1.c1Point.toXY(), 0, asn1.c1, 1, C1_LEN - 1);
            // 取c3
            int c3Idx = c1Idx + c1Len + 2;
            asn1.c3 = Arrays.copyOfRange(asn1Bts, c3Idx, c3Idx + C3_LEN);
            // 取c2
            int c2Idx = c3Idx + C3_LEN + 1;
            byte[] c2LenBts = getUnSignedLengthByte(asn1Bts, c2Idx);
            int c2Len = BigIntegers.fromUnsignedByteArray(c2LenBts).intValue();
            c2Idx += c2LenBts.length;
            if (c2Len > 127) {
                c2Idx++;
            }
            asn1.c2 = Arrays.copyOfRange(asn1Bts, c2Idx, c2Idx + c2Len);

            return asn1;
        }

        public byte[] toC1C2C3() {
            return ByteUtils.join(c1, c2, c3);
        }

        public byte[] toC1C3C2() {
            return ByteUtils.join(c1, c3, c2);
        }

        public byte[] toAsn1() {
            byte[] c1Asn1 = c1Point.toAsn1();
            // 计算长度
            int c1Len = c1Asn1.length;
            int c3Len = c3.length;
            // C2长度字节
            int c2Len = c2.length;
            byte[] c2LenBts = getLengthByte(c2Len);
            // C1C3C2长度字节
            int c1c3c2Len = c1Len + 2 + c3Len + 1 + c2LenBts.length + c2Len;
            byte[] lenBts = getLengthByte(c1c3c2Len);
            //总长度
            int len = 1 + lenBts.length + c1c3c2Len;
            // 拼接
            byte[] asn1 = new byte[len];
            int idx = 0;
            // 前缀
            asn1[idx++] = PREFIX;
            // 长度
            System.arraycopy(lenBts, 0, asn1, idx, lenBts.length);
            idx += lenBts.length;
            // c1
            System.arraycopy(c1Asn1, 0, asn1, idx, c1Len);
            idx += c1Len;
            // c3
            asn1[idx++] = PREFIX_C;
            asn1[idx++] = (byte) c3Len;
            System.arraycopy(c3, 0, asn1, idx, c3Len);
            idx += c3Len;
            // c2
            asn1[idx++] = PREFIX_C;
            System.arraycopy(c2LenBts, 0, asn1, idx, c2LenBts.length);
            idx += c2LenBts.length;
            System.arraycopy(c2, 0, asn1, idx, c2Len);

            return asn1;
        }

        public byte[] getC1() {
            return c1;
        }

        public byte[] getC2() {
            return c2;
        }

        public byte[] getC3() {
            return c3;
        }

        public BigInteger getX() {
            return BigIntegers.fromUnsignedByteArray(c1Point.getX());
        }

        public BigInteger getY() {
            return BigIntegers.fromUnsignedByteArray(c1Point.getY());
        }

        private static byte[] getX(byte[] c1) {
            if (c1.length > 64) {
                return Arrays.copyOfRange(c1, 1, RS_LEN + 1);
            }
            return Arrays.copyOfRange(c1, 0, RS_LEN);

        }

        private static byte[] getY(byte[] c1) {
            if (c1.length > 64) {
                return Arrays.copyOfRange(c1, RS_LEN + 1, c1.length);
            }
            return Arrays.copyOfRange(c1, RS_LEN, c1.length);
        }

        /**
         * 将长度转成字节数组: 字节长度,[Int -> byte[]]
         *
         * @param len
         * @return
         */
        private static byte[] getLengthByte(int len) {
            // 小于127,则没有长度字节
            if (len <= 127) {
                return new byte[]{(byte) len};
            }
            // 大于127,增加长度字节
            byte[] lenC3Bts = BigIntegers.asUnsignedByteArray(BigInteger.valueOf(len));
            byte[] rv = new byte[lenC3Bts.length + 1];
            rv[0] = (byte) (lenC3Bts.length - 128);
            System.arraycopy(lenC3Bts, 0, rv, 1, lenC3Bts.length);

            return rv;

        }
    }

    /**
     * 获取长度字节(不包含统计字节)
     *
     * @param lenBts
     * @return
     */
    private static byte[] getUnSignedLengthByte(byte[] lenBts, int idx) {
        int len = 1;
        if (lenBts[idx] < 0) {
            len = lenBts[idx] + 128;
            idx++;
        }
        return Arrays.copyOfRange(lenBts, idx, idx + len);
    }

调用:

// c1c3c2 -> asn1
byte[] c1c3c2;
byte[] asn1 = EncryptAsn1.ofC1C3C2(rs).toAsn1();
// c1c3c2 -> asn1
byte[] asn1;
byte[] c1c3c2 = EncryptAsn1.ofAsn1(rs).toC1C3C2();
// c1c2c3 -> c1c3c2
byte[] c1c2c3;
byte[] c1c3c2 = EncryptAsn1.ofC1C2C3(rs).toC1C3C2();

发表评论

电子邮件地址不会被公开。 必填项已用*标注