乐趣区

关于加密:对称加密算法汇总AES-DES-3DES-SM4-java-实现入门

明码的世界

如果你是黑帮老大,平时和手下沟通,如何保障本人的信息安全呢?

在神探夏洛克的第一季中,就讲述了一个如何侦破黑帮的加密交换的故事。

这种明码利用的是明码字典。

明码自身能够是一本书,比方常见的《圣经》、《杀死一只知更鸟》,或者纽约地图?

这种加密形式的长处就是如果不晓得字典自身,根本无奈破解。应用起来也非常简单,甚至你能够定期和手下更换字典。

谈到明码,另一个不得不提的故事就是二战时期的明码破译问题。

二战时期,德国创造的 ENIGMA 加密机器,让通信加密从人工手写时代逾越到了机器操作时代,也让人工破译有些无能为力。

为了破译德国的这套加密机器,从剑桥找来了三位优良的数学家:杰弗里期、威尔仕曼、阿兰. 图灵。

说到图灵,我想大家肯定都晓得,如果不晓得,倡议珍藏本篇文章,理解之后再持续浏览。

常言道,唯有魔法能够战胜魔法。那能够让奇怪博……啊,不好意思,还是让图灵来吧。

图灵认为使用数学上的 crib 办法来破解 ENIGMA 是可行的,在前期破译了大部分的德军情报信息。

当前的时代,咱们 用机器去战胜机器

加密的可逆性

加密算法咱们整体能够分为:可逆加密和不可逆加密;可逆加密又能够分为:对称加密和非对称加密。

当然个别的通信中,咱们都是须要进行解密的。

本文次要介绍近代最有名的四大加密算法:DES 3DES AES 和 SM4。

DES 算法

简介

DES 全称为 Data Encryption Standard,即数据加密规范,是一种应用密钥加密的块算法,1977 年被美国联邦政府的国家标准局确定为联邦材料解决规范(FIPS),并受权在非密级政府通信中应用,随后该算法在国内上宽泛流传开来。

设计准则

DES 设计中应用了分组明码设计的两个准则:混同(confusion)和扩散(diffusion),其目标是抗击敌手对明码零碎的统计分析。

混同是使密文的统计个性与密钥的取值之间的关系尽可能复杂化,以使密钥和明文以及密文之间的依赖性对明码剖析者来说是无奈利用的。

扩散的作用就是将每一位明文的影响尽可能迅速地作用到较多的输入密文位中,以便在大量的密文中打消明文的统计构造,并且使每一位密钥的影响尽可能迅速地扩大到较多的密文位中,以防对密钥进行逐段破译。

ps: 根本近代的加密算法应该遵循这两个准则,否则就会被统计攻打。

入门应用

这里提供了最简略的 DES 实现例子。

import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;

/**
 * DES 工具类
 *
 * @author binbin.hou
 * @since 0.0.6
 */
public final class DesUtil {private DesUtil() { }

    /**
     * des
     *
     * @since 0.0.6
     */
    private static final String DES = "DES";

    /**
     * 加密
     *
     * @param plainText 待加密内容
     * @param password  明码
     * @return 加密后果
     * @since 0.0.6
     */
    public static byte[] encrypt(String plainText, String password) {byte[] bytes = plainText.getBytes();
        return encrypt(bytes, password);
    }

