常见加密算法实现——DES、AES、RSA、MD5

2023-11-12

一、对称加密

1、介绍

对称加密:加密和解密使用同一个密钥。
对称加密算法:DES、3DES、AES等。
     DES:数据加密标准,是一种使用密钥加密的块算法;
     3DES:DES向AES过渡的加密算法;
     AES:高级加密标准,替代DES;

对称加密的特点:

  • 加密速度快,可加密大文件;
  • 密文可逆,数据容易暴露;
  • 加密后编码找不到对应字符,出现乱码;
  • 一般结合base64使用

2、加密模式

有两种加密模式:ECB、CBC
ECB:电子密码本. 需要加密的消息按照块密码的块大小被分为数个块,并对每个块进行独立加密。

  • 优点:可以并行处理数据;
  • 缺点:同样的原文生成同样的密文, 不能很好的保护数据;

CBC:密码块链接. 每个明文块先与前一个密文块进行异或后,再进行加密。

  • 优点:同样的原文生成的密文不一样;
  • 缺点:串行处理数据.;

3、填充模式

当需要按块处理的数据, 数据长度不符合块处理需求时, 按照一定的方法填充满块长的规则。

NoPadding:不填充;

  • 在DES加密算法下, 要求原文长度必须是8byte的整数倍
  • 在AES加密算法下, 要求原文长度必须是16byte的整数倍

PKCS5Padding:数据块的大小为8位, 不够就补足;

4、Base64算法

  • Base64算法是可读性编码算法,不是为了保护数据安全性。是为了数据可读;
  • 可读性编码不改变信息内容,只改变信息的表现形式;
  • Base64在编码过程中用到了64种字符,A-Z,a-z,0-9,“+”,“/”;

Base64算法原理:

  • base64是3个字节为1组,1个字节8位,一共24位;然后把3个字节转成4组,每组6位;缺少的2为,高位补0;这样base64的取值就控制在0-63之间了;
  • base64是3个字节为1组,位数不够时,用 = 来补齐;

说明:

  • 默认情况下, 加密模式和填充模式为 : ECB/PKCS5Padding;
  • 如果使用CBC模式, 在初始化Cipher对象时, 需要增加参数, 初始化向量IV : IvParameterSpec iv = new IvParameterSpec(key.getBytes());

5、DES/AES加密解密代码

/**
 * @author:秋一叶
 * @date:2020-11-18 9:11
 *  DES/AES加密解密
 */
public class DesAesDemo {
    public static void main(String[] args) throws Exception {
        String input = "原文";

        //key:DES加密算法的key必须是8个字节
        String key = "abcd1234";
        //key:AES加密算法的key必须是16个字节
        String key2 = "abcdefgh12345678";

        //获取Cipher对象的算法,默认加密模式和填充模式为 ECB/PKCS5Padding
        String transformation = "DES";
        //加密模式为CBC,必须指定初始向量,初始向量中密钥长度必须是8个字节
        String transformation1 = "DES/ECB/PKCS5Padding";
        //填充模式为NoPadding,原文的长度必须是8字节的整数倍
        String transformation2 = "DES/ECB/PKCS5Padding";

        //指定加密算法
        String algorithm = "DES";

        String encryptDES = encryptDES(input, key, transformation, algorithm);
        System.out.println("加密后为:" + encryptDES);

        String decryptDES =  decryptDES(encryptDES, key, transformation, algorithm);
        System.out.println("解密后为:" + decryptDES);
    }

    /**
     * 加密
     * @param input 原文
     * @param key   密钥
     * @param transformation    获取Cipher对象的算法
     * @param algorithm         获取密钥的算法
     * @return
     */
    public static String encryptDES(String input, String key, String transformation, String algorithm) throws Exception {
        //获取加密对象
        Cipher cipher = Cipher.getInstance(transformation);
        //创建加密规则
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);

        //加密模式为CBC时:初始向量,长度必须是8位
        IvParameterSpec iv = new IvParameterSpec(key.getBytes());

