Please follow https://github.com/Open-QKD-Network/qkd-net/blob/disable-spring-auth/README.md branch to get start.
The OpenQKDNetwork project aims to provide a reference implementation of a 4-layer Quantum Key Distribution (QKD) network solution. Two sample applications are also provided to show case how an application can fetch and make use of the keys generated by a QKD network.
A very flexible layered approach has been adopted adhering to SOLID principles.
Microservice based architecture approach has been taken for software design and and implementation. One benefit of it is to have flexibility in production deployment.
Complied and tested successfully on Ubuntu 16.04 and Linux Mint 18.3 with Java 8. Changes will be needed for working in other environments (OS, Java version, etc.)
The fourth layer is the User (or Host) Layer, which belongs to the client of this system, and thus is beyond the scope of this project. QKD devices belong to the QLL, and may need a vendor specific glue layer of code in QLL to make it work with the other layers, before any international standard (e.g. ETSI, ITU-T) on the interface is widely adopted.
The KMS layer provides an application interface for fetching keys for symmetric cryptography. The details of how the key is used belong to the applications at the User layer.
KMS layer comprises the following microservices:
QNL is the core compoent to extend the QKD technology from point-to-point to network level. It is the middle layer sandwiched between KMS layer and QLL (Quantum Link Layer). QNL provides key blocks to KMS after fetching it from QLL. Thus, it keeps the KMS layer QKD-technology-agnostic.
QNL currently consists of a single microservice:
Key Routing Service contains a routing modual and key relaying modual, to react to the QKD network topology dynamics automatically and in a timely fashion. It not only pushes key blocks to KMS QNL service for KMS service, but also responds to pull requests for key blocks directly from KMS service.
Ideally, QLL consists of working QKD devices. A QLL simulator is provided in this project for situations where real QKD devices based links are unavailable, e.g., a planned satellite based QKD link between two nodes that are geographically far away.
Install following before proceeding. Make sure the executables are in system path.
On a Linux(Ubuntu) system apt-get can be used to install the programs.
On two Linux (Ubuntu) systems, please follow the steps below to get a two nodes system running quickly.
Assume IP address of A is 192.168.2.207 and IP address of B is 192.168.2.212
On Ubuntu A
cd qkd-net
cd kms
./scripts/build
rm ~/.qkd (Step 6 generates ~/.qkd directory)
cd ..
tar xvf qkd-kaiduan-a.tar
mv .qkd ~/
On Ubuntu A, changes IP address of B in the ~/.qkd/qnl/routes.json.
{
"adjacent": {
"B": "192.168.2.212"
},
"nonAdjacent": {
}
}
Run commands 3 to 8 on Ubuntu B
tar xvf qkd-kaiduan-b.tar
mv .qkd ~/
On Ubuntu B, changes IP address of A in the ~/.qkd/qnl/routes.json
{
"adjacent": {
"A": "192.168.2.207"
},
"nonAdjacent": {
}
}
On Ubuntu A, cd qkd-net/kms, run command ./scripts/run
On Ubuntu B, cd qkd-net/kms, run command ./scripts/run
We will run tls-demo application alice on Ubuntu A and run bob on Ubuntu B
On Ubuntu A, cd ../applications/tls-demo/, run make command
On Ubuntu B, cd ../applications/tls-demo/, change function static char site_id(char ip) in src/bob.c as below, and run make
static char* site_id(char* ip) {
if (strcmp(ip, "192.168.2.212") == 0)
return "B";
else if (strcmp(ip, "192.168.2.207") == 0)
return "A";
else
return "C";
}
On Ubuntu B, run command ./bob -b 10446
On Ubuntu A, run command ./alice -i 192.168.2.212 -b 10446 -f ./data/whale.mp3
On Ubuntu A, you should see something like below
-- Successfully conected to Bob
-- Received PSK identity hint 'B c5460688-c6ff-4e0e-8c7c-7c82d18ce0cc 0'
HTTP-FETCH-REQUEST,url:http://localhost:9992/uaa/oauth/token,header:authorization:Basic aHRtbDU6cGFzc3dvcmQ=,post:password=bot&client_secret=password&client=html5&username=pwebb&grant_type=password&scope=openid
HTTP-FETCH-RESPONSE:{"access_token":"e5d40647-81c6-467b-98f2-54fe2e9086d5","token_type":"bearer","refresh_token":"fd26f0a0-8c30-43af-beae-700147bed","expires_in":43199,"scope":"openid"}
post String siteid=B&index=0&blockid=c5460688-c6ff-4e0e-8c7c-7c82d18ce0cc
HTTP-FETCH-REQUEST,url:http://localhost:8095/api/getkey,header:Authorization: Bearer e5d40647-81c6-467b-98f2-54fe2e9086d5,post:siteid=B&index=0&blockid=c5460688-c6ff-4e0e-8c7c-7c82d18ce0cc
HTTP-FETCH-RESPONSE:{"index":0,"hexKey":"e27444fab22da64bb65dd108adc84f12a2a94a0fd5129e37df44025ca1622942","blockId":"c5460688-c6ff-4e0e-8c7c-7c82d18ce0cc"}
index: 0
key: e27444fab22da64bb65dd108adc84f12a2a94a0fd5129e37df44025ca1622942
blockId: c5460688-c6ff-4e0e-8c7c-7c82d18ce0cc
On Ubuntu B, file is received and saved in bobdemo and should see something like below
Bob is listening for incomming connections on port 10446 ...
HTTP-FETCH-REQUEST, url:http://localhost:9992/uaa/oauth/token,header:authorization:Basic aHRtbDU6cGFzc3dvcmQ=,post:password=bot&client_secret=password&client=html5&ername=pwebb&grant_type=password&scope=openid
HTTP-FETCH-RESPONSE:{"access_token":"24b4b875-1146-406d-84cf-4379a4da2b96","token_type":"bearer","refresh_token":"52f93b1b-b642-4884-96e3-0186aaf69381","expires_in":43199,"scope":"openid"}
key_post : siteid=A
HTTP-FETCH-REQUEST, url:http://localhost:8095/api/newkey,header:Authorization: Bearer 24b4b875-1146-406d-84cf-4379a4da2b96,post:siteid=A
HTTP-FETCH-RESPONSE:{"index":0,"hexKey":"e27444fab22da64bb65dd108adc84f12a2a94a0fd5129e37df44025ca1622942","blockId":"c5460688-c6ff-4e0e-8c7c-7c82d18ce0cc"}
index: 0
key: e27444fab22da64bb65dd108adc84f12a2a94a0fd5129e37df44025ca1622942
blockId: c5460688-c6ff-4e0e-8c7c-7c82d18ce0cc
SSL-Server-PSK-Hint:B c5460688-c6ff-4e0e-8c7c-7c82d18ce0cc 0
-- SHA1 of the received key : 8F23A277146D8DB4F9C4B6F320BE5D772396CD10
-- TLS Closed
-- Connection Closed
-- Accept Connection
For 3 nodes system, extract qkd-kaiduan-c.tar on Ubuntu, assume we will run alice on A and bob on C, the network topology looks below,
A <----> B <---> C
Assume IP address of C is 192.168.2.235, Add C to B's adjacent nodes
{
"adjacent": {
"A": "192.168.2.207",
"C": "192.168.2.235"
},
"nonAdjacent": {
}
}
As this is a multi-layer distributed system, a few configuration files are used to facilitate the deployment for different nodes (or sites). They need to be carefully checked before running/testing the system.
Sample applications provided (qTox and tls-demo) require kms.conf to be present under the $HOME/.qkd directory.
This file can be manually created by puting following entries:
http://localhost:9992/uaa/oauth/token
http://localhost:8095/api/newkey
http://localhost:8095/api/getkey
C
Depending on where the KMS node is deployed, localhost
can be replaced by the IP address of
the host running the KMS layer.
The last line represents the KMS site id, which should be updated with the
correct site id. Above is just an example.
config-repo directory under $HOME/
contains all the configuration property
files required by all the microservices.
All the files reside under $HOME/config-repo
and checked in a local git repository.
This file is located under
Explanation of site specific configuration properties used by KMS service:
//Number of keys per block
kms.keys.blocksize=1024
//Size of a key in bytes
kms.keys.bytesize=32
//Top level location for locating key blocks
kms.keys.dir=${HOME}/.qkd/kms/pools/
//IP address of the host where key routing service is running
qnl.ip=localhost
//Port on which key routing service is listening for key block requests
qnl.port=9292
This file is copied from
Expalantion of configuration properties used by KMS QNL service:
//Port on which KMS QNL service is listening
port: 9393
//Size of a key in bytes
keyByteSz: 32
//Number of keys in a block. Key routing service provides KMS keys in blocks of size
keyBlockSz: 1024
//Location where KMS QNL service puts the pushed key blocks from key-routing service
poolLoc: kms/pools
This file is copied from $HOME/.qkd/qnl
.
Topology information is contained in route.json
.
This information is populated manually for adjacent (neighboring) nodes, while the non-adjacent nodes will be discovered by the routing module. Adjacent nodes section contains the name of the node as key and it's IP address as the value.
Example route.json
file for a QNL Node "B":
{
"adjacent": {
"A": "192.168.1.101",
"C": "192.168.1.103"
},
"nonAdjacent": {
}
}
This file is copied from
Brief explanation of various properties is given with the following example file:
//Base location for finding other paths and configuration files.
base: .qkd/qnl
//Route configuration file name.
routeConfigLoc: routes.json
//Location where QLL puts the key blocks for QNL to carve out key blocks for KMS.
qnlSiteKeyLoc: qll/keys
//Each site has an identifier uniquely identifying that site.
siteId: A
//Port on which key routing service is listening for key block requests.
port: 9292
//Size of a key in bytes.
keyBytesSz: 32
//Number of keys in a block. Key routing service provides KMS keys in blocks of size.
keyBlockSz: 1024
//Key routing service expects QLL to provide keys in blocks of qllBlockSz.
qllBlockSz: 4096
//IP address of the host running KMS QNL service.
kmsIP: localhost
//Port on which KMS QNL service is listening.
kmsPort: 9393
//One Time Key configuration.
OTPConfig:
//Same as above
keyBlockSz: 1024
//Location of the OTP key block.
keyLoc: otp/keys
For building the services,
cd <top level director>/qkd-net/kms
./scripts/build
For running the services
cd <top level director>/qkd-net/kms
./scripts/run
Open a browser, check http://localhost:8761/
Since OAuth is enabled, first access token is fetched:
curl -X POST -H"authorization:Basic aHRtbDU6cGFzc3dvcmQ=" -F"password=bot" -F"client_secret=password" -F"client=html5" -F"username=pwebb" -F"grant_type=password" -F"scope=openid" http://localhost:9992/uaa/oauth/token | jq
Sample output:
{
"access_token": "291a94d5-d624-4269-a2bb-07db62130bb3",
"token_type": "bearer",
"refresh_token": "99d4cdd9-641e-4290-ac4b-865b1d7068a6",
"expires_in": 43017,
"scope": "openid"
}
Once the access token is available, different endpoints can be accessed.
Assuming we have 2 sites setup with siteid as A and B repsectively. Some application from site A initiates a connection to an application on site B. Pre-shared key fetching can be simulated using the two calls below.
There are two REST API endpoints:
Application at site B makes a newkey call.
Request
Method : POST URL path : /api/newkey URL params: siteid=[alhpanumeric] e.g. siteid=A
Response Format in JSON
{
index: Index of he key
hexKey: Key in hexadecimal format
blockId: Id of the block containing the key
}
e.g. request-response:
curl 'http://localhost:8095/api/newkey?siteid=A' -H"Authorization: Bearer 291a94d5-d624-4269-a2bb-07db62130bb3" | jq
{
"index": 28,
"hexKey": "a2e1ff3429ff841f5d469893b9c28cbcb586d55c8ecf98c83c704824e889fc43"
"blockId": "133ad3f8de6cc9da"
}
Application on site A makes the getkey call by using part of the response from the newkey call above.
NOTE: Since the sites are different hence OAuth tokens will be different, which means a new OAuth token like above is fetched first by the application on site A.
Request
Method : POST
URL path : /api/getkey
URL params: siteid=[alhpanumeric] e.g. siteid=B
blockid=
index=[Integer]
Response Format in JSON
{
index: Index of he key
hexKey: Key in hexadecimal format
blockId: Id of the block containing the key
}
e.g. request-response:
curl 'http://localhost:8095/api/getkey?siteid=B&index=1&blockid=' -H"Authorization: Bearer abcdef12-d624-4269-a2bb-07db62130bb3" | jq
{
"index": 1,
"hexKey": "4544a432fb045f4940e1e2fe005470e1a35d85ede55f78927ca80f46a0a4b045"
"blocId": "8a94dc22e761de8c5501addc05"
}
The Open QKD Network project is led by Professors Michele Mosca and Norbert Lutkenhaus at Institute for Quantum Computing (IQC) of the University of Waterloo.
Main contributors to this master branch so far include: