美文网首页
ECC/SM2 公钥(点)压缩与还原

ECC/SM2 公钥(点)压缩与还原

作者: fish_leong | 来源:发表于2018-05-14 15:45 被阅读728次

ECC/SM2 公钥(点)压缩方法,64字节公钥压缩成33字节公钥。

一、C

void compress(const uint8_t *public_key, uint8_t *compressed)
{
    int i;
    for (i = 0; i < 32; ++i)
    {
        compressed[i+1] = public_key[i];
    }
    compressed[0] = 2 + (public_key[32 * 2 - 1] & 0x01);
}

二、Java

/**
* ECC/SM2 公钥压缩
* 
* @param pk64
* 64字节公钥
* @return 压缩后的33字节公钥
*/
public byte[] compress(byte[] pk64) {
   byte[] pk33 = new byte[33];
   for (int i = 0; i < pk64.length - 1; ++i) {
      pk33[i + 1] = pk64[i];
   }
   pk33[0] = (byte) (2 + (pk64[32 * 2 - 1] & 0x01));
   return pk33;
}
  • Java基于bcprov-jdk1.5.0_08的点压缩
    // 以SM2参数为例
    public static String[] ecc_param = { "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",
            "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",
            "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",
            "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",
            "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",
            "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0" };
    // 待压缩的公钥(随便写的)
    public static String[] pk = { "AAAAAAAA31F2225EE5F4C93BF98FFFF6E6667F814ECD49966E9936A6CB9A3F3B",
            "AAAA8D0EACCCCD42B3B65A891AAAA4DDDD9A5F5524492F1BAAAAA12669E0AAC6" };

    public void test(){
        BigInteger ecc_p = new BigInteger(ecc_param[0], 16);
        BigInteger ecc_a = new BigInteger(ecc_param[1], 16);
        BigInteger ecc_b = new BigInteger(ecc_param[2], 16);
        ECCurve ecc_curve = new ECCurve.Fp(ecc_p, ecc_a, ecc_b);
        // 构造点
        BigInteger ecc_p1 = new BigInteger(pk[0], 16);
        BigInteger ecc_p2 = new BigInteger(pk[1], 16);
        ECFieldElement aaaecc_gx_fieldelement = new Fp(ecc_p, ecc_p1);
        ECFieldElement aaaecc_gy_fieldelement = new Fp(ecc_p, ecc_p2);
        ECPoint ecPK64 = new ECPoint.Fp(ecc_curve, aaaecc_gx_fieldelement, aaaecc_gy_fieldelement);
        // 得到压缩后的公钥
        byte[] key33 = ecPK64.getEncoded(true);
    }

三、GoLang

func compress(public_key string) string {
    pk33 := ""
    i := 0
    for i < 32 {
        pk33 += public_key[i*2 : (i*2)+2]
        i += 1
    }
    values, _ := strconv.ParseInt(public_key[(32*2*2)-2:], 0, 16)
    head := 2 + (values & 0x01)
    headStr:=strconv.FormatInt(head,16)
    if head<16 {
        headStr="0"+headStr
    }
    pk33 =headStr+pk33
    return pk33
}

四、Python

#压缩64字节公钥至33字节
def compress(public_key):
        pk33 = ""
        i=0
        while(i<32):
            pk33+=  public_key[i*2:(i*2)+2]
            i+=1
        head=int("0x"+public_key[(32 * 2*2 )- 2:],16)
        head=2 + ( head & 0x01)
        pk33 = getdata(binascii.b2a_hex(bytes((head,))))+pk33
        return pk33

ECC/SM2 压缩公钥还原

一、Java

    // 以SM2参数为例
    public static String[] ecc_param = { "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",
            "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",
            "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",
            "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",
            "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",
            "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0" };

    public void test(){
        BigInteger ecc_p = new BigInteger(ecc_param[0], 16);// p
        BigInteger ecc_a = new BigInteger(ecc_param[1], 16);// a
        BigInteger ecc_b = new BigInteger(ecc_param[2], 16);// b
        ECCurve ecc_curve = new ECCurve.Fp(ecc_p, ecc_a, ecc_b);
        // 完整的公钥1B62C2D3CB8109EA6A29AF2BBD4F4FC0423F8D3C4C38342F10681C266E31852F266725C743B9373660549A8A0C64C7507457D8913A18D65404ECE27C1BF930F2
        // 压缩后的公钥
        String key = "021B62C2D3CB8109EA6A29AF2BBD4F4FC0423F8D3C4C38342F10681C266E31852F";
        // 根据X恢复点Y,
        ECPoint point = ecc_curve.decodePoint(
                hexStringToBytes(key));
        String y = point.getY().toBigInteger().toString(16).toUpperCase();
        // 原始公钥
        System.out.println("原始公钥:" + key.substring(2, key.length()) + y);
    }

    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }

二、其他语言

由于公司业务上没有用到其他语言,所以暂时只有java版的公钥还原,想用其他语言实现的,建议看一下org.bouncycastle.math.ec.ECCurve.decodePoint(byte[] point)方法

相关文章

网友评论

      本文标题:ECC/SM2 公钥(点)压缩与还原

      本文链接:https://www.haomeiwen.com/subject/vxkjdftx.html