本文介绍了SHAKE128和SHAKE256这两种可扩展输出函数(XOF),它们是SHA-3的变体,可以生成任意长度的哈希值。同时,还介绍了cSHAKE128和cSHAKE256,它们允许在哈希过程中添加上下文字符串,从而实现域分离。文章通过代码示例展示了如何在Zig语言中使用这些函数,并演示了如何使用上下文字符串来区分不同的哈希应用场景,例如添加pepper字符串。

如果将 SHA-3 从其固定长度输出中分离出来,你将得到一个 可扩展输出函数(EXtendable Output Function,XOF)。 这现在具有产生几乎无限的输出集合的潜力,因此我们可以取一个字节并产生十亿字节的输出,或者甚至取十亿字节的输入并产生单个字节的输出。 本质上,它是一个状态生成器,通过给定的输入,我们可以达到一个明确定义的状态。 我们可以将状态暴露给任何人,因为他们不会知道允许我们进入前一个和下一个状态的秘密。
对于 SHA-3,我们可以使用 SHAKE128 或 SHAKE256 来实现可变长度的哈希,其中 SHAKE128 为我们提供 128 位的安全性,而 SHAKE256 提供 256 位的安全性。 使用 cSHAKE,我们还可以向哈希过程中添加上下文字符串,这使我们可以使用域字符串分隔哈希。 同样,我们可以有 cSHAKE128 和 cSHAKE256。
使用可扩展输出函数(XOF)哈希函数,例如 SHAKE128 和 SHAKE256,创建一个 variable;length 哈希函数:

因此,SHA-3 的主要方法是 SHAKE128 和 SHAKE256:

使用 cSHAKE128 和 cSHAKE256,我们可以将上下文字符串添加到哈希过程中,并且我们需要提供所需的上下文字符串和原始输入数据值,才能生成相同的哈希输出。 我们还可以提供长度值来定义输出哈希长度。
以下代码使用 Zig Version 0.15.1 编译 [ 这里]:
const std = @import("std");
const crypto = std.crypto.hash;
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var stdout_buffer: [4096]u8 = undefined;
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
const stdout = &stdout_writer.interface;
// Get the command-line arguments
// 获取命令行参数
var data: []u8 = undefined;
var length: []u8 = undefined;
var context: []u8 = undefined;
const args = try std.process.argsAlloc(std.heap.page_allocator);
defer std.process.argsFree(std.heap.page_allocator, args);
// Check if there are any arguments
// 检查是否有任何参数
if (args.len > 1) {
data = args[1];
}
if (args.len > 2) {
context = args[2];
}
if (args.len > 3) {
length = args[3];
}
const len = try std.fmt.parseInt(usize, length, 10);
const Shake128 = try allocator.alloc(u8, len);
defer allocator.free(Shake128);
const Shake256 = try allocator.alloc(u8, len);
defer allocator.free(Shake256);
const CShake128 = try allocator.alloc(u8, len);
defer allocator.free(CShake128);
const CShake256 = try allocator.alloc(u8, len);
defer allocator.free(CShake256);
crypto.sha3.Shake128.hash(data, Shake128, .{});
crypto.sha3.Shake256.hash(data, Shake256, .{});
crypto.sha3.CShake128.hash(data, CShake128, .{ .context = context });
crypto.sha3.CShake256.hash(data, CShake256, .{ .context = context });
try stdout.print("Data: {s}\n", .{data});
try stdout.print("Size: {s} bytes\n", .{length});
try stdout.print("\nSHAKE128: {x}\n", .{Shake128});
try stdout.print("SHAKE256: {x}\n", .{Shake256});
try stdout.print("\nContext string: {s}\n", .{context});
try stdout.print("cSHAKE128: {x}\n", .{CShake128});
try stdout.print("cSHAKE256: {x}\n", .{CShake256});
try stdout.flush();
}

在 Microsoft Windows 上,我们使用以下命令编译为可执行文件:
> zig build-exe zig_shake.zig
然后我们可以运行文件 zig_shake.exe。 对于哈希“Hello”和“Goodbye”的上下文字符串的 64 字节数据的示例运行是:
Data: Hello
Size: 64 bytes
SHAKE128: 4131f8db5745776b48b86caa68d251fa9b19cf46b92b16289bb0c98e57e0e0de58c94a8b24ea4a9902a8307840b2ffbf2df2f0b1aa199ebea1c774e90c3b32a8
SHAKE256: 555796c90bfb8f3256a1cb0d7e574877fd48750e4147cf40aa43da122b4d64dafec00acf1ff59f4c3805f9589ec1ee3b712bc3701ce7d825cba56ca4942f6ffd
Context string: Goodbye
CShake128: 09ca205255cf4aea5a0e0a815d564115d6e94e029243575517f8c79591dd8c16ff5d510f4bf8efbf5fed5866f66dedba5ce1ed855124ec5498096d1f19644c47
CShake256: a48827790a451da39be18e3236b293bb9baa3d07ae6c50de42c6c71df9bef4377e9697020f57b0cbb7247ccd36643fa622888c02f2cde646e858caad3feaf200
对于哈希“Hello”和“Goodbye”的上下文字符串的 16 字节数据的示例运行是:
Data: Hello
Size: 16 bytes
SHAKE128: 4131f8db5745776b48b86caa68d251fa
SHAKE256: 555796c90bfb8f3256a1cb0d7e574877
Context string: Goodbye
cSHAKE128: 09ca205255cf4aea5a0e0a815d564115
cSHAKE256: a48827790a451da39be18e3236b293bb
总的来说,上下文字符串可用于在哈希之间创建分隔。 其中的一个例子是为哈希过程定义一个 盐(pepper) 字符串,该字符串是保密的,而 盐(salt) 值可能会更多地暴露出来。 这样,入侵者可能会发现使用的 盐(salt) 值,但无法发现 盐(pepper) 字符串。
- 原文链接: medium.com/asecuritysite...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!