    /**
     * 加密
     *
     * @param plainText 待加密内容
     * @param password  明码
     * @return 加密后果
     * @since 0.0.6
     */
    public static byte[] encrypt(byte[] plainText, String password) {
        try {SecureRandom random = new SecureRandom();
            DESKeySpec desKey = new DESKeySpec(password.getBytes());
            // 创立一个密匙工厂,而后用它把 DESKeySpec 转换成
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
            SecretKey secretKey = keyFactory.generateSecret(desKey);
            // Cipher 对象理论实现加密操作
            Cipher cipher = Cipher.getInstance(DES);
            // 用密匙初始化 Cipher 对象
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, random);
            // 当初,获取数据并加密
            // 正式执行加密操作
            return cipher.doFinal(plainText);
        } catch (Exception e) {throw new SecretRuntimeException(e);
        }
    }

    /**
     * 解密
     *
     * @param src      byte[]
     * @param password String
     * @return 解密后果
     * @since 0.0.6
     */
    public static byte[] decrypt(byte[] src, String password) {
        try {
            // DES 算法要求有一个可信赖的随机数源
            SecureRandom random = new SecureRandom();
            // 创立一个 DESKeySpec 对象
            DESKeySpec desKey = new DESKeySpec(password.getBytes());
            // 创立一个密匙工厂
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
            // 将 DESKeySpec 对象转换成 SecretKey 对象
            SecretKey secretKey = keyFactory.generateSecret(desKey);
            // Cipher 对象理论实现解密操作
            Cipher cipher = Cipher.getInstance(DES);
            // 用密匙初始化 Cipher 对象
            cipher.init(Cipher.DECRYPT_MODE, secretKey, random);
            // 真正开始解密操作
            return cipher.doFinal(src);
        } catch (InvalidKeyException | NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException e) {throw new SecretRuntimeException(e);
        }
    }

    /**
     * 解密
     *
     * @param src      byte[]
     * @param password String
     * @return 解密后果
     * @since 0.0.6
     */
    public static String decryptToString(byte[] src, String password,
                                         String charset) {
        try {byte[] bytes = decrypt(src, password);

            return new String(bytes, charset);
        } catch (UnsupportedEncodingException e) {throw new SecretRuntimeException(e);
        }
    }

    /**
     * 解密
     *
     * @param src      byte[]
     * @param password String
     * @return 解密后果
     * @since 0.0.6
     */
    public static String decryptToString(byte[] src, String password) {return decryptToString(src, password, "UTF-8");
    }

}

测试代码

测试代码如下:

public static void main(String[] args) {
    // 待加密内容
    String str = "测试内容";
    // 明码,长度要是 8 的倍数
    String password = "01234567";
    byte[] result = DesUtil.encrypt(str, password);
    System.out.println("加密后:" + HexUtil.byteToHexString(result));
    // 间接将如上内容解密
    String decryResult = DesUtil.decryptToString(result, password);
    System.out.println("解密后:" + decryResult);
}

日志如下:

加密后:77C25C0143F544CFFF102E43BDE1ABE1
解密后:测试内容

拓展浏览

具体算法原理倡议浏览:

DES 加密算法入门及算法原理:http://houbb.github.io/2020/06/17/althgorim-cryptograph-05-des

3DES

算法介绍

