栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android 中使用AES-CMAC数据加密

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android 中使用AES-CMAC数据加密

一般需要分为三个步骤:

算出L的值,然后算出K1,K2的值,可以对比AES在线加密工具作为对比

    
    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("AC362C7FCCE2BD996153C64B7D39A82A");

        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;
    }

    
    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;
    }

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/666859.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号