[工具方法]对称加密AES/CBC/PKCS5PADDING 加解密的Java实现

2021-04-14 371点热度 0人点赞 0条评论

简介

AES,高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。包括AES-ECB,AES-CBC,AES-CTR,AES-OFB,AES-CFB

我们项目里用的多的是较多的是AES/CBC/PKCS5PADDING,下面介绍下如何使用Java来实现加解密。

关于如何使用Javascript实现(加解密结果和Java版本互通),请查看这篇:[Javascript]实现对称加解密AES/CBC/PKCS5PADDING

Python版本的实现(加解密结果同样和本篇互通),请查看这篇:https://blog.terrynow.com/2021/04/16/python-tool-aes-cbc-pkcs5padding-implement/

Java实现加解密,纯代码干货

AesCBC.java:

/*
 * Copyright (c) 2021.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.terrynow.test;

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

/**
 * @author Terry E-mail: yaoxinghuo at 126 dot com
 * @date 2021-4-13 20:37
 * @description
 */
public class AesCBC {
    private final SecretKeySpec key;
    private final IvParameterSpec iv;

    /**
     * 构造函数,传入key和iv
     * @param key 一定需要16个字节的
     * @param iv 一定需要16个字节的
     */
    public AesCBC(String key, String iv) {
        this.key = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
        this.iv = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 构造函数,传入key和iv
     * @param key 一定需要16个字节的bytes
     * @param iv 一定需要16个字节的bytes
     */
    public AesCBC(byte[] key, byte[] iv) {
        this.key = new SecretKeySpec(key, "AES");
        this.iv = new IvParameterSpec(iv);
    }

    /**
     * AES加密
     * @param source 明文string
     * @return 加密后的bytes
     */
    public byte[] encrypt(byte[] source) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(Cipher.ENCRYPT_MODE, key, iv);
        return cipher.doFinal(source);
    }

    /**
     * AES加密
     * @param source 明文string
     * @return 加密后的bytes转成十六进制string
     */
    public String encryptToHexString(String source) {
        try {
            byte[] encrypted = encrypt(source.getBytes(StandardCharsets.UTF_8));
            return HexBin.encode(encrypted);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * AES加密
     * @param source 明文string
     * @return 加密后的bytes转成base64
     */
    public String encryptToBase64(String source) {
        try {
            byte[] encrypted = encrypt(source.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * AES解密
     * @param source bytes
     * @return 解密后的bytes
     */
    public byte[] decrypt(byte[] source) throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(Cipher.DECRYPT_MODE, key, iv);
        return cipher.doFinal(source);
    }

    /**
     * AES解密
     * @param source Base64编码的密文
     * @return 解密后的明文string
     */
    public String decryptWithBase64(String source) {
        try {
            byte[] original = decrypt(Base64.getDecoder().decode(source));
            return  new String(original);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * AES解密
     * @param source 十六进制密文
     * @return 解密后的明文string
     */
    public String decryptWithHexString(String source) {
        try {
            byte[] original = decrypt(HexBin.decode(source));
            return  new String(original);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    //测试
    public static void main(String[] args) throws Exception {
        // key和iv需要16个字符长度
//        byte[] key = new byte[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
//        byte[] iv = new byte[]{16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1};
        String key = "sixteencharacter";//16位
        String iv = "1234567890ABCDEF";//16位
        AesCBC aesCBC = new AesCBC(key, iv);
        String string1 = aesCBC.encryptToHexString("你好");
        System.out.println(string1);//697E93390662D4EC94A2718FCC40DE0B
        String string2 = aesCBC.encryptToBase64("你好");
        System.out.println(string2);//aX6TOQZi1OyUonGPzEDeCw==

        String string3 = aesCBC.decryptWithHexString("697E93390662D4EC94A2718FCC40DE0B");
        System.out.println(string3);//你好
        String string4 = aesCBC.decryptWithBase64("aX6TOQZi1OyUonGPzEDeCw==");
        System.out.println(string4);//你好
    }
}

 

/*
 * Copyright (c) 2021.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.terrynow.test;

/**
 * @author Terry E-mail: yaoxinghuo at 126 dot com
 * @date 2019-03-01 10:00
 * @description http://www.java2s.com/Code/Java/Data-Type/Decodehexstringtoabytearray.htm
 * 把bytes转换成十六进制进制文本,或者把十六进制进制文本转成ytes
 */
public class HexBin {
    static private final int  BASELENGTH   = 128;
    static final private byte [] hexNumberTable    = new byte[BASELENGTH];


    static {
        for (int i = 0; i < BASELENGTH; i++ ) {
            hexNumberTable[i] = -1;
        }
        for ( int i = '9'; i >= '0'; i--) {
            hexNumberTable[i] = (byte) (i-'0');
        }
        for ( int i = 'F'; i>= 'A'; i--) {
            hexNumberTable[i] = (byte) ( i-'A' + 10 );
        }
        for ( int i = 'f'; i>= 'a'; i--) {
            hexNumberTable[i] = (byte) ( i-'a' + 10 );
        }
    }

    /**
     * Decode hex string to a byte array
     *
     * @param encoded encoded string
     * @return return array of byte to encode
     */
    static public byte[] decode(String encoded) {
        if (encoded == null)
            return null;
        int lengthData = encoded.length();
        if (lengthData % 2 != 0)
            return null;

        char[] binaryData = encoded.toCharArray();
        int lengthDecode = lengthData / 2;
        byte[] decodedData = new byte[lengthDecode];
        byte temp1, temp2;
        char tempChar;
        for( int i = 0; i<lengthDecode; i++ ){
            tempChar = binaryData[i*2];
            temp1 = (tempChar < BASELENGTH) ? hexNumberTable[tempChar] : -1;
            if (temp1 == -1)
                return null;
            tempChar = binaryData[i*2+1];
            temp2 = (tempChar < BASELENGTH) ? hexNumberTable[tempChar] : -1;
            if (temp2 == -1)
                return null;
            decodedData[i] = (byte)((temp1 << 4) | temp2);
        }
        return decodedData;
    }

    private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
    public static String encode(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = HEX_ARRAY[v >>> 4];
            hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
        }
        return new String(hexChars);
    }
}

admin

这个人很懒,什么都没留下

文章评论

*

code