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

2021-04-14 1286点热度 1人点赞 1条评论

简介

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

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

文章评论

  • kafrots

    cheap generic cialis Kqztcp Acticin Where To Purchase Website Fedex Shipping No Doctors Consult buy generic cialis online cheap comprar viagra en linea Controindicazioni Levitra Slvzeo best price cialis

    2022-04-17
  • 您需要 登录 之后才可以评论