3DES(或称为 Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块明码的通称。

它相当于是对每个数据块利用三次 DES 加密算法。

因为计算机运算能力的加强,原版 DES 明码的密钥长度变得容易被暴力破解;

3DES 即是设计用来提供一种绝对简略的办法,即 通过减少 DES 的密钥长度来防止相似的攻打,而不是设计一种全新的块明码算法

java 入门

3DES 的工具类实现如下:

import com.github.houbb.heaven.constant.CharsetConst;
import com.github.houbb.secret.api.exception.SecretRuntimeException;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;

/**
 * 3DES 工具类
 *
 * @author binbin.hou
 * @since 0.0.7
 */
public final class TripleDesUtil {private TripleDesUtil() { }

    /**
     * 算法名称
     *
     * @since 0.0.7
     */
    private static final String ALGORITHM = "DESede";

    /**
     * 加密函数
     *
     * @param keyBytes 加密密钥,长度为 24 字节
     * @param plainBytes 被加密的数据缓冲区(源)* @return 后果
     * @since 0.0.7
     */
    public static byte[] encrypt(byte[] keyBytes, byte[] plainBytes) {
        try {
            // 生成密钥
            SecretKey deskey = new SecretKeySpec(keyBytes, ALGORITHM);
            // 加密
            Cipher c1 = Cipher.getInstance(ALGORITHM);
            c1.init(Cipher.ENCRYPT_MODE, deskey);
            return c1.doFinal(plainBytes);
        } catch (Exception e1) {throw new SecurityException(e1);
        }
    }

    /**
     * 加密函数
     *
     * @param keyBytes 加密密钥,长度为 24 字节
     * @param plainText 被加密的数据缓冲区(源)* @return 后果
     * @since 0.0.7
     */
    public static byte[] encrypt(byte[] keyBytes, String plainText) {return encrypt(keyBytes, plainText.getBytes());
    }

    /**
     * 解密函数
     * @param keyBytes 加密密钥,长度为 24 字节
     * @param secretBytes 加密后的缓冲区
     * @return 后果
     * @since 0.0.7
     */
    public static byte[] decrypt(byte[] keyBytes, byte[] secretBytes) {
        try {
            // 生成密钥
            SecretKey deskey = new SecretKeySpec(keyBytes, ALGORITHM);
            // 解密
            Cipher c1 = Cipher.getInstance(ALGORITHM);
            c1.init(Cipher.DECRYPT_MODE, deskey);
            return c1.doFinal(secretBytes);
        } catch (Exception e1) {throw new SecretRuntimeException(e1);
        }
    }

    /**
     * 解密函数
     * @param keyBytes 加密密钥,长度为 24 字节
     * @param secretBytes 加密后的缓冲区
     * @param charsetName 编码名称
     *
     * @return 后果
     * @since 0.0.7
     */
    public static String decryptToString(byte[] keyBytes, byte[] secretBytes, String charsetName) {
        try {byte[] bytes = decrypt(keyBytes, secretBytes);

            return new String(bytes, charsetName);
        } catch (UnsupportedEncodingException e) {throw new SecretRuntimeException(e);
        }
    }

    /**
     * 解密函数
     * @param keyBytes 加密密钥,长度为 24 字节
     * @param secretBytes 加密后的缓冲区
     *
     * @return 后果
     * @since 0.0.7
     */
    public static String decryptToString(byte[] keyBytes, byte[] secretBytes) {return decryptToString(keyBytes, secretBytes, CharsetConst.UTF8);
    }

    
}

测试

public static void main(String[] args) {
    String text = "我爱中华!";
    String password = "123456781234567812345678";
    byte[] bytes = encrypt(password.getBytes(), text);
    System.out.println(HexUtil.byteToHexString(bytes));
    String plainText = decryptToString(password.getBytes(), bytes);
    System.out.println(plainText);
}

日志信息:

A60CBC97EEFF2958DF4384215E0838C0
我爱中华!

拓展浏览

具体算法原理倡议浏览:

3DES 加密算法入门及算法原理:http://houbb.github.io/2020/06/17/althgorim-cryptograph-06-3des

AES 算法

算法简介

密码学中的高级加密规范(Advanced Encryption Standard,AES),又称 Rijndael 加密法,是美国联邦政府采纳的一种区块加密规范。

2006 年,高级加密规范未然成为对称密钥加密中最风行的算法之一。

这种算法比 3DES 的安全性更高。

java 入门

java 的工具类实现如下。

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;

/**
 * 3DES 工具类
 *
 * @author binbin.hou
 * @since 0.0.7
 */
public final class AesUtil {private AesUtil() { }

    /**
     * 算法名称
     *
     * @since 0.0.7
     */
    private static final String ALGORITHM = "AES";

    /**
     * 依据密钥对指定的明文 plainText 进行加密.
     *
     * @param plainBytes 明文
     * @param keyBytes   明码
     * @return 加密后的密文.
     * @since 0.0.8
     */
    public static byte[] encrypt(byte[] plainBytes, byte[] keyBytes) {
        try {SecretKey secretKey = getSecretKey(keyBytes);
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            return cipher.doFinal(plainBytes);
        } catch (Exception e) {throw new RuntimeException(e);
        }
    }

    /**
     * 依据密钥对指定的密文 cipherBytes 进行解密.
     *
     * @param cipherBytes 加密密文
     * @param keyBytes    秘钥
     * @return 解密后的明文.
     * @since 0.0.8
     */
    public static byte[] decrypt(byte[] cipherBytes, byte[] keyBytes) {
        try {SecretKey secretKey = getSecretKey(keyBytes);

            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            return cipher.doFinal(cipherBytes);
        } catch (Exception e) {throw new RuntimeException(e);
        }
    }

    /**
     * 获取加密 key
     *
     * @param keySeed seed
     * @return 后果
     * @since 0.0.8
     */
    private static SecretKey getSecretKey(byte[] keySeed) {
        try {
            // 防止 linux 零碎呈现随机的问题
            SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
            secureRandom.setSeed(keySeed);
            KeyGenerator generator = KeyGenerator.getInstance("AES");
            generator.init(secureRandom);
            return generator.generateKey();} catch (Exception e) {throw new RuntimeException(e);
        }
    }
    
}

测试代码

public static void main(String[] args) throws UnsupportedEncodingException {
    String text = "我爱中华!";
    // 密钥, 256 位 32 个字节
    String password = "uBdUx82vPHkDKb284d7NkjFoNcKWBuka";
    byte[] bytes = encrypt(text.getBytes(), password.getBytes());
    String text2 = new String(decrypt(bytes, password.getBytes()), "UTF-8");
    System.out.println(text2);
}

输入:我爱中华!

拓展浏览

具体算法原理倡议浏览:

AES 加密算法入门及算法原理:http://houbb.github.io/2020/06/17/althgorim-cryptograph-07-aes

SM4 算法

算法简介

SM4 是一种分组明码算法,其分组长度为 128 位(即 16 字节,4 字),密钥长度也为 128 位(即 16 字节,4 字)。

其加解密过程采纳了 32 轮迭代机制(与 DES、AES 相似),每一轮须要一个轮密钥(与 DES、AES 相似)。

SM4 算法,又称国密算法。因为这是属于中国人本人的加密算法,国内的金融等畛域都会应用。

java 入门

maven 依赖

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.59</version>
</dependency>

工具封装

import com.github.houbb.secret.api.exception.SecretRuntimeException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.Security;
import java.util.Arrays;

/**
 * Sm4 国密算法
 *
 * @author binbin.hou
 * @since 0.0.5
 */
public final class Sm4Util {private Sm4Util() { }

    static {Security.addProvider(new BouncyCastleProvider());
    }

    private static final String ENCODING = "UTF-8";

    private static final String ALGORITHM_NAME = "SM4";

    /**
     * PKCS5Padding  NoPadding 补位规定,PKCS5Padding 缺位补 0,NoPadding 不补
     */
    private static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding";

    /**
     * ECB 加密模式,无向量
     * @param algorithmName 算法名称
     * @param mode          模式
     * @param key           key
     * @return 后果
     */
    private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key) throws Exception {Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
        Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
        cipher.init(mode, sm4Key);
        return cipher;
    }

    /**
     * sm4 加密
     * 加密模式:ECB 密文长度不固定,会随着被加密字符串长度的变动而变动
     *
     * @param hexKey   16 进制密钥(疏忽大小写)* @param plainText 待加密字符串
     * @return 返回 16 进制的加密字符串
     * @since 0.0.5
     */
    public static String encryptEcb(String hexKey, String plainText) {
        try {
            String cipherText = "";
            // 16 进制字符串 -->byte[]
            byte[] keyData = ByteUtils.fromHexString(hexKey);
            // String-->byte[]
            // 当加密数据为 16 进制字符串时应用这行
            byte[] srcData = plainText.getBytes(ENCODING);
            // 加密后的数组
            byte[] cipherArray = encryptEcbPadding(keyData, srcData);
            // byte[]-->hexString
            cipherText = ByteUtils.toHexString(cipherArray);
            return cipherText;
        } catch (Exception exception) {throw new SecretRuntimeException(exception);
        }
    }

    /**
     * 加密模式之 Ecb
     *
     * @param key 秘钥
     * @param data 待加密的数据
     * @return 字节数组
     * @since 0.0.5
     */
    public static byte[] encryptEcbPadding(byte[] key, byte[] data) {
        try {
            // 宣称 Ecb 暗号, 通过第二个参数判断加密还是解密
            Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE, key);
            return cipher.doFinal(data);
        } catch (Exception exception) {throw new SecretRuntimeException(exception);
        }
    }

    // 解密 ****************************************

    /**
     * sm4 解密
     *
     * 解密模式:采纳 ECB
     * @param hexKey     16 进制密钥
     * @param cipherText 16 进制的加密字符串(疏忽大小写)* @return 解密后的字符串
     * @since 0.0.5
     */
    public static String decryptEcb(String hexKey, String cipherText) {
        try {
            // 用于接管解密后的字符串
            String decryptStr = "";
            // hexString-->byte[]
            byte[] keyData = ByteUtils.fromHexString(hexKey);
            // hexString-->byte[]
            byte[] cipherData = ByteUtils.fromHexString(cipherText);
            // 解密
            byte[] srcData = decryptEcbPadding(keyData, cipherData);
            // byte[]-->String
            decryptStr = new String(srcData, ENCODING);
            return decryptStr;
        } catch (Exception exception) {throw new SecretRuntimeException(exception);
        }
    }

    /**
     * 解密
     *
     * @param key 秘钥
     * @param cipherText 密文
     * @return 后果
     * @since 0.0.5
     */
    public static byte[] decryptEcbPadding(byte[] key, byte[] cipherText) {
        try {
            // 生成 Ecb 暗号, 通过第二个参数判断加密还是解密
            Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, key);
            return cipher.doFinal(cipherText);
        } catch (Exception exception) {throw new SecretRuntimeException(exception);
        }
    }

    /**
     * 验证数据
     * @param hexKey key
     * @param cipherText 密文
     * @param plainText 明文
     * @return 后果
     * @since 0.0.5
     */
    public static boolean verifyEcb(String hexKey, String cipherText, String plainText) {
        try {
            // 用于接管校验后果
            boolean flag = false;
            // hexString-->byte[]
            byte[] keyData = ByteUtils.fromHexString(hexKey);
            // 将 16 进制字符串转换成数组
            byte[] cipherData = ByteUtils.fromHexString(cipherText);
            // 解密
            byte[] decryptData = decryptEcbPadding(keyData, cipherData);
            // 将原字符串转换成 byte[]
            byte[] srcData = plainText.getBytes(ENCODING);
            // 判断 2 个数组是否统一
            flag = Arrays.equals(decryptData, srcData);
            return flag;
        } catch (Exception exception) {throw new SecretRuntimeException(exception);
        }
    }

}

