zig/lib/std / crypto.zig

Cryptography.

//! Cryptography.

timing_safe

crypto/timing_safe.zig

Authenticated Encryption with Associated Data


const std = @import("std.zig");

aead

Authentication (MAC) functions.


pub const timing_safe = @import("crypto/timing_safe.zig");

aegis

Core functions, that should rarely be used directly by applications.


/// Authenticated Encryption with Associated Data
pub const aead = struct {

aegis

Modes are generic compositions to construct encryption/decryption functions from block ciphers and permutations. These modes are designed to be building blocks for higher-level constructions, and should generally not be used directly by applications, as they may not provide the expected properties and security guarantees. Most applications may want to use AEADs instead.

    pub const aegis = struct {
        const variants = @import("crypto/aegis.zig");

Aegis128X2

Diffie-Hellman key exchange functions.


        pub const Aegis128X4 = variants.Aegis128X4;
        pub const Aegis128X2 = variants.Aegis128X2;

Aegis128L

Key Encapsulation Mechanisms.

        pub const Aegis128L = variants.Aegis128L;

Aegis256X4

Elliptic-curve arithmetic.


        pub const Aegis256X4 = variants.Aegis256X4;

Aegis256X2

Hash functions.

        pub const Aegis256X2 = variants.Aegis256X2;

Aegis256

Key derivation functions.

        pub const Aegis256 = variants.Aegis256;

Aegis128X4_256

MAC functions requiring single-use secret keys.


        pub const Aegis128X4_256 = variants.Aegis128X4_256;

Aegis128X2_256

A password hashing function derives a uniform key from low-entropy input material such as passwords. It is intentionally slow or expensive. With the standard definition of a key derivation function, if a key space is small, an exhaustive search may be practical. Password hashing functions make exhaustive searches way slower or way more expensive, even when implemented on GPUs and ASICs, by using different, optionally combined strategies: - Requiring a lot of computation cycles to complete - Requiring a lot of memory to complete - Requiring multiple CPU cores to complete - Requiring cache-local data to complete in reasonable time - Requiring large static tables - Avoiding precomputations and time/memory tradeoffs - Requiring multi-party computations - Combining the input material with random per-entry data (salts), application-specific contexts and keys Password hashing functions must be used whenever sensitive data has to be directly derived from a password.

        pub const Aegis128X2_256 = variants.Aegis128X2_256;

Aegis128L_256

Digital signature functions.

        pub const Aegis128L_256 = variants.Aegis128L_256;

Aegis256X4_256

Stream ciphers. These do not provide any kind of authentication. Most applications should be using AEAD constructions instead of stream ciphers directly.


        pub const Aegis256X4_256 = variants.Aegis256X4_256;

Aegis256X2_256

Finite-field arithmetic.

        pub const Aegis256X2_256 = variants.Aegis256X2_256;

Aegis256_256

This is a thread-local, cryptographically secure pseudo random number generator.

        pub const Aegis256_256 = variants.Aegis256_256;
    };

aes_gcm

Encoding and decoding


    pub const aes_gcm = struct {

Aes128Gcm

crypto/aes_gcm.zig

Side-channels mitigations.

        pub const Aes128Gcm = @import("crypto/aes_gcm.zig").Aes128Gcm;

Aes256Gcm

crypto/aes_gcm.zig

No additional side-channel mitigations are applied. This is the fastest mode.

        pub const Aes256Gcm = @import("crypto/aes_gcm.zig").Aes256Gcm;
    };

aes_ocb

The basic mode protects against most practical attacks, provided that the application or implements proper defenses against brute-force attacks. It offers a good balance between performance and security.


    pub const aes_ocb = struct {

Aes128Ocb

crypto/aes_ocb.zig

The medium mode offers increased resilience against side-channel attacks, making most attacks unpractical even on shared/low latency environements. This is the default mode.

        pub const Aes128Ocb = @import("crypto/aes_ocb.zig").Aes128Ocb;

Aes256Ocb

crypto/aes_ocb.zig

The full mode offers the highest level of protection against side-channel attacks. Note that this doesn't cover all possible attacks (especially power analysis or thread-local attacks such as cachebleed), and that the performance impact is significant.

        pub const Aes256Ocb = @import("crypto/aes_ocb.zig").Aes256Ocb;
    };

chacha_poly

Sets a slice to zeroes. Prevents the store from being optimized out.


    pub const chacha_poly = struct {

ChaCha20Poly1305

crypto/chacha20.zig
        pub const ChaCha20Poly1305 = @import("crypto/chacha20.zig").ChaCha20Poly1305;

ChaCha12Poly1305

crypto/chacha20.zig
        pub const ChaCha12Poly1305 = @import("crypto/chacha20.zig").ChaCha12Poly1305;

ChaCha8Poly1305

crypto/chacha20.zig
        pub const ChaCha8Poly1305 = @import("crypto/chacha20.zig").ChaCha8Poly1305;

XChaCha20Poly1305

crypto/chacha20.zig
        pub const XChaCha20Poly1305 = @import("crypto/chacha20.zig").XChaCha20Poly1305;

XChaCha12Poly1305

crypto/chacha20.zig
        pub const XChaCha12Poly1305 = @import("crypto/chacha20.zig").XChaCha12Poly1305;

XChaCha8Poly1305

crypto/chacha20.zig
        pub const XChaCha8Poly1305 = @import("crypto/chacha20.zig").XChaCha8Poly1305;
    };

isap

crypto/isap.zig

    pub const isap = @import("crypto/isap.zig");

salsa_poly


    pub const salsa_poly = struct {

XSalsa20Poly1305

crypto/salsa20.zig
        pub const XSalsa20Poly1305 = @import("crypto/salsa20.zig").XSalsa20Poly1305;
    };

Error

};

