Hmac算法

目录

一、概述

二、实现

1.HmacMD5加密:

2.按照字节数组恢复密钥

3.按照字符串恢复密钥

三、总结:


一、概述

        在前面讲到哈希算法时,我们说,存储用户的哈希口令时,要加盐存储,目的就在于抵御彩虹表攻击。我们回顾一下哈希算法:

digest = hash(input)

正是因为相同的输入会产生相同的输出,我们加盐的目的就在于,使得输入有所变化:
digest = hash(salt + input)
这个salt可以看作是一个额外的“认证码”,同样的输入,不同的认证码,会产生不同的输出。因此,要验证输出的哈希,必须同时提供“认证码”。
        Hmac算法就是一种基于密钥的消息认证码算法,它的全称是Hash-based Message Authentication Code,是一种更安全的消息摘要算法。
Hmac算法总是和某种哈希算法配合起来用的。例如,我们使用MD5算法,对应的就是Hmac MD5算法,它相当于“加盐”的MD5:HmacMD5 ≈ md5(secure_random_key, input)
因此,HmacMD5可以看作带有一个安全的key的MD5。使用HmacMD5而不是用MD5加salt,有如下好处:
● HmacMD5使用的key长度是64字节,更安全;
● Hmac是标准算法,同样适用于SHA-1等其他哈希算法;
● Hmac输出和原有的哈希算法长度一致。
        可见,Hmac本质上就是把key混入摘要的算法。验证此哈希时,除了原始的输入数据,还要提供key。为了保证安全,我们不会自己指定key,而是通过Java标准库的KeyGenerator生成一个安全的随机的key。

二、实现

1.HmacMD5加密:

步骤:

1.产生密钥(通过KeyGenerator类获取一个实例,使用SecretKey接口生成密钥)

2.使用密钥,进行加密(使用Mac类获取HmacMD5加密算法对象)

        ①初始化

        ②更新原始加密内容

        ③加密处理

代码如下:

//HmacMD5算法
public class Demo10 {
    public static void main(String[] args) {
        String password = "wbjxxmy";
        try {
            //1.产生密钥
            //获取HmacMD5密钥生成器
            KeyGenerator keyGen = KeyGenerator.getInstance("HmacMd5");
            //生成密钥
            SecretKey secretKey = keyGen.generateKey();
            System.out.println("密钥:" + Arrays.toString(secretKey.getEncoded()));
            System.out.println("密钥长度(64字节):" + secretKey.getEncoded().length);
            System.out.println("密钥:" + HashTools.bytesToHex(secretKey.getEncoded()));
            //2.使用密钥,进行加密
            //获取HmacMD5加密算法对象
            Mac mac = Mac.getInstance("HmacMD5");
            mac.init(secretKey);    //初始化密钥
            mac.update(password.getBytes());        //更新原始加密内容
            byte[] bytes = mac.doFinal();           //加密处理,并获取加密结果
            String ret1 = HashTools.bytesToHex(bytes);
            System.out.println("加密结果16进制字符串:" + ret1);
            System.out.println("加密结果(16位字节)长度:" + bytes.length);
            System.out.println("加密结果(32位字符)长度:" + ret1.length());

        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        } catch (InvalidKeyException e) {
            throw new RuntimeException(e);
        }
    }
}

2.按照字节数组恢复密钥

//按照字节数组恢复密钥
public class Demo11 {
    public static void main(String[] args) {
        //原始密码
        String password = "wbjxxmy";
        //密钥(字节数组)
        byte[] bytes = {-71, -53, 43, 52, -89, 117, 96, 34, -95, 2, 94, -11, 85, 63, -27, 104, 32, 79, 36, -45, 62, -7, 111, -92, -113, -110, 90, 3, -56, -93, -95, -68, -28, -119, -34, 102, 99, 61, 121, 75, -18, -96, -82, -73, -86, -91, -96, 70, -85, 6, -8, -42, -105, 83, 88, -2, -106, -118, 126, -98, 60, -57, -77, 7};

        try {
            //创建HmacMD5加密算法对象
            Mac mac = Mac.getInstance("HmacMd5");
            //恢复密钥(字节数组)
            SecretKey key = new SecretKeySpec(bytes,"HmacMd5");
            mac.init(key);
            mac.update(password.getBytes());
            String hash = HashTools.bytesToHex(mac.doFinal());
            //fb7db9f386fb985d97fc3e2abbdb2598
            System.out.println("字节数组验证:" + hash);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        } catch (InvalidKeyException e) {
            throw new RuntimeException(e);
        }
    }
}

3.按照字符串恢复密钥