测试代码

System.out.println("开始 ****************************");
String plainText = "96C63180C2806ED1F47B859DE501215B";
System.out.println("加密前:" + plainText);
// 自定义的 32 位 16 进制秘钥
String key = "86C63180C2806ED1F47B859DE501215B";
String cipher = encryptEcb(key, plainText);//sm4 加密
System.out.println("加密后:" + cipher);
// 校验加密前后是否为同一数据
System.out.println("校验:" + verifyEcb(key, cipher, plainText));
plainText = decryptEcb(key, cipher);// 解密
System.out.println("解密后:" + plainText);
System.out.println("完结 ****************************");

对应日志:

开始 ****************************
加密前:96C63180C2806ED1F47B859DE501215B
加密后:063c352bcec7d360da455ebaab2595347d0aa493d2a80a72396771b5585a49f81642326904c036af50b50f92e86cb274
校验:true
解密后:96C63180C2806ED1F47B859DE501215B
完结 ****************************

拓展浏览

具体算法原理倡议浏览:

SM4 加密算法入门及算法原理:http://houbb.github.io/2020/06/17/althgorim-cryptograph-04-sm4

第五大加密算法

当然,四大加密算法有 5 个,这不是常识吗?

安德鲁:为什么,我怎么不晓得?

咱们最初再聊一聊另一个常见的算法 Base64。

算法介绍

严格地说,Base64 并不是用于加密的,更多的用于编码,解码。

Base64 是一种能将任意 Binary 材料用 64 种字元组合成字串的办法,而这个 Binary 材料和字串材料彼此之间是能够相互转换的,非常不便。

在理论利用上,Base64 除了能将 Binary 材料可视化之外,也罕用来示意字串加密过后的内容。

java 工具类

import com.github.houbb.heaven.util.lang.StringUtil;
import com.github.houbb.secret.api.exception.SecretRuntimeException;

import java.io.UnsupportedEncodingException;

/**
 * Base64 工具类
 *
 * 转码类
 * @author binbin.hou
 * @since 0.0.4
 */
public final class Base64Util {private Base64Util() { }

    private static final char[] ALPHABET_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();

    private static final byte[] CODES = new byte[256];

    static {for (int i = 0; i < 256; i++) {CODES[i] = -1;
        }
        for (int i = 'A'; i <= 'Z'; i++) {CODES[i] = (byte) (i - 'A');
        }
        for (int i = 'a'; i <= 'z'; i++) {CODES[i] = (byte) (26 + i - 'a');
        }
        for (int i = '0'; i <= '9'; i++) {CODES[i] = (byte) (52 + i - '0');
        }
        CODES['+'] = 62;
        CODES['/'] = 63;
    }