        //初始化加密模式和算法
        cipher.init(Cipher.ENCRYPT_MODE, sks);
        //加密
        byte[] bytes = cipher.doFinal(input.getBytes());
        //对数据进行Base64编码
        String encode = Base64.encodeBase64String(bytes);
        return new String(encode);
    }

    /**
     * 解密
     * @param input
     * @param key
     * @param transformation
     * @param algorithm
     * @return
     * @throws Exception
     */
    public static String decryptDES(String input, String key, String transformation, String algorithm) throws Exception {
        //获取解密对象
        Cipher cipher = Cipher.getInstance(transformation);
        //指定密钥规则
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);

        //加密模式为CBC时:初始向量,长度必须是8位
        IvParameterSpec iv = new IvParameterSpec(key.getBytes());

        //初始化加密模式和算法
        cipher.init(Cipher.DECRYPT_MODE, sks);
        //对数据进行Base64转码,解密
        byte[] bytes = cipher.doFinal(Base64.decodeBase64(input));
        return new String(bytes);
    }
}

说明:

  • DES和AES代码一样,只需要将指定的加密算法换一下就可以。
  • DES加密算法的key必须是8个字节,AES加密算法的key必须是16个字节。
  • 默认加密模式和填充模式为 ECB/PKCS5Padding。
  • 加密模式为CBC,必须指定初始向量,初始向量中密钥长度必须是8个字节。
  • 填充模式为NoPadding,原文的长度必须是8字节(AES是16字节)的整数倍。

二、非对称加密

1、介绍

非对称加密:加密和解密使用一对密钥(公钥和私钥),公钥加密则私钥解密,私钥加密则公钥解密。
非对称加密算法:RSA、ECC等。

非对称加密的特点:

  • 处理数据的速度较慢, 因为安全级别高;

2、RSA加密与解密代码

/**
 * @author:秋一叶
 * @date:2020-11-18 16:01
 * 非对称加密RSA
 *      综合,先把私钥和公钥保存到本地文件中,再读取出来进行私钥加密,公钥解密
 */
public class RsaDemo03 {
    public static void main(String[] args) throws Exception {
        String input = "原文";

        //generateKeyToFile("RSA", "a.pub", "a.pri");
        PrivateKey privateKey = getPrivateKey("a.pri", "RSA");
        PublicKey publicKey = getPublicKey("a.pri", "RSA");

        //加密
        String encrypt = encryptRSA("RSA", privateKey, input);
        //解密
        String decrypt = decryptRSA("RSA", publicKey, encrypt);
        System.out.println("解密后:" + decrypt);

    }

    /**
     * 保存公钥和私钥到本地文件
     * @param algorithm 加密算法
     * @param pubPath   公钥保存路径
     * @param priPath   私钥保存路径
     * @throws Exception
     */
    private static void generateKeyToFile(String algorithm, String pubPath, String priPath) throws Exception{
        //创建密钥对生成器对象
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        //生成密钥对
        KeyPair keyPair = kpg.generateKeyPair();
        //生成私钥和公钥
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();
        //获取私钥公钥字节数组
        byte[] privateKeyEncoded = privateKey.getEncoded();
        byte[] publicKeyEncoded = publicKey.getEncoded();
        //对公私钥进行base64编码
        String privateKeyString = Base64.encodeBase64String(privateKeyEncoded);
        String publicKeyString = Base64.encodeBase64String(publicKeyEncoded);

        //保存文件
        FileUtils.writeStringToFile(new File(pubPath), publicKeyString, Charset.forName("UTF-8"));
        FileUtils.writeStringToFile(new File(priPath), privateKeyString, Charset.forName("UTF-8"));
    }

    /**
     * 读取私钥
     * @param priPath
     * @param algorithm
     * @return
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String priPath, String algorithm) throws Exception{
        //将文件内容转为字符串
        String privateKeyString = FileUtils.readFileToString(new File(priPath), Charset.defaultCharset());
        //获取密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        //构建密钥规范,进行Base64解码
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyString));
        //生成私钥
        return keyFactory.generatePrivate(spec);
    }

    /**
     * 读取公钥
     * @param pulickPath
     * @param algorithm
     * @return
     * @throws Exception
     */
    public static PublicKey getPublicKey(String pulickPath,String algorithm) throws Exception{
        // 将文件内容转为字符串
        String publicKeyString = FileUtils.readFileToString(new File(pulickPath), Charset.defaultCharset());
        // 获取密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        // 构建密钥规范 进行Base64解码
        X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyString));
        // 生成公钥
        return keyFactory.generatePublic(spec);
    }

    /**
     * 公钥解密
     * @param algorithm 加密算法
     * @param key   公钥
     * @param encrypted 密文
     * @return
     * @throws Exception
     */
    public static String decryptRSA(String algorithm,Key key,String encrypted) throws Exception{
        // 创建加密对象
        // 参数表示加密算法
        Cipher cipher = Cipher.getInstance(algorithm);
        // 私钥进行解密
        cipher.init(Cipher.DECRYPT_MODE,key);
        // 由于密文进行了Base64编码, 在这里需要进行解码
        byte[] decode = Base64.decodeBase64(encrypted);
        // 对密文进行解密,不需要使用base64,因为原文不会乱码
        byte[] bytes1 = cipher.doFinal(decode);
        System.out.println(new String(bytes1));
        return new String(bytes1);
    }

    /**
     * 私钥加密
     * @param algorithm 加密算法
     * @param key   私钥
     * @param input 原文
     * @return
     * @throws Exception
     */
    public static String encryptRSA(String algorithm,Key key,String input) throws Exception{
        // 创建加密对象
        // 参数表示加密算法
        Cipher cipher = Cipher.getInstance(algorithm);
        // 初始化加密
        // 第一个参数:加密的模式
        // 第二个参数:使用私钥进行加密
        cipher.init(Cipher.ENCRYPT_MODE,key);
        // 私钥加密
        byte[] bytes = cipher.doFinal(input.getBytes());
        // 对密文进行Base64编码
        return Base64.encodeBase64String(bytes);
    }
}

