java使用ECC密钥长度为256的非对称加密算法案例

介绍

椭圆曲线密码学(英语:Elliptic curve cryptography,缩写为ECC),一种建立公开密钥加密的演算法,基于椭圆曲线数学。椭圆曲线在密码学中的使用是在1985年由Neal Koblitz和Victor Miller分别独立提出的。

ECC的主要优势是在某些情况下它比其他的方法使用更小的密钥——比如RSA加密算法——提供相当的或更高等级的安全。ECC的另一个优势是可以定义群之间的双线性映射,基于Weil对或是Tate对;双线性映射已经在密码学中发现了大量的应用,例如基于身份的加密。不过一个缺点是加密和解密操作的实现比其他机制花费的时间长。(点击-->详细介绍)。

本文章借鉴了网上很多要点,但来源没有保存,若有侵权,请联系我。

 

本案例代码的特点:

1.解决了一部分jre环境由于美国出口限制,导致密钥长度不能超过128,此时可以利用反射对java对象进行修改,使得256位的密钥长度也能通过。(当然自己也可以替换jre环境的jar包,具体jar包可以去网上查找异常的解决方案)。

2.私钥和公钥可以使用Base'64进行编码,后用来传输。到其他服务使用时,可以将Base64字符串转成相应的私钥和公钥对象。

 

代码实现

package com.atguigu.springboot.jvm;

//import org.bouncycastle.jce.provider.BouncyCastleProvider;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.*;
import java.io.File;
import  java.io.FileInputStream;
import java.lang.reflect.Field;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.CryptoPermission;

/**
 * ECC非对称加密算法,密钥长度为256
 */
public class EccUtils {
    //密钥长度
    private final static int KEY_SIZE=256;

    //生成对应的签名,用来验签
    private final static String SIGNATURE="SHA256withECDSA";

