Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

CbcMac

FIPS 113 (1985): Computer Data Authentication https://csrc.nist.gov/publications/detail/fips/113/archive/1985-05-30

WARNING: CBC-MAC is insecure for variable-length messages without additional protection. Only use when required by protocols like CCM that mitigate this.

cbc_mac.CbcMac
pub fn CbcMac(comptime BlockCipher: type) type

File

lib/std/crypto/cbc_mac.zig:13

Code

pub fn CbcMac(comptime BlockCipher: type) type {
    const BlockCipherCtx = @typeInfo(@TypeOf(BlockCipher.initEnc)).@"fn".return_type.?;
    const Block = [BlockCipher.block.block_length]u8;

    return struct {
        const Self = @This();
        pub const key_length = BlockCipher.key_bits / 8;
        pub const block_length = BlockCipher.block.block_length;
        pub const mac_length = block_length;

        cipher_ctx: BlockCipherCtx,
        buf: Block = @splat(0),
        pos: usize = 0,

        pub fn create(out: *[mac_length]u8, msg: []const u8, key: *const [key_length]u8) void {
            var ctx = Self.init(key);
            ctx.update(msg);
            ctx.final(out);
        }

        pub fn init(key: *const [key_length]u8) Self {
            return Self{
                .cipher_ctx = BlockCipher.initEnc(key.*),
            };
        }

        pub fn update(self: *Self, msg: []const u8) void {
            const left = block_length - self.pos;
            var m = msg;

            // Partial buffer exists from previous update. Complete the block.
            if (m.len > left) {
                for (self.buf[self.pos..], 0..) |*b, i| b.* ^= m[i];
                m = m[left..];
                self.cipher_ctx.encrypt(&self.buf, &self.buf);
                self.pos = 0;
            }

            // Full blocks.
            while (m.len > block_length) {
                for (self.buf[0..block_length], 0..) |*b, i| b.* ^= m[i];
                m = m[block_length..];
                self.cipher_ctx.encrypt(&self.buf, &self.buf);
                self.pos = 0;
            }

            // Copy any remainder for next pass.
            if (m.len > 0) {
                for (self.buf[self.pos..][0..m.len], 0..) |*b, i| b.* ^= m[i];
                self.pos += m.len;
            }
        }

        pub fn final(self: *Self, out: *[mac_length]u8) void {
            // CBC-MAC: encrypt the current buffer state.
            // Partial blocks are implicitly zero-padded: buf[pos..] contains zeros from initialization.
            self.cipher_ctx.encrypt(out, &self.buf);
        }
    };
}