Skip to content

Commit 610a00b

Browse files
committed
Merge branch 'master' of https://github.com/alaaltoros/SafeTrace
2 parents c89c2db + ae22ca2 commit 610a00b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1015
-1681
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,6 @@ crashlytics-build.properties
116116
fabric.properties
117117

118118
/target
119-
**/*.rs.bk
119+
**/*.rs.bk
120+
121+
enigma-types.h

.gitmodules

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +0,0 @@
1-
[submodule "enclave/incubator-teaclave-sgx-sdk"]
2-
path = enclave/incubator-teaclave-sgx-sdk
3-
url = git@github.com:apache/incubator-teaclave-sgx-sdk.git
4-
branch = v1.1.1-testing

api-server/README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,20 @@ The geolocation + datetime data is to be provided in an array in JSON format as
6969
"lat": 40.757339,
7070
"lng": -73.985992,
7171
"startTS": 1583064000,
72-
"endTS": 1583067600
72+
"endTS": 1583067600,
73+
"testResult": false,
7374
},
7475
{
7576
"lat": 40.793840,
7677
"lng": -73.956900,
7778
"startTS": 1583150400,
78-
"endTS": 1583154000
79+
"endTS": 1583154000,
80+
"testResult": true,
7981
},
8082

8183
]
8284
```
83-
In the example above, the first datapoint is for Times Square in New York City on March 1st, 2020 from 12pm to 1pm, whereas the second data point is somewhere in Central Park the following day March 2nd, 2020 from 12pm to 1pm.
85+
In the example above, the first datapoint is for Times Square in New York City on March 1st, 2020 from 12pm to 1pm, whereas the second data point is somewhere in Central Park the following day March 2nd, 2020 from 12pm to 1pm. This user did not test positive for Coronavirus the first day, but he tested positive the following day.
8486

8587

8688
# Installation

client/README.md

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# Client interface to SafeTrace
2+
3+
This folder contains sample Javascript code to interface with the enclave via a JSON RPC Server. At the time of this writing
4+
there is a live instance of the enclave + JSON RPC Server that you can interact with at https://safetrace.enigma.co.
5+
6+
If you visit https://safetrace.enigma.co with your browser, you'll get a `405 Error: Method not allowed` because it does not
7+
accept GET requests like the ones that regular browsers make. Instead, you have to POST properly formatted JSON-RPC requests:
8+
9+
The client code in this folder is meant to be used as a reference and adapted for your own client. It has not been packaged
10+
as a library yet, but you should be able to copy/paste the relevant functions into your code. You can run:
11+
12+
```bash
13+
node index.js
14+
```
15+
16+
to see an example of working code that submits data for two users into the enclave, and later queries for a match between the
17+
two datasets, returning one match.
18+
19+
Below are included example requests and responses for each endpoint using [curl](https://curl.haxx.se/) from the command line.
20+
21+
## getEnclaveReport
22+
23+
* Request
24+
25+
```bash
26+
$ curl -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "id":1, "method":"getEnclaveReport", "params": {}}' https://safetrace.enigma.co
27+
```
28+
29+
* Response
30+
```bash
31+
{
32+
"jsonrpc":"2.0",
33+
"id":1,
34+
"result": {
35+
"id":"ed88a0a1f7",
36+
"type":"GetEnclaveReport",
37+
"result": {
38+
"signingKey":"5b4a6ba4809d94f3b0cccbaf43e17dea5d3bdba8",
39+
"report":"7b226964223a22353239313235363835323730343032363337353238343539303132303
40+
9363930353931343134222c2274696d657374616d70223a22323032302d30342d30315431343a3236
41+
3a30322e343737353631222c2276657273696f6e223a332c22697376456e636c61766551756f74655
42+
37461747573223a2247524f55505f4f55545f4f465f44415445222c22706c6174666f726d496e666f
43+
426c6f62223a223135303230303635303430303037303030303044304430323034303130313033303
44+
030303030303030303030303030303030304130303030304230303030303030323030303030303030
45+
303030303041433742453139303731323337303543343031394435363630433744443835313733313
46+
737304138343538414441344332433445354441334545363230463932433139424538383639434441
47+
353237374141333537353737363232304246323544303332313631383038443146463738334238393
48+
14532394434303238383344393534222c22697376456e636c61766551756f7465426f6479223a2241
49+
674141414d634b414141494141634141414141414c417a58394f38484d715067453635696d5167575
50+
331314d722f377379626b4251555851493072707947694167372f42502f2f41414141414141414141
51+
414141414141414141414141414141414141414141414141414141414141414141414141414141414
52+
14141414141427741414141414141414148414141414141414141466d644f7251736445764a434665
53+
624b7232454536637638444d5a314d64492b4b6f7858517a4956385a4941414141414141414141414
54+
1414141414141414141414141414141414141414141414141414141414141434431786e6e6665724b
55+
4648443275765971545864444138695a32326b434435787737683338434d664f6e674141414141414
56+
141414141414141414141414141414141414141414141414141414141414141414141414141414141
57+
414141414141414141414141414141414141414141414141414141414141414141414141414141414
58+
141414141414141414141414141414141414141414141414141414141414141414141414141414141
59+
414141414141414141414141414141414141414141414141414141414141414141414141414141414
60+
141414141414141414141414141414141414141414141414141414141414141414141414141414141
61+
4141414262536d756b674a32553837444d79363944345833715854766271414141414141414141414
62+
141414141414141414141414141414141414141414141414141414141414141414141414141414141
63+
4141414141414141227d",
64+
"signature":"981fc554b5a92149c0b5cfc07ae8c82cdfa213b1405ee867f2dce49ff77f219c8419
65+
3fe67363255cf371a4404b5f62cf85f06361fec00327409e302973a1043d17b76b0ef0b32f95974d4
66+
e612702c1d618f3035a37fa56883a2bb0ee485e8c3b7f85d1305be58490c393de178cdb2a91006b26
67+
6c3225ec3b244c2373bbc2c5e206d372d754142527e5c75893ebb2384d3f3844ca63d91367833cce8
68+
031b6f8f8666f9e93bf5897fc9248839e51cff80f0c455ea217a51befbe4942ea077bc4cf29e87693
69+
3d170778285fa043fd91fb9391b340a607d47a6a0fbee9c5d7ee1818b4899e41020b3de91e5b1b33f
70+
abc36449b35f22a403635b6ab9e429cdc542654"
71+
}
72+
}
73+
}
74+
```
75+
76+
## newTaskEncryptionKey
77+
78+
* Request
79+
80+
```bash
81+
{"jsonrpc":"2.0","id":1,"result":{"id":"5708a053c9","type":"NewTaskEncryptionKey","result":{"taskPubKey":"1a75beafbc32c5a4ba881dcca795fb0f87b4b473e5689592db942366b763d52466922a7103a6975be699cf6f3b499294f5dd92cbe5a2e15470dd03bc971c770d","sig":"1994e259d3befd9fab06c6b9f00c4f892bb6c6d54f6449ccd0b42df79ceeb7ae057aa85b3fe2d070c21775a5cac60274bf1ac8e3c0e104872601a136c978deeb1b"}}}
82+
```
83+
84+
* Response
85+
86+
```json
87+
{
88+
"jsonrpc":"2.0",
89+
"id":1,
90+
"result": {
91+
"id":"5708a053c9",
92+
"type":"NewTaskEncryptionKey",
93+
"result": {
94+
"taskPubKey":"1a75beafbc32c5a4ba881dcca795fb0f87b4b473e5689592db942366b763d52466922a7
95+
103a6975be699cf6f3b499294f5dd92cbe5a2e15470dd03bc971c770d","sig":"1994e259d3befd9fab0
96+
6c6b9f00c4f892bb6c6d54f6449ccd0b42df79ceeb7ae057aa85b3fe2d070c21775a5cac60274bf1ac8e3
97+
c0e104872601a136c978deeb1b"
98+
}
99+
}
100+
}
101+
```
102+
103+
## newTaskEncryptionKey
104+
105+
* Request
106+
107+
```bash
108+
curl -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "id":1, "method":"addPersonalData", "params": {"encryptedUserId":"15806c56ed8fb37a9a45c8c3efa227a98a406c5787bf3ff90f0c89fde8ad3d6fdd", "encryptedData": "85d6f1e75cd29d761e291f9c8fd3e8dc5ac289df327960a39938a0934bcaee41f7b17c61ec450b7a8fc01474e9495d12d6d07754d01217c88774b678c03032e3085155ba65f9cf9617de36a538c30c6664e05c3f07f812a3cf10b23ca90fc765912f82bfddd864ba4d4f7e6ab41c11f6d43006b2aee150ddef72215f2baeadd1957fdeac9d2f582e779e79cabc604a3ba50f9c870952239ee4a2437d54952f891090a677b3c38972a2982a739bd43c911c14f67c80cd53b34001285a5091c4525f1d68cef4d89ebb805181a3a11d8c52e57ba4e802e7", "userPubKey": "cc955077ff7aeb67e544bb0dfad0a5ac1d3117f4115c528d38da9c2337cb033ec08f1d12a580d2ccfed02144e70d961c72e28e92ef48b9056c08137918c5ab2d"}}' https://safetrace.enigma.co
109+
```
110+
111+
*NOTE: The parameters `encryptedUserId` and `encryptedData` are encrypted with an ephemeral Diffie-Hellman key, so you need
112+
to run the method `newTaskEncryptionKey` everytime to be able to derive that key, and use it to encrypt these parameters. This
113+
also means that the encrypted values will change every time.*
114+
115+
* Response
116+
117+
```json
118+
{
119+
"jsonrpc":"2.0",
120+
"id":1,
121+
"result": {
122+
"id":"eb2f102370",
123+
"type":"AddPersonalData",
124+
"addPersonalData": {
125+
"status":0
126+
}
127+
}
128+
}
129+
```
130+
131+
## findMatch
132+
133+
* Request
134+
135+
```bash
136+
curl -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "id":1, "method":"findMatch", "params": {"encryptedUserId":"15806c56ed8fb37a9a45c8c3efa227a98a406c5787bf3ff90f0c89fde8ad3d6fdd", "userPubKey": "cc955077ff7aeb67e544bb0dfad0a5ac1d3117f4115c528d38da9c2337cb033ec08f1d12a580d2ccfed02144e70d961c72e28e92ef48b9056c08137918c5ab2d"}}' https://safetrace.enigma.co
137+
```
138+
139+
* Response
140+
141+
```json
142+
{
143+
"jsonrpc":"2.0",
144+
"id":1,
145+
"result": {
146+
"id": "d23d723a6a",
147+
"type": "FindMatch",
148+
"findMatch": {
149+
"status": 0,
150+
"encryptedOutput": "45c90f568a5bb096fc39ae8429c3e05cd29f40c30c0f89e8c0395cf431f5c2934d
151+
232cff4eb3c27b18e9704790e65b0bdecdcd02d6e8b5b668991d3e53b804c23b24c7f5d9e5d1a2c322036a
152+
3068991ddc0ebd7a56ddd1b90a7d857c790844f5233b22aad906bea938c77d24882b1043d2e84b2c8d959d
153+
d0"
154+
}
155+
}
156+
}
157+
```
158+
159+
*NOTE: Analogously to the previous method, the input and output from this method are encrypted, which you can encrypt and
160+
decrypt with the key derived through Diffie-Hellman. Again, the command and output included here are for reference
161+
purposes, but you will not be able to reproduce verbatim. Instead, you have to run `newTaskEncryptionKey` and use that
162+
for encryption and decryption.*
163+

client/data.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
module.exports.DataUser1 = [
2+
{
3+
"lat": 40.757339,
4+
"lng": -73.985992,
5+
"startTS": 1583064001,
6+
"endTS": 1583067601,
7+
"testResult": false,
8+
},
9+
{
10+
"lat": 40.793840,
11+
"lng": -73.956900,
12+
"startTS": 1583150401,
13+
"endTS": 1583154001,
14+
"testResult": false,
15+
},
16+
]
17+
18+
module.exports.DataUser2 = [
19+
{
20+
"lat": 41.757339,
21+
"lng": -73.985992,
22+
"startTS": 1583064000,
23+
"endTS": 1583067600,
24+
"testResult": true,
25+
},
26+
{
27+
"lat": 40.793840,
28+
"lng": -73.956900,
29+
"startTS": 1583150400,
30+
"endTS": 1583154000,
31+
"testResult": true,
32+
},
33+
]

client/index.js

Lines changed: 80 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const EthCrypto = require('eth-crypto');
44
const jaysonBrowserClient = require('jayson/lib/client/browser');
55
const enigma = require('enigma-js/lib/enigma-js.node');
66
const web3utils = require('web3-utils');
7+
const data = require('./data.js');
78

89

910
const JSON_RPC_Server='http://localhost:8080';
@@ -47,15 +48,55 @@ function getClientKeys(seed='') {
4748
return {privateKey, publicKey};
4849
}
4950

50-
async function add_data(userId, data){
51+
async function getEncryptionKey(publicKey) {
52+
const getEncryptionKeyResult = await new Promise((resolve, reject) => {
53+
client.request('newTaskEncryptionKey', {userPubKey: publicKey},
54+
(err, response) => {
55+
if (err) {
56+
reject(err);
57+
return;
58+
}
59+
resolve(response);
60+
});
61+
});
62+
63+
const {result, id} = getEncryptionKeyResult;
64+
const {taskPubKey, sig} = result;
65+
// ToDo: verify signature
66+
return taskPubKey;
67+
}
68+
69+
function encrypt(taskPubKey, privateKey, variable){
70+
// Generate derived key from enclave public encryption key and user's private key
71+
const derivedKey = enigma.utils.getDerivedKey(taskPubKey, privateKey);
72+
// Encrypt function and ABI-encoded args
73+
return enigma.utils.encryptMessage(derivedKey, variable);
74+
}
75+
76+
function decrypt(taskPubKey, privateKey, enc_variable){
77+
// Generate derived key from enclave public encryption key and user's private key
78+
const derivedKey = enigma.utils.getDerivedKey(taskPubKey, privateKey);
79+
// Decrypt function and ABI-encoded args
80+
let outputHex = enigma.utils.decryptMessage(derivedKey, enc_variable);
81+
let outputStr = enigma.utils.hexToAscii(outputHex);
82+
return JSON.parse(outputStr);
83+
}
5184

52-
let {publicKey, privateKey} = getClientKeys();
5385

54-
console.log(publicKey)
86+
async function addData(userId, data){
87+
88+
let {publicKey, privateKey} = getClientKeys();
5589

5690
try {
57-
const getWorkerEncryptionKeyResult = await new Promise((resolve, reject) => {
58-
client.request('newTaskEncryptionKey', {userPubKey: publicKey},
91+
let taskPubKey = await getEncryptionKey(publicKey);
92+
let encryptedUserId = encrypt(taskPubKey, privateKey, userId);
93+
let encryptedData = encrypt(taskPubKey, privateKey, data);
94+
95+
const addPersonalDataResult = await new Promise((resolve, reject) => {
96+
client.request('addPersonalData', {
97+
encryptedUserId: encryptedUserId,
98+
encryptedData: encryptedData,
99+
userPubKey: publicKey},
59100
(err, response) => {
60101
if (err) {
61102
reject(err);
@@ -65,28 +106,30 @@ async function add_data(userId, data){
65106
});
66107
});
67108

68-
const {result, id} = getWorkerEncryptionKeyResult;
69-
const {taskPubKey, sig} = result;
70-
// ToDo: verify signature
109+
const {addPersonalData} = addPersonalDataResult;
71110

72-
// Generate derived key from worker's encryption key and user's private key
73-
const derivedKey = enigma.utils.getDerivedKey(taskPubKey, privateKey);
74-
// Encrypt function and ABI-encoded args
75-
const encryptedUserId = enigma.utils.encryptMessage(derivedKey, userId);
76-
const encryptedData = enigma.utils.encryptMessage(derivedKey, data);
77-
const msg = web3utils.soliditySha3(
78-
{t: 'bytes', v: encryptedUserId},
79-
{t: 'bytes', v: encryptedData},
80-
);
111+
if(addPersonalData.status == 0) {
112+
console.log('Personal data added successfully to the enclave.');
113+
} else {
114+
console.log('Something went wrong. Time to debug...')
115+
}
116+
} catch(err) {
117+
console.log(err);
118+
// Or throw an error
119+
}
120+
}
81121

82-
// const a = getClientKeys();
122+
async function findMatch(userId){
83123

84-
// console.log(a.publicKey);
124+
let {publicKey, privateKey} = getClientKeys();
85125

86-
const addPersonalDataResult = await new Promise((resolve, reject) => {
87-
client.request('addPersonalData', {
126+
try {
127+
let taskPubKey = await getEncryptionKey(publicKey);
128+
let encryptedUserId = encrypt(taskPubKey, privateKey, userId);
129+
130+
const findMatchResult = await new Promise((resolve, reject) => {
131+
client.request('findMatch', {
88132
encryptedUserId: encryptedUserId,
89-
encryptedData: encryptedData,
90133
userPubKey: publicKey},
91134
(err, response) => {
92135
if (err) {
@@ -97,26 +140,28 @@ async function add_data(userId, data){
97140
});
98141
});
99142

100-
const {addPersonalData} = addPersonalDataResult;
143+
if(findMatchResult.findMatch.status == 0) {
144+
console.log('Find Match operation successful');
101145

102-
if(addPersonalData.status == 0) {
103-
console.log('Personal data added successfully to the enclave.');
146+
let output = decrypt(taskPubKey, privateKey, findMatchResult.findMatch.encryptedOutput);
147+
148+
if(output.length){
149+
console.log('Find matches:');
150+
console.log(output);
151+
} else {
152+
console.log('No matches');
153+
}
104154
} else {
105155
console.log('Something went wrong. Time to debug...')
106156
}
107-
108-
109157
} catch(err) {
110-
console.log(err);
111-
// Or Throw an error
158+
console.log(err);
159+
// Or throw an error
112160
}
113-
114161
}
115162

116-
add_data('myUserId', 'myDataString')
117-
118-
119-
120-
let seed = '';
121163

164+
addData('user1', JSON.stringify(data.DataUser1));
165+
addData('user2', JSON.stringify(data.DataUser2));
122166

167+
findMatch('user1');

0 commit comments

Comments
 (0)