JAVA 簡單實現AES加密

昨天有個功能,跟其他系統對接,所以研究了下AES加密,綜合的幾個博客,新建了個demo。
效果預覽,原理什麼的就不解釋了(因爲我也不大懂(-_ - *),看着好像都差不多,湊合方法整成能用就行)
效果預覽
好處是不用外部jar包
在這裏插入圖片描述
新建個隨便整個springboot工程,搞個手寫個工具類

package com.encryption.demo;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.util.Arrays;

/**
 * @Description AES加密工具類
 * @Author 古大帥哥
 * @Date 2020/5/20 14:19
 */
public class AesUtils {
    private IvParameterSpec iv;
    private SecretKeySpec keySpec;

    public AesUtils(byte[] aesKey) {
        if (aesKey == null || aesKey.length < 16) {
            throw new RuntimeException("錯誤的初始密鑰");
        }
        keySpec = new SecretKeySpec(aesKey, "AES");
        this.iv = new IvParameterSpec(getMD5Bytes(aesKey));
    }

    public AesUtils(byte[] aesKey, byte[] iv) {
        if (aesKey == null || aesKey.length < 16 || (iv != null && iv.length < 16)) {
            throw new RuntimeException("錯誤的初始密鑰");
        }
        if (iv == null) {
            iv = getMD5Bytes(aesKey);
        }
        keySpec = new SecretKeySpec(aesKey, "AES");
        this.iv = new IvParameterSpec(iv);
    }


    public byte[] encryptBytes(String data){
        Cipher cipher;
        byte[] result = null;
        try {
            cipher = Cipher.getInstance("AES/CFB/NoPadding");
            try {
                cipher.init(cipher.ENCRYPT_MODE, keySpec, iv);
            } catch (InvalidAlgorithmParameterException e) {
                e.printStackTrace();
            }
            result = cipher.doFinal(data.getBytes());

        } catch (NoSuchPaddingException | InvalidKeyException | NoSuchAlgorithmException | IllegalBlockSizeException | BadPaddingException e) {
            e.printStackTrace();
        }
        return result;
    }

    public String decryptBytes(byte[] data){
        Cipher cipher;
        try {
            cipher = Cipher.getInstance("AES/CFB/NoPadding");
            cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
            data = cipher.doFinal(data);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
        return new String(data);
    }

    public static Key randomKey(int size) {
        byte[] result = null;
        Key  key;
        try {
            KeyGenerator gen = KeyGenerator.getInstance("AES");
            gen.init(size, new SecureRandom());
            result = gen.generateKey().getEncoded();
            key = new SecretKeySpec(result, "AES");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return key;
    }

    public byte[] getMD5Bytes(byte[] data){
        MessageDigest md5 = null;
        try{
            md5 = MessageDigest.getInstance("MD5");
        }catch (Exception e){
            e.printStackTrace();
        }
        String s = new String(data);
        char[] charArray = s.toCharArray();
        byte[] byteArray = new byte[charArray.length];

        for (int i = 0; i < charArray.length; i++) {
            byteArray[i] = (byte) charArray[i];
        }
        byte[] md5Bytes = md5.digest(byteArray);
        StringBuffer hexValue = new StringBuffer();
        for (int i = 0; i < md5Bytes.length; i++){
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16){
                hexValue.append("0");
            }
            hexValue.append(Integer.toHexString(val));
        }

        return hexValue.toString().substring(8,24).getBytes();
    }

    public static SecretKeySpec getKey(String password) throws UnsupportedEncodingException {
        int keyLength = 128;
        byte[] keyBytes = new byte[keyLength / 8];
        Arrays.fill(keyBytes, (byte) 0x0);

        byte[] passwordBytes = password.getBytes("UTF-8");
        int length = passwordBytes.length < keyBytes.length ? passwordBytes.length : keyBytes.length;
        System.arraycopy(passwordBytes, 0, keyBytes, 0, length);
        SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
        return key;
    }
}


demo測試類
爲了模擬接受端和發送端,另建了個工具類AesUtils2,代碼跟上面的一樣,就不重複貼了

package com.encryption;

import com.encryption.demo.AesUtils;
import com.encryption.demo.AesUtils2;
import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin;
import org.junit.jupiter.api.Test;

import java.io.UnsupportedEncodingException;
import java.security.Key;

/**
 * @Description 加密測試類
 * @Author 古大帥哥
 * @Date 2020/5/20 9:33
 */

public class EncryptionTest {

