-- vim: ft=terra
local const = {
keybits = 2048;
sighash = lib.md.MBEDTLS_MD_SHA256;
}
local err = {
rawcode = terra(code: int)
if code < 0 then code = -code end
return code and 0xFF80
end;
toobig = -lib.pk.MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE;
}
const.maxpemsz = math.floor((const.keybits / 8)*6.4) + 128 -- idk why this formula works but it basically seems to
local ctx = lib.pk.mbedtls_pk_context
local m = {
pemfile = uint8[const.maxpemsz];
}
local callbacks = {}
if config.feat.randomizer == 'kern' then
local rnd = terralib.externfunction('getrandom', {&opaque, intptr, uint} -> ptrdiff);
terra callbacks.randomize(ctx: &opaque, dest: &uint8, sz: intptr): int
return rnd(dest, sz, 0)
end
elseif config.feat.randomizer == 'devfs' then
terra callbacks.randomize(ctx: &opaque, dest: &uint8, sz: intptr): int
var gen = lib.io.open("/dev/urandom",0)
lib.io.read(gen, dest, sz)
lib.io.close(gen)
return sz
end
elseif config.feat.randomizer == 'libc' then
local rnd = terralib.externfunction('rand', {} -> int);
local srnd = terralib.externfunction('srand', uint -> int);
local time = terralib.includec 'time.h'
lib.init[#lib.init + 1] = quote srnd(time.time(nil)) end
print '(warn) using libc soft-rand function for cryptographic purposes, this is very bad!'
terra callbacks.randomize(ctx: &opaque, dest: &uint8, sz: intptr): int
for i=0,sz do dest[i] = [uint8](rnd()) end
return sz
end
end
terra m.pem(pub: bool, key: &ctx, buf: &uint8): bool
if pub then
return lib.pk.mbedtls_pk_write_pubkey_pem(key, buf, const.maxpemsz) == 0
else
return lib.pk.mbedtls_pk_write_key_pem(key, buf, const.maxpemsz) == 0
end
end
m.destroy = lib.dispatch {
[ctx] = function(v) return `lib.pk.mbedtls_pk_free(&v) end;
[false] = function(ptr) return `ptr:free() end;
}
terra m.genkp(): lib.pk.mbedtls_pk_context
lib.dbg('generating new keypair')
var pk: ctx
lib.pk.mbedtls_pk_init(&pk)
lib.pk.mbedtls_pk_setup(&pk, lib.pk.mbedtls_pk_info_from_type(lib.pk.MBEDTLS_PK_RSA))
var rsa = [&lib.rsa.mbedtls_rsa_context](pk.pk_ctx)
lib.rsa.mbedtls_rsa_gen_key(rsa, callbacks.randomize, nil, const.keybits, 65537)
return pk
end
terra m.loadpriv(buf: &uint8, len: intptr): ctx
lib.dbg('parsing saved keypair')
var pk: ctx
lib.pk.mbedtls_pk_init(&pk)
lib.pk.mbedtls_pk_parse_key(&pk, buf, len + 1, nil, 0)
return pk
end
terra m.sign(pk: &ctx, txt: rawstring, len: intptr)
lib.dbg('signing message')
var osz: intptr = 0
var sig = lib.mem.heapa(int8, 2048)
var hash: uint8[32]
lib.dbg('(1/2) hashing message')
if lib.md.mbedtls_md(lib.md.mbedtls_md_info_from_type(const.sighash), [&uint8](txt), len, hash) ~= 0 then
lib.bail('could not hash message')
end
lib.dbg('(2/2) signing hash')
var ret = lib.pk.mbedtls_pk_sign(pk, const.sighash, hash, 0, [&uint8](sig.ptr), &osz, callbacks.randomize, nil)
if ret ~= 0 then lib.bail('could not sign message hash')
else sig:resize(osz) end
return sig
end
terra m.verify(pk: &ctx, txt: rawstring, len: intptr,
sig: rawstring, siglen: intptr): {bool, uint8}
lib.dbg('verifying signature')
var osz: intptr = 0
var hash: uint8[64]
-- there does not appear to be any way to extract the hash algorithm
-- from the message, so we just have to try likely algorithms until
-- we find one that fits or give up. a security level is attached
-- to indicate our relative confidence in the hash; 0 == 'likely forgeable'
var algs = array(
-- common hashes
{lib.md.MBEDTLS_MD_SHA256, 'sha256', 2},
{lib.md.MBEDTLS_MD_SHA512, 'sha512', 3},
{lib.md.MBEDTLS_MD_SHA1, 'sha1', 1},
-- uncommon hashes
{lib.md.MBEDTLS_MD_SHA384, 'sha384', 2},
{lib.md.MBEDTLS_MD_SHA224, 'sha224', 2},
-- bad hashes
{lib.md.MBEDTLS_MD_MD5, 'md5', 0},
{lib.md.MBEDTLS_MD_MD4, 'md4', 0},
{lib.md.MBEDTLS_MD_MD2, 'md2', 0}
)
for i = 0, [algs.type.N] do
var hk, aname, secl = algs[i]
lib.dbg('(1/2) trying hash algorithm ',aname)
if lib.md.mbedtls_md(lib.md.mbedtls_md_info_from_type(hk), [&uint8](txt), len, hash) ~= 0 then
lib.bail('could not hash message')
end
lib.dbg('(2/2) verifying hash')
if lib.pk.mbedtls_pk_verify(pk, hk, hash, 0, [&uint8](sig), siglen) == 0 then
return true, secl
end
end
lib.dbg('all hash algorithms failed')
return false, 0
end
return m