    /**
     * 将原始数据编码为 base64 编码
     *
     * @param data 数据
     * @since 0.0.4
     */
    public static char[] encode(byte[] data) {char[] out = new char[((data.length + 2) / 3) * 4];

        for (int i = 0, index = 0; i < data.length; i += 3, index += 4) {
            boolean quad = false;
            boolean trip = false;
            int val = (0xFF & (int) data[i]);
            val <<= 8;
            if ((i + 1) < data.length) {val |= (0xFF & (int) data[i + 1]);
                trip = true;
            }
            val <<= 8;
            if ((i + 2) < data.length) {val |= (0xFF & (int) data[i + 2]);
                quad = true;
            }
            out[index + 3] = ALPHABET_CHARS[(quad ? (val & 0x3F) : 64)];
            val >>= 6;
            out[index + 2] = ALPHABET_CHARS[(trip ? (val & 0x3F) : 64)];
            val >>= 6;
            out[index + 1] = ALPHABET_CHARS[val & 0x3F];
            val >>= 6;
            out[index + 0] = ALPHABET_CHARS[val & 0x3F];
        }
        return out;
    }

    /**
     * 将 base64 编码的数据解码成原始数据
     *
     * @param data 数组
     * @since 0.0.4
     */
    public static byte[] decode(char[] data) {int len = ((data.length + 3) / 4) * 3;
        if (data.length > 0 && data[data.length - 1] == '=') {--len;}
        if (data.length > 1 && data[data.length - 2] == '=') {--len;}
        byte[] out = new byte[len];
        int shift = 0;
        int accum = 0;
        int index = 0;
        for (char datum : data) {int value = CODES[datum & 0xFF];
            if (value >= 0) {
                accum <<= 6;
                shift += 6;
                accum |= value;
                if (shift >= 8) {
                    shift -= 8;
                    out[index++] = (byte) ((accum >> shift) & 0xff);
                }
            }
        }

        if (index != out.length) {throw new SecretRuntimeException("miscalculated data length!");
        }
        return out;
    }

    /**
     * 编码
     * @param text 文本
     * @return 后果
     * @since 0.0.4
     */
    public static char[] encode(String text) {if(StringUtil.isEmpty(text)) {return new char[]{};}
        byte[] data = text.getBytes();

        return encode(data);
    }

    /**
     * 编码为字符串
     *
     * @param text 文本
     * @return 后果
     * @since 0.0.4
     */
    public static String encodeToString(String text) {if(StringUtil.isEmpty(text)) {return text;}
        char[] chars = encode(text);

        return new String(chars);
    }

    /**
     * 将 base64 编码的数据解码成原始数据
     *
     * @param text 解码
     * @since 0.0.4
     */
    public static byte[] decode(String text) {if(StringUtil.isEmpty(text)) {return new byte[]{};}

        char[] chars = text.toCharArray();
        return decode(chars);
    }

    /**
     * 将 base64 编码的数据解码成原始数据
     *
     * @param text 解码
     * @param charset 编码
     * @since 0.0.4
     */
    public static String decodeToString(String text, String charset) {
        try {byte[] bytes = decode(text);

            return new String(bytes, charset);
        } catch (UnsupportedEncodingException e) {throw new SecretRuntimeException(e);
        }
    }

}

测试

public static void main(String[] args) {
    String text = "我爱中国!";
    String base64 = encodeToString(text);
    System.out.println(base64);
    String decode64 = decodeToString(base64, "UTF-8");
    System.out.println(decode64);
}

输入如下:

5oiR54ix5Lit5Zu9IQ==
我爱中国!

拓展浏览

具体算法原理倡议浏览:

BASE64 加密算法入门及算法原理:http://houbb.github.io/2020/06/17/althgorim-cryptograph-03-base64

小结

信息时代,始终在谋求 2 个指标:速度与平安(不是激情)。

平安算法也永远随着时代的提高而一直演变,是一场永不平息的攻防之战。

针对本文的所有算法,我都做了对立的编码实现汇总,便于大家应用。感兴趣的能够关注【老马啸东风】,后盾回复【加密】即可获取。

另外,有工夫咱们能够聊一聊不可逆加密,以及非对称加密。

我是老马,期待与你的下次重逢。

退出移动版