RSA加密算法的java实现

RSA加密算法的java实现最近有一个外部合作项目要求在数据传输过程中使用RSA加密算法对数据进行加密,所以需要编写一个加解密的工具类,因为对方不是java语言,所以是各自实现的这个工具,本文主要讨论实现以及双方调试过程中的一些插曲,希望给大家不要再次踩坑。关于加解密的核心部分,网上有很多博主都有实现过,我也是参考了一些博主的方法自己实现了一个加解密的工具。packagecom.chen.test;importorg.

大家好,又见面了,我是你们的朋友全栈君。

最近有一个外部合作项目要求在数据传输过程中使用RSA加密算法对数据进行加密,所以需要编写一个加解密的工具类,因为对方不是java语言,所以是各自实现的这个工具,本文主要讨论实现以及双方调试过程中的一些插曲,希望给大家不要再次踩坑。
关于加解密的核心部分,网上有很多博主都有实现过,我也是参考了一些博主的方法自己实现了一个加解密的工具。
package com.chen.test;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

public class RSAUtils { 
   

    public static final String CHARSET = "UTF-8";
    public static final String RSA_ALGORITHM = "RSA";


    public static Map<String, String> createKeys(int keySize){
        //为RSA算法创建一个KeyPairGenerator对象
        KeyPairGenerator kpg;
        try{
            kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM);
        }catch(NoSuchAlgorithmException e){
            throw new IllegalArgumentException("No such algorithm-->[" + RSA_ALGORITHM + "]");
        }

        //初始化KeyPairGenerator对象,密钥长度
        kpg.initialize(keySize);
        //生成密匙对
        KeyPair keyPair = kpg.generateKeyPair();
        //得到公钥
        Key publicKey = keyPair.getPublic();
        String publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded());
        //得到私钥
        Key privateKey = keyPair.getPrivate();
        String privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded());
        Map<String, String> keyPairMap = new HashMap<String, String>();
        keyPairMap.put("publicKey", publicKeyStr);
        keyPairMap.put("privateKey", privateKeyStr);

        return keyPairMap;
    }

    /** * 得到公钥 * @param publicKey 密钥字符串(经过base64编码) * @throws Exception */
    public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        //通过X509编码的Key指令获得公钥对象
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
        RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
        return key;
    }

    /** * 得到私钥 * @param privateKey 密钥字符串(经过base64编码) * @throws Exception */
    public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        //通过PKCS#8编码的Key指令获得私钥对象
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
        RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
        return key;
    }

    /** * 公钥加密 * @param data * @param publicKey * @return */
    public static String publicEncrypt(String data, RSAPublicKey publicKey){
        try{
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus().bitLength()));
        }catch(Exception e){
            throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
        }
    }

    /** * 私钥解密 * @param data * @param privateKey * @return */

    public static String privateDecrypt(String data, RSAPrivateKey privateKey){
        try{
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), privateKey.getModulus().bitLength()), CHARSET);
        }catch(Exception e){
            throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
        }
    }

    /** * 私钥加密 * @param data * @param privateKey * @return */

    public static String privateEncrypt(String data, RSAPrivateKey privateKey){
        try{
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), privateKey.getModulus().bitLength()));
        }catch(Exception e){
            throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
        }
    }

    /** * 公钥解密 * @param data * @param publicKey * @return */

    public static String publicDecrypt(String data, RSAPublicKey publicKey){
        try{
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), publicKey.getModulus().bitLength()), CHARSET);
        }catch(Exception e){
            throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
        }
    }

    private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize){
        int maxBlock = 0;
        if(opmode == Cipher.DECRYPT_MODE){
            maxBlock = keySize / 8;
        }else{
            maxBlock = keySize / 8 - 11;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] buff;
        int i = 0;
        try{
            while(datas.length > offSet){
                if(datas.length-offSet > maxBlock){
                    buff = cipher.doFinal(datas, offSet, maxBlock);
                }else{
                    buff = cipher.doFinal(datas, offSet, datas.length-offSet);
                }
                out.write(buff, 0, buff.length);
                i++;
                offSet = i * maxBlock;
            }
        }catch(Exception e){
            throw new RuntimeException("加解密阀值为["+maxBlock+"]的数据时发生异常", e);
        }
        byte[] resultDatas = out.toByteArray();
        IOUtils.closeQuietly(out);
        return resultDatas;
    }

}

简单测试一下。

