Java实现加密(五)Base64编码

news2024/12/23 3:43:48

目录

    • 一、Base64是怎么诞生的
    • 二、Base64定义
    • 三、Base64原理
      • 1.ASCII码转Base64(字节数 % 3 == 0)
      • 2.ASCII码转Base64(字节数 % 3 == 2)
      • 3.ASCII码转Base64(字节数 % 3 == 1)
      • 4.UTF-8转Base64
    • 四、Java实现Base64编解码
      • 1.方法一:DatatypeConverter(JDK6)
      • 2.方法二:Base64(JDK8)
      • 3.方法三:commons工具包
    • 五、总结
    • 六、补充:JS实现Base64编解码

Base64 在线编码/解码: https://base64.us/

一、Base64是怎么诞生的

  • 互联网发展早期,电子邮件是最有效的应用。
  • 电子邮件的 SMTP 传输协议在早期,只能用于传送 7 位的 ASCII 码,而ASCII码就是基于英语设计的,对于非英语国家的文字等资源就无法发送。
  • 为了解决这个问题,后来有了通用互联网邮件扩充协议 MIME ,这是一种用于在互联网上传输数据的标准,增加了邮件主题结构,定义了邮件、文本、音频、图像和多媒体文件等非ASCII码的编码传输规则。
  • Base64是MIME的一种编码方式。MIME规范中定义了Base64编码作为一种可靠的方式,用于在文本协议中表示二进制数据。通过使用Base64编码,可以将二进制数据转换为可打印字符,从而保证数据在传输过程中不受损失,并且能够被各种文本协议(如SMTP、HTTP)正确处理。
  • MIME中,当需要在文本协议中传输二进制数据(如邮件附件或图片数据)时,通常会将数据先进行Base64编码,然后将编码后的数据作为文本内容进行传输。

二、Base64定义

Base64 是一种用64个字符(a-z, A-Z, 0-9, +, /)来表示任意二进制数据的方法。

Base64 是一种索引编码,由于 2^6=64,所以每 6 个比特为一个单元,对应某个可打印字符,每个字符都对应一个索引。

索引和打印字符的对应关系如下:

索引对应字符索引对应字符索引对应字符索引对应字符
0A16Q32g48w
1B17R33h49x
2C18S34i50y
3D19T35j51z
4E20U36k520
5F21V37l531
6G22W38m542
7H23X39n553
8I24Y40o564
9J25Z41p575
10K26a42q586
11L27b43r597
12M28c44s608
13N29d45t619
14O30e46u62+
15P31f47v63/

三、Base64原理

Base64 编码要求把 3 个 8 位的字节(3*8=24)转化为 4 个 6 位的字节(4*6=24),之后在 6 位的前面补两个 0,形成 8 位一个字节的形式。 如果剩下的字符不足 3 个字节,则用 0 填充,输出字符使用 =,因此编码后输出的文本末尾可能会出现 1 或 2 个 =。

为了保证所输出的编码位可读字符,Base64 制定了一个编码表,以便进行统一转换。编码表的大小为 2^6=64,这也是 Base64 名称的由来。

1.ASCII码转Base64(字节数 % 3 == 0)

ASCII是8位一个字节,Base64是6位一个字节,

3个字节的ASCII编码刚好等于4个字节的Base64编码,3 * 8 = 4 * 6 = 24

示例:

  • ASCII编码:you
  • Base64编码:eW91

在这里插入图片描述

2.ASCII码转Base64(字节数 % 3 == 2)

ASCII是8位一个字节,Base64是6位一个字节,

2个字节的ASCII编码补2位零等于3个字节的Base64编码,不足4个字节的Base64编码使用 = 代替一个字节来补齐,2 * 8 + 2 = 3 * 6 = 18

示例:

  • ASCII编码:yo
  • Base64编码:eW8=

在这里插入图片描述

3.ASCII码转Base64(字节数 % 3 == 1)

ASCII是8位一个字节,Base64是6位一个字节,

