美文网首页
Java 实现 ECC 非对称加密算法加解密和签名验签

Java 实现 ECC 非对称加密算法加解密和签名验签

作者: 小波同学 | 来源:发表于2022-05-06 17:24 被阅读0次

    一、ECC 椭圆曲线算法简介

    ECC是椭圆曲线算法,其加密算法叫ECIES,签名算法叫ECDSA。JDK 并不支持 ECC 算法,可以引入 BouncyCastle 库使用。ECC算法相当耗费资源,如果单纯使用CPU进行加密/解密,效率低下。

    引入 BouncyCastle 库

    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk15on</artifactId>
        <version>1.70</version>
    </dependency>
    
    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.15</version>
    </dependency>       
    

    二、ECC 加解密代码实例

    1.生成 ECC 密钥

    由于 BouncyCastle 库对 keysize 有指定要求的,可以看 BouncyCastle 库中的类:KeyPairGeneratorSpi,从中可以看出支持的 keysize 就这么几个:192、239、256、224、384、521。

    注意: 需要使用静态初始化块初始化 Provider,常量 EC_ALGORITHM = ”EC“ EC_PROVIDER = “BC”

    static{
        try{
            Security.addProvider(new BouncyCastleProvider());
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    
    • 密钥对对象
    /**
     * @author: huangyibo
     * @Date: 2022/4/29 18:47
     * @Description: 非对称加密 密钥对对象
     */
    
    public class RsaKeyPair {
    
        private String publicKey;
    
        private String privateKey;
    
        public RsaKeyPair(String publicKey, String privateKey) {
            this.publicKey = publicKey;
            this.privateKey = privateKey;
        }
    
        public String getPublicKey() {
            return publicKey;
        }
    
        public String getPrivateKey() {
            return privateKey;
        }
    }
    
    • 生成密钥对
    /**
     * 生成密钥对
     *
     * @param keySize   密钥长度
     * @return          密钥对象
     */
    public static RsaKeyPair generateEccKeyPair(int keySize) {
        try {
            // 获取指定算法的密钥对生成器
            KeyPairGenerator generator = KeyPairGenerator.getInstance(EC_ALGORITHM, EC_PROVIDER);
            // 初始化密钥对生成器(指定密钥长度, 使用默认的安全随机数源)
            generator.initialize(keySize);
            // 随机生成一对密钥(包含公钥和私钥)
            KeyPair keyPair = generator.generateKeyPair();
            PublicKey publicKey = keyPair.getPublic();
            PrivateKey privateKey = keyPair.getPrivate();
            String publicKeyString = Base64.encodeBase64String(publicKey.getEncoded());
            String privateKeyString = Base64.encodeBase64String(privateKey.getEncoded());
            return new RsaKeyPair(publicKeyString, privateKeyString);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    

    2.ECC 加解密

    ECIES_ALGORITHM = “ECIES”
    EC_PROVIDER = “BC”

    /**
     * ECC 加密
     *
     * @param publicKeyText 公钥
     * @param data      原文
     * @return 密文
     */
    public static String eccEncrypt(String publicKeyText, String data) {
        try {
            X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
            KeyFactory keyFactory = KeyFactory.getInstance(EC_ALGORITHM);
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2);
            Cipher cipher = Cipher.getInstance(ECIES_ALGORITHM, EC_PROVIDER);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] result = cipher.doFinal(data.getBytes());
            return Base64.encodeBase64String(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * ECC 解密
     *
     * @param privateKeyText 私钥
     * @param data          密文
     * @return 原文
     */
    public static String eccDecrypt(String privateKeyText, String data) {
        try {
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
            KeyFactory keyFactory = KeyFactory.getInstance(EC_ALGORITHM);
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
            Cipher cipher = Cipher.getInstance(ECIES_ALGORITHM, EC_PROVIDER);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] result = cipher.doFinal(Base64.decodeBase64(data));
            return new String(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    

    3.测试代码

    public static void main(String[] args) {
        // 测试文本 
        String plain = "12345678";
    
        // 生成密钥对
        RsaKeyPair rsaKeyPair = generateEccKeyPair(256);
        System.out.println("ECC公钥: "+rsaKeyPair.getPublicKey());
        System.out.println("ECC私钥: "+rsaKeyPair.getPrivateKey());
    
        // 加解密
        String encrypt = eccEncrypt(rsaKeyPair.getPublicKey(), plain);
        String decrypt = eccDecrypt(rsaKeyPair.getPrivateKey(), encrypt);
        System.err.println(plain.equals(decrypt));
    }
    

    三、ECC 签名验签代码实例

    签名验签使用的密钥同上,签名算法使用:SHA256withECDSA 即 SIGNATURE = “SHA256withECDSA”。

    1. ECC 签名验签

    /**
     * 私钥签名
     *
     * @param privateKey 私钥
     * @param data       原文
     * @return 签名
     */
    public static String eccSign(String privateKey, String data) {
        try {
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
            KeyFactory keyFactory = KeyFactory.getInstance(EC_ALGORITHM);
            PrivateKey key = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
            Signature signature = Signature.getInstance(SIGNATURE);
            signature.initSign(key);
            signature.update(data.getBytes());
            return new String(Base64.encodeBase64(signature.sign()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 公钥验签
     *
     * @param publicKey 公钥
     * @param srcData   原文
     * @param sign      签名
     * @return
     */
    public static boolean eccVerify(String publicKey, String srcData, String sign) {
        try {
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
            KeyFactory keyFactory = KeyFactory.getInstance(EC_ALGORITHM);
            PublicKey key = keyFactory.generatePublic(keySpec);
            Signature signature = Signature.getInstance(SIGNATURE);
            signature.initVerify(key);
            signature.update(srcData.getBytes());
            return signature.verify(Base64.decodeBase64(sign.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
    

    2. 测试代码

    public static void main(String[] args) {
        // 测试文本
        String plain = "12345678";
    
        // 生成密钥对
        RsaKeyPair rsaKeyPair = generateEccKeyPair(256);
        System.out.println("ECC公钥: "+rsaKeyPair.getPublicKey());
        System.out.println("ECC私钥: "+rsaKeyPair.getPrivateKey());
    
        // 签名验签
        String sign = eccSign(rsaKeyPair.getPrivateKey(), plain);
        boolean verify = eccVerify(rsaKeyPair.getPublicKey(), plain, sign);
        System.err.println(verify);
    }
    

    完整代码

    import com.yibo.dsa.RsaKeyPair;
    import org.apache.commons.codec.binary.Base64;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    
    import javax.crypto.Cipher;
    import java.security.*;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    
    /**
     * @author: huangyibo
     * @Date: 2022/4/29 10:31
     * @Description:
     */
    
    public class ECCUtils {
    
        private static final String EC_ALGORITHM = "EC";
    
        private static final String EC_PROVIDER = "BC";
    
        private static final String ECIES_ALGORITHM = "ECIES";
    
        private static final String SIGNATURE = "SHA256withECDSA";
    
        static{
            try{
                Security.addProvider(new BouncyCastleProvider());
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    
        /**
         * 生成密钥对
         *
         * @param keySize   密钥长度
         * @return          密钥对象
         */
        public static RsaKeyPair generateEccKeyPair(int keySize) {
            try {
                // 获取指定算法的密钥对生成器
                KeyPairGenerator generator = KeyPairGenerator.getInstance(EC_ALGORITHM, EC_PROVIDER);
                // 初始化密钥对生成器(指定密钥长度, 使用默认的安全随机数源)
                generator.initialize(keySize);
                // 随机生成一对密钥(包含公钥和私钥)
                KeyPair keyPair = generator.generateKeyPair();
                PublicKey publicKey = keyPair.getPublic();
                PrivateKey privateKey = keyPair.getPrivate();
                String publicKeyString = Base64.encodeBase64String(publicKey.getEncoded());
                String privateKeyString = Base64.encodeBase64String(privateKey.getEncoded());
                return new RsaKeyPair(publicKeyString, privateKeyString);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * ECC 加密
         *
         * @param publicKeyText 公钥
         * @param data      原文
         * @return 密文
         */
        public static String eccEncrypt(String publicKeyText, String data) {
            try {
                X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
                KeyFactory keyFactory = KeyFactory.getInstance(EC_ALGORITHM);
                PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2);
                Cipher cipher = Cipher.getInstance(ECIES_ALGORITHM, EC_PROVIDER);
                cipher.init(Cipher.ENCRYPT_MODE, publicKey);
                byte[] result = cipher.doFinal(data.getBytes());
                return Base64.encodeBase64String(result);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * ECC 解密
         *
         * @param privateKeyText 私钥
         * @param data          密文
         * @return 原文
         */
        public static String eccDecrypt(String privateKeyText, String data) {
            try {
                PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
                KeyFactory keyFactory = KeyFactory.getInstance(EC_ALGORITHM);
                PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
                Cipher cipher = Cipher.getInstance(ECIES_ALGORITHM, EC_PROVIDER);
                cipher.init(Cipher.DECRYPT_MODE, privateKey);
                byte[] result = cipher.doFinal(Base64.decodeBase64(data));
                return new String(result);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * 私钥签名
         *
         * @param privateKey 私钥
         * @param data       原文
         * @return 签名
         */
        public static String eccSign(String privateKey, String data) {
            try {
                PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
                KeyFactory keyFactory = KeyFactory.getInstance(EC_ALGORITHM);
                PrivateKey key = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
                Signature signature = Signature.getInstance(SIGNATURE);
                signature.initSign(key);
                signature.update(data.getBytes());
                return new String(Base64.encodeBase64(signature.sign()));
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
         * 公钥验签
         *
         * @param publicKey 公钥
         * @param srcData   原文
         * @param sign      签名
         * @return
         */
        public static boolean eccVerify(String publicKey, String srcData, String sign) {
            try {
                X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
                KeyFactory keyFactory = KeyFactory.getInstance(EC_ALGORITHM);
                PublicKey key = keyFactory.generatePublic(keySpec);
                Signature signature = Signature.getInstance(SIGNATURE);
                signature.initVerify(key);
                signature.update(srcData.getBytes());
                return signature.verify(Base64.decodeBase64(sign.getBytes()));
            } catch (Exception e) {
                e.printStackTrace();
            }
            return false;
        }
    
        public static void main(String[] args) {
            // 测试文本
            String plain = "12345678";
    
            // 生成密钥对
            RsaKeyPair rsaKeyPair = generateEccKeyPair(256);
            System.out.println("ECC公钥: "+rsaKeyPair.getPublicKey());
            System.out.println("ECC私钥: "+rsaKeyPair.getPrivateKey());
    
            // 加解密
            String encrypt = eccEncrypt(rsaKeyPair.getPublicKey(), plain);
            String decrypt = eccDecrypt(rsaKeyPair.getPrivateKey(), encrypt);
            System.err.println(plain.equals(decrypt));
    
            // 签名验签
            String sign = eccSign(rsaKeyPair.getPrivateKey(), plain);
            boolean verify = eccVerify(rsaKeyPair.getPublicKey(), plain, sign);
            System.err.println(verify);
        }
    }
    

    参考:
    https://blog.csdn.net/yuanjian0814/article/details/109815473

    相关文章

      网友评论

          本文标题:Java 实现 ECC 非对称加密算法加解密和签名验签

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