~sircmpwn/hare-ssh

46f9feeeb1c5606e7ef1e9ac1e22fb4767e4da2f — Drew DeVault 2 months ago 2136f37
net::ssh: add some mac algorithms
1 files changed, 157 insertions(+), 0 deletions(-)

A net/ssh/mac.ha
A net/ssh/mac.ha => net/ssh/mac.ha +157 -0
@@ 0,0 1,157 @@
// TODO: It would be nice to avoid an extra allocation here for every packet,
// can we reset the mac state?
use crypto::hmac;
use crypto::mac;
use crypto::sha1;
use endian;
use io;

export type mac = struct {
	name: str,
	keysz: size,
	digestsz: size,
	init: *fn(key: []u8) *mac::mac,

};
// Returns the name of the given MAC algorithm.
export fn mac_name(mac: *mac) const str = {
	return mac.name;
};

// Returns the size of the key for the given MAC algorithm.
export fn mac_keysz(mac: *mac) size = {
	return mac.keysz;
};

// Returns the size of the MAC for the given MAC algorithm.
export fn mac_digestsz(mac: *mac) size = {
	return mac.digestsz;
};

// Looks up the MAC algorithm with the given name.
export fn mac_lookup(name: str) const nullable *mac = {
	for (let i = 0z; i < len(mactable); i += 1) {
		if (mactable[i].name == name) {
			return &mactable[i];
		};
	};
	return null;
};

// Returns a [[crypto::mac::mac]] for the given MAC algorithm.
export fn mac_init(mac: *mac, key: []u8) *mac::mac = {
	return mac.init(key);
};

const mactable: [_]mac = [
	mac {
		name = "hmac-sha1",
		keysz = 20,
		digestsz = 20,
		init = &hmac_sha1_init,
	},
	mac {
		name = "hmac-sha1-96",
		keysz = 20,
		digestsz = 12,
		init = &hmac_sha1_96_init,
	},
	mac {
		name = "hmac-sha2-256",
		keysz = 32,
		digestsz = 32,
		init = &hmac_sha256_init,
	},
];

type hmac_sha1 = struct {
	mac::mac,
	mac: hmac::sha1state,
};

const hmac_sha1_vtable: io::vtable = io::vtable {
	writer = &hmac_sha1_write,
	...
};

fn hmac_sha1_init(key: []u8) *mac::mac = {
	let sha1 = hmac::sha1(key);
	return alloc(hmac_sha1 {
		stream = &hmac_sha1_vtable,
		sum = &hmac_sha1_sum,
		finish = &hmac_sha1_finish,
		sz = mac::sz(&sha1),
		bsz = mac::bsz(&sha1),
		mac = sha1,
	});
};

fn hmac_sha1_write(st: *io::stream, buf: const []u8) (size | io::error) = {
	const mac = st: *hmac_sha1;
	mac::write(&mac.mac, buf);
	return len(buf);
};

fn hmac_sha1_sum(mac: *mac::mac, out: []u8) void = {
	const mac = mac: *hmac_sha1;
	mac::sum(&mac.mac, out);
};

fn hmac_sha1_finish(mac: *mac::mac) void = {
	const mac = mac: *hmac_sha1;
	mac::finish(&mac.mac);
	free(mac);
};

fn hmac_sha1_96_init(key: []u8) *mac::mac = {
	let mac = hmac_sha1_init(key);
	mac.sum = &hmac_sha1_96_sum;
	mac.sz = 12;
	return mac;
};

fn hmac_sha1_96_sum(mac: *mac::mac, out: []u8) void = {
	const mac = mac: *hmac_sha1;
	let macbuf: [sha1::SIZE]u8 = [0...];
	mac::sum(&mac.mac, macbuf);
	out[..12] = macbuf[..12];
};

type hmac_sha256 = struct {
	mac::mac,
	mac: hmac::sha256state,
};

const hmac_sha256_vtable: io::vtable = io::vtable {
	writer = &hmac_sha256_write,
	...
};

fn hmac_sha256_init(key: []u8) *mac::mac = {
	let sha256 = hmac::sha256(key);
	return alloc(hmac_sha256 {
		stream = &hmac_sha256_vtable,
		sum = &hmac_sha256_sum,
		finish = &hmac_sha256_finish,
		sz = mac::sz(&sha256),
		bsz = mac::bsz(&sha256),
		mac = sha256,
	});
};

fn hmac_sha256_write(st: *io::stream, buf: const []u8) (size | io::error) = {
	const mac = st: *hmac_sha256;
	mac::write(&mac.mac, buf);
	return len(buf);
};

fn hmac_sha256_sum(mac: *mac::mac, out: []u8) void = {
	const mac = mac: *hmac_sha256;
	mac::sum(&mac.mac, out);
};

fn hmac_sha256_finish(mac: *mac::mac) void = {
	const mac = mac: *hmac_sha256;
	mac::finish(&mac.mac);
	free(mac);
};