working dh aes flow
This commit is contained in:
157
src/main.zig
157
src/main.zig
@@ -10,12 +10,12 @@ const Encryptor = struct {
|
||||
kp: DH.KeyPair,
|
||||
|
||||
pub fn init() !Self {
|
||||
const self = Self{};
|
||||
var self: Self = undefined;
|
||||
|
||||
var seed: [DH.seed_length]u8 = undefined;
|
||||
std.crypto.random.bytes(&seed);
|
||||
self.kp = try DH.KeyPair.create(seed);
|
||||
@memset(seed, 0);
|
||||
@memset(&seed, 0);
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -27,11 +27,12 @@ const Peer = struct {
|
||||
public_key: [DH.public_length]u8,
|
||||
shared_key: [AES.key_length]u8,
|
||||
|
||||
pub fn init(me: DH.KeyPair, peer_key: [DH.public_length]u8) Self {
|
||||
const self = Self{ .public_key = peer_key };
|
||||
pub fn init(me: DH.KeyPair, peer_key: [DH.public_length]u8) !Self {
|
||||
var self: Self = undefined;
|
||||
self.public_key = peer_key;
|
||||
|
||||
const secret = try DH.scalarmult(me.secret_key, peer_key);
|
||||
SHA.hash(&secret, self.shared_key, .{});
|
||||
SHA.hash(&secret, &self.shared_key, .{});
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -46,8 +47,10 @@ const Peer = struct {
|
||||
}
|
||||
|
||||
/// Caller must free result
|
||||
pub fn decrypt(self: Self, ally: std.mem.Allocator, msg: []const u8) ![]const u8 {
|
||||
|
||||
pub fn decrypt(self: Self, ally: std.mem.Allocator, pkt: Packet) ![]const u8 {
|
||||
const msg: []u8 = try ally.alloc(u8, pkt.cipher_text.len);
|
||||
try AES.decrypt(msg, pkt.cipher_text, pkt.tag, "", pkt.nonce, self.shared_key);
|
||||
return msg;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -55,57 +58,108 @@ const Packet = struct {
|
||||
ally: std.mem.Allocator,
|
||||
nonce: [AES.nonce_length]u8,
|
||||
tag: [AES.tag_length]u8,
|
||||
|
||||
cipher_text: []u8,
|
||||
};
|
||||
|
||||
pub fn main() !void {
|
||||
const me = try Encryptor.init();
|
||||
const him = try Encryptor.init();
|
||||
const bob = try Encryptor.init();
|
||||
const alice = try Encryptor.init();
|
||||
|
||||
const my_peer = Peer.init(me, him.kp.public_key);
|
||||
const his_peer = Peer.init(him, me.kp.public_key);
|
||||
std.debug.print(
|
||||
"Bob sends {s}\n",
|
||||
.{std.fmt.bytesToHex(bob.kp.public_key, .lower)},
|
||||
);
|
||||
std.debug.print(
|
||||
"Alice sends {s}\n",
|
||||
.{std.fmt.bytesToHex(alice.kp.public_key, .lower)},
|
||||
);
|
||||
|
||||
var seed: [dh.X25519.seed_length]u8 = undefined;
|
||||
std.crypto.random.bytes(&seed);
|
||||
const kp1 = try dh.X25519.KeyPair.create(seed);
|
||||
std.crypto.random.bytes(&seed);
|
||||
const kp2 = try dh.X25519.KeyPair.create(seed);
|
||||
const bob_peer = try Peer.init(bob.kp, alice.kp.public_key);
|
||||
const alice_peer = try Peer.init(alice.kp, bob.kp.public_key);
|
||||
|
||||
std.debug.print("{any}\n{any}\n\n", .{ kp1.public_key, kp1.secret_key });
|
||||
std.debug.print("{any}\n{any}\n\n", .{ kp2.public_key, kp2.secret_key });
|
||||
|
||||
const sec_1 = try dh.X25519.scalarmult(kp1.secret_key, kp2.public_key);
|
||||
const sec_2 = try dh.X25519.scalarmult(kp2.secret_key, kp1.public_key);
|
||||
|
||||
var key: [aead.aes_gcm.Aes256Gcm.key_length]u8 = undefined;
|
||||
std.crypto.hash.sha2.Sha256.hash(&sec_1, &key, .{});
|
||||
|
||||
std.debug.print("{any}\n", .{sec_1});
|
||||
std.debug.print("{any}\n", .{sec_2});
|
||||
std.debug.print(
|
||||
"Bob deduces {s}\n",
|
||||
.{std.fmt.bytesToHex(bob_peer.shared_key, .lower)},
|
||||
);
|
||||
std.debug.print(
|
||||
"Alice deduces {s}\n",
|
||||
.{std.fmt.bytesToHex(alice_peer.shared_key, .lower)},
|
||||
);
|
||||
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const ally = gpa.allocator();
|
||||
var arena = std.heap.ArenaAllocator.init(gpa.allocator());
|
||||
defer arena.deinit();
|
||||
|
||||
const m: []const u8 = "hello world!";
|
||||
const ad: []const u8 = "foo";
|
||||
const ally = arena.allocator();
|
||||
|
||||
// see https://crypto.stackexchange.com/a/5818
|
||||
// the nonce does not need to be random, it can be a counter
|
||||
// it can be sent in clear, or each end may deduce it
|
||||
// but it ___MUST___ be unique and unrelated to the key
|
||||
var iv: [aead.aes_gcm.Aes256Gcm.nonce_length]u8 = undefined;
|
||||
std.crypto.random.bytes(&iv);
|
||||
// bob send a message to alice
|
||||
const msg = "Hello World!";
|
||||
|
||||
const c: []u8 = try ally.alloc(u8, m.len);
|
||||
defer ally.free(c);
|
||||
std.debug.print(
|
||||
"Bob sending message '{s}' ({s})\n",
|
||||
.{ msg, std.fmt.bytesToHex(msg, .lower) },
|
||||
);
|
||||
|
||||
@memset(c, 0);
|
||||
var tag: [aead.aes_gcm.Aes256Gcm.tag_length]u8 = undefined;
|
||||
const pkt = try bob_peer.encrypt(ally, msg);
|
||||
defer ally.free(pkt.cipher_text);
|
||||
|
||||
std.debug.print("c: {any}\n", .{c});
|
||||
aead.aes_gcm.Aes256Gcm.encrypt(c, &tag, m, ad, iv, key);
|
||||
std.debug.print("{any} {any} {any}\n", .{ c, tag, iv });
|
||||
std.debug.print(
|
||||
"Packet: {s} {s} {s}\n",
|
||||
.{
|
||||
try digest(ally, pkt.cipher_text, .lower),
|
||||
try digest(ally, &pkt.nonce, .lower),
|
||||
try digest(ally, &pkt.tag, .lower),
|
||||
},
|
||||
);
|
||||
std.debug.assert(!std.mem.eql(u8, pkt.cipher_text, msg));
|
||||
|
||||
const rcv = try alice_peer.decrypt(ally, pkt);
|
||||
defer ally.free(rcv);
|
||||
std.debug.print(
|
||||
"Alice received '{s}' ({s})\n",
|
||||
.{ rcv, try digest(ally, rcv, .lower) },
|
||||
);
|
||||
|
||||
// var seed: [dh.X25519.seed_length]u8 = undefined;
|
||||
// std.crypto.random.bytes(&seed);
|
||||
// const kp1 = try dh.X25519.KeyPair.create(seed);
|
||||
// std.crypto.random.bytes(&seed);
|
||||
// const kp2 = try dh.X25519.KeyPair.create(seed);
|
||||
//
|
||||
// std.debug.print("{any}\n{any}\n\n", .{ kp1.public_key, kp1.secret_key });
|
||||
// std.debug.print("{any}\n{any}\n\n", .{ kp2.public_key, kp2.secret_key });
|
||||
//
|
||||
// const sec_1 = try dh.X25519.scalarmult(kp1.secret_key, kp2.public_key);
|
||||
// const sec_2 = try dh.X25519.scalarmult(kp2.secret_key, kp1.public_key);
|
||||
//
|
||||
// var key: [aead.aes_gcm.Aes256Gcm.key_length]u8 = undefined;
|
||||
// std.crypto.hash.sha2.Sha256.hash(&sec_1, &key, .{});
|
||||
//
|
||||
// std.debug.print("{any}\n", .{sec_1});
|
||||
// std.debug.print("{any}\n", .{sec_2});
|
||||
//
|
||||
// var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
// const ally = gpa.allocator();
|
||||
//
|
||||
// const m: []const u8 = "hello world!";
|
||||
// const ad: []const u8 = "foo";
|
||||
//
|
||||
// // see https://crypto.stackexchange.com/a/5818
|
||||
// // the nonce does not need to be random, it can be a counter
|
||||
// // it can be sent in clear, or each end may deduce it
|
||||
// // but it ___MUST___ be unique and unrelated to the key
|
||||
// var iv: [aead.aes_gcm.Aes256Gcm.nonce_length]u8 = undefined;
|
||||
// std.crypto.random.bytes(&iv);
|
||||
//
|
||||
// const c: []u8 = try ally.alloc(u8, m.len);
|
||||
// defer ally.free(c);
|
||||
//
|
||||
// @memset(c, 0);
|
||||
// var tag: [aead.aes_gcm.Aes256Gcm.tag_length]u8 = undefined;
|
||||
//
|
||||
// std.debug.print("c: {any}\n", .{c});
|
||||
// aead.aes_gcm.Aes256Gcm.encrypt(c, &tag, m, ad, iv, key);
|
||||
// std.debug.print("{any} {any} {any}\n", .{ c, tag, iv });
|
||||
|
||||
// aead.aes_gcm.Aes256Gcm.encrypt(c: []u8, tag: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8)
|
||||
|
||||
@@ -132,3 +186,18 @@ test "simple test" {
|
||||
try list.append(42);
|
||||
try std.testing.expectEqual(@as(i32, 42), list.pop());
|
||||
}
|
||||
|
||||
/// caller takes ownership of result
|
||||
fn digest(ally: std.mem.Allocator, data: []const u8, case: std.fmt.Case) ![]const u8 {
|
||||
const charset = switch (case) {
|
||||
.lower => "0123456789abcdef",
|
||||
.upper => "0123456789ABCDEF",
|
||||
};
|
||||
|
||||
var res = try ally.alloc(u8, data.len * 2);
|
||||
for (data, 0..) |ch, idx| {
|
||||
res[idx * 2 + 0] = charset[ch >> 4];
|
||||
res[idx * 2 + 1] = charset[ch & 0xf];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
Reference in New Issue
Block a user