Compare commits

...

6 commits

4 changed files with 147 additions and 61 deletions

View file

@ -1,14 +1,14 @@
///////////////// Imports ///////////////// Imports
// //
const AES = @import("crypto/aes.zig"); pub const Aes = @import("crypto/aes.zig");
const ED25519 = @import("crypto/ed25519.zig"); pub const Ed25519 = @import("crypto/ed25519.zig");
const HKDF = @import("crypto/hkdf.zig"); pub const Hkdf = @import("crypto/hkdf.zig");
const HMAC = @import("crypto/hmac.zig"); pub const Hmac = @import("crypto/hmac.zig");
const SHA256 = @import("crypto/sha256.zig"); pub const Sha256 = @import("crypto/sha256.zig");
const SHA512 = @import("crypto/sha512.zig"); pub const Sha512 = @import("crypto/sha512.zig");
const X25519= @import("crypto/x25519.zig"); pub const X25519= @import("crypto/x25519.zig");
const RANDOM = @import("crypto/random.zig"); pub const Random = @import("crypto/random.zig");
///////////////// Errors ///////////////// Errors
@ -25,25 +25,25 @@ pub const CryptoError = error {
// //
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,
sha256: ? SHA256.Implementation = null, sha256: ? Sha256.Implementation = null,
sha512: ? SHA512.Implementation = null, sha512: ? Sha512.Implementation = null,
x25519: ? X25519.Implementation = null, x25519: ? X25519.Implementation = null,
random: ? RANDOM.Implementation = null, random: ? Random.Implementation = null,
}; };
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,
sha256: SHA256.Implementation, sha256: Sha256.Implementation,
sha512: SHA512.Implementation, sha512: Sha512.Implementation,
x25519: X25519.Implementation, x25519: X25519.Implementation,
random: RANDOM.Implementation, random: Random.Implementation,
}; };
@ -56,14 +56,14 @@ pub const Engine = struct {
pub fn resolveEngine(comptime provider: PartialEngine) Engine { pub fn resolveEngine(comptime provider: PartialEngine) Engine {
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, .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 = provider.random orelse RANDOM.defaultImplementation, .random = provider.random orelse Random.defaultImplementation,
}; };
} }

View file

