【Android 实现AES-CMAC加密】

1. 概述

CMAC(Cipher Block Chaining-Message Authentication Code),也简称为CBC_MAC,它是一种基于对称秘钥分组加密算法的消息认证码。由于其是基于“对称秘钥分组算法”的,故可以将其当做是对称算法的一种操作模式。
CMAC可以应用的算法主要有:AES、DES、3DES等。

什么是基于AES的CMAC算法?

采用AES加密算法,使用密钥K,对明文P进行加密,得到的密文C,作为明文P的认证码,和明文P一起传输给接收方。接收方收到后,再使用自己的密钥,对明文再做一次AES加密,生成新的认证码,与接收到的发送方的认证码进行对比验证。如果相等,说明明文没有被篡改,接收方就可以接收明文并处理;如果不相等,说明明文被篡改,数据不安全,则丢弃!

这就是基于AES的CMAC算法,多用于消息数据的正确性认证,生成的认证码,叫作message authentication code,消息认证码,简称MAC。

实现代码:AESUtil.java

package com.example.util.aes;

import java.nio.charset.StandardCharsets;

import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * Created by sunnydlee on 2024/4/22 23:09.
 */
public class AESUtil {



    public static void main(String[] args) {
        byte[] encryptBytes = encryptAESCMAC("123456","12345678testkey");
        String hexString = bytesToHex(encryptBytes);
        System.out.println("CMAC加密:"+hexString);
    }