hmac

crypto/hmac.zig

/// Authentication (MAC) functions.
pub const auth = struct {
    pub const hmac = @import("crypto/hmac.zig");

siphash

crypto/siphash.zig
    pub const siphash = @import("crypto/siphash.zig");

aegis

    pub const aegis = struct {
        const variants = @import("crypto/aegis.zig");

Aegis128X4Mac

        pub const Aegis128X4Mac = variants.Aegis128X4Mac;

Aegis128X2Mac

        pub const Aegis128X2Mac = variants.Aegis128X2Mac;

Aegis128LMac

        pub const Aegis128LMac = variants.Aegis128LMac;

Aegis256X4Mac


        pub const Aegis256X4Mac = variants.Aegis256X4Mac;

Aegis256X2Mac

        pub const Aegis256X2Mac = variants.Aegis256X2Mac;

Aegis256Mac

        pub const Aegis256Mac = variants.Aegis256Mac;

Aegis128X4Mac_128


        pub const Aegis128X4Mac_128 = variants.Aegis128X4Mac_128;

Aegis128X2Mac_128

        pub const Aegis128X2Mac_128 = variants.Aegis128X2Mac_128;

Aegis128LMac_128

        pub const Aegis128LMac_128 = variants.Aegis128LMac_128;

Aegis256X4Mac_128


        pub const Aegis256X4Mac_128 = variants.Aegis256X4Mac_128;

Aegis256X2Mac_128

        pub const Aegis256X2Mac_128 = variants.Aegis256X2Mac_128;

Aegis256Mac_128

        pub const Aegis256Mac_128 = variants.Aegis256Mac_128;
    };

cmac

crypto/cmac.zig
    pub const cmac = @import("crypto/cmac.zig");

Error

};

aes

crypto/aes.zig

/// Core functions, that should rarely be used directly by applications.
pub const core = struct {
    pub const aes = @import("crypto/aes.zig");

keccak

crypto/keccak_p.zig
    pub const keccak = @import("crypto/keccak_p.zig");

Ascon

crypto/ascon.zig

    pub const Ascon = @import("crypto/ascon.zig").State;

modes

crypto/modes.zig

    /// Modes are generic compositions to construct encryption/decryption functions from block ciphers and permutations.
    ///
    /// These modes are designed to be building blocks for higher-level constructions, and should generally not be used directly by applications, as they may not provide the expected properties and security guarantees.
    ///
    /// Most applications may want to use AEADs instead.
    pub const modes = @import("crypto/modes.zig");

Error

};

X25519

crypto/25519/x25519.zig

/// Diffie-Hellman key exchange functions.
pub const dh = struct {
    pub const X25519 = @import("crypto/25519/x25519.zig").X25519;

Error

};

kyber_d00

crypto/ml_kem.zig

/// Key Encapsulation Mechanisms.
pub const kem = struct {
    pub const kyber_d00 = @import("crypto/ml_kem.zig").d00;

ml_kem

crypto/ml_kem.zig
    pub const ml_kem = @import("crypto/ml_kem.zig").nist;

Error

};

Curve25519

crypto/25519/curve25519.zig

/// Elliptic-curve arithmetic.
pub const ecc = struct {
    pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519;

Edwards25519

crypto/25519/edwards25519.zig
    pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519;

P256

crypto/pcurves/p256.zig
    pub const P256 = @import("crypto/pcurves/p256.zig").P256;

P384

crypto/pcurves/p384.zig
    pub const P384 = @import("crypto/pcurves/p384.zig").P384;

Ristretto255

crypto/25519/ristretto255.zig
    pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255;

Secp256k1

crypto/pcurves/secp256k1.zig
    pub const Secp256k1 = @import("crypto/pcurves/secp256k1.zig").Secp256k1;

Error

};

blake2

crypto/blake2.zig

/// Hash functions.
pub const hash = struct {
    pub const blake2 = @import("crypto/blake2.zig");

Blake3

crypto/blake3.zig
    pub const Blake3 = @import("crypto/blake3.zig").Blake3;

Md5

crypto/md5.zig
    pub const Md5 = @import("crypto/md5.zig").Md5;

Sha1

crypto/Sha1.zig
    pub const Sha1 = @import("crypto/Sha1.zig");

sha2

crypto/sha2.zig
    pub const sha2 = @import("crypto/sha2.zig");

sha3

crypto/sha3.zig
    pub const sha3 = @import("crypto/sha3.zig");

composition

crypto/hash_composition.zig
    pub const composition = @import("crypto/hash_composition.zig");

Error

};

hkdf

crypto/hkdf.zig

/// Key derivation functions.
pub const kdf = struct {
    pub const hkdf = @import("crypto/hkdf.zig");

Error

};

Ghash

crypto/ghash_polyval.zig

/// MAC functions requiring single-use secret keys.
pub const onetimeauth = struct {
    pub const Ghash = @import("crypto/ghash_polyval.zig").Ghash;

Polyval

crypto/ghash_polyval.zig
    pub const Polyval = @import("crypto/ghash_polyval.zig").Polyval;

Poly1305

crypto/poly1305.zig
    pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305;

Error

};

Encoding


/// A password hashing function derives a uniform key from low-entropy input material such as passwords.
/// It is intentionally slow or expensive.
///
/// With the standard definition of a key derivation function, if a key space is small, an exhaustive search may be practical.
/// Password hashing functions make exhaustive searches way slower or way more expensive, even when implemented on GPUs and ASICs, by using different, optionally combined strategies:
///
/// - Requiring a lot of computation cycles to complete
/// - Requiring a lot of memory to complete
/// - Requiring multiple CPU cores to complete
/// - Requiring cache-local data to complete in reasonable time
/// - Requiring large static tables
/// - Avoiding precomputations and time/memory tradeoffs
/// - Requiring multi-party computations
/// - Combining the input material with random per-entry data (salts), application-specific contexts and keys
///
/// Password hashing functions must be used whenever sensitive data has to be directly derived from a password.
pub const pwhash = struct {
    pub const Encoding = enum {
        phc,
        crypt,
    };

Error


    pub const Error = HasherError || error{AllocatorRequired};

HasherError

    pub const HasherError = KdfError || phc_format.Error;

KdfError

    pub const KdfError = errors.Error || std.mem.Allocator.Error || std.Thread.SpawnError;

argon2

crypto/argon2.zig

    pub const argon2 = @import("crypto/argon2.zig");

bcrypt

crypto/bcrypt.zig
    pub const bcrypt = @import("crypto/bcrypt.zig");

scrypt

crypto/scrypt.zig
    pub const scrypt = @import("crypto/scrypt.zig");

pbkdf2

crypto/pbkdf2.zig
    pub const pbkdf2 = @import("crypto/pbkdf2.zig").pbkdf2;

phc_format

crypto/phc_encoding.zig

    pub const phc_format = @import("crypto/phc_encoding.zig");
};

sign


/// Digital signature functions.
pub const sign = struct {

Ed25519

crypto/25519/ed25519.zig
    pub const Ed25519 = @import("crypto/25519/ed25519.zig").Ed25519;

ecdsa

crypto/ecdsa.zig
    pub const ecdsa = @import("crypto/ecdsa.zig");
};

stream


