base64算法详解

引言

Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。

以上是百度百科的定义。

当需要对二进制数据进行编码时,通常使用Base64编码方案,这些二进制数据需要通过设计用来处理文本数据的媒体进行存储和传输。这是为了确保数据在传输过程中不发生任何修改而保持完整。Base64通常用于许多应用程序中,包括通过MIME发送电子邮件和用XML存储复杂数据。

Base64算法原理

构成base所需的64个字符的特定字符的选择因实现而异。通常的规则是选择一组64个字符,它们既是大多数编码所共有的子集的一部分,也是可打印的。这种组合使得数据不太可能在通过电子邮件等传统上不是8位加密的系统传输时进行修改。例如,MIME的Base64实现对前62个值使用A-Z、A-Z和0-9。其他的变体,通常来自Base64,共享这个属性,但是在最后两个值中选择的符号不同。通常说的Base64最后两个字符是'+'和'/',映射表如下:

20180808210348.png

Base64的加密过程图解如下:

20180808214808.png

20180808214546.png

首先,先将字符以标准字节(byte)为单位转化为二进制,一个字节占8位(bit),如M的二进制是01001101,将字符串的的所有字符转成二进制后,再将这些二进制以base64的规则进行6位一组进行分割(不足6位在右侧补0),然后将每组转成十进制(000000-111111即0-63)作为索引从映射表中获取字符进行组装,得到最后的密文。在最后的密文组装中也需要4个一组,如果最后的内容不足4位,则用'(pad)='进行补位,因此得到的密文长度一定是4的倍数。

解码的方式将上面的过程反过来即可。

由于Base64算法公开,通过固定的规则就能得到加密字符串,但是其内部的字符映射表可以动态调整,理论上只要私有的映射表不公开,那么Base64得到的密文就是安全的。

Java简单实现加密/解密过程

(一段渣渣代码,以表敬意)

package com.znz.test.base64;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 
 * base64工具类:<br>
 * <ul>    
 * <li>加密字符串<br>
 * <li>解密字符串<br>
 * </ul>
 * @author nick
 * @version 5.0 since 2018年8月7日
 */
public class Base64Util {
    //映射表
    private static String[] index = new String[64];
    //映射字符索引表
    private static Map<String, Integer> deindex = new HashMap<>(); 
    
    //初始化映射表
    static{
        int cur = 0;
        //A-Z
        for (int i = 65; i <= 90; i++) {
            String v = String.valueOf((char) i);
            index[cur] =  v;
            deindex.put(v, cur);
            cur++;
        }
        //a-z
        for (int i = 97; i <= 122; i++) {
            String v = String.valueOf((char) i);
            index[cur] =  v;
            deindex.put(v, cur);
            cur++;
        }
        //0-9
        for (int i = 0; i <= 9; i++) {
            String v = String.valueOf(i);
            index[cur] =  v;
            deindex.put(v, cur);
            cur++;
        }
        //char
        index[cur] = "+" ;
        deindex.put("+", cur);
        cur++;
        index[cur] = "/" ;
        deindex.put("/", cur);
    }
    
    /**
     * 加密
     * @param str
     * @return
     */
    public static String encode(String str){
        String binary = str2Binary(str);
//      System.out.println("binary: "+binary);
        List<String> groups = groups(binary, 6);
//      System.out.println("groups: "+groups);
        
        StringBuilder sb = new StringBuilder();
        List<String> t = new ArrayList<>(4);
        for (int j = 0; j < groups.size(); j++) {
            BigInteger bigInteger = new BigInteger(groups.get(j), 2);
            int i_index = Integer.parseInt(bigInteger.toString());
            t.add(index[i_index]);
            //最后一组长度不够4,用"="补位
            if(j == groups.size()-1){
                if(t.size() < 4){
                    int s = 4 - t.size();
                    for (int i = 0; i < s; i++) {
                        t.add("=");
                    }
                }
            }
            //每组满了之后放到最终字符转中
            if(t.size() == 4){
                for (int i = 0; i < t.size(); i++) {
                    sb.append(t.get(i));
                }
                t.clear();
            }
        }
        return sb.toString();
    }
    
    /**
     * 解密
     * @param codeStr
     * @return
     */
    public static String decode(String codeStr){
        StringBuilder sb = new StringBuilder();
        
        StringBuilder binary = new StringBuilder();
        
        int length = codeStr.length();
        for (int i = 0; i < length; i++) {
            String s = String.valueOf(codeStr.charAt(i));
            if("=".equals(s)){
                continue;
            }
            int d_index = deindex.get(s);
            binary.append(int2Binary(d_index));
        }
        
        List<String> groups = groups(binary.toString(), 8);
        
        for (String group : groups) {
            String binary2Str = binary2Str(group);
            sb.append(binary2Str);
        }
        
        return sb.toString();
    }
    
    /**
     * int转二进制字符串
     * @param i
     * @return
     */
    private static String int2Binary(int i){
        StringBuilder sb = new StringBuilder();
        
        String binaryString = Integer.toBinaryString(i);
        int len = binaryString.length();
        if(len < 6){
            for (int j = 0; j < 6-len; j++) {
                sb.append("0");
            }
        }
        sb.append(binaryString);
        return sb.toString();
    }
    
    /**
     * 对字符串分组
     * @param binary
     * @return
     */
    private static List<String> groups(String binary, int perGroupSize){
        int length = binary.length();
        int rest = length % perGroupSize;
        if(rest != 0){
            int tmp = perGroupSize - rest;
            for (int i = 0; i < tmp; i++) {
                binary += "0";
            }
        }
//      System.out.println("dealed-binary: "+binary);
        List<String> rt = new ArrayList<>();
        for (int i = 0; i < length; i+=perGroupSize) {
            int start = i;
            int end = i + perGroupSize;
            String substring = binary.substring(start, end);
            rt.add(substring);
        }
        return rt;
    }
    
    /**
     * 将字符串转成二进制
     * @param s
     * @return
     */
    private static String str2Binary(String s){
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
            char cur = s.charAt(i);
            String binaryString = Integer.toBinaryString(cur);
            if(binaryString.length() < 8){
                int gap = 8 - binaryString.length();
                StringBuilder sb = new StringBuilder();
                for (int j = 0; j < gap; j++) {
                    sb.append("0");
                }
                sb.append(binaryString);
                binaryString = sb.toString();
            }
            builder.append(binaryString);
        }
        
        return builder.toString();
    }
    
    /**
     * 二进制转字符串
     * @param binary
     * @return
     */
    private static String binary2Str(String binary){
        StringBuilder builder = new StringBuilder();
        int[] temp = BinstrToIntArray(binary);
        int sum = 0;
        for (int i = 0; i < temp.length; i++) {
            sum += temp[temp.length - 1 - i] << i;
        }
        builder.append((char) sum);
        return builder.toString();
    }
    
    // 将二进制字符串转换成int数组
    private static int[] BinstrToIntArray(String binStr) {
        char[] temp = binStr.toCharArray();
        int[] result = new int[temp.length];
        for (int i = 0; i < temp.length; i++) {
            result[i] = temp[i] - 48;
        }
        return result;
    }

}

原文地址:https://www.cnblogs.com/nickhan/p/13702552.html