~apreiml/hare-ssh

dbcb4b4e134cd057bb68ee306da9964e0fec68ad — Armin Preiml 1 year, 7 months ago 0e3024d
ssh::format: add functions to encode raw keys
3 files changed, 110 insertions(+), 1 deletions(-)

A format/ssh/+test/rawkey.ha
M format/ssh/ed25519.ha
M format/ssh/key.ha
A format/ssh/+test/rawkey.ha => format/ssh/+test/rawkey.ha +29 -0
@@ 0,0 1,29 @@
use bufio;
use bytes;
use io;

@test fn ed25519_rawkeys() void = {
	const reader = bufio::fixed(testkey, io::mode::READ);
	const sshkey = decodesshprivate(&reader)!;
	defer sshprivkey_finish(&sshkey);
	const private = decodeprivate(&sshkey)!;

	let private = private: *ed25519key;
	let copy = new_ed25519key();

	let pubbuf = bufio::dynamic(io::mode::RDWR);
	defer io::close(&pubbuf)!;
	key_encoderawpub(private, &pubbuf)!;
	io::seek(&pubbuf, 0, io::whence::SET)!;
	key_decoderawpub(&copy, &pubbuf)!;

	assert(bytes::equal(private.pubkey, copy.pubkey));

	let privbuf = bufio::dynamic(io::mode::RDWR);
	defer io::close(&privbuf)!;
	key_encoderawpriv(private, &privbuf)!;
	io::seek(&privbuf, 0, io::whence::SET)!;
	key_decoderawpriv(&copy, &privbuf)!;

	assert(bytes::equal(private.privkey, copy.privkey));
};

M format/ssh/ed25519.ha => format/ssh/ed25519.ha +46 -0
@@ 14,6 14,10 @@ const ed25519_vtable: key_vtable = key_vtable {
	decodepub = &ed25519_decodepub,
	decodepriv = &ed25519_decodepriv,
	encodepub = &ed25519_encodepub,
	encoderawpub = &ed25519_encoderawpubfunc,
	decoderawpub = &ed25519_decoderawpubfunc,
	encoderawpriv = &ed25519_encoderawprivfunc,
	decoderawpriv = &ed25519_decoderawprivfunc,
	sign = &ed25519_sign,
	verify = &ed25519_verify,
	finish = &ed25519_finish,


@@ 60,6 64,48 @@ fn ed25519_encodepub(key: *const key, sink: io::handle) (void | io::error) = {
	writeslice(sink, key.pubkey)?;
};

fn ed25519_encoderawpubfunc(
	key: *const key,
	sink: io::handle
) (void | io::error) = {
	let key = key: *ed25519key;
	io::writeall(sink, key.pubkey)?;
};

fn ed25519_decoderawpubfunc(key: *key, src: io::handle) (void | error) = {
	let key = key: *ed25519key;
	match (io::readall(src, key.pubkey)?) {
	case io::EOF =>
		return invalid;
	case let n: size =>
		if (n != ed25519::PUBKEYSZ) {
			return n: io::underread;
		};
	};
};

fn ed25519_encoderawprivfunc(
	key: *const key,
	sink: io::handle
) (void | io::error) = {
	let key = key: *ed25519key;
	io::writeall(sink, key.privkey)?;
};

fn ed25519_decoderawprivfunc(key: *key, src: io::handle) (void | error) = {
	let key = key: *ed25519key;
	match (io::readall(src, key.privkey)?) {
	case io::EOF =>
		bytes::zero(key.privkey);
		return 0: io::underread;
	case let n: size =>
		if (n != ed25519::PRIVKEYSZ) {
			bytes::zero(key.privkey);
			return n: io::underread;
		};
	};
};

fn ed25519_sign(
	key: *const key,
	sink: io::handle,

M format/ssh/key.ha => format/ssh/key.ha +35 -1
@@ 8,6 8,10 @@ use io;
export type decodepubfunc = fn(key: *key, buf: io::handle) (void | error);
export type decodeprivfunc = fn(key: *key, buf: io::handle) (void | error);
export type encodepubfunc = fn(key: *const key, sink: io::handle) (void | io::error);
export type encoderawpubfunc = fn(key: *const key, sink: io::handle) (void | io::error);
export type encoderawprivfunc = fn(key: *const key, sink: io::handle) (void | io::error);
export type decoderawpubfunc = fn(key: *key, src: io::handle) (void | error);
export type decoderawprivfunc = fn(key: *key, src: io::handle) (void | error);
export type signfunc = fn(key: *const key, sink: io::handle, msg: []u8) (void | io::error);
export type verifyfunc = fn(key: *const key, source: io::handle, msg: []u8) (void | error);
export type finishfunc = fn(key: *key) void;


@@ 17,6 21,10 @@ export type key_vtable = struct {
	decodepub: *decodepubfunc,
	decodepriv: *decodeprivfunc,
	encodepub: *encodepubfunc,
	encoderawpub: *encoderawpubfunc,
	encoderawpriv: *encoderawprivfunc,
	decoderawpub: *decoderawpubfunc,
	decoderawpriv: *decoderawprivfunc,
	sign: *signfunc,
	verify: *verifyfunc,
	finish: *finishfunc,


@@ 77,7 85,7 @@ export fn decodepublic(src: io::handle) (*key | error) = {

// Encodes a private key's public component using the SSH wire format, writing
// it into the given stream.
export fn encode_pubkey(sink: io::handle, key: *const key) (void | io::error) = {
export fn encode_pubkey(sink: io::handle, key: const *key) (void | io::error) = {
	writestr(sink, keytype(key))?;
	key.vtable.encodepub(key, sink)?;
};


@@ 94,6 102,28 @@ export fn encode_pubkeystr(sink: io::handle, key: *key) (void | io::error) = {
	};
};

// Encodes the raw private key part only, in such a way that it only may be 
// decoded using [[key_decodepriv]].
export fn key_encoderawpriv(key: *key, sink: io::handle) (void | io::error) = {
	return key.vtable.encoderawpriv(key, sink);
};

// Decode a raw private key encoded with [[key_encodepriv]].
export fn key_decoderawpriv(key: *key, src: io::handle) (void | error) = {
	return key.vtable.decoderawpriv(key, src);
};

// Encodes the raw public key part only, in such a way that it only may be 
// decoded using [[key_decodepub]].
export fn key_encoderawpub(key: *key, sink: io::handle) (void | io::error) = {
	return key.vtable.encoderawpub(key, sink);
};

// Decode a raw public key encoded with [[key_encodepub]].
export fn key_decoderawpub(key: *key, src: io::handle) (void | error) = {
	return key.vtable.decoderawpub(key, src);
};

// Securely wipes data associated with a private key from memory and frees the
// key resource.
export fn key_free(key: *key) void = {


@@ 107,3 137,7 @@ export fn keytype(key: *key) const str = {
	return key.vtable.keytype;
};

// Returns the key comment.
export fn key_comment(key: *key) str = {
	return key.comment;
};