@@ 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);
+};