PKCS7Padding的Java实现

一、填充原理        

        PKCS7Padding填充模式原理与16的倍数进行相比,缺少多少位就填充多少位的位数值 

二、java代码实现

package com.zhangzz.crypto.util;

import javax.crypto.BadPaddingException;
import java.util.Arrays;


public class PKCS7Padding {

	/**
	 * java实现SM4 PKCS7Padding填充模式 原理:与16的倍数进行相比,缺少多少位就填充多少位的位数值
	 * 例:test字节数为4,填充12个0x0c;12345678字节数为8,填充8个8
	 *
	 * @param inputByte
	 * @return byte[]
	 */
	protected byte[] encodeBlock(byte[] inputByte, int baseBlockSize) throws BadPaddingException {
		// 判断参数是否为空,为空抛出错误
		if (isEmpty(inputByte)) {
			throw new IllegalArgumentException("数据异常,填充参数为空!");
		}
		try {
			// 获字节长度
			int length = inputByte.length;
			// 补齐位数
			int leftLength = baseBlockSize - (length % baseBlockSize == 0 ? baseBlockSize : length % baseBlockSize);
			// 定义新字节
			byte[] arrayReturn = new byte[length + leftLength];
			// 定义填充字节
			byte[] plusbyte = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
					0x0e, 0x0f };
			// 是否满足为baseBlockSize字节倍数
			if (leftLength > 0) {
				// 不满足baseBlockSize倍数自动填充
				for (int i = 0; i < length + leftLength; i++) {
					if (i < length) {
						// 赋值
						arrayReturn[i] = inputByte[i];
					} else {
						// 补齐位数
						arrayReturn[i] = plusbyte[leftLength];
					}
				}
			} else {
				// 为baseBlockSize字节倍数不需要补齐,直接返回
				return inputByte;
			}
			return arrayReturn;
		} catch (Exception e) {
			e.printStackTrace();
			throw new BadPaddingException(e.getMessage());
		}

	}

	/**
	 * PKCS5Padding填充模式还原 将数组拆分两部分,还原最后16字节的数组后再重新组合
	 * 
	 * @param paramArray
	 * @return
	 */
	protected byte[] decodeBlock(byte[] paramArray, int baseBlockSize) throws BadPaddingException {
		if (isEmpty(paramArray)) {
			throw new IllegalArgumentException("数据异常,字节填充还原错误,参数为空!");
		}
		try {
			// 定义是否需要消除填充数据
			boolean needRestore = true;
			int length = paramArray.length;// 获取字符串长度
			// 拆分并获取最后一组16倍数数值
			byte[] paramByteLast = Arrays.copyOfRange(paramArray, length - baseBlockSize, length);
			// 获取最后一个字节
			byte byteLast = paramByteLast[paramByteLast.length - 1];
			// 开始填充字节位置
			int paddingNum = paramByteLast.length - byteLast;
			if (paddingNum > 0) {
				// 判断数组字节位数的字节是否与最后字节相等
				for (int i = paddingNum; i < paramByteLast.length; i++) {
					byte paramSon = paramByteLast[i];
					if (byteLast != paramSon) {
						needRestore = false;
					}
				}
			} else {
				needRestore = false;
			}

			if (needRestore) {
				// 组合新数组并返回
				byte[] resultArray = Arrays.copyOfRange(paramArray, 0, length - byteLast);
				return resultArray;
			}
			return paramArray;
		} catch (Exception e) {
			throw new BadPaddingException("数据异常,字节填充还原错误,异常抛出!" + e.getMessage());
		}
	}

	private boolean isEmpty(byte[] data) {

		if (data != null && data.length > 0) {
			return false;
		}

		return true;
	}

}

三、模拟对称算法分组加密

        使用PKCS7Padding填充,以下列举的是加密,解密是同理的,对称加解密的明文和密文长度是相等的,如果不想当,则是加密的时候有填充。注释,解密需要调用另一个方法将填充的数据去掉,才可以恢复为明文。

/**
 * 每次分组加解密的块大小
 */
private static final int BLOCK_SIZE = 8192;


/**
 * 加密中,原文不足16的倍数需补位,此处模拟示例,不可运行。
 *
 */
public byte[] encrypt(){
    PKCS7Padding pkcs7Padding = new PKCS7Padding();        
    byte[] block = null;
    byte[] ciphertextBlocks = new byte[0];
    //循环以BLOCK_SIZE块大小进行分组加密
    for (int i = 0; i < inData.length; i += BLOCK_SIZE) {

        //不足块大小则进行填充,否则,复制BLOCK_SIZE大小的字节数组进行加密
        if((inData.length - i) < BLOCK_SIZE){
            block = new byte[inData.length - i];
            System.arraycopy(inData, i, block, 0, (inData.length - i));
            block = pkcs7Padding.encodeBlock(algorithm, block);
        }else{
            block = new byte[BLOCK_SIZE];
            System.arraycopy(inData, i, block, 0, BLOCK_SIZE);
        }

        // 对每个明文块进行加密
        int ret = api.SDF_Encrypt(sessionHandle, hKeyHandle, uiAlgID, iv, block, block.length, pucEncData, puiEncDataLength);
        if (ret != ErrorCode.ERR_OK.getValue()) {
            throw new EncryptFailException("加密失败,错误码【" + ret + "】,原因:" + ErrorCode.getName(ret));
        }
        pucEncData = HsmUtil.getData(pucEncData, puiEncDataLength.getValue());
        //与之前的密文进行合并
        ciphertextBlocks = ByteUtil.byteMerger(ciphertextBlocks, pucEncData);
    }

    return ciphertextBlocks;
}

你可能感兴趣的:(密码学,java,算法)