6

快速掌握 Base 64 | Java JS 密码系列 - 程序员优雅哥

 2 years ago
source link: https://www.cnblogs.com/youyacoder/p/16613053.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Java 密码系列 - Java 和 JS Base 64

Base 64 不属于密码技术,仅是编码方式。但由于在 Java、JavaScript、区块链等出现的频率较高,故在本系列文章中首先分享 Base 64 编码技术。前面部分主要介绍 Base 64 理论性的内容,如果只看在 Java(SpringBoot)或 JS(Vue)中的实现,可以直接跳到最后。

本文所有代码可在 github 上获取:

  • 后端代码搜索 hero-springboot-demo
  • 前端代码搜索 hero-vue3-demo

1 Base 64 介绍

要说清楚 Base 64 编码,首先得从 byte 开始说。

1.1 关于byte

在 Java 中,byte 是 8 种基本数据类型之一。byte 类型表示字节,一个字节由 8 个 bit (比特/位)组成。每个 bit 位表示一个二进制,即 0 或 1。在操作系统中,byte 是数据存储的基本单位,如描述硬盘的大小是 512 MB,其基本单位就是 byte。

  • bit:比特、位,每个 bit 不是 0 就是 1;
  • byte:字节,数据存储的基本单位;
  • 1 byte = 8 bit

在 Java 中可以通过 getBytes(StandardCharsets.UTF_8) 方法获取字符串的 byte 数组。

@Test
public void testStrBytes() {
    String str = "a";
    byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
    for (byte b : bytes) {
        System.out.println(b); // 97
        System.out.println(Integer.toBinaryString(b)); // 1100001
    }
}

字符 a 的 ASCII 码是 97,通过 Integer.toBinaryString(b) 方法,获取字节对应的 bit 字符串。二进制 1100001 对应的十进制为 97。

一个英文字符对应了1个 byte,即 8 个 bit;如果是 3个英文字符,则会对应 3 个 byte,也就是 3 * 8 = 24 个 bit。彻底弄清楚 byte 和 bit 后,接下来看看 Base 64 编码。

1.2 Base 64 组成

前面说过,Base 64 是一种编码方式,目的是提高可读性,不具有安全的功能。

从名字上看。64 是指 64 个字符,就是指这种编码方式得到的结果在这 64 个字符中。注意,不是说编码后的结果的长度为 64,而是组成编码结果每一位的字符都在 64 个字符之内。这 64 个字符包括:

  • 大写 A - Z,共 26 个;
  • 小写 a - z,共 26个;
  • 数字 0 - 9,共 10 个;
  • 两个符号:加号 + 和 斜线 /

26 + 26 + 10 + 2 = 64。

这 64 个字符各自对应一个值,依次为 0 - 63,例如 X 的码值为23, 如果某一位计算后的结果为 23,则该位为 X。 具体对应关系如下图所示:

image-20220815010154596

在区块链中有种类似的编码 —— Base 58,与 Base 64 类似,在其基础上少了 6 个字符,这六个字符包括 斜线加号 两个符号、看似双胞胎的字符:数字 0、小写字母 o、大写字母 I 和 小写字母 i

1.3 Base 64 原理

在 1.1 中谈到一个字节 byte 为 8 个bit,那么一个字节的取值范围就是 00000000 - 11111111,对应的十进制为 0 - 255,而上表中的码值为 0 - 63,那 Base 64 是如何处理的呢,如何将所有字符、文字都控制在 0 - 63 之间呢?

  • 首先进行分组。3 个字节分为一组,由于一个字节有 8 位(bit),一共就是 3 * 8 = 24 位;
  • 接着分组转换。把上面的 24 位分成 4 组,每组就有 24 / 4 = 6 位(bit)
  • 最后高位补0。由于一个字节 byte 为 8 位 bit,上面每组只有 6 位,于是就在高位补 0。

通过上面步骤,就将 3 个字节 byte 转换为 4 个字节 byte,且转换后的每个 byte 最高两位都为 0,意味着转换后的每个字节都在 00000000 - 00111111 之间,对应的十进制就是 0 - 63。

上面说按 3 个字节进行分组,但并非所有的字符或文本都是 3 的整数倍,这时候怎么办呢?当不够 3 位时,首先补 0 进行分组,计算得到结果后使用了几个 0 补齐就使用几个等号 = 来补齐。差一位就用一个等号,差两位就用两个等号。

举例:对字符串 ab 进行 Base64

字符串 ab 只占了两个字节,还差一位,于是最后一位补 0 来进行分组和计算,在最后使用一个等号=来补齐。计算过程如下图所示:

image-20220815015739522

这样便得到字符串 ab Base 64 的结果为:YWI=

2 Java 实现

2.1 使用 java.util.Base64

JDK 中提供了 java.util.Base64 类来实现 Base 64 的编码和解码。

Base64.getEncoder().encodeToString(bytes);
Base64.getDecoder().decode(bytes);

2.2 使用 springframework

在 SpringBoot 中,springframework 对 java.util.Base64 进行了封装,提供了 org.springframework.util.Base64Utils 类方便进行编码和解码。

package com.yygnb.demo.crypto;

import org.junit.Test;
import org.springframework.util.Base64Utils;

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

/**
 * Base64 编码解码测试
 */
public class Base64Test {

    /**
     * JDK Base64 编码
     */
    @Test
    public void testEncode() {
        String result = Base64.getEncoder().encodeToString("ab".getBytes(StandardCharsets.UTF_8));
        System.out.println(result); // YWI=
    }

    /**
     * JDK Base64 解码
     */
    @Test
    public void testDecode() {
        byte[] decode = Base64.getDecoder().decode("YWI=");
        String plainText = new String(decode);
        System.out.println(plainText); // ab
    }

    /**
     * springframework Base64 编码
     */
    @Test
    public void testUtilsEncode() {
        String result = Base64Utils.encodeToString("ab".getBytes(StandardCharsets.UTF_8));
        System.out.println(result); // YWI=
    }

    /**
     * springframework Base64 解码
     */
    @Test
    public void testUtilsDecode() {
        byte[] bytes = Base64Utils.decodeFromString("YWI=");
        System.out.println(new String(bytes)); // ab
    }
}

3 JS 实现

JS 在浏览器环境中有两种实现方式:基于原生 JS 和基于 js-base64。

3.1 使用原生 JS

window.btoa(unescape(encodeURIComponent(value)))
decodeURIComponent(escape(window.atob(value)))

使用这种方式不需要额外添加依赖,但是兼容性各种问题,不推荐使用。建议使用 js-base64 的方式。

3.2 使用 js-base64

js-base64 是使用较高的 Base 64 库,使用方便,兼容性和容错性较好,推荐使用这种方式。

1)安装依赖:

yarn add js-base64

2)引入 js-base64

import { Base64 } from 'js-base64'

3)编码:

Base64.encode(value)

4)解码:

Base64.decode(value)

对应 demo 位于 src/views/base64.vue

image

\/ “程序员优雅哥”,今日学习到此结束~~~


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK