一、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