一般需要分为三个步骤:
算出L的值,然后算出K1,K2的值,可以对比AES在线加密工具作为对比
/ * 算法逻辑 * * @param key * @param data * @return */ public static byte[] Aes_Cmac01(byte[] key, byte[] data) { // 子密钥生成 // 步骤1,将具有密钥K的AES-128应用于全零输入块。 byte[] L = aesEncryptNoPadding(key, new byte[16], new byte[16]); Log.i(TAG, "configUUIDValue L: " + ByteUtils.bytes2HexStr(L)); // 步骤2,通过以下操作得出K1: //如果L的最高有效位等于0,则K1是L的左移1位。 byte[] FirstSubkey = Rol(L); if ((L[0] & 0x80) == 0x80) { // 否则,K1是const_Rb的异或和L左移1位。 FirstSubkey[15] ^= 0x87; } // Log.i(TAG, "configUUIDValue K1: "+ ByteUtils.bytes2HexStr(FirstSubkey)); // FirstSubkey = ByteUtils.hexStr2Bytes("AC362C7FCCE2BDC64B7D39A82A"); Log.i(TAG, "configUUIDValue K1: " + ByteUtils.bytes2HexStr(FirstSubkey)); // 步骤3,通过以下操作得出K2: //如果K1的最高有效位等于0,则K2是K1左移1位 byte[] SecondSubkey = Rol(FirstSubkey); if ((FirstSubkey[0] & 0x80) == 0x80) { // 否则,K2是const_Rb的异或,且K1左移1位 SecondSubkey[15] ^= 0x87; } // Log.i(TAG, "configUUIDValue K2: "+ ByteUtils.bytes2HexStr(SecondSubkey)); // SecondSubkey = ByteUtils.hexStr2Bytes("586C58FF99C57B32C2A78C96FA7350D3"); Log.i(TAG, "configUUIDValue K2: " + ByteUtils.bytes2HexStr(SecondSubkey)); Log.i(TAG, "configUUIDValue data: " + ByteUtils.bytes2HexStr(data)); // MAC 计算 if (((data.length != 0) && (data.length % 16 == 0)) == true) { //如果输入消息块的大小等于块大小(128位) // 最后一个块在处理之前应与K1异或 for (int j = 0; j < FirstSubkey.length; j++) { data[data.length - 16 + j] ^= FirstSubkey[j]; } } else { // 否则,最后一个块应填充10 ^ i byte[] padding = new byte[16 - data.length % 16]; padding[0] = (byte) 0x80; byte[] newData = new byte[data.length + padding.length]; System.arraycopy(data, 0, newData, 0, data.length); System.arraycopy(padding, 0, newData, data.length, padding.length); // data = data.Concat
(padding.AsEnumerable()).ToArray(); // 并与K2进行异或运算 for (int j = 0; j < SecondSubkey.length; j++) { newData[newData.length - 16 + j] ^= SecondSubkey[j]; } data = newData; } Log.i(TAG, "configUUIDValue data1: " + ByteUtils.bytes2HexStr(data)); // 先前处理的结果将是最后一次加密的输入。 byte[] encResult = aesEncryptNoPadding(key, new byte[16], data); // 先前处理的结果将是最后一次加密的输入。 byte[] HashValue = new byte[16]; System.arraycopy(encResult, encResult.length - HashValue.length, HashValue, 0, HashValue.length); Log.i(TAG, "configUUIDValue data HashValue: " + ByteUtils.bytes2HexStr(HashValue)); return HashValue; } private static byte[] Rol(byte[] b) { byte[] output = new byte[b.length]; byte overflow = 0; for (int i = b.length - 1; i >= 0; i--) { output[i] = (byte) (b[i] << 1); output[i] |= overflow; if ((b[i] & 0x80) > 0) { overflow = 1; } else { overflow = 0; } } return output; } / * AES加密 * * @param keys * @param iv * @param data * @return */ public static byte[] aesEncryptNoPadding(byte[] keys, byte[] iv, byte[] data) { try { //1.根据字节数组生成AES密钥 SecretKey key = new SecretKeySpec(keys, "AES"); //2.根据指定算法AES自成密码器 "算法/模式/补码方式" Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); //3.CBC模式需要向量vi IvParameterSpec ivps = new IvParameterSpec(iv); //4.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二个参数为使用的KEY cipher.init(Cipher.ENCRYPT_MODE, key, ivps); //5.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码 byte[] byte_encode = data; //6.根据密码器的初始化方式--加密:将数据加密 byte[] byte_AES = cipher.doFinal(byte_encode); Log.i(TAG, "aesEncryptNoPadding: keys:" + ByteUtils.bytes2HexStr(keys)); Log.i(TAG, "aesEncryptNoPadding: 加密前:"+ByteUtils.bytes2HexStr(data)); Log.i(TAG, "aesEncryptNoPadding: 加密后:"+ByteUtils.bytes2HexStr(byte_AES)); //7.返回 return byte_AES; } catch (GeneralSecurityException e) { e.printStackTrace(); } return null; } public static byte[] aesEncryptPadding(byte[] keys, byte[] iv, byte[] data) { try { //1.根据字节数组生成AES密钥 SecretKey key=new SecretKeySpec(keys, "AES"); //2.根据指定算法AES自成密码器 "算法/模式/补码方式" Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); //3.CBC模式需要向量vi IvParameterSpec ivps = new IvParameterSpec(iv); //4.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二个参数为使用的KEY cipher.init(Cipher.ENCRYPT_MODE, key,ivps); //5.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码 byte [] byte_encode=data; //6.根据密码器的初始化方式--加密:将数据加密 byte [] byte_AES=cipher.doFinal(byte_encode); //7.返回 return byte_AES; }catch (GeneralSecurityException e) { e.printStackTrace(); } return null; } public static byte[] aesDecryptPadding(byte[] keys, byte[] iv, byte[] data) { try { //1.根据字节数组生成AES密钥 SecretKey key=new SecretKeySpec(keys, "AES"); //2.根据指定算法AES自成密码器 "算法/模式/补码方式" Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); //3.CBC模式需要向量vi IvParameterSpec ivps = new IvParameterSpec(iv); //4.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二个参数为使用的KEY cipher.init(Cipher.DECRYPT_MODE, key,ivps); //5.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码 byte [] byte_encode=data; //6.根据密码器的初始化方式--加密:将数据加密 byte [] byte_AES=cipher.doFinal(byte_encode); //7.返回 return byte_AES; }catch (GeneralSecurityException e) { e.printStackTrace(); } return null; } public static byte[] aesDecryptNoPadding(byte[] keys, byte[] iv, byte[] data) { try { //1.根据字节数组生成AES密钥 SecretKey key=new SecretKeySpec(keys, "AES"); //2.根据指定算法AES自成密码器 "算法/模式/补码方式" Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); //3.CBC模式需要向量vi IvParameterSpec ivps = new IvParameterSpec(iv); //4.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二个参数为使用的KEY cipher.init(Cipher.DECRYPT_MODE, key,ivps); //5.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码 byte [] byte_encode=data; //6.根据密码器的初始化方式--加密:将数据加密 byte [] byte_AES=cipher.doFinal(byte_encode); //7.返回 return byte_AES; }catch (GeneralSecurityException e) { e.printStackTrace(); } return null; }
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/226321.html原文链接:https://javaforall.net
