Commit 8b6372e4 authored by Jaromil's avatar Jaromil
Browse files

various improvements to higher level de/crypt api and type checks

update also integration tests and iot examples
parent ba703036
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
......@@ -2,6 +2,9 @@
-- defines data validation shcemas that can be used on both ends
-- complementary to other script for reception
-- curve used
curve = 'ed25519'
-- data schemas
keys_schema = SCHEMA.Record {
device_id = SCHEMA.String,
......@@ -21,31 +24,38 @@ output_schema = SCHEMA.Record {
-- import and validate keys
keys = read_json(KEYS, keys_schema)
-- import community's public key
comkey = ECDH.new()
comkey:public(
base64(keys['community_pubkey']))
-- generate a new device keypair every time
-- this could be optimised by creating keys onetime at first run
-- or temporarily, i.e: every day or every hour
devkey = ECDH.new()
devkey:keygen()
devkey = ECDH.keygen(curve)
-- compute the session key using private/public keys
-- it may change to use random, but then we need a session channel
session = devkey:session(comkey)
-- payload is a nested json structure to be encrypted
payload = {}
payload['device_id'] = keys['device_id']
payload['data'] = DATA
SCHEMA.check(payload, payload_schema)
validate(payload, payload_schema)
-- output is the packet, json formatted
-- only the device's public key is transmitted in clear
-- The device's public key, the 'community_id' and the encryption
-- curve type are transmitted in clear inside the header, which is
-- authenticated (AEAD)
header = {}
header['device_pubkey'] = devkey:public():base64()
header['community_id'] = keys['community_id']
-- content( header )
output = encrypt(devkey, comkey, MSG.pack(payload), MSG.pack(header))
print( JSON.encode( map(output, base64) ) )
-- content( header ) -- uncomment for debug
-- The output is a table with crypto contents which is standard for
-- zenroom's functions encrypt/decrypt: .checksum .header .iv .text
output = encrypt(devkey,
base64(keys.community_pubkey),
pack(payload), pack(header))
output = map(output, O.to_base64)
output.zenroom = VERSION
output.encoding = 'base64'
output.curve = curve
-- content(output) -- uncomment for debug
print( JSON.encode( output ) ) -- map(output, base64) ) )
......@@ -85,7 +85,9 @@ end
-- validate against a schema
function validate(data, schema)
if(type(data) ~= "table") then
error("validate: argument is not a table: cannot process schema validation") return end
error("validate: first argument is not a table, cannot process validation") return end
if(type(schema) ~= "function") then
error("validate: second argument is not a function, invalid schema") return end
return SCHEMA.CheckSchema(data,schema)
end
......
local octet = require'octet'
function zentype(data)
if(type(data):sub(1,7) == "zenroom") then
return true
else return false end
end
-- implicit functions to convert both ways
function hex(data)
if (type(data) == "string") then return octet.hex(data)
......@@ -17,8 +23,10 @@ function bin(data)
end
end
function base64(data)
if (type(data) == "string") then return octet.base64(data)
elseif(type(data) == "zenroom.octet") then return data:base64()
if(type(data) == "zenroom.octet") then return data:base64()
elseif zentype(data) then return(data) -- skip other zenroom types
elseif not O.is_base64(data) then return(data) -- skip non base64
elseif(type(data) == "string") then return octet.base64(data)
end
end
function base58(data)
......@@ -29,8 +37,11 @@ end
-- explicit functions to import/export octets
octet.to_base64 = function(o)
if(type(o) ~= "zenroom.octet") then
error("OCTET.to_base64: argument is not an octet") return end
if(type(o) == "string") then
if octet.is_base64(o) then return(o) -- skip what is already base64
else return octet.string(o):base64() end
elseif(type(o) ~= "zenroom.octet") then
error("OCTET.to_base64: invalid argument type for conversion (%s)",type(o)) return end
return o:base64()
end
octet.from_base64 = function(s)
......@@ -39,11 +50,14 @@ octet.from_base64 = function(s)
return O.base64(s)
end
-- msgpack returning octets
function pack(data)
if (type(data) == "zenroom.octet") then return MSG.pack(data:string()) end
if (type(data) == "zenroom.octet") then return str(MSG.pack(data:string())) end
-- else
return MSG.pack(data)
return str(MSG.pack(data))
end
-- msgunpack returning lua's tables or single types
function unpack(data)
if (type(data) == "table") then error("unpack: argument is already a table") return
elseif(type(data) == "zenroom.octet") then return MSG.unpack(data:string())
......
This diff is collapsed.
......@@ -70,14 +70,14 @@ static int getlen_base58(int len) { return( ((3+(5*(len/3))) & ~0x03)+0x0f ); }
// assumes null terminated string
// returns 0 if not base else length of base encoded string
int is_base64(const char *in) {
if(!in) { ERROR(); return 0; }
if(!in) { return 0; }
int c;
for(c=0; in[c]!='\0'; c++) {
if (!(isalnum(in[c])
|| '+' == in[c]
|| '=' == in[c]
|| '/' == in[c])) {
ERROR(); return 0; }
return 0; }
}
return c;
}
......@@ -218,6 +218,51 @@ static int xor_n(lua_State *L) {
return 1;
}
static int lua_is_base64(lua_State *L) {
const char *s = lua_tostring(L, 1);
luaL_argcheck(L, s != NULL, 1, "string expected");
int len = is_base64(s);
if(!len) {
lua_pushboolean(L, 0);
func(L, "string is not a valid base64 sequence");
return 1; }
lua_pushboolean(L, 1);
return 1;
}
static int lua_is_base58(lua_State *L) {
const char *s = lua_tostring(L, 1);
luaL_argcheck(L, s != NULL, 1, "string expected");
int len = is_base58(s);
if(!len) {
lua_pushboolean(L, 0);
func(L, "string is not a valid base58 sequence");
return 1; }
lua_pushboolean(L, 1);
return 1;
}
static int lua_is_hex(lua_State *L) {
const char *s = lua_tostring(L, 1);
luaL_argcheck(L, s != NULL, 1, "string expected");
int len = is_hex(s);
if(!len) {
lua_pushboolean(L, 0);
func(L, "string is not a valid hex sequence");
return 1; }
lua_pushboolean(L, 1);
return 1;
}
static int lua_is_bin(lua_State *L) {
const char *s = lua_tostring(L, 1);
luaL_argcheck(L, s != NULL, 1, "string expected");
int len = is_bin(s);
if(!len) {
lua_pushboolean(L, 0);
func(L, "string is not a valid binary sequence");
return 1; }
lua_pushboolean(L, 1);
return 1;
}
static int from_base64(lua_State *L) {
const char *s = lua_tostring(L, 1);
luaL_argcheck(L, s != NULL, 1, "base64 string expected");
......@@ -593,9 +638,14 @@ int luaopen_octet(lua_State *L) {
{"new", newoctet},
{"concat",concat_n},
{"xor", xor_n},
{"is_base64", lua_is_base64},
{"is_base58", lua_is_base58},
{"is_hex", lua_is_hex},
{"is_bin", lua_is_bin},
{"base64",from_base64},
{"base58",from_base58},
{"string",from_string},
{"str", from_string},
{"hex", from_hex},
{"bin", from_bin},
{NULL,NULL}
......
......@@ -34,7 +34,7 @@ EOF
done
}
encrypt() {
test_encrypt() {
from=$1
to=$2
cat <<EOF | $zen -k $tmp/$from-keys.json -a $tmp/$to-envelop.json \
......@@ -45,18 +45,12 @@ recipient = ECDH.new('$curve')
recipient:public(hex(data['pubkey']))
sender = ECDH.new('$curve')
sender:private(hex(keys['private']))
k = sender:session(recipient)
iv = sender:random(16)
enc,tag = sender:encrypt(k,str(data['message']),iv,str('header'))
print(JSON.encode({
iv=iv:hex(),
tag=tag:hex(),
encmsg=enc:hex(),
pubkey=keys['public']}))
enc,tag = encrypt(sender,recipient,str(data['message']),sender:public())
print(JSON.encode(map(enc,hex)))
EOF
}
decrypt() {
test_decrypt() {
from=$1
to=$2
cat <<EOF | $zen -k $tmp/$to-keys.json -a $tmp/from-$from-to-$to-cryptomsg.json
......@@ -65,12 +59,9 @@ data = JSON.decode(DATA)
recipient = ECDH.new('$curve')
recipient:private(hex(keys['private']))
sender = ECDH.new('$curve')
sender:public(hex(data['pubkey']))
k = recipient:session(sender)
iv = hex(data['iv'])
tag = hex(data['tag'])
dec = recipient:decrypt(k,hex(data['encmsg']),iv,str('header'), tag)
print(dec:string())
sender:public(hex(data['header']))
dec = decrypt(recipient,sender,map(data,hex))
print(dec.text:string())
EOF
}
......@@ -83,7 +74,7 @@ for p in $ppl; do
from=$p
to=$pp
print "ENCRYPT $from -> $to"
encrypt $p $pp
test_encrypt $p $pp
cat $tmp/from-$from-to-$to-cryptomsg.json | json_pp
done
done
......@@ -94,7 +85,7 @@ for p in $ppl; do
from=$pp
to=$p
print "DECRYPT $from -> $to"
res=`decrypt $from $to`
res=`test_decrypt $from $to`
if [[ "$secret" != "$res" ]]; then
print - "ERROR in integration ecdh test: $tmp"
print - "INPUT keys:"
......
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