diff --git a/src/crypto.zig b/src/crypto.zig index 921b0d0..e9813cd 100644 --- a/src/crypto.zig +++ b/src/crypto.zig @@ -11,21 +11,11 @@ const X25519= @import("crypto/x25519.zig"); const RANDOM = @import("crypto/random.zig"); -///////////////// Errors -// - -pub const CryptoError = error { - InvalidSignature, - FailedKeyGeneration, - InvalidKey, - NotImplemented -}; - ///////////////// Structs // pub const PartialEngine = struct { - aes_cbc256: ? AES.CBC256.Implementation = null, + aes_cbc256: ? AES.CBC256_Implementation = null, ed25519: ? ED25519.Implementation = null, hkdf: ? HKDF.Implementation = null, hmac: ? HMAC.Implementation = null, @@ -36,7 +26,7 @@ pub const PartialEngine = struct { }; pub const Engine = struct { - aes_cbc256: AES.CBC256.Implementation, + aes_cbc256: AES.CBC256_Implementation, ed25519: ED25519.Implementation, hkdf: HKDF.Implementation, hmac: HMAC.Implementation, @@ -55,15 +45,18 @@ pub const Engine = struct { // function and its sub-structs. pub fn resolveEngine(comptime provider: PartialEngine) Engine { + // Used by other engine components + const randomImpl = provider.random orelse RANDOM.defaultImplementation; + return .{ - .aes_cbc256 = provider.aes_cbc256 orelse AES.CBC256.defaultImplementation, - .ed25519 = provider.ed25519 orelse ED25519.defaultImplementation, - .hkdf = provider.hkdf orelse HKDF.defaultImplementation, - .hmac = provider.hmac orelse HMAC.defaultImplementation, - .sha256 = provider.sha256 orelse SHA256.defaultImplementation, - .sha512 = provider.sha512 orelse SHA512.defaultImplementation, - .x25519 = provider.x25519 orelse X25519.defaultImplementation, - .random = provider.random orelse RANDOM.defaultImplementation, + .aes_cbc256 = provider.aes_cbc256 orelse AES.CBC256_DefaultImplementation, + .ed25519 = provider.ed25519 orelse ED25519.DefaultImplementation(randomImpl), + .hkdf = provider.hkdf orelse HKDF.DefaultImplementation, + .hmac = provider.hmac orelse HMAC.DefaultImplementation, + .sha256 = provider.sha256 orelse SHA256.DefaultImplementation, + .sha512 = provider.sha512 orelse SHA512.DefaultImplementation, + .x25519 = provider.x25519 orelse X25519.DefaultImplementation, + .random = randomImpl, }; } @@ -76,9 +69,9 @@ const std = @import("std"); test "AES encryption defaults" { const crypto = resolveEngine(.{}); - - var data: []u8 = undefined; - const key: [32]u8 = undefined; - const iv: [16]u8 = undefined; - crypto.aes_cbc256.encrypt(&key, &iv, &data); + + var data = [_]u8{ 1, 2, 3, 4 }; + const key = [_]u8{ 1, 2, 3, 4 }; + const iv = [_]u8{ 1, 2, 3, 4 }; + crypto.aes_cbc256.encrypt(&data, &key, &iv); } diff --git a/src/crypto/aes.zig b/src/crypto/aes.zig index 1498678..aceb2c9 100644 --- a/src/crypto/aes.zig +++ b/src/crypto/aes.zig @@ -1,34 +1,27 @@ -pub const CBC256 = struct { - - pub const block_size = 16; - pub const key_size = 32; +pub const CBC256_Implementation = struct { - pub const Implementation = struct { + pub const BLOCK_SIZE = 16; + pub const KEY_SIZE = 32; - // NOTE: data should be padded to make its length be a multiple of BLOCK_SIZE - encrypt: *const fn (key: *const [key_size]u8, iv: *const [block_size]u8, data: *const []u8) void, - decrypt: *const fn (key: *const [key_size]u8, iv: *const [block_size]u8, data: *const []u8) void, - }; + // NOTE: data should be padded to make its length be a multiple of BLOCK_SIZE + encypt: *const fn (key: *const [KEY_SIZE]u8, iv: *const [BLOCK_SIZE]u8, data: *const []u8) void, + decrypt: *const fn (key: *const [KEY_SIZE]u8, iv: *const [BLOCK_SIZE]u8, data: *const []u8) void, +}; - // TODO +// TODO +pub const CBC256_DefaultImplementation = struct { // Zig stdlib seems to provide no support for AES CBC265 // It may need some custom implementation or another library - fn encrypt(key: *const [key_size]u8, iv: *const [block_size]u8, data: *const []u8) void { + pub fn encrypt(key: *const [32]u8, iv: *const [16]u8, data: *const []u8) !void { _ = key; _ = iv; _ = data; } - fn decrypt(key: *const [key_size]u8, iv: *const [block_size]u8, data: *const []u8) void { + pub fn decrypt(key: *const [32]u8, iv: *const [16]u8, data: *const []u8) !void { _ = key; _ = iv; _ = data; } - - pub const defaultImplementation: Implementation = .{ - .decrypt = decrypt, - .encrypt = encrypt, - }; }; - diff --git a/src/crypto/ed25519.zig b/src/crypto/ed25519.zig index 889f713..ff6d552 100644 --- a/src/crypto/ed25519.zig +++ b/src/crypto/ed25519.zig @@ -1,51 +1,50 @@ -// Errors -const CryptoError = @import("../crypto.zig").CryptoError; -// Constants and default implementation -const Ed25519 = @import("std").crypto.sign.Ed25519; +pub const Implementation = struct { + + secret_key_size: comptime_int, + public_key_size: comptime_int, + signature_size: comptime_int, + + generateKeys: *const fn (pubkey_buffer: *[Implementation.public_key_size]u8, privkey_buffer: *[Implementation.secret_key_size]u8) void, + sign: *const fn (key: *const [Implementation.private_key_size]u8, data: *const []const u8, signature_out: *const [Implementation.signature_size]u8) void, + verify: *const fn (key: *const [Implementation.public_key_size]u8, data: *const []const u8, signature: *const [Implementation.signature_size]u8) void, +}; + // Random number generation const rngProvider = @import("random.zig").Implementation; -pub const secret_key_size: comptime_int = Ed25519.SecretKey.encoded_length; -pub const public_key_size: comptime_int = Ed25519.PublicKey.encoded_length; -pub const signature_size : comptime_int = Ed25519.Signature.encoded_length; +pub fn defaultImplementation(comptime random: rngProvider) type { -pub const Implementation = struct { + return struct { + + const Ed25519 = @import("std").crypto.sign.Ed25519; - generateKeys: *const fn (pubkey_buffer: *[public_key_size]u8, privkey_buffer: *[secret_key_size]u8, rng: rngProvider) CryptoError!void, - sign: *const fn (key: *const [secret_key_size]u8, data: []const u8, signature_out: *const [signature_size]u8) CryptoError!void, - verify: *const fn (key: *const [public_key_size]u8, signature: *const [signature_size]u8, data: []const u8) CryptoError!void, -}; + pub const secret_key_size = Ed25519.SecretKey.encoded_length; + pub const public_key_size = Ed25519.PublicKey.encoded_length; + pub const signature_size = Ed25519.Signature.encoded_length; + pub fn generateKeys(pubkey_buffer: *[Ed25519.SecretKey.encoded_length]u8, privkey_buffer: *[Ed25519.SecretKey.encoded_length]u8) !void { + + const seed_buffer: [Ed25519.KeyPair.seed_length]u8 = undefined; + random.generate(&seed_buffer); + const keypair: Ed25519.KeyPair = try Ed25519.KeyPair.generateDeterministic(seed_buffer); + + + @memcpy(pubkey_buffer[0..public_key_size], keypair.public_key.bytes); + @memcpy(privkey_buffer[0..secret_key_size], keypair.secret_key.bytes); + } + + pub fn sign(key: *const [secret_key_size]u8, data: *const []const u8, signature_out: *const [signature_size]u8) !void { + _ = key; + _ = data; + _ = signature_out; + return error.NotImplemented; + } + + pub fn verify(signature: *const [signature_size]u8, data: *const []const u8) !void { + _ = signature; + _ = data; + return error.NotImplemented; + } + }; -pub fn generateKeys(pubkey_buffer: *[public_key_size]u8, privkey_buffer: *[secret_key_size]u8, rng: rngProvider) !void { - - var seed_buffer: [Ed25519.KeyPair.seed_length]u8 = undefined; - rng.generate(&seed_buffer); - const keypair: Ed25519.KeyPair = Ed25519.KeyPair.generateDeterministic(seed_buffer) catch return CryptoError.FailedKeyGeneration; - - - @memcpy(pubkey_buffer[0..public_key_size], &keypair.public_key.bytes); - @memcpy(privkey_buffer[0..secret_key_size], &keypair.secret_key.bytes); } - -pub fn sign(key: *const [secret_key_size]u8, data: []const u8, signature_out: *const [signature_size]u8) !void { - _ = key; - _ = data; - _ = signature_out; - return CryptoError.NotImplemented; -} - -pub fn verify(key: *const [public_key_size]u8, signature: *const [signature_size]u8, data: []const u8) !void { - // TODO maybe find a more efficient way to do that (excessive copies) - const sig = Ed25519.Signature.fromBytes(signature.*); - const pubkey = Ed25519.PublicKey.fromBytes(key.*) catch return CryptoError.InvalidKey; - - return sig.verify(data, pubkey) catch CryptoError.InvalidSignature; -} - - -pub const defaultImplementation: Implementation = .{ - .generateKeys = generateKeys, - .sign = sign, - .verify = verify, -}; diff --git a/src/crypto/hkdf.zig b/src/crypto/hkdf.zig index d571a08..05a93a8 100644 --- a/src/crypto/hkdf.zig +++ b/src/crypto/hkdf.zig @@ -1,30 +1,29 @@ -const Sha256 = @import("std").crypto.hash.sha2.Sha256; -const Hmac = @import("std").crypto.auth.hmac.Hmac(Sha256); -const Hkdf = @import("std").crypto.kdf.hkdf.Hkdf(Hmac); - -pub const prk_length: comptime_int = Hkdf.prk_length; - - pub const Implementation = struct { - expand: *const fn (out: []u8, ctx: []const u8, prk: *[prk_length]u8) void, - extract: *const fn (out: *[prk_length]u8, salt: []const u8, ikm: []const u8) void, + prk_length: comptime_int, + + expand: *const fn (out: []u8, ctx: []const u8, prk: *[Implementation.prk_length]u8) void, + extract: *const fn (out: *[Implementation.prk_length]u8, salt: []const u8, ikm: []const u8) void, }; +pub const defaultImplementation = struct { + + const Sha256 = @import("std").crypto.hash.sha2.Sha256; -fn expand(out: []u8, ctx: []const u8, prk: *[prk_length]u8) void { - // TODO enhance efficiency (excessive copies) - Hkdf.expand(out, ctx, prk.*); -} + const HashImpl = Sha256; + const HmacImpl = @import("std").crypto.auth.hmac.Hmac(HashImpl); -fn extract(out: *[prk_length]u8, salt: []const u8, ikm: []const u8) void { - // TODO enhance efficiency (excessive copies) - out.* = Hkdf.extract(salt, ikm); -} + const Hkdf = @import("std").crypto.kdf.hkdf.Hkdf(HmacImpl); + pub const prk_length = Hkdf.prk_length; + + pub fn expand(out: []u8, ctx: []const u8, prk: *[prk_length]u8) void { + Hkdf.expand(out, ctx, prk); + } + + pub fn extract(out: *[prk_length]u8, salt: []const u8, ikm: []const u8) void { + out *= Hkdf.extract(salt, ikm); + } -pub const defaultImplementation: Implementation = .{ - .expand = expand, - .extract = extract, }; diff --git a/src/crypto/hmac.zig b/src/crypto/hmac.zig index 96d19b1..131bb20 100644 --- a/src/crypto/hmac.zig +++ b/src/crypto/hmac.zig @@ -1,18 +1,20 @@ -const Sha256 = @import("std").crypto.hash.sha2.Sha256; -const Hmac = @import("std").crypto.auth.hmac.Hmac(Sha256); - -pub const mac_length: comptime_int = Hmac.mac_length; - - pub const Implementation = struct { - create: *const fn (out: *[mac_length]u8, msg: []const u8, key: []const u8) void, + mac_length: comptime_int, + + create: *const fn (out: *[Implementation.mac_length]u8, msg: []const u8, key: []const u8) void, }; -fn create(out: *[mac_length]u8, msg: []const u8, key: []const u8) void { - Hmac.create(out, msg, key); -} +pub const defaultImplementation = struct { + + const Sha256 = @import("std").crypto.hash.sha2.Sha256; -pub const defaultImplementation: Implementation = .{ - .create = create, + const HashImpl = Sha256; + const Hmac = @import("std").crypto.auth.hmac.Hmac(Sha256); + + pub const mac_length = Hmac.mac_length; + + pub fn create(out: *[mac_length]u8, msg: []const u8, key: []const u8) void { + Hmac.create(out, msg, key); + } }; diff --git a/src/crypto/random.zig b/src/crypto/random.zig index 57530bb..b4d99d9 100644 --- a/src/crypto/random.zig +++ b/src/crypto/random.zig @@ -2,14 +2,14 @@ pub const Implementation = struct { generate: *const fn (out: []u8) void, }; -fn generate(out: []u8) void { - // WARNING This is not secure at all, use only for testing purposes - for(out) |*byte| { - byte.* = undefined; +// TODO +pub const defaultImplementation = struct { + + pub fn generate(out: []u8) void { + // WARNING This is not secure at all, use only for testing purposes + for(out) |*byte| { + byte *= undefined; + } } -} - -pub const defaultImplementation: Implementation = .{ - .generate = generate, }; diff --git a/src/crypto/sha256.zig b/src/crypto/sha256.zig index 34937e5..0d913a1 100644 --- a/src/crypto/sha256.zig +++ b/src/crypto/sha256.zig @@ -1,16 +1,17 @@ -const Sha256 = @import("std").crypto.hash.sha2.Sha256; - -pub const hash_len: comptime_int = Sha256.digest_length; - pub const Implementation = struct { - hash: *const fn (buffer: []const u8, out: *[hash_len]u8) void, + hash_length: comptime_int, + + hash: *const fn (buffer: []const u8, out: *[Implementation.hash_length]u8) void, }; -pub fn hash(buffer: []const u8, out: *[hash_len]u8) void { - Sha256.hash(buffer, out, .{}); -} +pub const defaultImplementation = struct { + + const Sha256 = @import("std").crypto.hash.sha2.Sha256; -pub const defaultImplementation: Implementation = .{ - .hash = hash, + pub const hash_len = Sha256.digest_length; + + pub fn hash(buffer: []const u8, out: *[hash_len]u8) !void { + Sha256.hash(buffer, out, .{}); + } }; diff --git a/src/crypto/sha512.zig b/src/crypto/sha512.zig index f42221b..a69a88d 100644 --- a/src/crypto/sha512.zig +++ b/src/crypto/sha512.zig @@ -1,16 +1,18 @@ -const Sha512 = @import("std").crypto.hash.sha2.Sha512; - -pub const hash_len: comptime_int = Sha512.digest_length; - pub const Implementation = struct { - hash: *const fn (buffer: []const u8, out: *[hash_len]u8) void, + hash: *const fn (buffer: []const u8, out: []u8) void, }; -pub fn hash(buffer: []const u8, out: *[hash_len]u8) void { - Sha512.hash(buffer, out, .{}); -} +pub const defaultImplementation = struct { + + const Sha512 = @import("std").crypto.sha2.Sha512; -pub const defaultImplementation: Implementation = .{ - .hash = hash, + const HASH_LEN = 64; // In bytes + + pub fn hash(buffer: []const u8, out: []u8) !void { + if (out.len < HASH_LEN) { + return error.BufferTooShort; + } + Sha512.hash(buffer, out, .{}); + } }; diff --git a/src/crypto/x25519.zig b/src/crypto/x25519.zig index 0d756e8..f3f6607 100644 --- a/src/crypto/x25519.zig +++ b/src/crypto/x25519.zig @@ -1,12 +1,10 @@ -//TODO - -const X25519 = @import("std").std.crypto.dh.X25519; - pub const Implementation = struct { }; -pub const defaultImplementation: Implementation = .{ +pub const defaultImplementation = struct { + + const X25519 = @import("std").std.crypto.dh.X25519; // One problem, it uses the zig's io module, which is not supported yet as it depends on the target OS // It may need a custom implementation or some other library