1个字节的ASCII编码补4位零等于2个字节的Base64编码,不足4个字节的Base64编码使用 = 代替一个字节来补齐,1 * 8 + 4 = 2 * 6 = 12

示例:

  • UTF8编码:y
  • Base64编码:eQ==

在这里插入图片描述

4.UTF-8转Base64

UTF-8是8位一个字节,Base64是6位一个字节,

UTF-8里中文是三个字节,所以一个UTF-8编码的中文刚好可以转换为4个字节的Base64编码。3 * 8 = 4 * 6 = 24

示例:

  • ASCII编码:
  • Base64编码:5Lit

首先,由于系统中默认字符串的编码格式为 unicode,需要将字符串 转换为 utf-8 格式的二进制数组:

/**
 * 字节数组 转 二进制字符串
 * @param bytes 高位 到 低位
 * @return 二进制字符串
 */
public static String byteToBinStr2(byte[] bytes) {
    StringBuilder s1 = new StringBuilder();
    for (byte aByte : bytes) {
        s1.append(Long.toBinaryString((aByte & 0xFF) + 0x100).substring(1));
    }
    return s1.toString();
}

public static void main(String[] args) {
    System.out.println(byteToBinStr2("中".getBytes(StandardCharsets.UTF_8)));
}

执行结果:

在这里插入图片描述

每8位1字节分隔得到:

11100100 10111000 10101101

Base64编码:

在这里插入图片描述


四、Java实现Base64编解码

1.方法一:DatatypeConverter(JDK6)

使用 jdk 自带的 DatatypeConverter.java 类实现,但是 jdk 版本必须 >= 1.6

import java.io.UnsupportedEncodingException;
import javax.xml.bind.DatatypeConverter;

编码:

/**
 * base64 编码(方法一)
 * @explain DatatypeConverter.java实现
 * @param str 待编码字符串
 * @return 编码字符串
 */
