Commit ba703036 authored by Jaromil's avatar Jaromil
Browse files

updated iot examples to use strong encryption

various language improvements to simplify packing/unpacking and
validation as well mapping simple conversion functions to table values
parent 66205ff3
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
......@@ -2,37 +2,35 @@
-- key schema
keys_schema = SCHEMA.Record {
community_seckey = SCHEMA.String
}
-- same as output in iotdev-to-dashboard
keys_schema = SCHEMA.Record { community_seckey = SCHEMA.String }
data_schema = SCHEMA.Record {
device_pubkey = SCHEMA.String,
community_id = SCHEMA.String,
payload = SCHEMA.String
text = SCHEMA.string,
iv = SCHEMA.string,
header = SCHEMA.string,
checksum = SCHEMA.string
}
-- same as payload in iotdev-to-dashboard
payload_schema = SCHEMA.Record {
device_id = SCHEMA.String,
data = SCHEMA.String
}
data = read_json(DATA,data_schema)
keys = read_json(KEYS,keys_schema)
data = read_json(DATA) -- TODO: data_schema validation
keys = read_json(KEYS, keys_schema)
header = unpack( base64(data.header) )
dashkey = ECDH.new()
dashkey:private( base64(keys['community_seckey']) )
dashkey:private( base64(keys.community_seckey) )
devkey = ECDH.new()
devkey:public( base64(data['device_pubkey']) )
payload,ck = decrypt(dashkey,
base64( header.device_pubkey ),
map(data, base64))
session = dashkey:session(devkey)
-- validate the payload
validate(payload, payload_schema)
payload =
dashkey:decrypt_weak_aes_cbc(
session,
base64(data['payload']))
-- validate the schema
read_json(payload:string(),payload_schema)
-- payload is already json encoded
print(payload:string())
-- print("Header:")
-- content(unpack(payload.header) )
print(JSON.encode(unpack(payload.text) ))
......@@ -43,15 +43,9 @@ SCHEMA.check(payload, payload_schema)
-- output is the packet, json formatted
-- only the device's public key is transmitted in clear
output = {}
output['device_pubkey'] = devkey:public():base64()
output['community_id'] = keys['community_id']
output['payload'] =
devkey:encrypt_weak_aes_cbc(
session,
str(json.encode(payload))
):base64()
SCHEMA.check(output, output_schema)
-- print out the json packet ready to be sent
print(JSON.encode(output))
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) ) )
......@@ -3,16 +3,20 @@
JSON = require('json')
SCHEMA = require('schema')
S = SCHEMA -- alias
RNG = require('zenroom_rng')
OCTET = require('zenroom_octet')
O = OCTET -- alias
ECDH = require('ecdh')
LAMBDA = require('functional')
L = LAMBDA -- alias
INSIDE = require('inspect')
I = INSIDE -- alias
ECP = require('ecp')
ECP2 = require('ecp2')
BIG = require('zenroom_big')
HASH = require('zenroom_hash')
H = HASH -- alias
MSG = require('msgpack')
-- override type to recognize zenroom's types
......@@ -35,10 +39,13 @@ function content(var)
end
end
-- encrypt with default AES-GCM technique, returns base58 encoded
-- values into a table containing: .text .iv .checksum .header
function encrypt(alice, bob, msg, header)
key = alice:session(bob)
iv = RNG.new():octet(16)
local key = alice:session(bob)
local iv = RNG.new():octet(16)
-- convert strings to octets
local omsg, ohead
if(type(msg) == "string") then
omsg = str(msg) else omsg = msg end
if(type(header) == "string") then
......@@ -51,13 +58,37 @@ 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)
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
-- map values in place
function map(data, fun)
if(type(data) ~= "table") then
error "map: first argument is not a table"
return nil end
if(type(fun) ~= "function") then
error "map: second argument is not a function"
return nil end
out = {}
L.map(data,function(k,v) out[k] = fun(v) end)
return(out)
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
return SCHEMA.CheckSchema(data,schema)
end
function ECP2.G() return ECP2.new() end
function ECP2.generator() return ECP2.new() end
......@@ -96,7 +127,7 @@ function read_json(data, validation)
else
-- operate schema validation if argument is present
if validation then
local err = SCHEMA.CheckSchema(out, validation)
local err = validate(out, validation)
if err then
-- error "read_json: schema validation failed"
error(SCHEMA.FormatOutput(err))
......
local octet = require'octet'
function hex(data) return octet.hex(data) end
function str(data) return octet.string(data) end
function base64(data) return octet.base64(data) end
function base58(data) return octet.base58(data) end
function bin(data) return octet.bin(data) end
-- implicit functions to convert both ways
function hex(data)
if (type(data) == "string") then return octet.hex(data)
elseif(type(data) == "zenroom.octet") then return data:hex()
end
end
function str(data)
if (type(data) == "string") then return octet.string(data)
elseif(type(data) == "zenroom.octet") then return data:string()
end
end
function bin(data)
if (type(data) == "string") then return octet.bin(data)
elseif(type(data) == "zenroom.octet") then return data:bin()
end
end
function base64(data)
if (type(data) == "string") then return octet.base64(data)
elseif(type(data) == "zenroom.octet") then return data:base64()
end
end
function base58(data)
if (type(data) == "string") then return octet.base58(data)
elseif(type(data) == "zenroom.octet") then return data:base58()
end
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
return o:base64()
end
octet.from_base64 = function(s)
if(type(s) == "zenroom.octet") then
error("OCTET.from_base64: argument is already an octet") return end
return O.base64(s)
end
function pack(data)
if (type(data) == "zenroom.octet") then return MSG.pack(data:string()) end
-- else
return MSG.pack(data)
end
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())
elseif(type(data) == "string") then return MSG.unpack(data)
else error("unpack: argument of unknown type") return
end
end
function zero(len) return octet.new(len):zero(len) end
return octet
This diff is collapsed.
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