    //注册BouncyCastle加密包
    static{
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 输出BouncyCastleProvider支持的算法,其中就有支持ECC加密的算法
     */
    private static void printProvider(){
        Provider provider=new BouncyCastleProvider();
        for(Provider.Service service:provider.getServices()){
            System.out.println(service.getType()+":"+service.getAlgorithm());
        }
    }

    /**
     * 生成密钥对
     * @return
     * @throws Exception
     */
    public static KeyPair getKeyPair() throws Exception{
        //BC即BouncyCastle加密包,EC为ECC算法
        KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance("EC","BC");
        keyPairGenerator.initialize(KEY_SIZE,new SecureRandom());
        KeyPair keyPair=keyPairGenerator.generateKeyPair();
        return keyPair;
    }

    /**
     * 获取公钥(BASE64编码成字符串后方便用于其他人解码)
     * @param keyPair
     * @return
     */
    public static String getPublicKey(KeyPair keyPair){
        ECPublicKey publicKey=(ECPublicKey)keyPair.getPublic();
        byte[] bytes=publicKey.getEncoded();
        return Base64.getEncoder().encodeToString(bytes);
    }

    /**
     * 获取私钥(Base64编码)
     * @param keyPair
     * @return
     */
    public static String getPrivateKey(KeyPair keyPair){
        ECPrivateKey privateKey=(ECPrivateKey)keyPair.getPrivate();
        byte[] bytes=privateKey.getEncoded();
        return Base64.getEncoder().encodeToString(bytes);
    }

    /**
     * 公钥加密
     * @param content
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static byte[] encrypt(byte[] content,ECPublicKey publicKey) throws Exception{
        Cipher cipher=Cipher.getInstance("ECIES","BC");
        //setFieldValueByFieldName(cipher);
        cipher.init(Cipher.ENCRYPT_MODE,publicKey);
        return cipher.doFinal(content);
    }

    /**
     * 私钥解密
     * @param content
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static byte[] decrypt(String content,ECPrivateKey privateKey) throws Exception{
        //content是采用base64编码后的内容,方便用于传输,下面会解码为byte[]类型的值
        Cipher cipher=Cipher.getInstance("ECIES","BC");
        //setFieldValueByFieldName(cipher);
        cipher.init(Cipher.DECRYPT_MODE,privateKey);
        return cipher.doFinal(Base64.getDecoder().decode(content));
    }

    /**
     * 使用反射解决因美国出口限制,ECC算法的密钥长度不能超过128的问题,如果需要的话,可以加
     * @param object
     */
    private static void setFieldValueByFieldName(Cipher object){
        if(object==null){
            return;
        }
        //获取Obj类的字节文件对像
        Class cipher=object.getClass();
        try{
            //获取该类的成员变量CryptoPermission cryptoPerm;
            Field cipherField=cipher.getDeclaredField("cryptoPerm");
            cipherField.setAccessible(true);
            Object cryptoPerm=cipherField.get(object);

            //获取CryptoPermission类的成员变量maxKeySize
            Class c=cryptoPerm.getClass();

            Field[] cs=c.getDeclaredFields();
            Field cryptoPermField=c.getDeclaredField("maxKeySize");
            cryptoPermField.setAccessible(true);
            //设置maxKeySize的值为257,257>256
            cryptoPermField.set(cryptoPerm,257);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 私钥签名
     * @param content
     * @param privateKey
     * @return
     */
    public static byte[] sign(String content,ECPrivateKey privateKey) throws Exception {
        Signature signature=Signature.getInstance(SIGNATURE);
        signature.initSign(privateKey);
        signature.update(content.getBytes());
        return signature.sign();
    }

    /**
     * 公钥验签
     * @param content
     * @param sign
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static boolean verify(String content,byte[] sign,ECPublicKey publicKey) throws Exception{
        Signature signature=Signature.getInstance(SIGNATURE);
        signature.initVerify(publicKey);
        signature.update(content.getBytes());
        return signature.verify(sign);
    }

    /**
     * 解析证书的签名算法,单独一本公钥或者私钥是无法解析的,证书的内容远不止公钥或者私钥
     * @param certFile
     * @return
     * @throws Exception
     */
    private static String getSignature(File certFile) throws Exception{
        CertificateFactory certificateFactory=CertificateFactory.getInstance("X.509","BC");
        X509Certificate x509Certificate=(X509Certificate) certificateFactory.generateCertificate(new FileInputStream(certFile));
        return x509Certificate.getSigAlgName();
    }

    /**
     * 将Base64编码后的公钥转换成PublicKey对象,Base64编码后的公钥可以用于网络传输
     * @param pubStr
     * @return
     * @throws Exception
     */
    public static ECPublicKey string2PublicKey(String pubStr) throws Exception{
        byte[] keyBytes=Base64.getDecoder().decode(pubStr);
        X509EncodedKeySpec keySpec=new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory=KeyFactory.getInstance("EC","BC");
        ECPublicKey publicKey=(ECPublicKey)keyFactory.generatePublic(keySpec);
        return publicKey;
    }

    /**
     * 将Base64编码后的私钥转换成PrivateKey对象,Base64编码后的私钥可以用于网络传输
     * @param priStr
     * @return
     * @throws Exception
     */
    public static ECPrivateKey string2PrivateKey(String priStr)throws Exception{
        byte[] keyBytes=Base64.getDecoder().decode(priStr);
        PKCS8EncodedKeySpec keySpec=new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory=KeyFactory.getInstance("EC","BC");
        ECPrivateKey privateKey=(ECPrivateKey) keyFactory.generatePrivate(keySpec);
        return privateKey;
    }

    public static void main(String[] args){
        try{
            KeyPair keyPair=getKeyPair();
            //生成公钥和私钥对象
            ECPublicKey publicKey=(ECPublicKey) keyPair.getPublic();
            ECPrivateKey privateKey=(ECPrivateKey) keyPair.getPrivate();

            //生成一个Base64编码的公钥字符串,可用来传输
            System.out.println("[publickey]:\t"+getPublicKey(keyPair));
            System.out.println("[privateKey]:\t"+getPrivateKey(keyPair));
            System.out.println();

            ECPublicKey publicKey2=string2PublicKey("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6G9CUzeBivIkq+m3n6v/hqJylI+lrgbGhJqgLMaQWmotqSlXHcUUUryf0fOFvbLLYHATbAmxWrycptSsydtsYA==");
            ECPrivateKey privateKey2=string2PrivateKey("MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgkPjCWsEvqDD37uh0UzyWIzUIN+LQOvTLdLw5rv+bfuqgCgYIKoZIzj0DAQehRANCAATob0JTN4GK8iSr6befq/+GonKUj6WuBsaEmqAsxpBaai2pKVcdxRRSvJ/R84W9sstgcBNsCbFavJym1KzJ22xg");
            //测试文本
            String content="test123";

            //加密
            byte[] cipherTxt=encrypt(content.getBytes(), publicKey2);
            System.out.println("content: "+content);
            System.out.println("cipherTxt["+cipherTxt.length+"]"+new String(cipherTxt));

            //解密,此字符串可用来网络传输
            String cipherString=Base64.getEncoder().encodeToString(cipherTxt);
            byte[] clearTxt=decrypt(cipherString, privateKey2);
            System.out.println("clearTxt:"+new String(clearTxt));


        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

 

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
非对称加密算法是一种常用的加密方式,它采用了一对密钥,即公钥和私钥。公钥是公开的,可以任意分发,而私钥则只能由密钥的所有者持有,用于解密加密数据。常见的非对称加密算法包括RSA、DSA、ECC等。 下面是一个使用RSA算法实现非对称加密的Java示例代码: ```java import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import javax.crypto.Cipher; public class RSAEncryptionExample { public static void main(String[] args) throws Exception { String input = "Hello World!"; KeyPair keyPair = generateRSAKeyPair(); PrivateKey privateKey = keyPair.getPrivate(); PublicKey publicKey = keyPair.getPublic(); byte[] encryptedData = rsaEncrypt(input.getBytes(), publicKey); byte[] decryptedData = rsaDecrypt(encryptedData, privateKey); System.out.println("Original data: " + input); System.out.println("Encrypted data: " + new String(encryptedData)); System.out.println("Decrypted data: " + new String(decryptedData)); } public static KeyPair generateRSAKeyPair() throws Exception { KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); generator.initialize(2048); // key size KeyPair keyPair = generator.generateKeyPair(); return keyPair; } public static byte[] rsaEncrypt(byte[] data, PublicKey publicKey) throws Exception { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] encryptedData = cipher.doFinal(data); return encryptedData; } public static byte[] rsaDecrypt(byte[] data, PrivateKey privateKey) throws Exception { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] decryptedData = cipher.doFinal(data); return decryptedData; } } ``` 这个示例代码中,我们首先生成了一个RSA密钥对,包括公钥和私钥。然后使用公钥对原始数据进行加密,得到加密后的数据。接着使用私钥对加密后的数据进行解密,得到原始数据。 需要注意的是,RSA算法使用密钥长度越长,安全性就越高,但加解密的速度也越慢。在实际应用中,需要根据实际需求和环境选择合适的密钥长度

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值