srctree

Gregory Mullen parent 8d3deabe 940aec1c
valid aes 256 cbc

something is wrong with key expantion, but the primitives are valid
src/cipher.zig added: 124, removed: 27, total 97
@@ -23,7 +23,7 @@ suite: union(enum) {
ecc: EllipticCurve,
aes: AnyAES,
} = .{ .invalid = {} },
sequence: u72 = 0, // this is chacha20 specific :/
sequence: u72 = 0, // u72 is chacha20 specific :/
 
pub fn Material(comptime enc: anytype, comptime hmac: anytype) type {
return struct {
@@ -219,7 +219,7 @@ pub const AnyAES = struct {
Sha256.create(&left, pre_left ++ seed, &aes.material.premaster);
Sha256.create(&right, pre_right ++ seed, &aes.material.premaster);
 
aes.material.master = left ++ right[0..16].*;
aes.material.master = (left ++ right[0..16].*);
 
{
const key_seed = "key expansion" ++ ctx.cli_random.? ++ ctx.srv_random.?;
@@ -293,7 +293,7 @@ pub const AnyAES = struct {
 
pub const CBC = struct {
pub const key_length = 32;
pub const nonce_length = 0;
pub const nonce_length = 16;
 
pub fn decrypt(key: [32]u8, cipher: []const u8, clear: []u8) !void {
if (cipher.len % 16 != 0) return error.InvalidCipherLength;
 
src/handshake.zig added: 124, removed: 27, total 97
@@ -140,23 +140,23 @@ pub const Finished = struct {
else => unreachable,
};
 
var sha = std.crypto.auth.hmac.sha2.HmacSha256.init(&master);
var sha = std.crypto.auth.hmac.sha2.HmacSha384.init(&master);
sha.update("client finished");
sha.update(ctx.handshake_record.items);
var verify: [32]u8 = undefined;
var verify: [48]u8 = undefined;
sha.final(&verify);
 
sha = std.crypto.auth.hmac.sha2.HmacSha256.init(&master);
sha.update(&verify);
sha.update("client finished");
sha.update(ctx.handshake_record.items);
sha.final(&verify);
//sha = std.crypto.auth.hmac.sha2.HmacSha384.init(&master);
//sha.update(&verify);
//sha.update("client finished");
//sha.update(ctx.handshake_record.items);
//sha.final(&verify);
 
// TODO do I need to zero this struct?
defer ctx.handshake_record.deinit();
 
try w.writeAll(&verify);
return 0x20;
return 48;
}
};
 
@@ -196,13 +196,14 @@ pub const ServerHello = struct {
=> {
ctx.cipher.suite = .{ .ecc = undefined };
},
.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
.TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
//.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
//.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
//.TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
//.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
//.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
=> {
print("cipher requested = {}\n", .{cipher_request});
ctx.cipher.suite = .{ .aes = undefined };
},
//else => ctx.cipher.suite = .{ .ecc = undefined },
 
src/root.zig added: 124, removed: 27, total 97
@@ -16,6 +16,8 @@ const ConnCtx = @import("context.zig");
const Handshake = @import("handshake.zig");
const Cipher = @import("cipher.zig");
 
const PRINT_DEBUG = true;
 
const ContentType = enum(u8) {
change_cipher_spec = 20,
alert = 21,
@@ -68,16 +70,19 @@ const TLSRecord = struct {
 
pub fn encrypt(record: TLSRecord, buffer: []u8, ctx: *ConnCtx) !usize {
var clear_buffer: [0x1000]u8 = undefined;
const len = try record.packFragment(&clear_buffer, ctx);
var len = try record.packFragment(&clear_buffer, ctx);
 
const empty: [0]u8 = undefined;
print("clear buffer {}\n", .{
std.fmt.fmtSliceHexLower(clear_buffer[0..len]),
});
//print("material iv {any}\n", .{ctx.cipher.suite.ecc.material.cli_iv});
//for (buffer[5..][0..12], ctx.cipher.suite.ecc.material.cli_iv, asBytes(&ctx.cipher.sequence)[4..]) |*dst, iv, seq|
// dst.* = iv ^ seq;
const encrypted_body = buffer[5..];
 
switch (ctx.cipher.suite) {
.ecc => {
const empty: [0]u8 = undefined;
const encrypted_body = buffer[5..];
std.crypto.aead.chacha_poly.ChaCha20Poly1305.encrypt(
encrypted_body[0..len],
encrypted_body[len..][0..16],
@@ -87,7 +92,39 @@ const TLSRecord = struct {
ctx.cipher.suite.ecc.material.cli_key,
);
},
.aes => |_| {},
.aes => |aes| {
var mac_buf: [0x200]u8 = undefined;
var fba = fixedBufferStream(&mac_buf);
var w = fba.writer().any();
try w.writeInt(u64, @truncate(ctx.cipher.sequence), .big);
try w.writeAll(clear_buffer[0..len]);
 
const mac_out: *[48]u8 = clear_buffer[len..][0..48];
std.crypto.auth.hmac.sha2.HmacSha384.create(mac_out, mac_buf[0 .. 8 + len], &aes.material.cli_mac);
print("mac buf {any}\n", .{mac_buf[0 .. 8 + len]});
len += 48;
 
var aes_ctx = std.crypto.core.aes.Aes256.initEnc(aes.material.cli_key);
const add = 16 - (len % 16);
if (add != 0) {
@memset(clear_buffer[len..][0..add], 0);
}
len += add;
@memcpy(buffer[5..][0..16], aes.material.cli_iv[0..]);
const encrypted_body = buffer[5..][16..];
 
var xord: [16]u8 = aes.material.cli_iv;
print("xor pre {any}\n", .{xord});
for (0..len / 16) |i| {
var clear: [16]u8 = clear_buffer[i * 16 ..][0..16].*;
const cipher: *[16]u8 = encrypted_body[i * 16 ..][0..16];
for (clear[0..], xord[0..]) |*c, xr| c.* ^= xr;
aes_ctx.encrypt(cipher, clear[0..]);
@memcpy(xord[0..16], cipher[0..16]);
print("{} {any}\n {any}\n", .{ i, clear, cipher });
}
len += 16; // IV
},
else => unreachable,
}
 
@@ -226,7 +263,7 @@ fn buildServer(data: []const u8, ctx: *ConnCtx) !void {
switch (hs.body) {
.server_hello => |hello| {
if (false) print("server hello {}\n", .{@TypeOf(hello)});
if (false) print("srv selected suite {any}\n", .{ctx.cipher});
if (true) print("srv selected suite {any}\n", .{ctx.cipher});
//if (ctx.cipher.suite != .ecc) {
// return error.UnexpectedCipherSuite;
//}
@@ -289,7 +326,21 @@ fn completeClient(conn: std.net.Stream, ctx: *ConnCtx) !void {
},
};
const fin_len = try fin_record.encrypt(&buffer, ctx);
if (false) print("fin: {any}\n", .{buffer[0..fin_len]});
if (true) print("fin: {any}\n", .{
std.fmt.fmtSliceHexLower(buffer[0..fin_len]),
});
print("client key {}\n", .{
std.fmt.fmtSliceHexLower(&ctx.cipher.suite.aes.material.cli_key),
});
print("client mac {}\n", .{
std.fmt.fmtSliceHexLower(&ctx.cipher.suite.aes.material.cli_mac),
});
print("client iv {}\n", .{
std.fmt.fmtSliceHexLower(buffer[5..][0..16]),
});
print("client msg {}\n", .{
std.fmt.fmtSliceHexLower(buffer[5..][16..][0 .. fin_len - 5 - 16]),
});
const finout = try conn.write(buffer[0..fin_len]);
if (false) print("fin delivered, {}\n", .{finout});
 
@@ -364,7 +415,7 @@ test "probe" {
}
 
test "tls" {
if (false) return error.SkipZigTest;
if (true) return error.SkipZigTest;
const addr = net.Address.resolveIp(TESTING_IP, TESTING_PORT) catch |err| {
print("unable to resolve address because {}\n", .{err});
return err;
@@ -386,7 +437,7 @@ test "cbc" {
const conn = try net.tcpConnectToAddress(addr);
 
var ctx = try startHandshakeCustomSuites(conn, &[_]Cipher.Suites{
.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
});
errdefer ctx.handshake_record.deinit();
var server: [0x1000]u8 = undefined;
@@ -518,3 +569,48 @@ test "mock server response" {
//try std.testing.expectEqual(43, len);
//print("CKE: {any}\n", .{buffer[0..43]});
}
 
const test_key: [32]u8 = [_]u8{12} ** 32;
const test_iv: [16]u8 = [_]u8{6} ** 16;
 
test "aes" {
if (true) return error.SkipZigTest;
const clear: [16]u8 = "this is a test!!".*;
 
//print("test iv {any}\n", .{xord});
var cipher: [16]u8 = undefined;
var aes_ctx_en = std.crypto.core.aes.Aes256.initEnc(test_key);
var man_xor: [16]u8 = undefined;
for (man_xor[0..], clear[0..], test_iv[0..]) |*out, in, iv| {
out.* = in ^ iv;
}
aes_ctx_en.encrypt(cipher[0..], man_xor[0..]);
//@memcpy(&xord, cipher[0..]);
print("clear {} \n", .{
std.fmt.fmtSliceHexLower(clear[0..]),
});
 
print("man_xor {} \n", .{
std.fmt.fmtSliceHexLower(man_xor[0..]),
});
 
print("crypto {} \n", .{
std.fmt.fmtSliceHexLower(cipher[0..]),
});
 
const iv: [16]u8 = test_iv;
var xord: [16]u8 = undefined;
aes_ctx_en.xor(xord[0..], clear[0..], iv);
print("man_xor {} \n", .{
std.fmt.fmtSliceHexLower(xord[0..]),
});
 
var aes_ctx_de = std.crypto.core.aes.Aes256.initDec(test_key);
var output: [16]u8 = undefined;
aes_ctx_de.decrypt(output[0..], cipher[0..]);
print("crypto {s} {any}\n", .{ output, cipher });
for (output[0..], test_iv[0..]) |*out, iv2| {
out.* = out.* ^ iv2;
}
print("crypto {s} {any}\n", .{ output, cipher });
}