Java中字节流16位分组补齐算法解析 -以国密SM4算法为例

在文件加密解密过程中,经常将字节流按 16 位分成一组,方便运算。但是源文件若不是16的整数倍怎么办?这就可能导致解密文件多出几个字节的失真。
本文中的 padding() 算法即实现了最后一组 16 位的补齐以及最后的还原,代码如下:

国密算法工程示例源码:https://github.com/zhichaosong/hsd-cipher-sm

	/**
		余数补齐算法
	*/
	private byte[] padding(byte[] input, int mode)
	{
		if (input == null)
		{
			return null;
		}

		byte[] ret = (byte[]) null;
		if (mode == SM4_ENCRYPT) // 加密模式
		{
			int p = 16 - input.length % 16; // p:看最后要补多少位
			ret = new byte[input.length + p]; // ret:新的 16 倍数组
			System.arraycopy(input, 0, ret, 0, input.length); // 原内容拷到新数组
			for (int i = 0; i < p; i++) // 最后 p 位填充内容也为 p,方便解密时删除相应位数,此循环改进建议见下文
			{
				ret[input.length + i] = (byte) p;
			}
		}
		else // 解密模式
		{
			int p = input[input.length - 1]; // 从最后一位读出 p,即补的位数
			ret = new byte[input.length - p]; // 生成原数组大小的新数组
			System.arraycopy(input, 0, ret, 0, input.length - p); // 把补位前的内容还原
		}
		return ret;
	}

一点感悟:

  • 补位思想可见注释,还是比较精巧的,值得注意的是,即使原数组本来就是 16 的整数倍,也会给补上 16 位,方便算法统一处理。
  • 如果说优化的话,个人感觉加密补位的时候没必要把最后 p 位全部赋值,只赋值最后一位为 p 即可,因为解密的时候也只用了这一位,for 循环代码改进成一行即可:
ret[input.length + p - 1] = (byte) p;

你可能感兴趣的:(数据结构与算法,Java)