美文网首页
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 非对称加密算法加解密和签名验签

    一、ECC 椭圆曲线算法简介 ECC是椭圆曲线算法,其加密算法叫ECIES,签名算法叫ECDSA。JDK 并不支持...

  • 011各种加密算法比较

    算法选择:对称加密AES,非对称加密: ECC,消息摘要: MD5,数字签名:DSA 对称加密算法(加解密密钥相同...

  • RSA加密算法

    RSA加解密、签名验签過程 RSA加密是一种非对称加密,通常使用公钥加密,私钥解密,私钥签名,公钥验签。私钥是個人...

  • polarssl和Java端RSA公私钥转换

    背景 polarssl库是C语言的加密库,包括RSA加解密,签名验签等功能。Java端也有自己专门做加解密,验签的...

  • swift-RSA(五)-签名/验签

    RSA支持加解密,也支持签名/验签。使用rsa如何签名/验签呢? 1.rsa 签名 2.rsa 验签 3.调用

  • Java加密-Signature数据签名

    Signature类用于提供数字签名,用于保证数据的完整性,用非对称密钥中的私钥签名,公钥验签。 Java的实现 ...

  • 数字证书和证书链

    在介绍数字证书前,先谈谈签名/验签的流程,当 A 向 B 发送数据, A 先通过非对称加密算法,生成一对公钥和私钥...

  • DSA和ECC签名验签

    DSA DSA 是专业用于数字签名和验签,并且只有这个作用, 不能用于加密和解密。在安全性上,DSA和RSA差不多...

  • python实现sm2、sm3、sm4算法计算

    安装: pip 安装 SM2 国密公钥加解密签名验签 a. 密钥生成 签名 验签 加密 解密 SM3 国密哈希 a...

  • RSA非对称加解密原理及示例代码

    RSA非对称加解密可以实现安全传输,本文简单介绍一下其原理和实现代码 RSA加密算法 RSA加密算法是一种非对称加...

网友评论

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

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