    @Test
    public void test() throws UnsupportedEncodingException {
        //發送端
        Key key1 = AesUtils.getKey("{>|?23432512343dskljffy@123");
        AesUtils aesUtils = new AesUtils(key1.getEncoded());
        String str = "{\"APY18\":\"FE企業版\",\"ISMORSPS_REGISTE\":\"2020-05-19 00:00:00.0\",\"APY17\":\"沒有\",\"APY19\":\"22\",\"APY10\":\"場館中心綜合科科長\",\"APY12\":\"56\",\"APY11\":\"13766589422\",\"APY14\":\"6565\",\"APY13\":\"656\",\"APY16\":\"2018-12-26 00:00:00.0\",\"APY15\":\"6565\",\"SERVICE_ID\":\"5\",\"ACCOUNT_MANAGER\":\"徐xx\",\"LOCAL_MAINTAIN_END\":\"2020-05-19 00:00:00.0\",\"CONTRACT_NO\":\"\",\"APY32\":\"D4592347-0A29-530C-AC5A-CC7FF1DE515D\",\"APY31\":\"\",\"APY34\":\"FE6.0.2企業版\",\"APY33\":\"場館管理中心APP開發項目\",\"UFIDA_PASSWORD\":\"4\",\"APY30\":\"4\",\"SERVICE_PASSWORD\":\"4\",\"LOCAL_MAINTAIN_BEGIN\":\"2018-12-27 00:00:00.0\",\"APY29\":\"是\",\"APY28\":\"4\",\"ISMORSPS_DUE\":\"2020-05-19 00:00:00.0\",\"APY8\":\"深圳信息職業技術學院\",\"APY21\":\"500\",\"APY20\":\"500\",\"ABC01\":\"終端客戶\",\"APY23\":\"\",\"APY22\":\"565665\",\"APY4\":\"鄧水平\",\"APY25\":\"mysql5.6\",\"ABC04\":\"深信息\",\"APY24\":\"\",\"APY27\":\"2018-12-26 00:00:00.0\",\"APY26\":\"44\",\"ABC06\":\"深圳市龍崗區龍翔大道\"}";
        byte[] encriptBytes = aesUtils.encryptBytes(str);
        //轉換成16進制字符串傳輸
        String s = HexBin.encode(encriptBytes);

        //接收端
        System.out.println("接受端獲取密文" + s);
        Key key2 = AesUtils2.getKey("{>|?23432512343dskljffy@123");
        AesUtils2 aesUtils2 = new AesUtils2(key2.getEncoded());
        //16進制轉換成2進制
        byte[] decode = HexBin.decode(s);
        byte[] data = aesUtils2.decryptBytes(decode);
        System.out.println("解密後明文:" + new String(data, "UTF-8"));

    }

}

第二天,同事給了鏈接
https://hutool.cn/docs/#/crypto/%E5%AF%B9%E7%A7%B0%E5%8A%A0%E5%AF%86-SymmetricCrypto
看了看,默默把昨天的代碼刪掉,尼瑪有這種現成好東西等老子弄完了纔給我。。。。
區別是:
一、需要導包
二、更簡單

		<dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.5</version>
        </dependency>

demo上面文檔裏面有,由於過於簡單,貼個解密的demo,加密基本一樣

package com.testhttp.httprequest.controller;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin;
import com.testhttp.httprequest.utils.AesUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.Key;

/**
 * @Description
 * @Author 古大帥哥
 * @Date 2020/5/21 11:30
 */
@Controller
public class HelloController {
    private static String LOCAL_KEY = "11111111";
    @ResponseBody
    @RequestMapping("/getMessage")
    public String getMessage(@RequestParam("data") String data, @RequestParam("key") String key){
        System.out.println("接受密鑰:"+ key);
        System.out.println("接受密文:" + data);
        String realkey = SecureUtil.md5(key).substring(7, 15);
        try {
            //解密
            AES aes = new AES(Mode.CTS, Padding.PKCS5Padding, (LOCAL_KEY + realkey).getBytes("UTF-8"), "0102030405060708".getBytes("UTF-8"));
            String ss = aes.decryptStr(data,  CharsetUtil.CHARSET_UTF_8);

            System.out.println("解密後密鑰:" + realkey);
            System.out.println("解密後明文:" + ss);

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        return "hello";
    }
}

其實代碼就兩行,

AES aes = new AES(Mode.CTS, Padding.PKCS5Padding, (16位長度的字符串”).getBytes("UTF-8"), "0102030405060708".getBytes("UTF-8"));
String ss = aes.decryptStr(data,  CharsetUtil.CHARSET_UTF_8);

加密同樣,只要保證那16位字符串的密鑰相同即可

所以我做了寫其他的騷操作,如demo中的,我傳了個動態字符串key,然後再MD5加密(固定返回32位字符串),截取其中的8位進行拼接還原真正的密鑰(加密同理),這樣被人家攔截也難篡改

在這裏插入圖片描述

部分請求端代碼

public void sendMessage(String id) throws UnsupportedEncodingException {
        String data = getAcceptJsonString(id);

        Properties properties = null;
        try {
            properties = PropertiesLoaderUtils.loadProperties(new ClassPathResource("fy.properties"));
        } catch (IOException e) {
            System.err.println("找不到配置文件");
        }
        String key = properties.getProperty("ENCRYPT_KEY");
        String s2 = RandomUtil.randomString(32);
        String s3 = SecureUtil.md5(s2).substring(7, 15);
        //拼接密鑰,加密數據
        AES aes = new AES(Mode.CTS, Padding.PKCS5Padding, (key + s3).getBytes("UTF-8"), "0102030405060708".getBytes("UTF-8"));
        String s1 = aes.encryptHex(data);
        Map<String,Object> map = new HashMap<>();
        map.put("data", "map");
        map.put("key", s2);
        HttpRequest.post("http://localhost:8087/hello")
                .form(data)
                .timeout(20000)
                .execute().body();

    }

執行請求結果
在這裏插入圖片描述
不得不說,Hutool這個工具庫實在太好用,開發效率很高,很多東西比如加密,發起http請求這些東西就幫你封裝好,一兩行代碼就可以執行,給他點個贊👍

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章