@ -2,40 +2,42 @@
const CryptoError = @import("../crypto.zig").CryptoError; const CryptoError = @import("../crypto.zig").CryptoError;
// Constants and default implementation // Constants and default implementation
const Ed25519 = @import("std").crypto.sign.Ed25519; const Ed25519 = @import("std").crypto.sign.Ed25519;
const secureZero = @import("std").crypto.secureZero;
// Random number generation // Random number generation
const rngProvider = @import("random.zig").Implementation; const rngProvider = @import("random.zig").Implementation;
pub const secret_key_size: comptime_int = Ed25519.SecretKey.encoded_length; // Keypair type
pub const public_key_size: comptime_int = Ed25519.PublicKey.encoded_length; pub const KeyPair = Ed25519.KeyPair;
pub const signature_size : comptime_int = Ed25519.Signature.encoded_length;
pub const secret_key_length: comptime_int = Ed25519.SecretKey.encoded_length;
pub const public_key_length: comptime_int = Ed25519.PublicKey.encoded_length;
pub const signature_length : comptime_int = Ed25519.Signature.encoded_length;
pub const seed_length : comptime_int = Ed25519.Signature.encoded_length;
pub const Implementation = struct { pub const Implementation = struct {
generateKeys: *const fn (pubkey_buffer: *[public_key_size]u8, privkey_buffer: *[secret_key_size]u8, rng: rngProvider) CryptoError!void, generateKeys: *const fn (destination: *KeyPair, rng: rngProvider) CryptoError!void,
sign: *const fn (key: *const [secret_key_size]u8, data: []const u8, signature_out: *const [signature_size]u8) CryptoError!void, sign: *const fn (key: *const [secret_key_length]u8, data: []const u8, signature_out: *const [signature_length]u8) CryptoError!void,
verify: *const fn (key: *const [public_key_size]u8, signature: *const [signature_size]u8, data: []const u8) CryptoError!void, verify: *const fn (key: *const [public_key_length]u8, signature: *const [signature_length]u8, data: []const u8) CryptoError!void,
}; };
pub fn generateKeys(pubkey_buffer: *[public_key_size]u8, privkey_buffer: *[secret_key_size]u8, rng: rngProvider) !void { pub fn generateKeys (destination: *KeyPair, rng: rngProvider) !void {
var seed_buffer: [Ed25519.KeyPair.seed_length]u8 = undefined; var seed_buffer: [KeyPair.seed_length]u8 = undefined;
defer secureZero(u8, &seed_buffer);
rng.generate(&seed_buffer); rng.generate(&seed_buffer);
const keypair: Ed25519.KeyPair = Ed25519.KeyPair.generateDeterministic(seed_buffer) catch return CryptoError.FailedKeyGeneration; destination.* = 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 { pub fn sign (key: *const [secret_key_length]u8, data: []const u8, signature_out: *const [signature_length]u8) !void {
_ = key; _ = key;
_ = data; _ = data;
_ = signature_out; _ = signature_out;
return CryptoError.NotImplemented; return CryptoError.NotImplemented;
} }
pub fn verify(key: *const [public_key_size]u8, signature: *const [signature_size]u8, data: []const u8) !void { pub fn verify (key: *const [public_key_length]u8, signature: *const [signature_length]u8, data: []const u8) !void {
// TODO maybe find a more efficient way to do that (excessive copies) // TODO maybe find a more efficient way to do that (excessive copies)
const sig = Ed25519.Signature.fromBytes(signature.*); const sig = Ed25519.Signature.fromBytes(signature.*);
const pubkey = Ed25519.PublicKey.fromBytes(key.*) catch return CryptoError.InvalidKey; const pubkey = Ed25519.PublicKey.fromBytes(key.*) catch return CryptoError.InvalidKey;

View file

@ -1,13 +1,38 @@
//TODO // Errors
const CryptoError = @import("../crypto.zig").CryptoError;
// Constants and default implementation
const X25519 = @import("std").crypto.dh.X25519;
const Ed25519 = @import("std").crypto.sign.Ed25519;
const secureZero = @import("std").crypto.secureZero;
// Random number generation
const rngProvider = @import("random.zig").Implementation;
const X25519 = @import("std").std.crypto.dh.X25519; // Keypair type
pub const KeyPair = X25519.KeyPair;
pub const secret_key_length: comptime_int = X25519.secret_length;
pub const public_key_length: comptime_int = X25519.public_length;
pub const seed_length: comptime_int = X25519.seed_length;
pub const Implementation = struct { pub const Implementation = struct {
generateKeys: *const fn (destination: *KeyPair, rng: rngProvider) CryptoError!void,
fromEd25519: *const fn (ed25519_keypair: *Ed25519.KeyPair, x25519_keypair: *KeyPair) CryptoError!void,
}; };
fn generateKeys (destination: *KeyPair, rng: rngProvider) !void {
var seed_buffer: [seed_length]u8 = undefined;
defer secureZero(u8, &seed_buffer);
rng.generate(&seed_buffer);
destination.* = X25519.KeyPair.generateDeterministic(seed_buffer) catch return CryptoError.FailedKeyGeneration;
}
fn fromEd25519 (ed25519_keypair: *Ed25519.KeyPair, x25519_keypair: *KeyPair) CryptoError!void {
x25519_keypair.* = X25519.KeyPair.fromEd25519(ed25519_keypair.*) catch return CryptoError.InvalidKey;
}
pub const defaultImplementation: Implementation = .{ pub const defaultImplementation: Implementation = .{
.generateKeys = generateKeys,
// One problem, it uses the zig's io module, which is not supported yet as it depends on the target OS .fromEd25519 = fromEd25519,
// It may need a custom implementation or some other library
}; };

View file

@ -1,7 +1,7 @@
///////////////// Imports ///////////////// Imports
// //
const CryptoEngine = @import("crypto.zig").Engine; const Crypto = @import("crypto.zig");
///////////////// Constants ///////////////// Constants
// //
@ -13,25 +13,38 @@ const CryptoEngine = @import("crypto.zig").Engine;
// //
// TODO // TODO
pub fn Identity(comptime crypto_engine: CryptoEngine) type { pub fn resolveIdentity(comptime crypto_engine: Crypto.Engine) type {
_ = crypto_engine;
return struct { return struct {
const Self = @This();
//////// Fields //////// Fields
// //
publicKey: []const u8, keys: Crypto.Ed25519.KeyPair,
privateKey: []const u8, signatureKeys: Crypto.X25519.KeyPair,
signature: []const u8, hash: [Crypto.Sha256.hash_len]u8,
hash: []const u8,
//////// Functions //////// Functions
// //
pub fn generate() !Identity { pub fn new() !Self {
return .{ const result: Self = undefined;
// .privateKey = crypto_engine.ed25519.generateKey(...), crypto_engine.ed25519.generateKeys(result.keys, crypto_engine.random);
// .signature = crypto_engine.x25519. crypto_engine.x25519.fromEd25519(result.keys, result.signatureKeys, crypto_engine.random);
}; result.update_hash();
return result;
}
pub fn generate(self: *Self) !void {
try crypto_engine.ed25519.generateKeys(&self.keys, crypto_engine.random);
try crypto_engine.x25519.fromEd25519(&self.keys, &self.signatureKeys);
self.update_hash();
}
pub fn update_hash(self: *Self) void {
//WARNING PUBLIC KEY SHOULD BE TRUNCATED
// We should define the truncated hash length somewhere
crypto_engine.sha256.hash(&self.keys.public_key.bytes, &self.hash);
} }
}; };
} }
@ -46,3 +59,49 @@ pub fn Identity(comptime crypto_engine: CryptoEngine) type {
const std = @import("std"); const std = @import("std");
const expect = std.testing.expect; const expect = std.testing.expect;
const memeql = std.mem.eql;
const testPattern: u8 = 0b10101010;
const pubkey_size = Crypto.Ed25519.public_key_length;
const privkey_size = Crypto.Ed25519.secret_key_length;
// Fills out with alternating 0s and 1s
fn fillPattern(out: []u8) void {
for(out) |*byte| {
byte.* = testPattern;
}
}
pub fn generateFakeKeys(destination: *Crypto.Ed25519.KeyPair, rng: Crypto.Random.Implementation) Crypto.CryptoError!void {
_ = rng;
fillPattern(&destination.public_key.bytes);
fillPattern(&destination.secret_key.bytes);
}
test "Basic identity generation" {
const fake_rng: Crypto.Random.Implementation = .{
.generate = fillPattern,
};
const fake_ed25519: Crypto.Ed25519.Implementation = .{
.generateKeys = generateFakeKeys,
.sign = undefined,
.verify = undefined,
};
const crypto_engine = comptime Crypto.resolveEngine(.{
.random = fake_rng,
.ed25519 = fake_ed25519,
});
const Identity = resolveIdentity(crypto_engine);
var new_id: Identity = undefined;
try new_id.generate();
const expected_secret_key = [_]u8{testPattern} ** new_id.keys.secret_key.bytes.len;
// const expected_signature_key = [_]u8{testPattern} ** new_id.signatureKeys.secret_key.len;
try expect(memeql(u8, &new_id.keys.secret_key.bytes, &expected_secret_key));
// try expect(memeql(u8, &new_id.signatureKeys.secret_key, &expected_signature_key));
// try expect(memeql(u8, new_id.hash, testPattern));
}