RSA解密,报错:“cn.hutool.crypto.CryptoException: BadBlockException: unable to decrypt block”

1.问题介绍

前端:angularjs

后端:springcloud

登录时,前端页面对password通过RSA加密后传入后端API接口,后端对RSA进行解密,......

通过系统页面登录一切正常,但是通过postman调用登录接口会报错。

 下面是用Postman测试接口,

- DUBBO - 服务响应: Client[consumer],InterfaceName=[SharetekRemoteClientService],MethodName=[queryByUserName],SpendTime=[23ms]
解密前1:G7BzsJn6LiCvXifIwW9KchNZq2u98dws9jLTCrkhjfLzXzmYRGaQr1lpYC1Y41TeBQ4h+BJZ2/1NPYu9FMrXDoYaOslNo0seCM9Ytg3XNxmvQZ6KDzxQxsDUorm4GPI1FvhI/tSOz9eSdohaWoQXzNkD4zUxX/8mKmqTt5NZUZY=
2024-07-03 18:43:12 [XNIO-1 task-2] INFO  c.s.c.log.event.LogEventListener
 - [127.0.0.1]内网IP[admin][Success][登录成功]
2024-07-03 18:43:12 [XNIO-1 task-2] INFO  c.s.c.d.filter.DubboRequestFilter
 - DUBBO - 服务调用: Client[consumer],InterfaceName=[RemoteLogService],MethodName=[saveLogininfor]
2024-07-03 18:43:12 [XNIO-1 task-2] INFO  c.s.c.d.filter.DubboRequestFilter
 - DUBBO - 服务响应: Client[consumer],InterfaceName=[RemoteLogService],MethodName=[saveLogininfor],SpendTime=[2ms]
2024-07-03 18:43:12 [XNIO-1 task-2] INFO  c.s.auth.listener.UserActionListener
 - user doLogin, useId:PC:1805808875250122752, token:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJQQzoxODA1ODA4ODc1MjUwMTIyNzUyIiwicm5TdHIiOiIyREhHcmx4NFhoa0g3eDJ5b2Z3ZWJNVkNpbllvYTZkWCIsInVzZXJJZCI6MTgwNTgwODg3NTI1MDEyMjc1MiwidXNlck5hbWUiOiJhZG1pbiIsImRlcHRJZCI6MSwiZGVwdE5hbWUiOiIiLCJkZXB0Q2F0ZWdvcnkiOiIifQ.ttv1dLxjSKPY8SO9JpyKsSl_jGyPva-yXQXc40pfd9Y
2024-07-03 18:43:12 [XNIO-1 task-2] INFO  c.s.auth.listener.UserActionListener
 - user doLogout, useId:PC:1805808875250122752, token:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJQQzoxODA1ODA4ODc1MjUwMTIyNzUyIiwicm5TdHIiOiJINEE3b2FUQ1BmWFFUZzB0UTI5M1l5c3I2U1JmUlp2cCIsInVzZXJJZCI6MTgwNTgwODg3NTI1MDEyMjc1MiwidXNlck5hbWUiOiJhZG1pbiIsImRlcHRJZCI6MSwiZGVwdE5hbWUiOiIiLCJkZXB0Q2F0ZWdvcnkiOiIifQ.BLGAMhsQvDza7AHGk1q2j7acF6UWg8n6psQp2rQNgp0
2024-07-03 18:43:17 [timeoutChecker_1_1] ERROR i.s.c.r.n.NettyClientChannelManager
 - no available service endpoint found in cluster 'default', please make sure registry config correct and keep your seata-server is running
2024-07-03 18:43:18 [timeoutChecker_2_1] ERROR i.s.c.r.n.NettyClientChannelManager
 - no available service endpoint found in cluster 'default', please make sure registry config correct and keep your seata-server is running
2024-07-03 18:43:27 [timeoutChecker_1_1] ERROR i.s.c.r.n.NettyClientChannelManager
 - no available service endpoint found in cluster 'default', please make sure registry config correct and keep your seata-server is running
2024-07-03 18:43:28 [timeoutChecker_2_1] ERROR i.s.c.r.n.NettyClientChannelManager
 - no available service endpoint found in cluster 'default', please make sure registry config correct and keep your seata-server is running
2024-07-03 18:43:37 [timeoutChecker_1_1] ERROR i.s.c.r.n.NettyClientChannelManager
 - no available service endpoint found in cluster 'default', please make sure registry config correct and keep your seata-server is running
2024-07-03 18:43:38 [timeoutChecker_2_1] ERROR i.s.c.r.n.NettyClientChannelManager
 - no available service endpoint found in cluster 'default', please make sure registry config correct and keep your seata-server is running
2024-07-03 18:43:40 [XNIO-1 task-2] INFO  c.s.c.d.filter.DubboRequestFilter
 - DUBBO - 服务调用: Client[consumer],InterfaceName=[SharetekRemoteClientService],MethodName=[queryByUserName]