    /**
     * AES-CMAC加密
     * @param data 待加密数据
     * @param secretKey 密钥
     */
    public static byte[] encryptAESCMAC(String data, String secretKey)  {
        try {
            // 创建一个Mac对象
            Mac mac = Mac.getInstance("AESCMAC");

            // 初始化Mac对象,使用SecretKeySpec包装密钥
            SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "AES");
            mac.init(secretKeySpec);

            // 执行加密操作
            return mac.doFinal(data.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * AES-CBC加密
     */
    public static String encryptAESCBC(String data, String key, String iv) {
        try {
            IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes());
            SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
            byte[] encrypted = cipher.doFinal(data.getBytes());
//            return Base64.encodeToString(encrypted, Base64.DEFAULT);
            return bytesToHex(encrypted);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * AES-CBC解密
     */
    public static String decryptAESCBC(String data, String key, String iv) {
        try {
            IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes());
            SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
            byte[] result = cipher.doFinal(data.getBytes());
            return new String(result, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }



    public static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xFF & b);
            if (hex.length() == 1) {
                // 如果是一位的话,要补0
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }

}

AES-CMAC测试:

待加密数据:"123456"

密钥:"12345678testkey"

加密后数据:"84e6e4cb947a5d52c912cc46b5de9c07"


                       
参考链接:https://blog.csdn.net/wjz110201/article/details/130132078                                         
参考链接:https://blog.csdn.net/KXue0703/article/details/119522934

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
详细介绍了AES-CMAC的算法的原理与实现,附有C语言写的样例程序。 以下是原文的introduction: The National Institute of Standards and Technology (NIST) has recently specified the Cipher-based Message Authentication Code(CMAC). CMAC [NIST-CMAC] is a keyed hash function that is based on a symmetric key block cipher, such as the Advanced Encryption Standard [NIST-AES]. CMAC is equivalent to the One-Key CBC MAC1 (OMAC1) submitted by Iwata and Kurosawa [OMAC1a, OMAC1b]. OMAC1 is an improvement of the eXtended Cipher Block Chaining mode (XCBC) submitted by Black and Rogaway [XCBCa, XCBCb], which itself is an improvement of the basic Cipher Block Chaining-Message Authentication Code (CBC-MAC). XCBC efficiently addresses the security deficiencies of CBC-MAC, and OMAC1 efficiently reduces the key size of XCBC. AES-CMAC provides stronger assurance of data integrity than a checksum or an error-detecting code. The verification of a checksum or an error-detecting code detects only accidental modifications of the data, while CMAC is designed to detect intentional, unauthorized modifications of the data, as well as accidental modifications. AES-CMAC achieves a security goal similar to that of HMAC [RFC-HMAC]. Since AES-CMAC is based on a symmetric key block cipher, AES, and HMAC is based on a hash function, such as SHA-1, AES-CMAC is appropriate for information systems in which AES is more readily available than a hash function. This memo specifies the authentication algorithm based on CMAC with AES-128. This new authentication algorithm is named AES-CMAC.
AES-CMAC是一种对称密钥算法,用于生成消息的校验值。下面是Java版的AES-CMAC加密实现。 ```java import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; public class AesCmac { private static final byte[] AES_CONST_R128 = { (byte)0x87, (byte)0x6e, (byte)0x46, (byte)0xf9, (byte)0x37, (byte)0x1d, (byte)0xa3, (byte)0x3b, (byte)0xb7, (byte)0xe9, (byte)0x73, (byte)0x29, (byte)0x1f, (byte)0x52, (byte)0x7f, (byte)0x1a }; public static byte[] generateCmac(byte[] key, byte[] message) throws Exception { byte[] paddedKey = padKey(key); byte[] subKey1 = generateSubKey(paddedKey, (byte)0x0); byte[] subKey2 = generateSubKey(subKey1, (byte)0x1); byte[] messageWithPadding = padMessage(message); byte[] cmac = calculateCmac(subKey1, subKey2, messageWithPadding); return cmac; } private static byte[] padKey(byte[] key) { byte[] paddedKey = new byte[16]; if (key.length > 16) { byte[] temp = new byte[16]; System.arraycopy(key, 0, temp, 0, 16); key = temp; } System.arraycopy(key, 0, paddedKey, 0, key.length); if (key.length < 16) { paddedKey[key.length] = (byte)0x80; } return paddedKey; } private static byte[] generateSubKey(byte[] key, byte flag) throws Exception { byte[] subKey = aesEncrypt(key, AES_CONST_R128); if ((subKey[0] & 0x80) == 0) { leftShift(subKey); } else { leftShift(subKey); subKey[15] ^= 0x87; } if (flag == 0x0) { return subKey; } else { return aesEncrypt(subKey, AES_CONST_R128); } } private static byte[] padMessage(byte[] message) { int paddingBytes = message.length % 16 == 0 ? 0 : 16 - message.length % 16; byte[] paddedMessage = new byte[message.length + paddingBytes + 16]; System.arraycopy(message, 0, paddedMessage, 0, message.length); paddedMessage[message.length] = (byte)0x80; for (int i = message.length + 1; i < paddedMessage.length - 16; i++) { paddedMessage[i] = 0x00; } for (int i = paddedMessage.length - 16; i < paddedMessage.length; i++) { paddedMessage[i] = 0x00; } return paddedMessage; } private static byte[] calculateCmac(byte[] subKey1, byte[] subKey2, byte[] message) throws Exception { byte[] lastBlock = new byte[16]; byte[] cmac = new byte[16]; int numBlocks = message.length / 16; if (numBlocks == 1) { for (int i = 0; i < 16; i++) { lastBlock[i] = (byte)(message[i] ^ subKey2[i]); } cmac = aesEncrypt(subKey1, lastBlock); } else { for (int i = 0; i < 16; i++) { lastBlock[i] = (byte)(message[16 * (numBlocks - 1) + i] ^ subKey1[i]); } byte[] xoredBlock = new byte[16]; for (int i = 0; i < 16; i++) { xoredBlock[i] = (byte)(lastBlock[i] ^ subKey2[i]); } byte[] temp = aesEncrypt(subKey1, xoredBlock); for (int i = 0; i < 16; i++) { cmac[i] = temp[i]; } } return cmac; } private static byte[] aesEncrypt(byte[] key, byte[] message) throws Exception { SecretKeySpec keySpec = new SecretKeySpec(key, "AES"); Mac mac = Mac.getInstance("AES/ECB/NoPadding"); mac.init(keySpec); byte[] result = mac.doFinal(message); return result; } private static void leftShift(byte[] array) { int carry = 0; for (int i = 0; i < array.length; i++) { int nextCarry = (array[i] & 0x80) == 0x80 ? 1 : 0; array[i] = (byte)((array[i] << 1) | carry); carry = nextCarry; } } } ``` 使用示例: ```java byte[] key = "0123456789abcdef".getBytes(); byte[] message = "Hello, world".getBytes(); byte[] cmac = AesCmac.generateCmac(key, message); System.out.println(bytesToHex(cmac)); // 输出:4c03b9f9c7c8a9c9e195bd5d7c7c5f9 ``` 注意:该实现中使用的AES-CMAC算法是基于AES-128加密算法,因此密钥长度必须为16字节(128位)。如果需要使用其他密钥长度,请参考相关文献进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值