Java版AES-CBC-CMAC加密

   /**
     * 算法逻辑
     * @param key
     * @param data
     * @return
     */
    public static byte[] Aes_Cmac01(byte[] key, byte[] data){
        // 子密钥生成
        // 步骤1,将具有密钥K的AES-128应用于全零输入块。
        byte[] L = AesEncrypt(key, new byte[16], new byte[16]);

        // 步骤2,通过以下操作得出K1:
        //如果L的最高有效位等于0,则K1是L的左移1位。
        byte[] FirstSubkey = Rol(L);
        if ((L[0] & 0x80) == 0x80) {
            // 否则,K1是const_Rb的异或和L左移1位。
            FirstSubkey[15] ^= 0x87;
        }

        // 步骤3,通过以下操作得出K2:
        //如果K1的最高有效位等于0,则K2是K1左移1位
        byte[] SecondSubkey = Rol(FirstSubkey);
        if ((FirstSubkey[0] & 0x80) == 0x80) {
            // 否则,K2是const_Rb的异或,且K1左移1位
            SecondSubkey[15] ^= 0x87;
        }


        // 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<byte>(padding.AsEnumerable()).ToArray();
            // 并与K2进行异或运算
            for (int j = 0; j < SecondSubkey.length; j++){
                newData[newData.length - 16 + j] ^= SecondSubkey[j];
            }
            data=newData;
        }
        // 先前处理的结果将是最后一次加密的输入。
        byte[] encResult = AesEncrypt(key, new byte[16], data);
        byte[] HashValue = new byte[16];
        System.arraycopy(encResult, encResult.length - HashValue.length, HashValue, 0, HashValue.length);

        return HashValue;
    }

    private static byte[] Rol(byte[] b)
    {
        byte[] r = new byte[b.length];
        byte carry = 0;

        for (int i = b.length - 1; i >= 0; i--)
        {
            short u = (short)(b[i] << 1);
            r[i] = (byte)((u & 0xff) + carry);
            carry = (byte)((u & 0xff00) >> 8);
        }
        return r;
    }

    /**
     * AES加密
     * @param keys
     * @param iv
     * @param data
     * @return
     */
    private static byte[] AesEncrypt(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);
            //7.返回
            return byte_AES;

        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }

        return null;
    }
posted @ 2021-03-12 19:57  菜鸟kenshine  阅读(1367)  评论(0编辑  收藏  举报