1.概述
利用key(密钥)和msg(信息)进行加密得到256位的哈希值,表示消息和密钥的认证结果hmac。
2.源代码
文件路径:net/mptcp/crypto.c
#include <linux/kernel.h>
#include <crypto/sha2.h>
#include <asm/unaligned.h>
#include "protocol.h"
#define SHA256_DIGEST_WORDS (SHA256_DIGEST_SIZE / 4)
void mptcp_crypto_key_sha(u64 key, u32 *token, u64 *idsn)
{
__be32 mptcp_hashed_key[SHA256_DIGEST_WORDS];
__be64 input = cpu_to_be64(key);
sha256((__force u8 *)&input, sizeof(input), (u8 *)mptcp_hashed_key);
if (token)
*token = be32_to_cpu(mptcp_hashed_key[0]);
if (idsn)
*idsn = be64_to_cpu(*((__be64 *)&mptcp_hashed_key[6]));
}
void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u8 *msg, int len, void *hmac)
{
u8 input[SHA256_BLOCK_SIZE + SHA256_DIGEST_SIZE];
u8 key1be[8];
u8 key2be[8];
int i;
if (WARN_ON_ONCE(len > SHA256_DIGEST_SIZE))
len = SHA256_DIGEST_SIZE;
put_unaligned_be64(key1, key1be);
put_unaligned_be64(key2, key2be);
/* Generate key xored with ipad */
memset(input, 0x36, SHA256_BLOCK_SIZE);
for (i = 0; i < 8; i++)
input[i] ^= key1be[i];
for (i = 0; i < 8; i++)
input[i + 8] ^= key2be[i];
memcpy(&input[SHA256_BLOCK_SIZE], msg, len);
/* emit sha256(K1 || msg) on the second input block, so we can
* reuse 'input' for the last hashing
*/
sha256(input, SHA256_BLOCK_SIZE + len, &input[SHA256_BLOCK_SIZE]);
/* Prepare second part of hmac */
memset(input, 0x5C, SHA256_BLOCK_SIZE);
for (i = 0; i < 8; i++)
input[i] ^= key1be[i];
for (i = 0; i < 8; i++)
input[i + 8] ^= key2be[i];
sha256(input, SHA256_BLOCK_SIZE + SHA256_DIGEST_SIZE, hmac);
}
#if IS_MODULE(CONFIG_MPTCP_KUNIT_TEST)
EXPORT_SYMBOL_GPL(mptcp_crypto_hmac_sha);
#endif
3.代码分析
文件路径:include/crypto/sha2.h
#define SHA256_DIGEST_SIZE 32
#define SHA256_BLOCK_SIZE 64
文件路径:net/mptcp/crypto.c
#include <linux/kernel.h>
#include <crypto/sha2.h>
#include <asm/unaligned.h>
#include "protocol.h"
#define SHA256_DIGEST_WORDS (SHA256_DIGEST_SIZE / 4)
//传入一个key,然后经过sha256加密,填充token很idsn
void mptcp_crypto_key_sha(u64 key, u32 *token, u64 *idsn)
{
//SHA256_DIGEST_WORDS=8, 8*be32=256位,对应sha256算法
__be32 mptcp_hashed_key[SHA256_DIGEST_WORDS];
//将传入的key以64位大端格式存储
__be64 input = cpu_to_be64(key);
//sha256是以字节流的方式处理输入数据所以用(__force u8 *)
//对input数据进行sha256加密处理,然后输出到mptcp_hashed_key中
sha256((__force u8 *)&input, sizeof(input), (u8 *)mptcp_hashed_key);
if (token)
//如果token不为空,将mptcp_hashed_key[8]数组的第一个be32,转换成主机模式传给token
*token = be32_to_cpu(mptcp_hashed_key[0]);
if (idsn)
//如果idsn不为空,将mptcp_hashed_key[8]数组的第7和第8个be32,转换成主机模式传给idsn
*idsn = be64_to_cpu(*((__be64 *)&mptcp_hashed_key[6]));
}
//用sha256算法对key1、key2、msg进行加密处理,最后得到hmac
void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u8 *msg, int len, void *hmac)
{
//input[64+32]
u8 input[SHA256_BLOCK_SIZE + SHA256_DIGEST_SIZE];
u8 key1be[8];
u8 key2be[8];
int i;
//由于下面要对nput[SHA256_BLOCK_SIZE]位置开始填充len长度的msg
//所以len不能大于SHA256_DIGEST_SIZE
if (WARN_ON_ONCE(len > SHA256_DIGEST_SIZE))
len = SHA256_DIGEST_SIZE;
//将一个 64 位值 key1 以大端(Big Endian)格式存储到 key1be 中
put_unaligned_be64(key1, key1be);
put_unaligned_be64(key2, key2be);
//下面用到一种叫hmac的加密算法,HMAC 是一种基于哈希函数的消息认证码(MAC),
//它利用一个密钥和一个哈希函数来生成一个用于验证消息完整性和认证消息来源的值。
/*
设密钥为 K,消息为 M,哈希函数为 H,则:
内层哈希:inner = H(K' ⊕ ipad || M),其中 K' 是经过处理后的密钥,ipad 是固定的 0x36 填充字节。
外层哈希:HMAC = H(K' ⊕ opad || inner),其中 opad 是固定的 0x5C 填充字节。
*/
/* Generate key xored with ipad */
memset(input, 0x36, SHA256_BLOCK_SIZE);将input的SHA256_BLOCK_SIZE大小设为0x36
for (i = 0; i < 8; i++)
input[i] ^= key1be[i]; //input前8字节和key1be异或运算
for (i = 0; i < 8; i++)
input[i + 8] ^= key2be[i]; //input前8~16字节和key2be异或运算
//input[SHA256_BLOCK_SIZE]位置开始填充msg
memcpy(&input[SHA256_BLOCK_SIZE], msg, len);
/* emit sha256(K1 || msg) on the second input block, so we can
* reuse 'input' for the last hashing
*/
sha256(input, SHA256_BLOCK_SIZE + len, &input[SHA256_BLOCK_SIZE]);
/* Prepare second part of hmac */
memset(input, 0x5C, SHA256_BLOCK_SIZE);
for (i = 0; i < 8; i++)
input[i] ^= key1be[i];
for (i = 0; i < 8; i++)
input[i + 8] ^= key2be[i];
//最后得到一个256位的哈希值,表示消息和密钥的认证结果
sha256(input, SHA256_BLOCK_SIZE + SHA256_DIGEST_SIZE, hmac);
}
#if IS_MODULE(CONFIG_MPTCP_KUNIT_TEST)
EXPORT_SYMBOL_GPL(mptcp_crypto_hmac_sha);
#endif
下面的结构图详细展示了如何通过 key1、key2 和 msg 来计算 HMAC 的过程:
plaintext
+-----------------------------------------------+
| HMAC |
|-----------------------------------------------|
| Step 1: Prepare Keys (key1, key2) |
| key1 --> key1be (Big Endian) |
| key2 --> key2be (Big Endian) |
+-----------------------------------------------+
|
v
+-----------------------------------------------+
| Step 2: Padding and XOR with ipad (0x36) |
| key1be XOR 0x36 --> part of input[0..63] |
| key2be XOR 0x36 --> part of input[0..63] |
| msg --> input[64..(64+len)] |
| (input) = [key1be XOR 0x36 | key2be XOR 0x36 | msg] |
+-----------------------------------------------+
|
v
+-----------------------------------------------+
| Step 3: First SHA256 (Hashing Step 1) |
| SHA256(input) -> intermediate_hash |
+-----------------------------------------------+
|
v
+-----------------------------------------------+
| Step 4: Padding and XOR with opad (0x5C) |
| key1be XOR 0x5C --> part of input[0..63] |
| key2be XOR 0x5C --> part of input[0..63] |
| intermediate_hash --> input[64..95] |
| (input) = [key1be XOR 0x5C | key2be XOR 0x5C | intermediate_hash] |
+-----------------------------------------------+
|
v
+-----------------------------------------------+
| Step 5: Second SHA256 (Final HMAC Calculation)|
| SHA256(input) -> final_hmac (32 bytes) |
+-----------------------------------------------+
|
v
+-----------------------------------------------+
| Final Output: HMAC |
| hmac = final_hmac (32 bytes, 256 bits) |
+-----------------------------------------------+