简介
椭圆加密算法(ECC)是一种公钥加密体制,最初由Koblitz和Miller两人于1985年提出,其数学基础是利用椭圆曲线上的有理点构成Abel加法群上椭圆离散对数的计算困难性。公钥密码体制根据其所依据的难题一般分为三类:大素数分解问题类、离散对数问题类、椭圆曲线类。有时也把椭圆曲线类归为离散对数类。
速度 ecc算法比RSA、DSA速度更快。
椭圆曲线密码学
椭圆曲线密码学(英语:Elliptic curve cryptography,缩写为ECC),一种建立公开密钥加密的演算法,基于椭圆曲线数学。椭圆曲线在密码学中的使用是在1985年由Neal Koblitz和Victor Miller分别独立提出的。
ECC的主要优势是在某些情况下它比其他的方法使用更小的密钥——比如RSA加密算法——提供相当的或更高等级的安全。ECC的另一个优势是可以定义群之间的双线性映射,基于Weil对或是Tate对;双线性映射已经在密码学中发现了大量的应用,例如基于身份的加密。不过一个缺点是加密和解密操作的实现比其他机制花费的时间长。
优点
有研究表示160位的椭圆密钥与1024位的RSA密钥安全性相同。
处理速度快
在私钥的加密解密速度上,ecc算法比RSA、DSA速度更快。
存储空间占用小。
带宽要求低。
ECC:Elliptic Curves Cryptography,椭圆曲线密码编码学
ECDSA:用于数字签名,是ECC与DSA的结合,整个签名过程与DSA类似,所不一样的是签名中采取的算法为ECC,最后签名出来的值也是分为r,s。
ECDH:是基于ECC(Elliptic Curve Cryptosystems,椭圆曲线密码体制,参看ECC)的DH( Diffie-Hellman)密钥交换算法。它是密钥协商算法,而不是加解密算法。
ECDH用途:
由于通过ECDH,双方可以在不共享任何秘密的前提下协商出一个共享秘密,因此,ECDH广泛用于协议之中,通过ECDH得到对称加密密钥。如TLS中的*_ECDH_*密码套件。使用DH算法的协议,都可以升级到ECDH算法。ECDH具有ECC的高强度、短密钥长度、计算速度快等优点。
密钥交换过程:
假设密钥交换双方为Alice、Bob,其有共享曲线参数(椭圆曲线E、阶N、基点G)。
1.Alice生成随机整数a,计算A=a*G。Bob生成随机整数b,计算B=b*G。
2.Alice将A传递给Bob。A的传递可以公开,即攻击者可以获取A。由于椭圆曲线的离散对数问题是难题,所以攻击者不可以通过A、G计算出a。Bob将B传递给Alice。同理,B的传递可以公开。
3.Bob收到Alice传递的A,计算Q=b*A
4.Alice收到Bob传递的B,计算Q‘=a*B
总结:
Alice、Bob双方即得Q=b*A=b*(a*G)=(b*a)*G=(a*b)*G=a*(b*G)=a*B=Q' (交换律和结合律),即双方得到一致的密钥Q。
java实现:
导包
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.62</version>
</dependency>
工具类
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.ECPrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class ECCUtils {
/**
* 生成密钥对(公钥和私钥)
*
* @return
* @throws Exception
*/
public static KeyPair initKey(int keySize, String KEY_ALGORITHM) throws Exception {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGen.initialize(keySize);
KeyPair keyPair = keyPairGen.generateKeyPair();
return keyPair;
}
/**
* 公钥加密
*
* @param data 源数据
* @param publicKey 公钥(BASE64编码)
* @return
* @throws Exception
*/
public static String encryptByPublicKey(String data, String publicKey)
throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(publicKey);
Security.addProvider(new BouncyCastleProvider());
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
Cipher cipher = Cipher.getInstance("ECIES", "BC");
cipher.init(Cipher.ENCRYPT_MODE, keyFactory.generatePublic(x509KeySpec));
return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes()));
}
/**
* 私钥解密
*
* @param encryptedData 已加密数据
* @param privateKey 私钥(BASE64编码)
* @return
* @throws Exception
*/
public static String decryptByPrivateKey(String encryptedData, String privateKey)
throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
Security.addProvider(new BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("ECIES", "BC");
cipher.init(Cipher.DECRYPT_MODE, keyFactory.generatePrivate(pkcs8KeySpec));
return Base64.getEncoder().encodeToString(cipher.doFinal(Base64.getDecoder().decode(encryptedData)));
}
/**
* 用私钥对信息生成数字签名
*
* @param content 已加密数据 base64
* @param priKey 私钥(BASE64编码)
* @param signatureAl 签名算法
* @return
* @throws Exception
*/
public static String sign(String content, String priKey, String signatureAl) throws Exception {
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(priKey));
KeyFactory keyFactory = KeyFactory.getInstance("EC");
ECPrivateKey privateK = (ECPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
Signature sign = Signature.getInstance(signatureAl);//"SHA256withECDSA/"
sign.initSign(privateK);
sign.update(Base64.getDecoder().decode(content));
return Base64.getEncoder().encodeToString(sign.sign());
}
public static void main(String[] args) {
try {
//初始化获取公钥和私钥
KeyPair keypair = initKey(256, "EC");
PublicKey publicKey = keypair.getPublic();
PrivateKey privateKey = keypair.getPrivate();
System.out.println("私钥原:" + privateKey);
System.out.println("公钥原:" + publicKey);
// String publicKeyBase64 = Base64.getEncoder().encodeToString(publicKey.getEncoded());
// String privateKeyBase64 = Base64.getEncoder().encodeToString(privateKey.getEncoded());
//生成固定公钥私钥
String publicKeyBase64 = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEvVlOVXJQe6yyLlCSCWQr246yay4Hl9qfB3C5S9al9t6cNzP3lwjJIRGzFmGywspn0OwiMJWmFV7daLhzCx79kQ==";
String privateKeyBase64 = "MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCDyvdnfevbZyiWDWOmwRp5hLDftlNWHzdD5YkiQW6hR6g==";
System.out.println("公钥:" + publicKeyBase64);
System.out.println("-----");
System.out.println("私钥:" + privateKeyBase64);
String con = "这是一条测试加密的数据,哈哈哈哈";
System.out.println("加密之前:" + con);
//加密
String content = encryptByPublicKey(con, publicKeyBase64);
//解密
String contentDe = decryptByPrivateKey(content, privateKeyBase64);
//解密之后
String deStr = new String(Base64.getDecoder().decode(contentDe));
System.out.println("解密之后:" + deStr);
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试结果