2024-07-03 18:43:40 [XNIO-1 task-2] INFO  c.s.c.d.filter.DubboRequestFilter
 - DUBBO - 服务响应: Client[consumer],InterfaceName=[SharetekRemoteClientService],MethodName=[queryByUserName],SpendTime=[29ms]
2024-07-03 18:43:40 [XNIO-1 task-2] INFO  c.s.c.d.filter.DubboRequestFilter
 - DUBBO - 服务调用: Client[consumer],InterfaceName=[SharetekRemoteClientService],MethodName=[queryByUserName]
2024-07-03 18:43:40 [XNIO-1 task-2] INFO  c.s.c.d.filter.DubboRequestFilter
 - DUBBO - 服务响应: Client[consumer],InterfaceName=[SharetekRemoteClientService],MethodName=[queryByUserName],SpendTime=[30ms]
解密前1:G7BzsJn6LiCvXifIwW9KchNZq2u98dws9jLTCrkhjfLzXzmYRGaQr1lpYC1Y41TeBQ4h BJZ2/1NPYu9FMrXDoYaOslNo0seCM9Ytg3XNxmvQZ6KDzxQxsDUorm4GPI1FvhI/tSOz9eSdohaWoQXzNkD4zUxX/8mKmqTt5NZUZY=
2024-07-03 18:43:40 [XNIO-1 task-2] ERROR c.s.c.w.h.GlobalExceptionHandler
 - 请求地址'/api/token',发生未知异常.
cn.hutool.crypto.CryptoException: BadBlockException: unable to decrypt block
	at cn.hutool.crypto.asymmetric.AsymmetricCrypto.decrypt(AsymmetricCrypto.java:277)
	at cn.hutool.crypto.asymmetric.RSA.decrypt(RSA.java:174)
	at cn.hutool.crypto.asymmetric.AsymmetricDecryptor.decrypt(AsymmetricDecryptor.java:58)
	at cn.hutool.crypto.asymmetric.AsymmetricDecryptor.decryptStr(AsymmetricDecryptor.java:71)
	at cn.hutool.crypto.asymmetric.AsymmetricDecryptor.decryptStr(AsymmetricDecryptor.java:83)
	at com.sharetek.auth.utils.RSAUtils.decrypt(RSAUtils.java:77)
	at com.sharetek.auth.service.impl.SharetekPasswordAuthStrategy.sharetekLogin(SharetekPasswordAuthStrategy.java:122)
	at com.sharetek.auth.service.ISharetekAuthStrategy.login(ISharetekAuthStrategy.java:32)
	at com.sharetek.auth.controller.SharetekTokenController.login(SharetekTokenController.java:99)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:831)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)

密文对比如下:


//正确解密前1:G7BzsJn6LiCvXifIwW9KchNZq2u98dws9jLTCrkhjfLzXzmYRGaQr1lpYC1Y41TeBQ4h+BJZ2/1NPYu9FMrXDoYaOslNo0seCM9Ytg3XNxmvQZ6KDzxQxsDUorm4GPI1FvhI/tSOz9eSdohaWoQXzNkD4zUxX/8mKmqTt5NZUZY=



//postman解密前1:G7BzsJn6LiCvXifIwW9KchNZq2u98dws9jLTCrkhjfLzXzmYRGaQr1lpYC1Y41TeBQ4h BJZ2/1NPYu9FMrXDoYaOslNo0seCM9Ytg3XNxmvQZ6KDzxQxsDUorm4GPI1FvhI/tSOz9eSdohaWoQXzNkD4zUxX/8mKmqTt5NZUZY=

2.解决方法

对rsa密文里的所有空格用'+'替换即可。

3.RSA加解密

在前端用js进行rsa加密和在java端用hutool进行rsa加密,秘钥相同的前提下,生成的密文格式不同,java生成的密文更长,但是在服务端用hutool解密后的结果是一样的,前端js的密文用hutool包也可以完成解密。


// js端对Sharetek加密rsa后的密文
G7BzsJn6LiCvXifIwW9KchNZq2u98dws9jLTCrkhjfLzXzmYRGaQr1lpYC1Y41TeBQ4h+BJZ2/1NPYu9FMrXDoYaOslNo0seCM9Ytg3XNxmvQZ6KDzxQxsDUorm4GPI1FvhI/tSOz9eSdohaWoQXzNkD4zUxX/8mKmqTt5NZUZY=



// 用hutool包进行SRA加密后:0d4109384740aa7508e47ec58a6a1870027b5cb4ae68de1343f49e6d2a1d8becfc6da7a3f3521323597522f54f896ffd271e458e406be0317532649becc5b88de9827c6c56ca2ba8f6a167cd889f8160a3f12473b4ff91c93b85d8dd61fad646c1394cc4d4e78db07776c4d445b704ac09d6958980ab3da37ab54bfeda6ded86

4.hutool包RSA加解密工具类

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-crypto</artifactId>
            <version>5.8.27</version>
        </dependency>