//按照字符串恢复密钥
public class Demo12 {
    public static void main(String[] args) {
        String password = "wbjxxmy";
        //密钥(字符串)
        String keystr = "b9cb2b34a7756022a1025ef5553fe568204f24d33ef96fa48f925a03c8a3a1bce489de66633d794beea0aeb7aaa5a046ab06f8d6975358fe968a7e9e3cc7b307";
        //用于保存密钥:密钥长度为64字节
        byte[] bytes = new byte[64];
        for (int i = 0,k = 0;i < keystr.length();i += 2,k++){
            String s = keystr.substring(i,i + 2);
            bytes[k] = (byte) Integer.parseInt(s,16);      //转换成16进制
        }
        try {
            //获取Hmac加密算法对象
            Mac mac = Mac.getInstance("HmacMD5");
            SecretKey key = new SecretKeySpec(bytes,"HmacMD5");

            mac.init(key);        //初始化密钥
            mac.update(password.getBytes());        //加密处理,并获取加密结果
            String hash = HashTools.bytesToHex(mac.doFinal());      //加密结果处理成16进制字符串
            System.out.println("字符串验证:" + hash);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        } catch (InvalidKeyException e) {
            throw new RuntimeException(e);
        }
    }
}

总结:

        Hmac算法是一种标准的基于密钥的哈希算法,可以配合MD5、SHA-1等哈希算法,计算的摘要长度和原摘要算法长度相同。

### HMAC算法的工作原理 HMAC(基于哈希的消息认证码)是一种利用加密散列函数生成消息认证码的技术。它结合了一个秘密密钥和一个输入消息,通过两次哈希运算生成最终的签名值[^1]。 #### 密钥扩展与填充 在 HMAC 的核心过程中,首先会对密钥 \( K \) 进行扩展处理。如果原始密钥长度小于内部块大小,则会将其用零字节填充到指定长度;如果密钥过长,则先对其进行一次哈希压缩再扩展[^4]。 接着分别使用两个固定常量 IPad (0x36) 和 OPad (0x5C),对扩展后的密钥执行 XOR 操作得到中间状态: \[ K_{ipad} = K \oplus IPad,\quad K_{opad} = K \oplus OPad \] 随后进行两轮哈希计算: \[ H(K_{opad} || H(K_{ipad} || message)) \] 其中 `||` 表示字符串连接操作符。 --- ### Python 中 HMAC 算法的具体实现 以下是采用面向对象方法构建的一个简单 HMAC 类实例化并调用了内置 hashlib 库完成主要功能演示: ```python import hmac from abc import ABC, abstractmethod class HashAlgorithm(ABC): @abstractmethod def create_hash(self, key: bytes, msg: bytes) -> str: pass class HMACSHA256(HashAlgorithm): def __init__(self, secret_key: str): self.key = secret_key.encode() def create_hash(self, msg: bytes) -> str: digest_maker = hmac.new(self.key, msg=msg, digestmod='sha256') return digest_maker.hexdigest() if __name__ == "__main__": sha256_instance = HMACSHA256(secret_key="my_secret") result = sha256_instance.create_hash(msg=b"Hello World!") print(f"HMAC SHA256 Result: {result}") ``` 上述代码片段展示了如何创建一个继承自抽象基类的对象,并实现了特定于 SHA-256 的 HMAC 计算逻辑。 --- ### Java 实现 HMAC-MD5 示例 下面是一个简单的例子说明如何在 Java 中生成 HmacMD5 并应用随机数作为密钥[^2]: ```java import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.security.Key; public class HmacExample { public static void main(String[] args)throws Exception{ String algorithm = "HmacMD5"; Mac macInstance = Mac.getInstance(algorithm); Key secretKey = new SecretKeySpec("secretkey".getBytes(),algorithm); macInstance.init(secretKey); byte[] textToEncryptBytes = "HellArtisan".getBytes(); byte[] encryptedTextArray = macInstance.doFinal(textToEncryptBytes); System.out.println(new sun.misc.BASE64Encoder().encode(encryptedTextArray)); } } ``` 此程序段显示了设置 MAC 实例的过程以及初始化阶段所需的参数配置。 --- ### PHP 手动实现 HMAC 当 hash_hmac 不可用时 当服务器环境不支持原生 `hash_hmac()` 函数时,可以按照如下方式重新编写其基本行为[^3]: ```php function custom_hmac($algo, $data, $key){ if(function_exists('hash_hmac')){ return hash_hmac($algo,$data,$key); } // Manual implementation starts here... $blocksize=64; if(strlen($key)>$blocksize){ $key=str_pad(hash($algo,$key,true),$blocksize,"\0"); }else{ $key=str_pad($key,$blocksize,"\0"); } $ipad=str_repeat(chr(0x36), $blocksize)^$key; $opad=str_repeat(chr(0x5c), $blocksize)^$key; return hash($algo,$opad.hash($algo,$ipad.$data)); } echo(custom_hmac('md5', 'message', 'key')); ``` 这段脚本提供了另一种途径,在缺乏必要扩展的情况下也能获得一致的结果。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sorenw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值