public static String encode(String str) {
    // base64字符串
    String base64Str = "";
    try {
        // 非字符串才进行编码
        if (str != null && str.length() > 0) {
        	// String 转 byte[]
        	byte[] bytes = str.getBytes("utf-8");
            // 编码
            base64Str = DatatypeConverter.printBase64Binary(bytes);
        }
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return base64Str;
}

解码:

/**
 * base解码(方法一)
 * @explain DatatypeConverter.java实现
 * @param base64Str 待解码字符串
 * @return 解码字符串
 */
public static String decode(String base64Str) {
    // 解码后的字符串
    String str = "";
    // 非空字符串才进行解码
    if (base64Str != null && base64Str.length() > 0) {
        // 解码
        byte[] base64Bytes = DatatypeConverter.parseBase64Binary(base64Str);
        try {
            // byte[] 转 String
            str = new String(base64Bytes, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
    return str;
}

测试代码:

public static void main(String[] args) {
    String s = "y";
    String base64Str = encode2(s);
    System.out.println("原文:" + s);
    System.out.println("base64编码后(方法一):" + base64Str);
    System.out.println("base64解码后(方法一):" + decode2(base64Str));
}

执行结果:

在这里插入图片描述

2.方法二:Base64(JDK8)

使用 jdk 自带的 Base64.java 类实现,但是 jdk 版本必须 >= 1.8

import java.util.Base64;
import java.nio.charset.StandardCharsets;

编码:

/**
 * base64编码(方法二)
 * @explain Base64.java实现
 * @param str 待编码字符串
 * @return 编码字符串
 */
public static String encode2(String str) {
    // 非空字符串才进行编码
    if (str != null && str.length() > 0) {
        // String 转 byte[]
        byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
        // 编码(base64字符串)
        return Base64.getEncoder().encodeToString(bytes);
    }
    return "";
}

解码:

/**
 * base64解码(方法二)
 * @explain Base64.java实现
 * @param base64Str 待解码字符串
 * @return 解码字符串
 */
public static String decode2(String base64Str) {
    // 非空字符串才进行解码
    if (base64Str != null && base64Str.length() > 0) {
        // 编码
        byte[] base64Bytes = Base64.getDecoder().decode(base64Str);
        // byte[] 转 String(解码后的字符串)
        return new String(base64Bytes, StandardCharsets.UTF_8);
    }
    return "";
}

测试代码:

public static void main(String[] args) {
    String s = "y";
    String base64Str = encode2(s);
    System.out.println("原文:" + s);
    System.out.println("base64编码后(方法二):" + base64Str);
    System.out.println("base64解码后(方法二):" + decode2(base64Str));
}

执行结果:

在这里插入图片描述

3.方法三:commons工具包

<dependency>
	<groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.15</version>
</dependency>
import org.apache.commons.codec.binary.Base64;
import java.nio.charset.StandardCharsets;

编码:

/**
 * base64编码(方法三)
 * @explain commons工具包实现
 * @param str 待编码字符串
 * @return 编码字符串
 */
public static String encode3(String str) {
    // 非空字符串才进行编码
    if (str != null && str.length() > 0) {
        // String 转 byte[]
        byte[] bytes =  str.getBytes(StandardCharsets.UTF_8);
        // 编码(base64字符串)
        return Base64.encodeBase64String(bytes).replaceAll(" \r\n", "");
    }
    return "";
}

解码:

/**
 * base64解码(方法三)
 * @explain commons工具包实现
 * @param base64Str 待解码字符串
 * @return 解码字符串
 */
public static String decode3(String base64Str) {
    // 非空字符串才进行解码
    if (base64Str != null && base64Str.length() > 0) {
        // 解码
        byte[] base64Bytes = Base64.decodeBase64(base64Str);
        // byte[] 转 String(解码后的字符串)
        return new String(base64Bytes, StandardCharsets.UTF_8);
    }
    return "";
}

测试代码:

public static void main(String[] args) {
    String s = "y";
    String base64Str = encode3(s);
    System.out.println("原文:" + s);
    System.out.println("base64编码后(方法三):" + base64Str);
    System.out.println("base64解码后(方法三):" + decode3(base64Str));
}

执行结果:

在这里插入图片描述


五、总结

执行结果:方法一、方法二、方法三一致

效率:快–>慢:方法二 > 方法一 > 方法三

因此,如果项目用的是 jdk1.8,最佳选择是方法二;jdk1.6,最佳选择是方法一。


六、补充:JS实现Base64编解码

JavaScript 提供了两个原生的方法,用来处理Base64编码:btoa()atob()

  • btoa():Base64编码。
  • atob():Base64解码。

以上两个方法如果操作的字符串不是 ASCII 编码会报错:

例如:btoa('中')

VM707:1 Uncaught DOMException: Failed to execute ‘btoa’ on ‘Window’: The string to be encoded contains characters outside of the Latin1 range.

在这里插入图片描述

可以使用这两个方法,将非ASCII码的字符作为URI组件进行编码,然后再进行Base64编码。

  • encodeURIComponent():作为URI组件进行编码。
  • decodeURIComponent():作为URI组件进行解码。

综上所述,适用于所有情况(ASCII码+非ASCII码)的Base64编解码方法如下:

  • btoa(encodeURIComponent(待编码内容)):Base64 编码。
  • decodeURIComponent(atob(待解码内容)):Base64 解码。

注意:这种方法和UTF-8格式的加密不能通用。

执行结果:

在这里插入图片描述

整理完毕,完结撒花~ 🌻





参考地址:

1.Base64编码知识详解,https://baijiahao.baidu.com/s?id=1735577033729027737&wfr=spider&for=pc

2.什么是base64,https://zhuanlan.zhihu.com/p/76666060

3.Base64 编码/解码 | 菜鸟工具,https://c.runoob.com/front-end/693/

4.java base64编码、解码的三种方式,https://blog.51cto.com/u_15964717/6093954

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/670895.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android Binder通信原理(一):简介

源码基于&#xff1a;Android R 0. 前言 在Linux 系统中现有的进程间通信&#xff08;IPC&#xff09;方式&#xff1a; 管道(PIPE)&#xff1a;在创建时分配一个page大小的内存&#xff0c;缓存区大小比较有限&#xff1b;命名管道(FIFO)&#xff1a;考虑 PIPE_BUF 和原子操…

华为流程体系:IPD流程之敏捷开发(限制版)

目录 前言 敏捷 逐步采用敏捷原则 专栏列表 CSDN学院课程地址 前言 今天继续来谈谈 IPD 体系中敏捷开发所涉及的一些相关内容。 无论是硬件产品的开发过程&#xff0c;还是在应用或者是学习 IPD 的过程中。 瀑布式流程几乎都是标配。 这其实跟硬件产品或者是传统 IPD …

ROS:配置VScode

目录 前言一、下载二、vscode 安装三、vscode 集成 ROS 插件四、vscode 使用4.1 创建 ROS 工作空间4.2启动 vscode4.3vscode 中编译 ros4.4创建 ROS 功能包4.5C 实现4.6python 实现4.7配置 CMakeLists.txt4.8编译4.9执行 前言 VSCode 全称 Visual Studio Code&#xff0c;是微…

关于华为云服务器安装宝塔面板后,点击终端无响应解决方案

问题再现: 下面是我沟通宝塔客服后&#xff0c;给的解决方案。 我在百般无奈的情况下、卸载了宝塔后&#xff0c;最终躺平&#xff0c;选择了问宝塔官方客服 1、从华为提供的远程登录方式选一种 二、输入服务器密码通过ssh远程登录 服务器 二、执行宝塔官方提供的 命令执…

电影《闪电侠》观后感

上周看了电影《闪电侠》&#xff0c;主要是闪电侠这个人成长过程&#xff0c;与以往英雄题材类还是有些不太一样的&#xff0c;像之前蜘蛛侠和钢铁侠&#xff0c;都是讲主人公怎么成为那个英雄的&#xff0c;而本部电影是一个类似倒叙&#xff0c;他自己本身就已经是闪电侠了&a…

zookeeper安装使用及工作原理分析

1. Zookeeper概念简介 Zookeeper是一个分布式协调服务&#xff1b;就是为用户的分布式应用程序提供协调服务&#xff0c;它是集群的管理者&#xff0c;监视着集群中各个节点的状态&#xff0c;根据节点提交的反馈进行下一步合理操作。 具体介绍&#xff1a; A、zookeeper是为…

Electron详解(二):基本使用与项目打包

一、electron的基本使用 创建一个 electron 项目 在使用Electron进行开发之前&#xff0c;您需要安装 Node.js&#xff0c;最低工作版本为 14.x&#xff0c;低于 14 的版本在后面的打包过程中可能会报错。 &#xff08;注意&#xff0c;因为 Electron 将 Node.js 嵌入到其二…

嵌入式系统与大数据:选择哪个方向更好?

嵌入式系统和大数据是两个不同的领域&#xff0c;各有其独特的优势和发展前景。选择嵌入式系统还是大数据方向&#xff0c;应根据个人兴趣、技能背景以及市场需求进行综合评估。 嵌入式系统方向的优势&#xff1a;我资料有嵌入式、plc、单片机资料需要得可以私我 物联网&#…

在 ZBrush 中雕刻漫画风格的蝙蝠侠半身像

今天瑞云渲染小编给大家带来Rishikesh Nandlaskar分享蝙蝠侠造型背后的制作过程&#xff0c;解释了 ZBrush 和 Substance 3D Painter 中的工作流程&#xff0c;并分享了 Arnold 中的渲染设置。 介绍 我叫 Rishikesh Nandlaskar&#xff0c;是伦敦 Framestore VFX 工作室的高级…

使用数据泵+ogg同步oracle数据

本次迁移背景&#xff1a; 机房要搬迁&#xff0c;新搭建了一套oracle数据库&#xff0c;计划不停机迁移&#xff0c;将源端旧库的数据迁移到目标端新库里。 原本想用RMAN方式迁移&#xff0c;但是由于旧库是AIX系统&#xff0c;新库是linux系统&#xff0c;用RMAN迁移会有问…

SpringBoot2.3集成Spring Security(二) JWT认证

项目背景 紧接上文&#xff0c;我们已经完成了 SpringBoot中集成Spring Security&#xff0c;并且用户名帐号和密码都是从数据库中获取。但是这种方式还是不能满足现在的开发需求。 使用JWT的好处&#xff1a; 无状态认证&#xff1a;JWT本身包含了认证信息和声明&#xff0…

仓库管理软件哪个好?一键解决仓库出入库、管理库存,选这些软件

仓库管理软件哪个好? 仓库管理企业进销存的重要组成部分之一&#xff0c;现代物流中不可缺少的重要环节&#xff0c;对于企业管理的重要性不言而喻。 到底该如何选择仓库管理软件&#xff1f;让进销存老研究员帮你搞定 选择一个好的软件&#xff0c;首先明白他的作用。 向你…

【操作系统】生产者消费者问题实现

目录 实验原理&#xff1a; 实验内容&#xff1a; 实验器材&#xff08;设备、元器件&#xff09;&#xff1a; 实验步骤&#xff1a; 实验数据及结果分析&#xff1a; 实验原理&#xff1a; 考虑n个缓冲区的缓冲池作为一个共享资源&#xff0c;当生产者进程从数据源—文…

高级数据结构——二叉搜索树

目录 1. 二叉搜索树的概念 2. 二叉搜索树的实现 结点类 二叉搜索树的类 2.1 默认成员函数 2.1.1 构造函数 2.1.2 拷贝构造函数 2.1.3 赋值运算符重载函数 2.1.4 析构函数 2.2 中序遍历 2.3 insert插入函数 2.3.1 非递归实现 2.3.2 递归实现 2.4 erase删除函数 2…

App Inventor 2 语音交互机器人Robot,使用讯飞语音识别引擎

应用介绍 App Inventor 2 语音识别及交互App。识别语言指令并控制机器人运动&#xff0c;主要用到语音识别器及文本朗读器组件&#xff0c;语音识别相关开发最佳入门。代码逻辑简单&#xff0c;App交互性及趣味性非常强~ 视频预览 语音Robot教程&#xff08;难度系数&#xf…

中科院、中科大团队精确测量子引力对量子自旋的影响

光子盒研究院 由中国科学院盛东教授、陆征天教授和中国科学技术大学的合作研究小组利用高精度氙气同位素磁力仪研究了中子自旋和引力之间的耦合效应。5月15日&#xff0c;这项题为Search for Spin-Dependent Gravitational Interactions at Earth Range的研究发表在《物理评论快…

three.js常用几何体介绍以及自定义几何体

一、自定义三角形几何体 核心代码&#xff1a; // 添加物体 // 创建几何体 for (let i 0; i < 50; i) {// 每一个三角形&#xff0c;需要3个顶点&#xff0c;每个顶点需要3个值const geometry new THREE.BufferGeometry();const positionArray new Float32Array(9);for …

Java创建多线程的五种写法

目录 一.lambda表达式(强烈推荐,最简单) 基础格式 举例 运行结果 二.继承 Thread, 重写 run 基础格式 举例 运行结果 三.实现 Runnable, 重写 run 基础格式 举例 运行结果 四.使用匿名内部类,继承 Thread, 重写 run 基础格式 举例 运行结果 五.使用匿名内部类,实…

locust学习教程(8) - event 事件

目录 1、对请求的测试前置、后置处理 2、在web界面添加新内容 3、监听测试的失败率或阀值 4、汇总总结 &#x1f381;更多干货 1、对请求的测试前置、后置处理 请求有一个上下文参数&#xff0c;通过数据有关的请求&#xff08;之类的用户名&#xff0c;标签等&#xff09…