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)
方法
网友评论