/// Stream ciphers. These do not provide any kind of authentication.
/// Most applications should be using AEAD constructions instead of stream ciphers directly.
pub const stream = struct {

chacha

    pub const chacha = struct {

ChaCha20IETF

crypto/chacha20.zig
        pub const ChaCha20IETF = @import("crypto/chacha20.zig").ChaCha20IETF;

ChaCha12IETF

crypto/chacha20.zig
        pub const ChaCha12IETF = @import("crypto/chacha20.zig").ChaCha12IETF;

ChaCha8IETF

crypto/chacha20.zig
        pub const ChaCha8IETF = @import("crypto/chacha20.zig").ChaCha8IETF;

ChaCha20With64BitNonce

crypto/chacha20.zig
        pub const ChaCha20With64BitNonce = @import("crypto/chacha20.zig").ChaCha20With64BitNonce;

ChaCha12With64BitNonce

crypto/chacha20.zig
        pub const ChaCha12With64BitNonce = @import("crypto/chacha20.zig").ChaCha12With64BitNonce;

ChaCha8With64BitNonce

crypto/chacha20.zig
        pub const ChaCha8With64BitNonce = @import("crypto/chacha20.zig").ChaCha8With64BitNonce;

XChaCha20IETF

crypto/chacha20.zig
        pub const XChaCha20IETF = @import("crypto/chacha20.zig").XChaCha20IETF;

XChaCha12IETF

crypto/chacha20.zig
        pub const XChaCha12IETF = @import("crypto/chacha20.zig").XChaCha12IETF;

XChaCha8IETF

crypto/chacha20.zig
        pub const XChaCha8IETF = @import("crypto/chacha20.zig").XChaCha8IETF;
    };

salsa


    pub const salsa = struct {

Salsa

crypto/salsa20.zig
        pub const Salsa = @import("crypto/salsa20.zig").Salsa;

XSalsa

crypto/salsa20.zig
        pub const XSalsa = @import("crypto/salsa20.zig").XSalsa;

Salsa20

crypto/salsa20.zig
        pub const Salsa20 = @import("crypto/salsa20.zig").Salsa20;

XSalsa20

crypto/salsa20.zig
        pub const XSalsa20 = @import("crypto/salsa20.zig").XSalsa20;
    };
};

nacl


pub const nacl = struct {
    const salsa20 = @import("crypto/salsa20.zig");

Box


    pub const Box = salsa20.Box;

SecretBox

    pub const SecretBox = salsa20.SecretBox;

SealedBox

    pub const SealedBox = salsa20.SealedBox;
};

ff

crypto/ff.zig

/// Finite-field arithmetic.
pub const ff = @import("crypto/ff.zig");

random

crypto/tlcsprng.zig

/// This is a thread-local, cryptographically secure pseudo random number generator.
pub const random = @import("crypto/tlcsprng.zig").interface;

codecs

crypto/codecs.zig

/// Encoding and decoding
pub const codecs = @import("crypto/codecs.zig");

errors

crypto/errors.zig

pub const errors = @import("crypto/errors.zig");

tls

crypto/tls.zig

pub const tls = @import("crypto/tls.zig");

Certificate

crypto/Certificate.zig
pub const Certificate = @import("crypto/Certificate.zig");

SideChannelsMitigations


/// Side-channels mitigations.
pub const SideChannelsMitigations = enum {
    /// No additional side-channel mitigations are applied.
    /// This is the fastest mode.
    none,
    /// The `basic` mode protects against most practical attacks, provided that the
    /// application or implements proper defenses against brute-force attacks.
    /// It offers a good balance between performance and security.
    basic,
    /// The `medium` mode offers increased resilience against side-channel attacks,
    /// making most attacks unpractical even on shared/low latency environements.
    /// This is the default mode.
    medium,
    /// The `full` mode offers the highest level of protection against side-channel attacks.
    /// Note that this doesn't cover all possible attacks (especially power analysis or
    /// thread-local attacks such as cachebleed), and that the performance impact is significant.
    full,
};

default_side_channels_mitigations


pub const default_side_channels_mitigations = .medium;

Test:

CSPRNG


