分布式环境下使用RSA算法实现登录密码的加密传输

2023-11-15

目录

效果

RSA介绍

实现思路

服务端实现

​RSAService:RSA算法的相关操作

RedisService:公钥和密钥的存储和获取

获取公钥的接口

客户端使用公钥加密

服务端使用私钥解密


效果

RSA介绍

        RSA是一种非对称加密算法。
        非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。 非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将公钥公开,需要向甲方发送信息的其他角色(乙方)使用该密钥(甲方的公钥)对机密信息进行加密后再发送给甲方;甲方再用自己私钥对加密后的信息进行解密。甲方想要回复乙方时正好相反,使用乙方的公钥对数据进行加密,同理,乙方使用自己的私钥来进行解密。

        在我们Web环境中,甲方即为我们的服务端,乙方即为客户端。服务端需要生成一个公钥和一个私钥,私钥保管在服务端不能泄露,公钥可以公开给所有客户端。

在这里插入图片描述

实现思路

  1. 服务端在启动时,生成一个公钥和一个私钥。由于是分布式环境,需要将公钥和私钥存储于Redis,并设置过期时间。公钥和私钥的被动 “续期”,参见代码实现。
  2. 为了公开向客户端公开公钥,服务端需要提供一个获取公钥的接口,该接口从Redis中获取公钥返回给客户端。
  3. 登录页面(客户端)通过公钥将登录密码加密,通过http请求服务端
  4. 服务端拿到加密后的密码(密文),从Redis中获取私钥解密,得到原始密码。将原始密码以注册时相同的加密规则加密,与数据库中存储的密码比对,即可判断密码是否正确

服务端实现

下面的所有实现代码均在:https://github.com/passerbyYSQ/forum

​RSAService:RSA算法的相关操作

/**
 * @author passerbyYSQ
 * @create 2022-09-25 16:42
 */
public interface RSAService {
    KeyPair generateKeyPair();

    String getPublicKey();

    String getPrivateKey();

    String decryptByPrivateKey(String encryptedText);

    String encryptByPublicKey(String rawText);
}
/**
 * @author passerbyYSQ
 * @create 2022-09-25 15:36
 */