public static void main (String[] args) throws Exception {
        Map<String, String> keyMap = RSAUtils.createKeys(1024);
        String  publicKey = keyMap.get("publicKey");
        String  privateKey = keyMap.get("privateKey");
        System.out.println("公钥: \n\r" + publicKey);
        System.out.println("私钥: \n\r" + privateKey);

        System.out.println("公钥加密——私钥解密");
        String str = "站在大明门前守卫的禁卫军,事先没有接到\n" +
                "有关的命令,但看到大批盛装的官员来临,也就\n" +
                "以为确系举行大典,因而未加询问。进大明门即\n" +
                "为皇城。文武百官看到端门午门之前气氛平静,\n" +
                "城楼上下也无朝会的迹象,既无几案,站队点名\n" +
                "的御史和御前侍卫“大汉将军”也不见踪影,不免\n" +
                "心中揣测,互相询问:所谓午朝是否讹传?";
        System.out.println("\r明文:\r\n" + str);
        System.out.println("\r明文大小:\r\n" + str.getBytes().length);
        String encodedData = RSAUtils.publicEncrypt(str, RSAUtils.getPublicKey(publicKey));
        System.out.println("密文:\r\n" + encodedData);
        String decodedData = RSAUtils.privateDecrypt(encodedData, RSAUtils.getPrivateKey(privateKey));
        System.out.println("解密后文字: \r\n" + decodedData);


    }

实现基本上就是这样,都是大同小异。不过,问题来了,结下来才是重点。
**1. RSA加密算法对于加密数据的长度是有要求的。一般来说,明文长度小于等于密钥长度(Bytes)-11。解决这个问题需要对较长的明文进行分段加解密,这个上面的代码已经实现了。
2. 一旦涉及到双方开发,语言又不相同,不能够采用同一个工具的时候,切记要约定以下内容。
a)约定双方的BASE64编码
b)约定双方分段加解密的方式。我踩的坑也主要是这里,不仅仅是约定大家分段的大小,更重要的是分段加密后的拼装方式。doFinal方法加密完成后得到的仍然是byte[],因为最终呈现的是编码后的字符串,所以你可以分段加密,分段编码和分段加密,一次编码两种方式(上面的代码采用的是后一种,也推荐采用这一种)。相信我不是所有人的脑回路都一样的,尤其是当他采用的开发语言和你不通时。**

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/132992.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • mysql binlog日志_事务日志

    mysql binlog日志_事务日志binlog就是binarylog,二进制日志文件,这个文件记录了mysql所有的dml操作。通过binlog日志我们可以做数据恢复,做主住复制和主从复制等等。对于开发者可能对binlog并不怎么关注,但是对于运维或者架构人员来讲是非常重要的。如何开启mysql的binlog日志呢?在my.inf主配置文件中直接添加三行log_bin=ONlog_bin_basenam

    2022年8月31日
    1
  • 修复未能连接一个window服务器,未能连接一个windows服务的修复方法

    修复未能连接一个window服务器,未能连接一个windows服务的修复方法Win7系统,最近出现一个问题,就是启动以后,在桌面右下角会弹出提示窗口,提示:未能连接一个windows服务的气泡弹窗,windows无法链接到XXXXX服务。此问题阻止标准用户登录系统。作为管理员用户,您可以复查系统时间日志,以获得有关此服务未响应原因的详细信息。出现这样的提示是怎么回事呢?下面最火软件站就为大家分享下windows服务无法连接的修复方法。操作步骤:1、首先键盘按W…

    2022年5月14日
    68
  • h3c路由器的配置命令_华三路由器清除配置命令

    h3c路由器的配置命令_华三路由器清除配置命令拓扑:设备开机后出现如下图样式*******************************************************************************Copyright(c)2004-2017NewH3CTechnologiesCo.,Ltd.Allrightsreserved.**Withouttheowner’spriorwrittenconsent,…

    2022年10月18日
    1
  • leetcode76_leetcode72

    leetcode76_leetcode72一、问题描述Giventwointegers n and k,returnallpossiblecombinationsof k numbersoutof1… n.Forexample,If n =4and k =2,asolutionis:[[2,4],[3,4],[2,3],[1,2],[1,3]

    2022年9月19日
    0
  • 深入理解深度学习分割网络Unet——U-Net: Convolutional Networks for Biomedical Image Segmentation

    深入理解深度学习分割网络Unet——U-Net: Convolutional Networks for Biomedical Image Segmentation背景Mask=Function(I)1.什么是图像分割问题呢?简单的来讲就是给一张图像,检测是用框出框出物体,而图像分割分出一个物体的准确轮廓。也这样考虑,给出一张图像I,这个问题就是求一个函数,从I映射到Mask。至于怎么求这个函数有多种方法。我们可以看到这个图,左边是给出图像,可以看到人和摩托车,右边是分割结果。2.求这个函数有很多方法,但是第一次将深…

    2022年4月25日
    35
  • winform与cefsharp混合开发_历史必修二笔记手写

    winform与cefsharp混合开发_历史必修二笔记手写在上一篇博文《WinForm内置浏览器之CefSharp笔记一》,简单介绍了CefSharp的快速入门。这篇博文接着上篇,主要记录C#如果调用JS中的方法。参照Github示例:传送门加载自定义网页修改网址,使用ChromiumWebBrowser类的Load方法,直接直接输入网址,也可以加载本地的html文件。m_chromeBrowser.Load(“https://www….

    2022年9月19日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号