Commit 66205ff3 authored by Jaromil's avatar Jaromil
Browse files

further improvements to ECDH for AES-GCM encryption as default

added high-level simple global functions to encrypt()/decrypt() which
execute KDF2 session and AES-GCM automatically by comparing headers.
Data format passed around is a table carrying the IV, header and checksum.
parent 8b1784a9
......@@ -8,6 +8,7 @@ OCTET = require('zenroom_octet')
ECDH = require('ecdh')
LAMBDA = require('functional')
INSIDE = require('inspect')
I = INSIDE -- alias
ECP = require('ecp')
ECP2 = require('ecp2')
BIG = require('zenroom_big')
......@@ -34,6 +35,29 @@ function content(var)
end
end
function encrypt(alice, bob, msg, header)
key = alice:session(bob)
iv = RNG.new():octet(16)
-- convert strings to octets
if(type(msg) == "string") then
omsg = str(msg) else omsg = msg end
if(type(header) == "string") then
ohead = str(header) else ohead = header end
cypher = {header = ohead, iv = iv}
cypher.text, cypher.checksum = ECDH.encrypt(key,omsg,iv,ohead)
return(cypher)
end
function decrypt(alice, bob, cypher)
key = alice:session(bob)
decode = {header = cypher.header}
decode.text, decode.checksum = ECDH.decrypt(key, cypher.text, cypher.iv, cypher.header)
if(cypher.checksum ~= decode.checksum) then
error("decrypt error: header checksum mismatch")
end
return(decode)
end
function ECP2.G() return ECP2.new() end
function ECP2.generator() return ECP2.new() end
......
This diff is collapsed.
......@@ -247,6 +247,9 @@ finish:{
octet *ses = o_new(L,e->keysize); SAFE(ses);
(*e->ECP__SVDP_DH)(e->seckey,pubkey,ses);
// here the NULL could be a salt (TODO: global?)
// its used as 'p' in the hash function
// ehashit(sha,z,counter,p,&H,0);
KDF2(e->hash,ses,NULL,e->hash,kdf);
return 2;
}
......@@ -359,6 +362,33 @@ static int ecdh_encrypt_weak_aes_cbc(lua_State *L) {
return 1;
}
/**
AES decrypts a plaintext to a ciphtertext. Function compabible
with IEEE-1363 specification for AES CBC using IV set to
zero. Decrypts a secret produced using
@{keyring:encrypt_weak_aes_cbc} in CBC mode.
@param key AES key octet
@param ciphertext input ciphertext octet
@return a new octet containing the decrypted plain text, or false when failed
@function keyring:decrypt_weak_aes_cbc(key, ciphertext)
*/
static int ecdh_decrypt_weak_aes_cbc(lua_State *L) {
HERE();
ecdh *e = ecdh_arg(L, 1); SAFE(e);
octet *k = o_arg(L, 2); SAFE(k);
octet *in = o_arg(L, 3); SAFE(in);
// output is padded to next word
octet *out = o_new(L, in->len+16); SAFE(out);
if(!AES_CBC_IV0_DECRYPT(k,in,out)) {
error(L, "%s: decryption failed.",__func__);
lua_pop(L, 1);
lua_pushboolean(L, 0);
}
return 1;
}
/**
AES-GCM encrypt with Additional Data (AEAD) encrypts and
authenticate a plaintext to a ciphtertext. Function compatible with
......@@ -384,51 +414,17 @@ static int ecdh_aead_encrypt(lua_State *L) {
// lerror(L,"AES-GCM/AEAD encryption only supports SHA256 hashing (32 bytes)");
// HEREecdh(e);
// return 0; }
octet *k = o_arg(L, 2); SAFE(k);
octet *in = o_arg(L, 3); SAFE(in);
octet *iv = o_arg(L, 4); SAFE(iv);
octet *h = o_arg(L, 5); SAFE(h);
HEREoct(k);
HEREoct(in);
HEREoct(iv);
HEREoct(h);
octet *k = o_arg(L, 1); SAFE(k);
octet *in = o_arg(L, 2); SAFE(in);
octet *iv = o_arg(L, 3); SAFE(iv);
octet *h = o_arg(L, 4); SAFE(h);
// output is padded to next word
octet *out = o_new(L, in->len+16); SAFE(out);
octet *t = o_new(L, 32); SAFE (t);
AES_GCM_ENCRYPT(k, iv, h, in, out, t);
HEREoct(out);
HEREoct(t);
return 2;
}
/**
AES decrypts a plaintext to a ciphtertext. Function compabible
with IEEE-1363 specification for AES CBC using IV set to
zero. Decrypts a secret produced using
@{keyring:encrypt_weak_aes_cbc} in CBC mode.
@param key AES key octet
@param ciphertext input ciphertext octet
@return a new octet containing the decrypted plain text, or false when failed
@function keyring:decrypt_weak_aes_cbc(key, ciphertext)
*/
static int ecdh_decrypt_weak_aes_cbc(lua_State *L) {
HERE();
ecdh *e = ecdh_arg(L, 1); SAFE(e);
octet *k = o_arg(L, 2); SAFE(k);
octet *in = o_arg(L, 3); SAFE(in);
// output is padded to next word
octet *out = o_new(L, in->len+16); SAFE(out);
if(!AES_CBC_IV0_DECRYPT(k,in,out)) {
error(L, "%s: decryption failed.",__func__);
lua_pop(L, 1);
lua_pushboolean(L, 0);
}
return 1;
}
/**
AES-GCM decrypt with Additional Data (AEAD) decrypts and
authenticate a plaintext to a ciphtertext . Compatible with IEEE
......@@ -444,26 +440,16 @@ static int ecdh_decrypt_weak_aes_cbc(lua_State *L) {
static int ecdh_aead_decrypt(lua_State *L) {
HERE();
ecdh *e = ecdh_arg(L, 1); SAFE(e);
octet *k = o_arg(L, 2); SAFE(k);
octet *in = o_arg(L, 3); SAFE(in);
octet *iv = o_arg(L, 4); SAFE(iv);
octet *h = o_arg(L, 5); SAFE(h);
octet *t = o_arg(L, 6); SAFE(t);
octet *k = o_arg(L, 1); SAFE(k);
octet *in = o_arg(L, 2); SAFE(in);
octet *iv = o_arg(L, 3); SAFE(iv);
octet *h = o_arg(L, 4); SAFE(h);
// output is padded to next word
octet *out = o_new(L, in->len+16); SAFE(out);
octet *t2 = o_new(L,t->len);
octet *t2 = o_new(L,32); SAFE(t2); // measured empirically is 16
AES_GCM_DECRYPT(k, iv, h, in, out, t2);
HEREoct(out);
if(!OCT_comp(t, t2)) {
error(L, "%s: aead decryption failed.",__func__);
lua_pop(L, 1);
lua_pop(L, 1);
lua_pushboolean(L, 0);
}
lua_pop(L, 1); // t2
return 1;
return 2;
}
/**
......@@ -635,7 +621,6 @@ static int ecdh_random(lua_State *L) {
{"session",ecdh_session}, \
{"public", ecdh_public}, \
{"private", ecdh_private}, \
{"decrypt", ecdh_aead_decrypt}, \
{"encrypt_weak_aes_cbc", ecdh_encrypt_weak_aes_cbc}, \
{"decrypt_weak_aes_cbc", ecdh_decrypt_weak_aes_cbc}, \
{"hash", ecdh_hash}, \
......@@ -649,6 +634,7 @@ int luaopen_ecdh(lua_State *L) {
{"new",lua_new_ecdh},
{"keygen",ecdh_new_keygen},
{"encrypt", ecdh_aead_encrypt},
{"decrypt", ecdh_aead_decrypt},
COMMON_METHODS,
{NULL,NULL}};
const struct luaL_Reg ecdh_methods[] = {
......
......@@ -2,61 +2,42 @@ print()
print '= ELLIPTIC CURVE DIFFIE-HELLMAN ALGORITHM TESTS'
print()
secret = octet.string([[
secret = str([[
Minim quis typewriter ut. Deep v ut man braid neutra culpa in officia consectetur tousled art party stumptown yuccie. Elit lo-fi pour-over woke venmo keffiyeh in normcore enim sunt labore williamsburg flexitarian. Tumblr distillery fanny pack, banjo tacos vaporware keffiyeh.
]])
rng = RNG.new()
function test_curve (name)
print (' ' .. name)
alice = ECDH.new(name)
apk,ask = alice:keygen()
bob = ECDH.new(name)
bpk,bsk = bob:keygen()
-- print 'test both ways of obtaining keys'
-- print 'public:'
-- print(pk:hex())
-- print(alice:public():hex())
-- print 'secret:'
-- print(sk:hex())
-- print(alice:private():hex())
assert(ask:hex() == alice:private():hex()) -- compare strings
assert(ask == alice:private()) -- compare octects
kdf = alice:session(bob)
-- print(ses)
-- print(#ses)
-- ciphermsg = alice:encrypt(ses,octet.from_string(secret))
-- print 'secret:'
-- print(secoctet:string())
-- print 'cipher message:'
-- print(#ciphermsg)
-- decipher = alice:decrypt(ses,ciphermsg)
-- assert(secret == decipher:string())
-- print 'decipher message:'
-- print(decipher:string())
-- print(#decipher)
-- print (' OK')
-- AES-GCM encryption
iv = alice:random(16)
iv = rng:octet(16)
-- iv = octet.hex('00000000000000000000000000000000')
header = octet.string('This is the header!')
ciphermsg, tag = alice:encrypt(kdf, secret, iv, header)
ciphermsg, ck = ECDH.encrypt(kdf, secret, iv, header)
print ('AES-GCM encrypt : ' .. ciphermsg:base64())
print ('AES-GCM tag : ' .. tag:base64())
print ('AES-GCM checksum : ' .. ck:base64())
decipher, ck2 = ECDH.decrypt(kdf, ciphermsg, iv, header)
decipher = alice:decrypt(kdf, ciphermsg, iv, header, tag)
print ('AES-GCM checksum : ' .. ck2:base64())
assert(secret == decipher)
print 'decipher message:'
print(header:string())
print(decipher:string())
print(#decipher)
print (' AES-GCM on ' .. name .. ' OK')
end
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment