structstd.crypto.salsa20.XSalsa20Poly1305[src]

The XSalsa stream cipher, combined with the Poly1305 MAC

Values

Constantmac_length[src]

Source Code

Source code
pub const mac_length = 16

Constantnonce_length[src]

Nonce length in bytes.

Source Code

Source code
pub const nonce_length = XSalsa20.nonce_length

Constantkey_length[src]

Key length in bytes.

Source Code

Source code
pub const key_length = XSalsa20.key_length

Functions

Functionencrypt[src]

pub fn encrypt(c: []u8, tag: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) void

c: ciphertext: output buffer should be of size m.len tag: authentication tag: output MAC m: message ad: Associated Data npub: public nonce k: private key

Parameters

c: []u8
tag: *[tag_length]u8
m: []const u8
ad: []const u8
npub: [nonce_length]u8
k: [key_length]u8

Source Code

Source code
pub fn encrypt(c: []u8, tag: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) void {
    debug.assert(c.len == m.len);
    const extended = extend(rounds, k, npub);
    var block0 = [_]u8{0} ** 64;
    const mlen0 = @min(32, m.len);
    @memcpy(block0[32..][0..mlen0], m[0..mlen0]);
    Salsa20.xor(block0[0..], block0[0..], 0, extended.key, extended.nonce);
    @memcpy(c[0..mlen0], block0[32..][0..mlen0]);
    Salsa20.xor(c[mlen0..], m[mlen0..], 1, extended.key, extended.nonce);
    var mac = Poly1305.init(block0[0..32]);
    mac.update(ad);
    mac.update(c);
    mac.final(tag);
}

Functiondecrypt[src]

pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) AuthenticationError!void

m: Message c: Ciphertext tag: Authentication tag ad: Associated data npub: Public nonce k: Private key Asserts c.len == m.len.

Contents of m are undefined if an error is returned.

Parameters

m: []u8
c: []const u8
tag: [tag_length]u8
ad: []const u8
npub: [nonce_length]u8
k: [key_length]u8

Source Code

Source code
pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) AuthenticationError!void {
    debug.assert(c.len == m.len);
    const extended = extend(rounds, k, npub);
    var block0 = [_]u8{0} ** 64;
    const mlen0 = @min(32, c.len);
    @memcpy(block0[32..][0..mlen0], c[0..mlen0]);
    Salsa20.xor(block0[0..], block0[0..], 0, extended.key, extended.nonce);
    var mac = Poly1305.init(block0[0..32]);
    mac.update(ad);
    mac.update(c);
    var computed_tag: [tag_length]u8 = undefined;
    mac.final(&computed_tag);

    const verify = crypto.timing_safe.eql([tag_length]u8, computed_tag, tag);
    if (!verify) {
        crypto.secureZero(u8, &computed_tag);
        @memset(m, undefined);
        return error.AuthenticationFailed;
    }
    @memcpy(m[0..mlen0], block0[32..][0..mlen0]);
    Salsa20.xor(m[mlen0..], c[mlen0..], 1, extended.key, extended.nonce);
}

Source Code

Source code
pub const XSalsa20Poly1305 = struct {
    /// Authentication tag length in bytes.
    pub const tag_length = Poly1305.mac_length;
    /// Nonce length in bytes.
    pub const nonce_length = XSalsa20.nonce_length;
    /// Key length in bytes.
    pub const key_length = XSalsa20.key_length;

    const rounds = 20;

    /// c: ciphertext: output buffer should be of size m.len
    /// tag: authentication tag: output MAC
    /// m: message
    /// ad: Associated Data
    /// npub: public nonce
    /// k: private key
    pub fn encrypt(c: []u8, tag: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) void {
        debug.assert(c.len == m.len);
        const extended = extend(rounds, k, npub);
        var block0 = [_]u8{0} ** 64;
        const mlen0 = @min(32, m.len);
        @memcpy(block0[32..][0..mlen0], m[0..mlen0]);
        Salsa20.xor(block0[0..], block0[0..], 0, extended.key, extended.nonce);
        @memcpy(c[0..mlen0], block0[32..][0..mlen0]);
        Salsa20.xor(c[mlen0..], m[mlen0..], 1, extended.key, extended.nonce);
        var mac = Poly1305.init(block0[0..32]);
        mac.update(ad);
        mac.update(c);
        mac.final(tag);
    }

    /// `m`: Message
    /// `c`: Ciphertext
    /// `tag`: Authentication tag
    /// `ad`: Associated data
    /// `npub`: Public nonce
    /// `k`: Private key
    /// Asserts `c.len == m.len`.
    ///
    /// Contents of `m` are undefined if an error is returned.
    pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) AuthenticationError!void {
        debug.assert(c.len == m.len);
        const extended = extend(rounds, k, npub);
        var block0 = [_]u8{0} ** 64;
        const mlen0 = @min(32, c.len);
        @memcpy(block0[32..][0..mlen0], c[0..mlen0]);
        Salsa20.xor(block0[0..], block0[0..], 0, extended.key, extended.nonce);
        var mac = Poly1305.init(block0[0..32]);
        mac.update(ad);
        mac.update(c);
        var computed_tag: [tag_length]u8 = undefined;
        mac.final(&computed_tag);

        const verify = crypto.timing_safe.eql([tag_length]u8, computed_tag, tag);
        if (!verify) {
            crypto.secureZero(u8, &computed_tag);
            @memset(m, undefined);
            return error.AuthenticationFailed;
        }
        @memcpy(m[0..mlen0], block0[32..][0..mlen0]);
        Salsa20.xor(m[mlen0..], c[mlen0..], 1, extended.key, extended.nonce);
    }
}