tiny.reticulum.crypto.hkdf
Defined in crypto.
API (4)
Actions
Public operations.
derive: Writeslengthderived bytes intooutand returns them, so a caller turns a shared secret into exactly as many key bytes as it needs, following Reticulum@1.5.0 RNS/Cryptography/HKDF.py:35-62.
Types and contracts
Public types and contracts.
Values and defaults
Public values and defaults.
Source
Source: lib/reticulum/src/crypto/hkdf.zig
zig
const std = @import("std");const crypto = @import("root.zig");pub const hash_length: u8 = crypto.hmac.tag_length;pub const max_output_length: u16 = std.math.maxInt(u16);pub const HkdfError = error{ InvalidLength, OutputTooLong, EmptyKeyMaterial, OutputTooSmall, OverlappingBuffers,};/// Writes `length` derived bytes into `out` and returns them, so a caller turns/// a shared secret into exactly as many key bytes as it needs, following/// Reticulum@1.5.0 RNS/Cryptography/HKDF.py:35-62. The first stage signs the/// key material under the salt, and the second stage builds the output one/// 32-byte block at a time, each block signed over the block before it, then/// the context, then a counter byte that starts at one and wraps at 256. A salt/// the caller leaves out, or passes empty, becomes 32 zero bytes. The call/// returns `error.InvalidLength` for a length of zero, `error.OutputTooLong`/// past 65,535 bytes, `error.EmptyKeyMaterial` for empty key material,/// `error.OutputTooSmall` when `out` is shorter than the length, and/// `error.OverlappingBuffers` when the key material, the salt, or the context/// overlaps the output.pub fn derive( length: u17, key_material: []const u8, salt: ?[]const u8, context: ?[]const u8, out: []u8,) HkdfError![]u8 { if (length == 0) return error.InvalidLength; if (length > max_output_length) return error.OutputTooLong; if (key_material.len == 0) return error.EmptyKeyMaterial; const output_length: usize = @intCast(length); if (out.len < output_length) return error.OutputTooSmall; const result = out[0..output_length]; if (overlaps(key_material, result)) return error.OverlappingBuffers; if (salt) |value| if (overlaps(value, result)) return error.OverlappingBuffers; if (context) |value| if (overlaps(value, result)) return error.OverlappingBuffers; const zero_salt: [hash_length]u8 = @splat(0); const selected_salt = effectiveSalt(salt, &zero_salt); const selected_context = context orelse ""; const pseudorandom_key = crypto.hmac.sign(selected_salt, key_material); expand(@intCast(length), pseudorandom_key, selected_context, result); return result;}fn effectiveSalt(salt: ?[]const u8, zero_salt: *const [hash_length]u8) []const u8 { const value = salt orelse return zero_salt; if (value.len == 0) return zero_salt; return value;}fn overlaps(input: []const u8, output: []u8) bool { if (input.len == 0) return false; const input_start = @intFromPtr(input.ptr); const output_start = @intFromPtr(output.ptr); const input_end = input_start + input.len; const output_end = output_start + output.len; return input_start < output_end and output_start < input_end;}fn expand( length: u16, pseudorandom_key: [hash_length]u8, context: []const u8, out: []u8,) void { const output_length: usize = length; std.debug.assert(output_length == out.len); std.debug.assert(length <= max_output_length); var previous: [hash_length]u8 = undefined; var previous_length: usize = 0; var written: usize = 0; var block_index: u16 = 0; while (written < output_length) : (block_index += 1) { const counter = [1]u8{@intCast((block_index + 1) % 256)}; var signer = crypto.hmac.Signer.init(&pseudorandom_key); signer.update(previous[0..previous_length]); signer.update(context); signer.update(&counter); previous = signer.final(); previous_length = hash_length; const take = @min(hash_length, output_length - written); @memcpy(out[written..][0..take], previous[0..take]); written += take; } std.debug.assert(written == output_length);}Source: lib/reticulum/src/crypto/root.zig:46
zig
pub const hkdf = @import("hkdf.zig");Complete caller list for crypto.hkdf.derive
7 direct callers.
lib.reticulum.src.crypto.test.expectHkdf[function] — private source atlib/reticulum/src/crypto/test.zig:185in nearest public ownerlib.reticulum.src.crypto.testlib.reticulum.src.crypto.test.test_HKDF_u16_maximum_and_maximum_plus_one_admission[function] — test source atlib/reticulum/src/crypto/test.zig:288in nearest public ownerlib.reticulum.src.crypto.testlib.reticulum.src.crypto.test.test_Reticulum@1.5.0_RNS/Cryptography/HKDF.py:35-62_differential_corpus[function] — test source atlib/reticulum/src/crypto/test.zig:101in nearest public ownerlib.reticulum.src.crypto.testlib.reticulum.src.identity.cipher.decryptWithKey[function] — private source atlib/reticulum/src/identity/cipher.zig:88in nearest public ownertiny.reticulum.identity.ciphertiny.reticulum.identity.cipher.encrypt[function] atlib/reticulum/src/identity/cipher.zig:46lib.reticulum.src.node.link.expand[function] — private source atlib/reticulum/src/node/link.zig:153in nearest public ownertiny.reticulum.node.linklib.reticulum.src.node.link.handshake[function] — private source atlib/reticulum/src/node/link.zig:167in nearest public ownertiny.reticulum.node.link
Audit
| Definitions | 5 |
|---|---|
| Public names | 5 |
| Members | 5 |
| Version | 26.7.0 |
| Revision | daab053ee433 |