Compare commits
4 commits
7d86c901e3
...
e594fab52f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e594fab52f | ||
|
|
fc71c1a65b | ||
|
|
891727d959 | ||
|
|
c292832280 |
9 changed files with 151 additions and 138 deletions
|
|
@ -11,11 +11,21 @@ const X25519= @import("crypto/x25519.zig");
|
||||||
const RANDOM = @import("crypto/random.zig");
|
const RANDOM = @import("crypto/random.zig");
|
||||||
|
|
||||||
|
|
||||||
|
///////////////// Errors
|
||||||
|
//
|
||||||
|
|
||||||
|
pub const CryptoError = error {
|
||||||
|
InvalidSignature,
|
||||||
|
FailedKeyGeneration,
|
||||||
|
InvalidKey,
|
||||||
|
NotImplemented
|
||||||
|
};
|
||||||
|
|
||||||
///////////////// Structs
|
///////////////// Structs
|
||||||
//
|
//
|
||||||
|
|
||||||
pub const PartialEngine = struct {
|
pub const PartialEngine = struct {
|
||||||
aes_cbc256: ? AES.CBC256_Implementation = null,
|
aes_cbc256: ? AES.CBC256.Implementation = null,
|
||||||
ed25519: ? ED25519.Implementation = null,
|
ed25519: ? ED25519.Implementation = null,
|
||||||
hkdf: ? HKDF.Implementation = null,
|
hkdf: ? HKDF.Implementation = null,
|
||||||
hmac: ? HMAC.Implementation = null,
|
hmac: ? HMAC.Implementation = null,
|
||||||
|
|
@ -26,7 +36,7 @@ pub const PartialEngine = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Engine = struct {
|
pub const Engine = struct {
|
||||||
aes_cbc256: AES.CBC256_Implementation,
|
aes_cbc256: AES.CBC256.Implementation,
|
||||||
ed25519: ED25519.Implementation,
|
ed25519: ED25519.Implementation,
|
||||||
hkdf: HKDF.Implementation,
|
hkdf: HKDF.Implementation,
|
||||||
hmac: HMAC.Implementation,
|
hmac: HMAC.Implementation,
|
||||||
|
|
@ -45,18 +55,15 @@ pub const Engine = struct {
|
||||||
// function and its sub-structs.
|
// function and its sub-structs.
|
||||||
pub fn resolveEngine(comptime provider: PartialEngine) Engine {
|
pub fn resolveEngine(comptime provider: PartialEngine) Engine {
|
||||||
|
|
||||||
// Used by other engine components
|
|
||||||
const randomImpl = provider.random orelse RANDOM.defaultImplementation;
|
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.aes_cbc256 = provider.aes_cbc256 orelse AES.CBC256_DefaultImplementation,
|
.aes_cbc256 = provider.aes_cbc256 orelse AES.CBC256.defaultImplementation,
|
||||||
.ed25519 = provider.ed25519 orelse ED25519.DefaultImplementation(randomImpl),
|
.ed25519 = provider.ed25519 orelse ED25519.defaultImplementation,
|
||||||
.hkdf = provider.hkdf orelse HKDF.DefaultImplementation,
|
.hkdf = provider.hkdf orelse HKDF.defaultImplementation,
|
||||||
.hmac = provider.hmac orelse HMAC.DefaultImplementation,
|
.hmac = provider.hmac orelse HMAC.defaultImplementation,
|
||||||
.sha256 = provider.sha256 orelse SHA256.DefaultImplementation,
|
.sha256 = provider.sha256 orelse SHA256.defaultImplementation,
|
||||||
.sha512 = provider.sha512 orelse SHA512.DefaultImplementation,
|
.sha512 = provider.sha512 orelse SHA512.defaultImplementation,
|
||||||
.x25519 = provider.x25519 orelse X25519.DefaultImplementation,
|
.x25519 = provider.x25519 orelse X25519.defaultImplementation,
|
||||||
.random = randomImpl,
|
.random = provider.random orelse RANDOM.defaultImplementation,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,8 +77,8 @@ test "AES encryption defaults" {
|
||||||
|
|
||||||
const crypto = resolveEngine(.{});
|
const crypto = resolveEngine(.{});
|
||||||
|
|
||||||
var data = [_]u8{ 1, 2, 3, 4 };
|
var data: []u8 = undefined;
|
||||||
const key = [_]u8{ 1, 2, 3, 4 };
|
const key: [32]u8 = undefined;
|
||||||
const iv = [_]u8{ 1, 2, 3, 4 };
|
const iv: [16]u8 = undefined;
|
||||||
crypto.aes_cbc256.encrypt(&data, &key, &iv);
|
crypto.aes_cbc256.encrypt(&key, &iv, &data);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,34 @@
|
||||||
pub const CBC256_Implementation = struct {
|
pub const CBC256 = struct {
|
||||||
|
|
||||||
pub const BLOCK_SIZE = 16;
|
pub const block_size = 16;
|
||||||
pub const KEY_SIZE = 32;
|
pub const key_size = 32;
|
||||||
|
|
||||||
|
pub const Implementation = struct {
|
||||||
|
|
||||||
// NOTE: data should be padded to make its length be a multiple of BLOCK_SIZE
|
// 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,
|
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,
|
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
|
// Zig stdlib seems to provide no support for AES CBC265
|
||||||
// It may need some custom implementation or another library
|
// It may need some custom implementation or another library
|
||||||
|
|
||||||
pub fn encrypt(key: *const [32]u8, iv: *const [16]u8, data: *const []u8) !void {
|
fn encrypt(key: *const [key_size]u8, iv: *const [block_size]u8, data: *const []u8) void {
|
||||||
_ = key;
|
_ = key;
|
||||||
_ = iv;
|
_ = iv;
|
||||||
_ = data;
|
_ = data;
|
||||||
}
|
}
|
||||||
pub fn decrypt(key: *const [32]u8, iv: *const [16]u8, data: *const []u8) !void {
|
fn decrypt(key: *const [key_size]u8, iv: *const [block_size]u8, data: *const []u8) void {
|
||||||
_ = key;
|
_ = key;
|
||||||
_ = iv;
|
_ = iv;
|
||||||
_ = data;
|
_ = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const defaultImplementation: Implementation = .{
|
||||||
|
.decrypt = decrypt,
|
||||||
|
.encrypt = encrypt,
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,50 +1,51 @@
|
||||||
pub const Implementation = struct {
|
// Errors
|
||||||
|
const CryptoError = @import("../crypto.zig").CryptoError;
|
||||||
secret_key_size: comptime_int,
|
// Constants and default implementation
|
||||||
public_key_size: comptime_int,
|
const Ed25519 = @import("std").crypto.sign.Ed25519;
|
||||||
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
|
// Random number generation
|
||||||
const rngProvider = @import("random.zig").Implementation;
|
const rngProvider = @import("random.zig").Implementation;
|
||||||
|
|
||||||
pub fn defaultImplementation(comptime random: rngProvider) type {
|
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;
|
||||||
|
|
||||||
return struct {
|
pub const Implementation = 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,
|
||||||
pub const secret_key_size = Ed25519.SecretKey.encoded_length;
|
verify: *const fn (key: *const [public_key_size]u8, signature: *const [signature_size]u8, data: []const u8) CryptoError!void,
|
||||||
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);
|
pub fn generateKeys(pubkey_buffer: *[public_key_size]u8, privkey_buffer: *[secret_key_size]u8, rng: rngProvider) !void {
|
||||||
@memcpy(privkey_buffer[0..secret_key_size], keypair.secret_key.bytes);
|
|
||||||
|
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 []const u8, signature_out: *const [signature_size]u8) !void {
|
pub fn sign(key: *const [secret_key_size]u8, data: []const u8, signature_out: *const [signature_size]u8) !void {
|
||||||
_ = key;
|
_ = key;
|
||||||
_ = data;
|
_ = data;
|
||||||
_ = signature_out;
|
_ = signature_out;
|
||||||
return error.NotImplemented;
|
return CryptoError.NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify(signature: *const [signature_size]u8, data: *const []const u8) !void {
|
pub fn verify(key: *const [public_key_size]u8, signature: *const [signature_size]u8, data: []const u8) !void {
|
||||||
_ = signature;
|
// TODO maybe find a more efficient way to do that (excessive copies)
|
||||||
_ = data;
|
const sig = Ed25519.Signature.fromBytes(signature.*);
|
||||||
return error.NotImplemented;
|
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,
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,30 @@
|
||||||
|
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 {
|
pub const Implementation = struct {
|
||||||
|
|
||||||
prk_length: comptime_int,
|
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,
|
||||||
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)
|
||||||
const HashImpl = Sha256;
|
Hkdf.expand(out, ctx, prk.*);
|
||||||
const HmacImpl = @import("std").crypto.auth.hmac.Hmac(HashImpl);
|
|
||||||
|
|
||||||
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 {
|
fn extract(out: *[prk_length]u8, salt: []const u8, ikm: []const u8) void {
|
||||||
out *= Hkdf.extract(salt, ikm);
|
// TODO enhance efficiency (excessive copies)
|
||||||
|
out.* = Hkdf.extract(salt, ikm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub const defaultImplementation: Implementation = .{
|
||||||
|
.expand = expand,
|
||||||
|
.extract = extract,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,18 @@
|
||||||
pub const Implementation = struct {
|
|
||||||
|
|
||||||
mac_length: comptime_int,
|
|
||||||
|
|
||||||
create: *const fn (out: *[Implementation.mac_length]u8, msg: []const u8, key: []const u8) void,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const defaultImplementation = struct {
|
|
||||||
|
|
||||||
const Sha256 = @import("std").crypto.hash.sha2.Sha256;
|
const Sha256 = @import("std").crypto.hash.sha2.Sha256;
|
||||||
|
|
||||||
const HashImpl = Sha256;
|
|
||||||
const Hmac = @import("std").crypto.auth.hmac.Hmac(Sha256);
|
const Hmac = @import("std").crypto.auth.hmac.Hmac(Sha256);
|
||||||
|
|
||||||
pub const mac_length = Hmac.mac_length;
|
pub const mac_length: comptime_int = Hmac.mac_length;
|
||||||
|
|
||||||
pub fn create(out: *[mac_length]u8, msg: []const u8, key: []const u8) void {
|
|
||||||
|
pub const Implementation = struct {
|
||||||
|
|
||||||
|
create: *const fn (out: *[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);
|
Hmac.create(out, msg, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const defaultImplementation: Implementation = .{
|
||||||
|
.create = create,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,14 @@ pub const Implementation = struct {
|
||||||
generate: *const fn (out: []u8) void,
|
generate: *const fn (out: []u8) void,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO
|
fn generate(out: []u8) void {
|
||||||
pub const defaultImplementation = struct {
|
|
||||||
|
|
||||||
pub fn generate(out: []u8) void {
|
|
||||||
// WARNING This is not secure at all, use only for testing purposes
|
// WARNING This is not secure at all, use only for testing purposes
|
||||||
for(out) |*byte| {
|
for(out) |*byte| {
|
||||||
byte *= undefined;
|
byte.* = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const defaultImplementation: Implementation = .{
|
||||||
|
.generate = generate,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,16 @@
|
||||||
pub const Implementation = struct {
|
|
||||||
|
|
||||||
hash_length: comptime_int,
|
|
||||||
|
|
||||||
hash: *const fn (buffer: []const u8, out: *[Implementation.hash_length]u8) void,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const defaultImplementation = struct {
|
|
||||||
|
|
||||||
const Sha256 = @import("std").crypto.hash.sha2.Sha256;
|
const Sha256 = @import("std").crypto.hash.sha2.Sha256;
|
||||||
|
|
||||||
pub const hash_len = Sha256.digest_length;
|
pub const hash_len: comptime_int = Sha256.digest_length;
|
||||||
|
|
||||||
pub fn hash(buffer: []const u8, out: *[hash_len]u8) !void {
|
pub const Implementation = struct {
|
||||||
|
|
||||||
|
hash: *const fn (buffer: []const u8, out: *[hash_len]u8) void,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn hash(buffer: []const u8, out: *[hash_len]u8) void {
|
||||||
Sha256.hash(buffer, out, .{});
|
Sha256.hash(buffer, out, .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const defaultImplementation: Implementation = .{
|
||||||
|
.hash = hash,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,16 @@
|
||||||
|
const Sha512 = @import("std").crypto.hash.sha2.Sha512;
|
||||||
|
|
||||||
|
pub const hash_len: comptime_int = Sha512.digest_length;
|
||||||
|
|
||||||
pub const Implementation = struct {
|
pub const Implementation = struct {
|
||||||
|
|
||||||
hash: *const fn (buffer: []const u8, out: []u8) void,
|
hash: *const fn (buffer: []const u8, out: *[hash_len]u8) void,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const defaultImplementation = struct {
|
pub fn hash(buffer: []const u8, out: *[hash_len]u8) void {
|
||||||
|
|
||||||
const Sha512 = @import("std").crypto.sha2.Sha512;
|
|
||||||
|
|
||||||
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, .{});
|
Sha512.hash(buffer, out, .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const defaultImplementation: Implementation = .{
|
||||||
|
.hash = hash,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
|
//TODO
|
||||||
|
|
||||||
|
const X25519 = @import("std").std.crypto.dh.X25519;
|
||||||
|
|
||||||
pub const Implementation = struct {
|
pub const Implementation = struct {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const defaultImplementation = struct {
|
pub const defaultImplementation: Implementation = .{
|
||||||
|
|
||||||
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
|
// 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
|
// It may need a custom implementation or some other library
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue