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,
|
kp: DH.KeyPair,
|
||||||
|
|
||||||
pub fn init() !Self {
|
pub fn init() !Self {
|
||||||
const self = Self{};
|
var self: Self = undefined;
|
||||||
|
|
||||||
var seed: [DH.seed_length]u8 = undefined;
|
var seed: [DH.seed_length]u8 = undefined;
|
||||||
std.crypto.random.bytes(&seed);
|
std.crypto.random.bytes(&seed);
|
||||||
self.kp = try DH.KeyPair.create(seed);
|
self.kp = try DH.KeyPair.create(seed);
|
||||||
@memset(seed, 0);
|
@memset(&seed, 0);
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -27,11 +27,12 @@ const Peer = struct {
|
|||||||
public_key: [DH.public_length]u8,
|
public_key: [DH.public_length]u8,
|
||||||
shared_key: [AES.key_length]u8,
|
shared_key: [AES.key_length]u8,
|
||||||
|
|
||||||
pub fn init(me: DH.KeyPair, peer_key: [DH.public_length]u8) Self {
|
pub fn init(me: DH.KeyPair, peer_key: [DH.public_length]u8) !Self {
|
||||||
const self = Self{ .public_key = peer_key };
|
var self: Self = undefined;
|
||||||
|
self.public_key = peer_key;
|
||||||
|
|
||||||
const secret = try DH.scalarmult(me.secret_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;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -46,8 +47,10 @@ const Peer = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Caller must free result
|
/// 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,
|
ally: std.mem.Allocator,
|
||||||
nonce: [AES.nonce_length]u8,
|
nonce: [AES.nonce_length]u8,
|
||||||
tag: [AES.tag_length]u8,
|
tag: [AES.tag_length]u8,
|
||||||
|
|
||||||
cipher_text: []u8,
|
cipher_text: []u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
const me = try Encryptor.init();
|
const bob = try Encryptor.init();
|
||||||
const him = try Encryptor.init();
|
const alice = try Encryptor.init();
|
||||||
|
|
||||||
const my_peer = Peer.init(me, him.kp.public_key);
|
std.debug.print(
|
||||||
const his_peer = Peer.init(him, me.kp.public_key);
|
"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;
|
const bob_peer = try Peer.init(bob.kp, alice.kp.public_key);
|
||||||
std.crypto.random.bytes(&seed);
|
const alice_peer = try Peer.init(alice.kp, bob.kp.public_key);
|
||||||
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(
|
||||||
std.debug.print("{any}\n{any}\n\n", .{ kp2.public_key, kp2.secret_key });
|
"Bob deduces {s}\n",
|
||||||
|
.{std.fmt.bytesToHex(bob_peer.shared_key, .lower)},
|
||||||
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);
|
std.debug.print(
|
||||||
|
"Alice deduces {s}\n",
|
||||||
var key: [aead.aes_gcm.Aes256Gcm.key_length]u8 = undefined;
|
.{std.fmt.bytesToHex(alice_peer.shared_key, .lower)},
|
||||||
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(.{}){};
|
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 ally = arena.allocator();
|
||||||
const ad: []const u8 = "foo";
|
|
||||||
|
|
||||||
// see https://crypto.stackexchange.com/a/5818
|
// bob send a message to alice
|
||||||
// the nonce does not need to be random, it can be a counter
|
const msg = "Hello World!";
|
||||||
// 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);
|
std.debug.print(
|
||||||
defer ally.free(c);
|
"Bob sending message '{s}' ({s})\n",
|
||||||
|
.{ msg, std.fmt.bytesToHex(msg, .lower) },
|
||||||
|
);
|
||||||
|
|
||||||
@memset(c, 0);
|
const pkt = try bob_peer.encrypt(ally, msg);
|
||||||
var tag: [aead.aes_gcm.Aes256Gcm.tag_length]u8 = undefined;
|
defer ally.free(pkt.cipher_text);
|
||||||
|
|
||||||
std.debug.print("c: {any}\n", .{c});
|
std.debug.print(
|
||||||
aead.aes_gcm.Aes256Gcm.encrypt(c, &tag, m, ad, iv, key);
|
"Packet: {s} {s} {s}\n",
|
||||||
std.debug.print("{any} {any} {any}\n", .{ c, tag, iv });
|
.{
|
||||||
|
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)
|
// 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 list.append(42);
|
||||||
try std.testing.expectEqual(@as(i32, 42), list.pop());
|
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