test {
    _ = aead.aegis.Aegis128L;
    _ = aead.aegis.Aegis256;

Test:

issue #4532: no index out of bounds


    _ = aead.aes_gcm.Aes128Gcm;
    _ = aead.aes_gcm.Aes256Gcm;

secureZero()


    _ = aead.aes_ocb.Aes128Ocb;
    _ = aead.aes_ocb.Aes256Ocb;

Test: secureZero


    _ = aead.chacha_poly.ChaCha20Poly1305;
    _ = aead.chacha_poly.ChaCha12Poly1305;
    _ = aead.chacha_poly.ChaCha8Poly1305;
    _ = aead.chacha_poly.XChaCha20Poly1305;
    _ = aead.chacha_poly.XChaCha12Poly1305;
    _ = aead.chacha_poly.XChaCha8Poly1305;

    _ = aead.isap;
    _ = aead.salsa_poly.XSalsa20Poly1305;

    _ = auth.hmac;
    _ = auth.cmac;
    _ = auth.siphash;

    _ = core.aes;
    _ = core.Ascon;
    _ = core.modes;

    _ = dh.X25519;

    _ = kem.kyber_d00;

    _ = ecc.Curve25519;
    _ = ecc.Edwards25519;
    _ = ecc.P256;
    _ = ecc.P384;
    _ = ecc.Ristretto255;
    _ = ecc.Secp256k1;

    _ = hash.blake2;
    _ = hash.Blake3;
    _ = hash.Md5;
    _ = hash.Sha1;
    _ = hash.sha2;
    _ = hash.sha3;
    _ = hash.composition;

    _ = kdf.hkdf;

    _ = onetimeauth.Ghash;
    _ = onetimeauth.Poly1305;

    _ = pwhash.Encoding;

    _ = pwhash.Error;
    _ = pwhash.HasherError;
    _ = pwhash.KdfError;

    _ = pwhash.argon2;
    _ = pwhash.bcrypt;
    _ = pwhash.scrypt;
    _ = pwhash.pbkdf2;

    _ = pwhash.phc_format;

    _ = sign.Ed25519;
    _ = sign.ecdsa;

    _ = stream.chacha.ChaCha20IETF;
    _ = stream.chacha.ChaCha12IETF;
    _ = stream.chacha.ChaCha8IETF;
    _ = stream.chacha.ChaCha20With64BitNonce;
    _ = stream.chacha.ChaCha12With64BitNonce;
    _ = stream.chacha.ChaCha8With64BitNonce;
    _ = stream.chacha.XChaCha20IETF;
    _ = stream.chacha.XChaCha12IETF;
    _ = stream.chacha.XChaCha8IETF;

    _ = stream.salsa.Salsa20;
    _ = stream.salsa.XSalsa20;

    _ = nacl.Box;
    _ = nacl.SecretBox;
    _ = nacl.SealedBox;

    _ = secureZero;
    _ = timing_safe;
    _ = ff;
    _ = random;
    _ = errors;
    _ = tls;
    _ = Certificate;
    _ = codecs;
}

test "CSPRNG" {
    const a = random.int(u64);
    const b = random.int(u64);
    const c = random.int(u64);
    try std.testing.expect(a ^ b ^ c != 0);
}

test "issue #4532: no index out of bounds" {
    const types = [_]type{
        hash.Md5,
        hash.Sha1,
        hash.sha2.Sha224,
        hash.sha2.Sha256,
        hash.sha2.Sha384,
        hash.sha2.Sha512,
        hash.sha3.Sha3_224,
        hash.sha3.Sha3_256,
        hash.sha3.Sha3_384,
        hash.sha3.Sha3_512,
        hash.blake2.Blake2s128,
        hash.blake2.Blake2s224,
        hash.blake2.Blake2s256,
        hash.blake2.Blake2b128,
        hash.blake2.Blake2b256,
        hash.blake2.Blake2b384,
        hash.blake2.Blake2b512,
    };

    inline for (types) |Hasher| {
        var block = [_]u8{'#'} ** Hasher.block_length;
        var out1: [Hasher.digest_length]u8 = undefined;
        var out2: [Hasher.digest_length]u8 = undefined;
        const h0 = Hasher.init(.{});
        var h = h0;
        h.update(block[0..]);
        h.final(&out1);
        h = h0;
        h.update(block[0..1]);
        h.update(block[1..]);
        h.final(&out2);

        try std.testing.expectEqual(out1, out2);
    }
}

/// Sets a slice to zeroes.
/// Prevents the store from being optimized out.
pub fn secureZero(comptime T: type, s: []volatile T) void {
    @memset(s, 0);
}

test secureZero {
    var a = [_]u8{0xfe} ** 8;
    var b = [_]u8{0xfe} ** 8;

    @memset(&a, 0);
    secureZero(u8, &b);

    try std.testing.expectEqualSlices(u8, &a, &b);
}