package com.sharetek.auth.utils;

import cn.hutool.core.io.file.FileReader;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;


/**
 * @author tianjunmou
 * @title RSAUtils
 * @date 2024/6/25 14:50
 * @description RSA加解密工具类
 */
public class RSAUtils {

    // 在classpath下的公私钥文件
    // 文本格式的私钥内容(不包含-----BEGIN PRIVATE KEY-----,-----END PRIVATE KEY-----)
    private static String pubKeyFilePathInClasspath = "keys/public_key.pem";
    private static String priKeyFilePathInClasspath = "keys/private_key.pem";

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

        // 要加密的文本
        String text = "Sharetek";

        System.out.println("原始密码:" + text);

        long startTime = System.currentTimeMillis();
        // 获取公钥并进行rsa加密
        String encryptedString = encrypt(text, getPublicKey(pubKeyFilePathInClasspath));
        System.out.println("SRA加密后:" + encryptedString);
        // 获取私钥并进行rsa解密
//        encryptedString = "Kz72esN2/Ndx5wUmYPT9ntCFsbzrHCB1qKZu0AlCGDkLfmsnpW4b6wxT+iDEIQ9KAHRGkHgwi0DpgibmU5mxjsVQ+Ep1dvzvLyZP+HPLNitmjSf3F9149lLLqQRfrh5CrJdqRQb2mcUcA7NwVDa28qebdpkH8kahrVTPW2cZZ+Q=";
//        encryptedString = "i4Q01UvbWIA0M2kS4iWFd0Bh6th/bDSS0I/tQ2xGG/MEFLJY3KgQgx5UBI5xKHA05/7oAPf7X2E+M5t/k7/nIOkafMX6QZTy6kSkcyipO1Nc8s68FLVYUWQWWD9uPm5xYAYTlh43aAfolEoow5XeeoMIih7mIJomq5SQ0CoTK2Q=";

        encryptedString = "Fwoz75HNOffQfwgRkNt7IUJZoEuLrCI5gSZjpAx4npo2fe0gH6nlAO+hi6r3YwH7tC8mqgp1GP0mvujATpQEz4Zl+aZfkm/f8P0sqJTj6dBCPu2ph3Wcg1SvXI0TGeDsi+iyeTrzNM2cww53AeTpJS332bi39vso3p8iMA0aQL0=";



        String decryptedString = decrypt(encryptedString);

        System.out.println("耗时:" + (System.currentTimeMillis() - startTime) + "ms");

        System.out.println("解密后:" + decryptedString);

    }

    /**
     * 使用公钥加密
     *
     * @param text      待使用rsa加密的明文
     * @param publicKey 文本格式的公钥内容(不包含-----BEGIN PUBLIC KEY-----,-----END PUBLIC KEY-----)
     * @return
     */
    private static String encrypt(String text, String publicKey) {
        return new RSA(null, publicKey).encryptHex(text, KeyType.PublicKey);
    }

    /**
     * 使用私钥解密
     *
     * @param encryptedString 使用rsa加密的密文串
     * @return
     */
    public static String decrypt(String encryptedString) {
        System.out.println("解密前1:" + encryptedString);
        encryptedString = encryptedString.replaceAll(" ", "+");
        System.out.println("解密前2:" + encryptedString);
        String privateKey = null;
        String publickKey = null;
        try {
            privateKey = getPrivateKey(priKeyFilePathInClasspath);
            publickKey = getPublicKey(pubKeyFilePathInClasspath);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return new RSA(privateKey, null).decryptStr(encryptedString, KeyType.PrivateKey);
    }

    /**
     * 从公钥文件中读取公钥数据
     *
     * @param pubKeyFilePathInClasspath classpath下的公钥文件路径
     * @return
     * @throws Exception
     */
    private static String getPublicKey(String pubKeyFilePathInClasspath) throws Exception {
        return new FileReader(getAbsolutePath(pubKeyFilePathInClasspath)).readString();
    }

    /**
     * 从私钥文件中读取私钥数据
     *
     * @param priKeyFilePathInClasspath classpath下的私钥文件路径
     * @return
     * @throws Exception
     */
    private static String getPrivateKey(String priKeyFilePathInClasspath) throws Exception {
        return new FileReader(getAbsolutePath(priKeyFilePathInClasspath)).readString();
    }

    /**
     * 获取classpath下指定文件的绝对路径
     *
     * @param filePathInClasspath classpath下文件路径
     * @return
     */
    private static String getAbsolutePath(String filePathInClasspath) {
        return ClassLoader.getSystemClassLoader()
            .getResource(filePathInClasspath).getPath();
    }


}

参考资料:

Hutool参考文档Hutool,Java工具集icon-default.png?t=N7T8https://hutool.cn/docs/#/crypto/%E9%9D%9E%E5%AF%B9%E7%A7%B0%E5%8A%A0%E5%AF%86-AsymmetricCrypto 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值