说明:

  • 该案例是私钥加密,公钥解密;
  • 先把密钥生成器生成的公钥和私钥保存到本地中,用的时候直接从本地中获取;

三、散列(哈希)算法

1、介绍

常见哈希算法:MD5、SHA-1、SHA-256、SHA-512;
哈希加密函数通常用来做消息摘要;

2、消息摘要

  • 消息摘要也叫数字摘要;
  • 使用数字摘要生成的值不可以篡改;
  • 消息摘要是单向,不可逆的;
  • 计算的出的消息摘要长度是固定的,MD5(128位),SHA-1(160位);

3、获取数字摘要代码

/**
 * @author:秋一叶
 * @date:2020-11-18 15:43
 * 消息摘要:MD5
 */
public class DigestDemo {
    public static void main(String[] args) throws Exception {
        String input = "原文";
        //获取数字摘要对象
        MessageDigest messageDigest = MessageDigest.getInstance("MD5");
        //获取数字摘要的字节数组
        byte[] digest = messageDigest.digest(input.getBytes());
        //System.out.println(Base64.encodeBase64String(digest));

        StringBuilder sb = new StringBuilder();
        for(byte b : digest){
            //转成16进制
            String s = Integer.toHexString(b & 0xff);
            if(s.length() == 1){
                s = "0" + s;
            }
            sb.append(s);
        }
        System.out.println(sb.toString());
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

常见加密算法实现——DES、AES、RSA、MD5 的相关文章

  • 在java中将StreamWriter转换为OutputStream?

    我正在尝试使用 System setOut 将 System out 重定向到字符串 它需要一个 PrintStream 有什么方法可以将 StringWriter 转换为 Stream 以便我可以将其传递给 setOut 吗 你不能完全这
  • JAVA - 带有特殊字符的 LDAP 密码不起作用

    我试图在我的系统上创建一个登录屏幕 在 Active Directory 中进行查询 但是当用户的密码包含一些特殊字符 如 和 时 它不会验证 我需要加密密码才能工作吗 我该怎么做 我使用 getPassword 通过 JPasswordF
  • 从 OMElement 对象获取 InputStream/io.Reader

    我有一个OMElement对象 从中我想得到一个InputStream或读者对象 我想要的是流式传输xml来自OMElement我有 没有加载到内存中 我只能得到XMLStreamReader对此表示反对 但我找不到办法得到InputStr
  • Java Swing:清除JList而不触发监听器

    我的情况如下 我有一个 JList 只要在列表中进行选择 它就会触发搜索 使用 ListSelectionListener 我正在尝试使用以下命令重置列表上的选择list clearSelection 这样做的问题是使用clearSelec
  • firestore快照监听器生命周期和定价之间有什么关系?

    在我的活动中 我有一个字符串列表 这些字符串表示我想要附加快照侦听器的 Firestore 文档 我使用 Acivity ModelView 存储库结构 在活动的 onCreate 中 我向 ViewModelProvider 询问适当的
  • 无法从后台服务通过 WiFi 访问互联网

    我将直接介绍我发现的一些事实 数据 如果您遇到 解决了类似的问题 请帮助我 我每 5 分钟向服务器发送一次数据 除非用户在服务器的帮助下手动将其关闭 wakeful broadcast receiver通过一个intent service
  • 会话 bean 中的 EntityManager 异常处理

    我有一个托管无状态会话 bean 其中注入了 EntityManager em 我想做的是拥有一个具有唯一列的数据库表 然后我运行一些尝试插入实体的算法 但是 如果实体存在 它将更新它或跳过它 我想要这样的东西 try em persist
  • LibGdx 如何使用 OrthographicCamera 滚动?

    我已经找了 10 个小时 字面意思 我已经完成了 我需要问一下 事情是我正在学习如何使用 LibGdx 来编写 Java 游戏 我正在做一个水平太空飞船游戏 所以 我最糟糕的问题是我不知道如何滚动 我认为绘制会更好地解释 我想绘制一个巨大的
  • JSP 标签+ scriptlet。如何启用脚本?

    我有一个使用标签模板的页面 我的 web xml 非常基本 我只是想在页面中运行一些代码 不 我对标签或其他替代品不感兴趣 我想使用不好的做法 scriptlet 哈哈 到目前为止 我收到了 HTTP ERROR 500 错误 Script
  • Java G1 GC 处理引用对象运行缓慢

    我已经在 J ava 上运行了计数器 它24小时工作 每秒点击通过100次左右 白天 GC 处理时间从 20 60 毫秒缓慢上升到 10000 60000 毫秒 然后下降到 20 60 毫秒 这种模式不时地重复 从 GC 日志中我发现 GC
  • 如何在将数据发送到 Firebase 数据库之前对其进行加密?

    我正在使用 Firebase 实时数据库制作聊天应用程序 我知道 Firebase 非常安全 只要您的规则正确 但我自己可以阅读使用我的应用程序的人的所有聊天记录 我想阻止这种情况 为此我需要一种解密和加密方法 我尝试使用凯撒解密 但失败了
  • 嵌入式 tomcat 7 servlet 3.0 注释不起作用

    我有一个精简的测试项目 其中包含 Servlet 版本 3 0 用注释声明 如下所示 WebServlet test public class TestServlet extends HttpServlet private static f
  • @TestPropertySource 不适用于 Spring 1.2.6 中使用 AnnotationConfigContextLoader 的 JUnit 测试

    似乎我在 Spring 4 1 17 中使用 Spring Boot 1 2 6 RELEASE 所做的任何事情都不起作用 我只想访问应用程序属性并在必要时通过测试覆盖它们 无需使用 hack 手动注入 PropertySource 这不行
  • 用 Java 创建迷宫求解算法

    我被分配了用 Java 创建迷宫求解器的任务 这是任务 Write an application that finds a path through a maze The maze should be read from a file A
  • 将字符串中的字符向左移动

    我是 Stack Overflow 的新手 有一道编程课的实验室问题一直困扰着我 该问题要求我们将字符串 s 的元素向左移动 k 次 例如 如果输入是 Hello World 和3 它将输出 lo WorldHel 对于非常大的 k 值 它
  • Scala repl 抛出错误

    当我打字时scala在终端上启动 repl 它会抛出此错误 scala gt init error error while loading AnnotatedElement class file usr lib jvm java 8 ora
  • JDK 7 的快速调试/调试构建

    我正在寻找 JDK 的调试 或者我猜他们称之为快速调试构建 以启用在运行时生成的打印程序集以及查找性能问题时所需的其他诊断 就目前情况而言 我似乎找不到可以直接使用的 现成的 快速调试构建二进制包 有人可以帮我提供下载链接 或者至少提供有关
  • 使用 Android 的 Mobile Vision API 扫描二维码

    我跟着这个tutorial http code tutsplus com tutorials reading qr codes using the mobile vision api cms 24680关于如何构建可以扫描二维码的 Andr
  • 如何在Java中跨类共享变量,我尝试了静态不起作用

    类 Testclass1 有一个变量 有一些执行会改变变量的值 现在在同一个包中有类 Testclass2 我将如何访问 Testclass2 中变量的更新值 由 Testclass1 更新 试过这个没用 注意 Testclass1和Tes
  • 如何使用 Spring AOP 建议静态方法?

    在执行类的静态方法之前和之后需要完成一些日志记录 我尝试使用 Spring AOP 来实现这一点 但它不起作用 而对于正常方法来说它起作用 请帮助我理解如何实现这一点 如果可以使用注释来完成 那就太好了 也许您应该在使用 Spring AO

随机推荐