AES-ECB(NoPadding)模式加密

yuanheci 2022年12月29日 468次浏览

  ps:(AES-ECB模式加密有三种:PKCS5PaddingPKCS7PaddingNoPadding,只有NoPadding需要自己写补齐的函数,其他两种都不用自己手写。。。)


  之前写的AES-CBC模式加密,kl说移动端解密不了,给了我个ECB模式的加密“板子”让我改成这个,结果试了试还报错,根本用不了啊。。。(ps: 明明之前的加密写法这么好为什么。。。
  好吧那让我们来看看这个新的()东西。
  和CBC模式不同的是,ECB加密模式对密钥长度和加密内容长度都有严格的要求,其字节数都需要是16的倍数。因此如果用CBC模式的代码,直接报错需要为16的倍数!
  由此可以想到我们需要额外写两个辅助函数来让我们的密钥和内容对齐16的倍数。

加密时字节补齐16的倍数

//key和content的字节数必须是16的倍数
    private static byte[] fillAESZeroPadding(String pwd){
        byte[] password = pwd.getBytes(StandardCharsets.UTF_8);
        int factor = 16; //计算因子
        int size = password.length; //传入的数据大小
        int offset = size % factor; //数据偏移量
        if(offset == 0) return password;
        int realSize = size + (factor - offset); //应返回的数据大小
        byte[] key = new byte[realSize];
        System.arraycopy(password, 0, key, 0, size);
        return key;
    }

解密内容后要去掉之前补的后缀

private static byte[] removeZeroPadding(byte[] bytes){
        int newLength = bytes.length;
        int length = bytes.length;
		//是后缀,因此从后往前找
        for (int i = length - 1; i >= 0; i--) {
            byte b = bytes[i];
            if ((int)b != 0) {
                break;
            }
            newLength--;
        }
        if (newLength == length) {
            return bytes;
        }
        byte[] newBytes = new byte[newLength];
        System.arraycopy(bytes, 0, newBytes, 0, newLength);
        return newBytes;
    }

并且依然需要用到base64做编解码,否则.getBytes()后和原来的String就变化了。。。

完整工具类代码如下:

package com.huanke.managesystem.framework.util;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * AES/ECB模式加密   成功的demo     2022/12/29--rsh
 */

public class AESECB {
    private static String transformation = "AES/ECB/NoPadding";
    private static String pwd = "123456789012345678901234";
    private static String content = "小明的书本";

    //key和content的字节数必须是16的倍数
    private static byte[] fillAESZeroPadding(String pwd){
        byte[] password = pwd.getBytes(StandardCharsets.UTF_8);
        int factor = 16; //计算因子
        int size = password.length; //传入的数据大小
        int offset = size % factor; //数据偏移量
        if(offset == 0) return password;
        int realSize = size + (factor - offset); //应返回的数据大小
        byte[] key = new byte[realSize];
        System.arraycopy(password, 0, key, 0, size);
        return key;
    }

    private static byte[] removeZeroPadding(byte[] bytes){
        int newLength = bytes.length;
        int length = bytes.length;

        for (int i = length - 1; i >= 0; i--) {
            byte b = bytes[i];
            if ((int)b != 0) {
                break;
            }
            newLength--;
        }
        if (newLength == length) {
            return bytes;
        }
        byte[] newBytes = new byte[newLength];
        System.arraycopy(bytes, 0, newBytes, 0, newLength);
        return newBytes;
    }

    public static String aesEncrypt(String data){
        try {
            byte[] key = fillAESZeroPadding(AESECB.pwd);
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
            Cipher cipher = Cipher.getInstance(AESECB.transformation);
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
            byte[] content = fillAESZeroPadding(data);
            byte[] result = cipher.doFinal(content);
            return Base64.getEncoder().encodeToString(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String aesDecrypt(String data){
        try {
            byte[] key = fillAESZeroPadding(AESECB.pwd);
            //解密的时候这里先Base64解码一下!
            byte[] content = Base64.getDecoder().decode(data.getBytes(StandardCharsets.UTF_8));
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
            Cipher cipher = Cipher.getInstance(AESECB.transformation);
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
            byte[] raw = cipher.doFinal(content);
            byte[] newRaw = removeZeroPadding(raw);
            return new String(newRaw);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String args[]) {
        String enc = AESECB.aesEncrypt(content);
        System.out.println("enc= " + enc);

        String dec = AESECB.aesDecrypt(enc);
        System.out.println("dec= " + dec);
    }
}


  好!尽力千辛万苦终于在本地成功完成了编解码,于是开开心心地放到云端部署,一运行跳出来这么个东西java.security.InvalidKeyException: Illegal key size or default parameters
  上网一查说是密钥长度超过128就会报这个错。可以通过修改jdk8无限制政策文件来解决
  步骤如下:
  (1)首先从Oracle官网下载一下jdk8无限制政策文件=====>网站在这里。需要登录一下才能下载=====>这个网站里有许多分享的账号密码
  (2)下载后替换jdk安装目录/jre/lib/security下的两个jar包就可以了。
  如何在Linux中查看jdk安装目录: echo $JAVA_HOME

  好啦这样问题就完美解决了~不知不觉又花了一晚上呜呜呜。