JAVA RSA加密Demo,应用

JAVA RSA加密Demo,应用

一,背景

项目上需要对接资方,并且使用RSA加密,此文章做一个当时踩坑记录。

二,代码

RSA加密核心流程:(使用分段加解密)

		// 流程: 加解密方式分段加解密,不然可能会提示 太长解密不了。
        // 1.先生成 密钥对 :见【生成密钥对.docx】
        // 2.交互: 公钥加密,私钥加签。
        // A 与 B 交互
        // A 使用 B 公钥加密报文 得到byte[],使用Base64编码数组,得到密文data
        // A 使用 A 私钥,加签密文data得到byte[],使用Base64编码数组,得到签名sign
        // 传输...
        // B 收到密文data,使用Base64编码data得到byte[]
        // B 使用A公钥验签
        // B 使用B私钥,解密byte[],得到明文报文
    生成 密钥对 :见【生成密钥对.docx】

代码

package com.madorangecat.artmartxt.utils.rsa;

import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

import javax.crypto.Cipher;

@Slf4j
public class RSAUtil {

    private static final String SIGNATURE_INSTANCE = "SHA512withRSA";
    private static final String KEY_ALGORITHM = "RSA";
    // 最大解密长度
    private static final int MAX_DECRYPT_BLOCK = 256;
    // 最大加密长度
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /**
     * @Title: getPublicKey
     * @Description:实例化公钥
     */
    public static PublicKey getPublicKey(String publicKey) throws Exception {
        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKey.getBytes());
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(keySpec);
    }

    /**
     * @Title: getPrivateKey
     * @Description:实例化私钥
     */
    public static PrivateKey getPrivateKey(String privateKey) throws Exception {
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKey.getBytes());
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(keySpec);
    }

    /**
     * @Title: sign
     * @Description:私钥签名
     */
    public static byte[] sign(byte[] content, String privateKey) throws Exception {
        Signature signature = Signature.getInstance(SIGNATURE_INSTANCE);
        signature.initSign(getPrivateKey(privateKey));
        signature.update(content);
        return signature.sign();
    }

    /**
     * @Title: verify
     * @Description:公钥验签
     */
    public static boolean verify(byte[] content, byte[] sign, String publicKey) throws Exception {
        Signature signature = Signature.getInstance(SIGNATURE_INSTANCE);
        signature.initVerify(getPublicKey(publicKey));
        signature.update(content);
        return signature.verify(sign);
    }

    /**
     * 使用私钥分段解密
     *
     * @param dataBytes     密文byte
     * @param privateKeyStr 密钥Str
     */
    public static String decryptByPrivateKeyPartition(byte[] dataBytes, String privateKeyStr) {

        String str = "";
        try {
            PrivateKey privateKey = getPrivateKey(privateKeyStr);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            int inputLen = dataBytes.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offset = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段解密
            while (inputLen - offset > 0) {
                if (inputLen - offset > MAX_DECRYPT_BLOCK) {
                    cache = cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
                }
                out.write(cache, 0, cache.length);
                i++;
                offset = i * MAX_DECRYPT_BLOCK;
            }
            byte[] decryptedData = out.toByteArray();
            out.close();
            // 解密后的内容
            str = new String(decryptedData, StandardCharsets.UTF_8);

        } catch (Exception e) {
            log.error("===== 私钥分段解密:decryptByPrivateKeyPartition,失败异常:", e);
        }
        return str;
    }


    /**
     * 使用公钥加密
     *
     * @param dataBytes    密文byte
     * @param publicKeyStr 公钥Str
     */
    public static String encryptByPublicKeyPartition(byte[] dataBytes, String publicKeyStr) {

        // 加密
        String str = "";
        try {
            PublicKey publicKey = getPublicKey(publicKeyStr);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            int inputLen = dataBytes.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            while (inputLen - offSet > 0) {
                //MAX_ENCRYPT_BLOCK 117
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(dataBytes, offSet, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(dataBytes, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }
            byte[] encryptedData = out.toByteArray();
            out.close();

            Base64.Encoder encoder = Base64.getEncoder();
            str = encoder.encodeToString(encryptedData);
        } catch (Exception e) {
            log.error("===== 加密失败 encryptByPublicKeyPartition :", e);
        }
        return str;
    }


    public static void main(String[] args) throws Exception {

        String content = "一段待加密的报文!!";

        String privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDJqiwH7oPZTbxUf5/7zWJ3qdCtuXanicuPlAoqE8mIgmUAWGEcJZMqPJge3PbsU2iALDCeKk4W6lWTwinwAo/lupvmvqw0a+1SFjTamZxQkl+OpDQTuUitgBOtKNBZy/019aOYVn1STMKiuzKMTe9K6gz0AhX3MHu4u9NoQxMkhNckyh2YSH7AvPh11mpE2fH3mA32ql23qqTcIdzdIpSx65kGF8ddHvX047IhngHZ8xc3bbtNCGoP4PwholK3r4HG0zd0T2fsEeAlM3gPjpCcF1F3Mtah5Teq/ZQt5VrGAjXQVxkx96PdHNWX5kWdNefhTOMcFA2U+N4ChTkzxSiXAgMBAAECggEAfLci99zH6ZGrkM5E0GKaLMr2ZRm3ibEsFKVHC/Kkxilt8SK3G8MZGhvTL/MTOd/zVqD9iDM9i+pr9i8z5FyRRU98rtzofprob8WP9kjdZO7A7eQa2L/TdIkqogIFqCMBe2doPwPuCQGztRP0FNT10eyhCh5oGzD+sqZl/arNodz0bUZ7MQAwO4oUOVAIowxArzMoFrKzqTQrdGdAryCtRhUzR2oolFAV3nfskKr33UfdPs/usgOTX1Ud0F4iy5heT5ix9verFD82J1Cd6yHa29q8CQArC+HjvCUc1gYZ8/E84hLB2Le/a1W0tS8afNhHB7y9oI56PwKMFCdxALuG8QKBgQDlAjshWrfY2V/T3Zb5EUsm7eU0/DGwr3FBR0AHw6sdYsFeb0SUitSvsXcTySxMhG0UIIAeBH3KccsNF/sTQOEOGNzLOhMfDedrwLZsIOjy1+WGzvkBBAoH/5z67r/ICzwFkc7SjZbT6yNDpeHr51yY8YRxvosMyS6WWlMb+DoDgwKBgQDhbueDAi7Z5r4s8t9iU3MULyfEVm6ODrslpyG/IQMq6j1vObNtckppivOUMqAEIoCGtFxuSlVn+kz6vSAPFTZOIrgyf6D3YBcpgMfZZASdFgf6devqiTIqCPrMfXHmS0inJZXOVRX2kaTheYc9Mugtf34675SIGDmhKtUrMMb2XQKBgQCKmJoOqqefbpcnUvFe1Y+FBO717TdpdhR17FgdGteBllXvACoiOA9WMXIeoF7WBEM7rhu7jv5OOiYoS34hfd92t6dQu1n9Ll4DgYMl15kD95OqzbI3YilsA9AOsdWRjPMLb94a4aQJp0IVW9xp+AC7c1ezuxzOZSdzyUCJKeZ6XwKBgF4M9Q2VRZKnT8RU95mAE0zid4bUQH+H6dBFsDCbR0UKQOM8gX0x55Ws4P59OIFBG7oXWVCyNnuQ07jwWoWwZd2nYo2+7ZsHPeKU1cv+jGY1INL/i5Nn9cPPx0K1O2XHFuKVLbDNksIx9UYUe7WunWsN+83+0ksNQE3bHuBME1YJAoGAGtQ7qOlCRwr8mDPDV4FYJN36SbFPSi5jv4vE/SNyqfiwbQIffea8uhAHujNZ+mPreV8HK1FrQR2EZ4nFBFruw/MMafwQRXAnek9RceLmNYB2na87yRqOH0WpB63JKs++XtYerWsMSKIXds1FQNiwPCLeUrx5EOQtbScxKwIT91Y=";
        String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyaosB+6D2U28VH+f+81id6nQrbl2p4nLj5QKKhPJiIJlAFhhHCWTKjyYHtz27FNogCwwnipOFupVk8Ip8AKP5bqb5r6sNGvtUhY02pmcUJJfjqQ0E7lIrYATrSjQWcv9NfWjmFZ9UkzCorsyjE3vSuoM9AIV9zB7uLvTaEMTJITXJModmEh+wLz4ddZqRNnx95gN9qpdt6qk3CHc3SKUseuZBhfHXR719OOyIZ4B2fMXN227TQhqD+D8IaJSt6+BxtM3dE9n7BHgJTN4D46QnBdRdzLWoeU3qv2ULeVaxgI10FcZMfej3RzVl+ZFnTXn4UzjHBQNlPjeAoU5M8UolwIDAQAB";

        Base64.Encoder encoder = Base64.getEncoder();
        Base64.Decoder decoder = Base64.getDecoder();

        // 加密
        String publicMessage = encryptByPublicKeyPartition(content.getBytes(StandardCharsets.UTF_8), publicKey);
        System.out.println("公钥加密密文:" + publicMessage);
        // 加签
        byte[] sign = sign(publicMessage.getBytes(StandardCharsets.UTF_8), privateKey);
        byte[] signEncode = encoder.encode(sign);
        String privateSign = new String(signEncode);
        System.out.println("私钥加签密文:" + privateSign);

        // 传输
        // ...


        // 解密
        byte[] decode = decoder.decode(publicMessage.getBytes());
        String decryMessage = decryptByPrivateKeyPartition(decode, privateKey);
        System.out.println("明文:" + decryMessage);
        // 验签
        byte[] signDecode = decoder.decode(privateSign.getBytes());
        boolean verify = verify(publicMessage.getBytes(), signDecode, publicKey);
        System.out.println("验签结果:" + verify);
        // 流程: 加解密方式分段加解密,不然可能会提示 太长解密不了。
        // 1.先生成 密钥对 :见【生成密钥对.docx】
        // 2.交互: 公钥加密,私钥加签。
        // A 与 B 交互
        // A 使用 B 公钥加密报文 得到byte[],使用Base64编码数组,得到密文data
        // A 使用 A 私钥,加签密文data得到byte[],使用Base64编码数组,得到签名sign
        // 传输...
        // B 收到密文data,使用Base64编码data得到byte[]
        // B 使用A公钥验签
        // B 使用B私钥,解密byte[],得到明文报文

    }

}

生成密钥对文档:
找不到上传文档的地方…

1.登录http://web.chacuo.net/netrsakeypair (证书在线生成)
2.点击 rsa秘钥对
在这里插入图片描述
3.生成秘钥位数选择2048 秘钥格式选择pksc#8

在这里插入图片描述
4.点击生成秘钥 按页面提示分别保存为 ***pub.key ***pri.key即可

在这里插入图片描述

一些坑的地方:
1.生成密钥这只是其中一种方法,用其他方式(命令)等,注意参数就可以了
证书可以不选择,生成的密钥,使用时,不要换行。否则会报错。
2.工具类公钥加密后得到的byte[],不能直接new String,控制台打印会是乱码,并且不能用于后续str.getByte(),去解密这些。所以需要使用Base64编码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值