@Service
@Slf4j
public class RSAServiceImpl implements RSAService, ApplicationListener<ContextRefreshedEvent> {
    @Resource
    private RedisService redisService;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        // 对于web应用会出现父子容器,这样就会触发两次
        if (event.getApplicationContext().getParent() == null) {
            redisService.saveRSAKeyPair();
            log.info("成功将RSA的KeyPair缓存至Redis");
        }
    }

    @Override
    public KeyPair generateKeyPair() {
        try {
            KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
            generator.initialize(1024, new SecureRandom());
            return generator.generateKeyPair();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    public String getPublicKey() {
        KeyPair keyPair = redisService.getRSAKeyPair();
        byte[] publicBytes = keyPair.getPublic().getEncoded();
        byte[] base64Bytes = Base64.getEncoder().encode(publicBytes);
        return new String(base64Bytes);
    }

    public String getPrivateKey() {
        KeyPair keyPair = redisService.getRSAKeyPair();
        byte[] privateBytes = keyPair.getPrivate().getEncoded();
        byte[] base64Bytes = Base64.getEncoder().encode(privateBytes);
        return new String(base64Bytes);
    }

    public String decryptByPrivateKey(String encryptedText) {
        if (ObjectUtils.isEmpty(encryptedText)) {
            return null;
        }
        try {
            KeyPair keyPair = redisService.getRSAKeyPair();
            byte[] decodedBytes = Base64.getDecoder().decode(encryptedText.getBytes());
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
            byte[] decryptedBytes = cipher.doFinal(decodedBytes);
            return new String(decryptedBytes);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public String encryptByPublicKey(String rawText) {
        if (ObjectUtils.isEmpty(rawText)) {
            return null;
        }
        try {
            KeyPair keyPair = redisService.getRSAKeyPair();
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
            byte[] encryptedBytes = cipher.doFinal(rawText.getBytes());
            byte[] base64Bytes = Base64.getEncoder().encode(encryptedBytes);
            return new String(base64Bytes);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

RedisService:公钥和密钥的存储和获取

/**
 * @author passerbyYSQ
 * @create 2021-06-02 13:18
 */
public interface RedisService {

    void saveRSAKeyPair();

    KeyPair getRSAKeyPair();
}
/**
 * @author passerbyYSQ
 * @create 2021-06-02 13:21
 */
@Slf4j
@Service
public class RedisServiceImpl implements RedisService {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private RSAService rsaService;
    
    @Override
    public void saveRSAKeyPair() {
        String key = String.format(Constant.REDIS_KEY_KEY_PAIR, "RSA");
        KeyPair keyPair = rsaService.generateKeyPair();
        if (!ObjectUtils.isEmpty(keyPair)) {
            redisTemplate.opsForValue().setIfAbsent(key, keyPair, Constant.DURATION_KEY_PAIR);
        }
    }

    @Override
    public KeyPair getRSAKeyPair() {
        String key = String.format(Constant.REDIS_KEY_KEY_PAIR, "RSA");
        KeyPair keyPair = (KeyPair) redisTemplate.opsForValue().get(key);
        if (ObjectUtils.isEmpty(keyPair)) {
            saveRSAKeyPair(); // KeyPair过期,则重新续费
        }
        // 重新获取KeyPair,因为如果并发续费,成功续上的有可能不是本机生成的KeyPair
        return (KeyPair) redisTemplate.opsForValue().get(key);
    }
}

获取公钥的接口

        Controller中新增一个方法,调用RedisService中的RsaService的getPublicKey()方法获取公钥。此处略,在项目中我是直接通过模板引擎,将公钥植入到登录页面的。如下图,代码仅供参考,思路是一样的。

客户端使用公钥加密

        前端使用的加密类库是 jsencrypt(https://github.com/travist/jsencrypt),js文件下载:https://github.com/travist/jsencrypt/tree/master/bin

        使用比较简单,参见上面截图

服务端使用私钥解密

        服务端调用 RsaService的decryptByPrivateKey()方法解密即可获得明文。下面代码截图,仅供参考,思路是一样的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

分布式环境下使用RSA算法实现登录密码的加密传输 的相关文章

随机推荐

  • WSL子系统启动报错 Wsl/Service/CreateInstance/CreateVm/HCS_E_SERVICE_NOT_AVAILABLE

    今天琢磨着WindowsLinux子系统研究研究新东西 结果当我启动WSL时却出现了下面的提示 WSL启动报错 由于未安装所需的特性 无法启动操作 Error code Wsl Service CreateInstance CreateVm
  • url pattern中/与/*的区别

  • 爬虫入门级(五)

    Python爬虫入门级 五 实现两个小案例 1 gt 爬取豆瓣电影的TOP250 2 gt 爬取电影的资源下载地址 爬取豆瓣电影的TOP250 1 分页爬取数据 2 csv数据加载到本地 抓取豆瓣电影排行 1 判断页面元代满是否有数据 2
  • Postman 发送GET请求传递List自定义对象参数举例

    这是一个GET请求 后端接收方式 用List
  • 微服务简介

    微服务简介 微服务架构是一种软件架构模式 它将一个大型应用程序拆分为一组小型 独立的服务 每个服务都有自己的业务逻辑和数据存储 这些服务可以独立开发 部署和扩展 通常使用HTTP或其他轻量级通信协议进行通信 以下是微服务架构的一些关键特点和
  • android基础知识题,史上最全的Android面试题集锦

    Android基本知识点 1 常规知识点 1 Android类加载器 在Android开发中 不管是插件化还是组件化 都是基于Android系统的类加载器ClassLoader来设计的 只不过Android平台上虚拟机运行的是Dex字节码
  • 找不到该项目(无法删除文件)

    win10桌面新建文件提示 找不到该项目 该项目不在C users 中 请确认该项目的位置 然后重试 的原因是系统错误导致的 具体解决方法步骤如下 1 首先新建一个txt文件 为了方便txt文件建在跟目标文件供一个目录下 2 然后把下面代码
  • 学习lava源码时遇到的python知识

    内置函数 参考 https docs python org 3 7 library functions html Built in Functions abs delattr hash memoryview all dict help mi
  • MVC 模式与三层架构

  • Pr批量字幕制作

    一 标题字幕 1 选择文件 新建 旧版标题 2 根据所需设置一下 视频属性的高宽 是根据自己视频情况而定 一般新建的时候 就会根据自己导入的视频而显示 无需再设置 3 添加文字后 根据自己所需设置所需字幕 钢笔工具可以设置字幕移动 滚动字幕
  • 第十三届蓝桥杯大赛软件组省赛 Python大学A组 个人题解

    Link 文章目录 Python大学A组 个人题解 试题 A 裁纸刀 思路 代码 试题 B 寻找整数 思路 代码 试题 C 质因数个数 思路 代码 试题 D 矩形拼接 思路 代码 试题 F 重新排序 思路 代码 试题 G 全排列的价值 思路
  • Spring 系列

    前面几篇文章我们聊过IOC以及Spring IOC 其中Spring IOC 的一个实现方式包含 依赖查找 和依赖注入 本文我们进一步详细聊一下 SpringIOC的依赖查找 及其对应的方式 以及安全性 内置依赖等 查找类型 1单一类型 根
  • QTableView 添加进度条、下拉选择框、日历、图片、文字等(QAbstractItemDelegate)

    本文主要记录QTableView 使用代理添加进度条 下拉选择框 日历等 并实现复制粘贴 右键菜单等 效果如下图所示 最后有动态展示 图片说明 1 图中红色1处是 和 双击可以相互切换显示 2 图中红色2处是Qspinbox 实现整数输入
  • Selenium基础 — 鼠标操作

    1 鼠标事件介绍 前面例子中我们已经学习到可以用click 来模拟鼠标的单击操作 而我们在实际的web产品测试中发现 有关鼠标的操作 不单单只有单击 有时候还要用到右击 双击 拖动等操作 这些操作包含在ActionChains类中 2 Ac
  • 【github】无需拉取项目,在线使用 vscode 进行 code review

    打开任意一个项目 将域名中的github改为github1s 例如 https github com ranmaxli python service https github1s com ranmaxli python service 即可
  • linux module 目录,/sys/module/ 模块信息目录与/proc/modules文件

    在内核模块编译中 会选择编译成模块 或者build in 内核镜像中 其中对内核模块有很好的的说明 这也是linux在嵌入式当中得到广泛应用的充分体现 内核中有很多功能选项 其中有许多使我们不需要的 内核设计成模块的优势所在就在这里 不需要
  • [Python从零到壹] 三十七.图像处理基础篇之图像融合处理和ROI区域绘制

    欢迎大家来到 Python从零到壹 在这里我将分享约200篇Python系列文章 带大家一起去学习和玩耍 看看Python这个有趣的世界 所有文章都将结合案例 代码和作者的经验讲解 真心想把自己近十年的编程经验分享给大家 希望对您有所帮助
  • 常见七大排序算法

    目录 前言 冒泡排序 选择排序 插入排序 希尔排序 shell 快速排序 归并排序 计数排序 前言 在前面我发布了常见的七大排序算法的相关博客 今天这一篇文章是做一个排序算法的小总结 把前面的博客集中分类到一起 方便大家查看 下面就可以去通
  • 树莓派 /bin/sh: 1: /usr/bin/apt-listchanges: not found 返回了一个错误号 (1) --apt

    问题 bin sh 1 usr bin apt listchanges not found E 子进程 usr bin apt listchanges apt test lt 10 返回了一个错误号 1 E Failure running
  • 分布式环境下使用RSA算法实现登录密码的加密传输

    目录 效果 RSA介绍 实现思路 服务端实现 RSAService RSA算法的相关操作 RedisService 公钥和密钥的存储和获取 获取公钥的接口 客户端使用公钥加密 服务端使用私钥解密 效果 RSA介绍 RSA是一种非对称加密算法