Skip to content

Latest commit

 

History

History
164 lines (129 loc) · 5.64 KB

README.md

File metadata and controls

164 lines (129 loc) · 5.64 KB

Overview

There are 2 database + backend setups in this repo:

  • Diagnosis DB (diagnosis-{api,db})
  • Exposure DB (not done yet)

Terminology

  • TEK (Temporary Exposure Key): revolving key generated by user; covers a day?
    • tek_i←CRNG(16)
    • app stores tek_i and i
  • RPI (Rotating Proximity Indicator): rotated every ~15 minutes. Generated from TEK, and ENIN:
    • RPIK_i←HKDF(tek_i,NULL,UTF8("EN-RPIK"),16)
    • RPI_i,j←AES128(RPIK_i,PaddedData_j)
    • PaddedData_j[0...5]=UTF8("EN-RPI")
    • PaddedData_j[6...11]=0x000000000000
    • PaddedData_j[12...15]=ENIN_j
  • ENIN (ENIntervalNumber): UTC timestamp / 10:
    • ENIntervalNumber(Timestamp)←Timestamp/60×10
  • HA (Health Authority): an administrative entity with the ability to diagnose a Report Key as a confirmed case
  • Report: a set of diagnosed TEKs uploaded to the diagnosis database

Key types:

  • Report Key: a key that is reported to backend or HA (usually in a batch)
  • Diagnosis Key: a TEK that is confirmed to correspond to a positive diagnosis
  • Exposure Key: a TEK that has been exposed to a diagnosis key: e.g. an entity notices an overlap in RPI-space with a diagnosed TEK and publishes its own TEK for that period. What lighthouses need
  • Self-diagnosis Key: a TEK that corresponds to an unconfirmed positive diagnosis
  • HAK (Health Authority Key): a public key associated with a health authority
  • LHK (Lighthouse Key): a unique identifier associated with a lighthouse

Setup

To run the development setup (postgres backend defined in *-db/, API backend defined in *-db/), use docker-compose:

docker-compose up

This should bring up:

  • Diagnosis Postgres backend (port 5434)
  • Diagnosis Postgres GRPC API (port 5000)

Simulation

We have a simple simulation demonstarting the workflow involved. N entities randomly interact and query the database for a configurable number of days. To run:

$ cd simulate
$ time python simulation.py --entities 100 --days 7
2020-05-02 00:00:00+00:00
2020-05-03 00:00:00+00:00
entity-75 was exposed at 2020-05-02 00:00:00
2020-05-04 00:00:00+00:00
entity-73 was exposed at 2020-05-03 00:00:00
entity-75 was exposed at 2020-05-02 00:00:00
entity-79 was exposed at 2020-05-03 00:00:00
2020-05-05 00:00:00+00:00
entity-35 was exposed at 2020-05-04 00:00:00
entity-67 was exposed at 2020-05-04 00:00:00
... etc

Reporting (DiagnosisDB)

The diagnosis backend receives TEKs (with timestamps marking the beginning of their 'valid' period) that have been "tainted" by an authority. This authority is trusted to perform a diagnosis of the entity who possesses the TEKs.

Reports use the AddReport(Report) GRPC call

// message sent by user
message Report {
    // a unique authorization key given to the user upon
    // interaction with an authorized (healthcare) professional
    bytes authorization_key = 3;

    // a set of timestamp-enin pairs (from the user)
    repeated TimestampedTEK reports = 2;
}

message TimestampedTEK {
    // user-generated TEK
    bytes TEK = 1;
    // corresponding ENIN for the TEK
    uint32 ENIN = 2;
}

// response received
message AddReportResponse {
    string error = 1;
}

Example: see diagnosis-api/usage.py

Authorization

In order to upload their TEK, ENINs to the backend (e.g. upon a diagnosis by a healthcare provider), a user needs an authorization key. An authorization key is a random 16-byte key that is given to the user by an authorized professional.

The authorized professional gets an authorization key by invoking the GetAuthorizationToken(TokenRequest) method on the server API. The caller authenticates to this method by providing an API key which is provided to them out-of-band and is stored in the backend database. The current prototype has a default API key of c3b9b61b687b895aff09eb072fb07d33

When generating a new authorization key, the professional must specify how the key is intended to be used through use of the KeyType field. Currently there is just one option (DIAGNOSED) but it must be specified in the request.

message TokenRequest {
    // secret API key that uniquely identifies an authorized organization
    bytes api_key = 1;
    // the kind of key being requested; this is stored in the backend along
    // with the generated authorization_key
    KeyType key_type = 2;
}

message TokenResponse {
    string error = 1;
    // unique 16-byte key generated to be given to a user. The generation
    // of this key means that the association of <authority, auth_key> is
    // stored in the backend
    bytes authorization_key = 2;
}

enum KeyType {
    UNKNOWN = 0;
    DIAGNOSED = 1;
}

Querying (DiagnosisDB)

Use the GetDiagnosisKeys(GetKeyRequest) GRPC call. This will eventually allow filtering by time and health authority source, among other filters.

Response is a stream of GetDiagnosisKeyResponse

// user query to the API
message GetKeyRequest {
    // retrieve keys for the given health authority
    bytes HAK = 1;
    // retrieve keys for the given day (ENIN rounded 'down'
    // to the nearest day)
    uint32 ENIN = 2;
    // alternatively fetch a temporal range of keys
    HistoricalRange hrange = 3;
}

// stream of messages from the server
message GetDiagnosisKeyResponse {
    string error = 1;
    TimestampedTEK record = 2;
}

message HistoricalRange {
    // YYYY-MM-DD  of *end* of day range; defaults to the current day
    string start_date = 1;
    // how many days back to retrieve records; defaults to 1
    uint32 days = 2;
}

message TimestampedTEK {
    bytes TEK = 1;
    uint32 ENIN = 2;
}

Example: see diagnosis-api/usage.py