ECC证书操作汇总(ECC certificate operations summary)

 

背景介绍

       项目里用到了ECC的证书使用,有一些证书的常规操作,在此进行汇总说明,以便后浪来踏。ECC的public key长度为65字节,第一个字节是标识符0x04,32字节biginteger X, 32字节biginteger Y; private key的长度是 32字节的biginteger。以下代码示例均为ECC secp256r1 曲线。

 

协商秘钥

       张三李四要加密通信,只要持有对方的ECC公钥就可以了。在具体交互时采用AES加密的方式,但每次交互AES秘钥是不同的,AES秘钥在交互时也不参与传输。对方通过当次会话传输过来的临时公钥(ECC Eph_pubKey)进行动态计算来获得本次的AES秘钥,然后用以解密数据包。

import javax.crypto.KeyAgreement;

public static byte[] keyAgree(PrivateKey selfSK, PublicKey otherPK) {
        try {
            KeyAgreement ka = KeyAgreement.getInstance("ECDH");
            ka.init(selfSK);
            ka.doPhase(otherPK, true);
            return ka.generateSecret();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

          举例过程 张三 -> 李四,张三持有李四的长期公钥。

  •           张三:发送 加密 AES = KeyAgree(张三的临时私钥,李四的长期公钥), 传输内容:张三的临时公钥 (65字节固定)+ 密文;
  •           李四:收到 解密 AES = KeyAgree(李四的长期私钥,张三的临时公钥),解密密文得到明文;

           反之,李四 -> 张三 是对等的。

 

解析ECC证书&私钥

        将文本证书及私钥文件反序列化为X509 Cert & ECC private key。

        

 1     public static X509Certificate deserialize(String path) {
 2         try {
 3             String cert = Files.lines(Paths.get(path))
 4                                .filter(line -> !line.startsWith("-----"))
 5                                .collect(Collectors.joining());
 6             if (StringUtils.isBlank(cert)) {
 7                 return null;
 8             }                   
 9             CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
10             ByteArrayInputStream bais = new ByteArrayInputStream(Base64.decodeBase64(base64Cert));
11             return (X509Certificate) (certFactory.generateCertificate(bais));
12         } catch (IOException e) {
13             e.printStackTrace();
14         }
15         return null;
16     }
17 
18 
19 
20     public static PrivateKey deserialize(String path) {
21         try {
22             String key = Files.lines(Paths.get(path))
23                               .filter(line -> !line.startsWith("-----"))
24                               .collect(Collectors.joining());
25             if (StringUtils.isBlank(key)) {
26                 return null;
27             }
28 
29             EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(key));
30             KeyFactory kf = KeyFactory.getInstance("EC");
31             return kf.generatePrivate(privateKeySpec);
32         } catch (Exception e) {
33             e.printStackTrace();
34         }
35         return null;
36     }

 

十六进制字符串公私钥反序列化

          How to convert hex string to ECC public key ?

 1     public static PublicKey deserializePubKey(String hexPubKey) throws Exception {
 2         byte[] pubKey = Hex.decode(hexPubKey)
 3         byte[] x = Arrays.copyOfRange(pubKey, 1, 33); // the first byte is 0x04 flag, ignored
 4         byte[] y = Arrays.copyOfRange(pubKey, 33, pubKey.length);
 5         ECPoint w = new ECPoint(new BigInteger(1, x), new BigInteger(1, y));
 6         KeyFactory kf = KeyFactory.getInstance("EC");
 7         return kf.generatePublic(new ECPublicKeySpec(w, ecParameterSpecForP256()));
 8     }
 9 
10     public static PrivateKey deserializePriKey(String hexPriKey) throws Exception {
11         KeyFactory kf = KeyFactory.getInstance("EC");
12         return kf.generatePrivate(new ECPrivateKeySpec(new BigInteger(Hex.decode(hexPriKey)), ecParameterSpecForP256()));
13     }
14 
15     private static ECParameterSpec ecParameterSpecForP256() throws Exception {
16         AlgorithmParameters params = AlgorithmParameters.getInstance("EC");
17         params.init(new ECGenParameterSpec("secp256r1"));
18         return params.getParameterSpec(ECParameterSpec.class);
19     }

 

以上。

 

posted @ 2021-12-18 00:24  walle搬砖  阅读(566)  评论(0编辑  收藏  举报