Android 中实现 HMAC-SHA256

按指定格式拼接原始字符串、UTF-8编码、HMAC-SHA256加密、转十六进制字符串,(兼容Java 8+,Android/后端通用),并做好异常处理和注释,直接复制就能用。

核心说明

Java中实现HMAC-SHA256需要用到javax.crypto包下的Mac类,十六进制转换需要手动实现(Java无原生直接转的方法),同时要处理字符编码加密异常,以下是完整实现。

完整Java代码(直接可用)

包含签名计算核心方法 +十六进制转换工具方法 +异常处理 +测试示例

java 复制代码
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * 设备登录签名计算工具
 * 实现的HMAC-SHA256签名逻辑,格式:dev={dev}&timestamp={timestamp}&nonce={nonce}&secret={secretKey}
 */
public class DeviceSignUtil {

    // 加密算法:HMAC-SHA256
    private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256";
    // 十六进制字符集(固定)
    private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray();

    /**
     * 计算设备登录HMAC-SHA256签名
     * @param dev 设备号
     * @param timestamp 时间戳(整型)
     * @param nonce 随机串
     * @param secretKey 秘钥
     * @return 十六进制签名字符串(小写)
     * @throws NoSuchAlgorithmException 算法不存在异常(理论上不会出现)
     * @throws InvalidKeyException 秘钥无效异常
     */
    public static String calculateDeviceSignature(String dev, long timestamp, String nonce, String secretKey)
            throws NoSuchAlgorithmException, InvalidKeyException {
        // 1. 严格按格式拼接原始字符串(注意参数名拼写:nonce/secret)
        String rawStr = String.format("dev=%s&timestamp=%d&nonce=%s&secret=%s",
                dev, timestamp, nonce, secretKey);

        // 2. 将字符串和秘钥编码为UTF-8字节数组
        byte[] rawBytes = rawStr.getBytes(StandardCharsets.UTF_8);
        byte[] secretBytes = secretKey.getBytes(StandardCharsets.UTF_8);

        // 3. 初始化HMAC-SHA256加密器
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretBytes, HMAC_SHA256_ALGORITHM);
        Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
        mac.init(secretKeySpec);

        // 4. 计算HMAC-SHA256并转十六进制字符串
        byte[] signBytes = mac.doFinal(rawBytes);
        return bytesToHex(signBytes);
    }

    /**
     * 字节数组转十六进制字符串(小写)
     * @param bytes 加密后的字节数组
     * @return 十六进制小写字符串
     */
    private static String bytesToHex(byte[] bytes) {
        char[] result = new char[bytes.length * 2];
        for (int i = 0; i < bytes.length; i++) {
            int val = bytes[i] & 0xFF; // 消除符号位影响
            result[i * 2] = HEX_CHARS[val >>> 4]; // 高4位
            result[i * 2 + 1] = HEX_CHARS[val & 0x0F]; // 低4位
        }
        return new String(result);
    }

    // 测试示例(可直接运行验证)
    public static void main(String[] args) {
        try {
            // 测试参数
            String dev = "DEVICE123456";
            long timestamp = 1735689600;
            String nonce = "abcdefg1234567";
            String secretKey = "myDeviceSecret123";

            // 计算签名
            String signature = calculateDeviceSignature(dev, timestamp, nonce, secretKey);
            System.out.println("设备签名结果:" + signature);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

异常处理说明

Java加密相关方法会抛出受检异常,需手动捕获/声明,主要异常:

  • NoSuchAlgorithmException:指定的HmacSHA256算法不存在(理论上不会出现,Java所有版本都支持);

  • InvalidKeyException:秘钥无效(如空秘钥),业务中需做秘钥非空校验;

  • 实际业务中建议在外层捕获异常,统一处理(如返回空签名、打印日志):

    java 复制代码
    // 业务中调用示例(捕获所有异常)
    public String getSign(String dev, long timestamp, String nonce, String secretKey) {
        try {
            return DeviceSignUtil.calculateDeviceSignature(dev, timestamp, nonce, secretKey);
        } catch (Exception e) {
            e.printStackTrace();
            return null; // 或返回空字符串,根据业务处理
        }
    }

Android端兼容说明

如果这段代码用于Android开发,无需额外依赖,直接复制即可:

  1. Android SDK 19+(4.4)完全支持StandardCharsets.UTF_8,低版本(<19)可替换为"UTF-8"字符串:

    java 复制代码
    // 低版本Android替换编码方式
    byte[] rawBytes = rawStr.getBytes("UTF-8");
    byte[] secretBytes = secretKey.getBytes("UTF-8");
  2. 无需添加额外权限,加密相关API属于Android核心库,无需在清单文件声明。

总结

  1. 核心实现:通过javax.crypto.Mac实现HMAC-SHA256,手动实现字节数组转十六进制;
  2. 关键兼容:UTF-8编码、小写十六进制输出、timestamp用long类型,保证跨语言签名一致;
  3. 直接使用:代码包含工具类、测试示例、异常处理,Android/Java后端通用,复制即可集成到项目中。
相关推荐
ValhallaCoder16 小时前
hot100-栈
数据结构·python·算法·
xuzhiqiang072419 小时前
Java进阶之路,Java程序员职业发展规划
java·开发语言
MediaTea19 小时前
Python:生成器表达式详解
开发语言·python
-To be number.wan20 小时前
Python数据分析:SciPy科学计算
python·学习·数据分析
Dxy123931021620 小时前
DataFrame数据修改:从基础操作到高效实践的完整指南
python·dataframe
overmind21 小时前
oeasy Python 115 列表弹栈用pop删除指定索引
开发语言·python
恋猫de小郭21 小时前
你是不是觉得 R8 很讨厌,但 Android 为什么选择 R8 ?也许你对 R8 还不够了解
android·前端·flutter
Never_Satisfied1 天前
在c#中,使用windows自带功能将文件夹打包为ZIP
开发语言·windows·c#
hnxaoli1 天前
win10程序(十六)通达信参数清洗器
开发语言·python·小程序·股票·炒股
电饭叔1 天前
文本为 “ok”、前景色为白色、背景色为红色,且点击后触发 processOK 回调函数的 tkinter 按钮
开发语言·python