-
Notifications
You must be signed in to change notification settings - Fork 1
/
crypto.cpp
116 lines (102 loc) · 3.53 KB
/
crypto.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <time.h>
#include <tuple>
#include <gcrypt.h>
#include <fstream>
#include <iostream>
#include <sstream>
#include <endian.h>
#include <vector>
#include "crypto.h"
uint32_t getENIntervalNumber() {
time_t t = time(NULL);
uint32_t intervalNumber = t / (60*10);
return intervalNumber;
}
class HMAC {
gcry_mac_hd_t hd;
public:
HMAC(const uint8_t* key, size_t keylen) {
gcry_mac_open(&hd, GCRY_MAC_HMAC_SHA256, 0, NULL);
gcry_mac_setkey(hd, key, keylen);
}
~HMAC() {
gcry_mac_close(hd);
}
void write(const std::vector<uint8_t>& v) {
gcry_mac_write(hd, v.data(), v.size());
}
void write(const std::string& s) {
gcry_mac_write(hd, s.data(), s.size());
}
void write(const uint8_t* d, const size_t len) {
gcry_mac_write(hd, d, len);
}
void read(uint8_t* buf, size_t sz) {
size_t rsz = sz;
gcry_mac_read(hd, buf, &rsz);
if (sz != rsz) throw std::runtime_error("Unexpected SHA-256 HMAC size");
}
};
void HKDF(const uint8_t* key, size_t keylen,
const uint8_t* salt, size_t saltlen,
const uint8_t* info, size_t infolen,
uint8_t* buf, size_t buflen) {
// Step 1: extract
HMAC extract_mac(salt,saltlen);
extract_mac.write(key,keylen);
uint8_t prk[32];
extract_mac.read(prk,32);
// Step 2: expand. We only need 16 octets, so this is an
// incomplete implementation.
HMAC expand_mac(prk,32);
expand_mac.write(info,infolen);
uint8_t end_octet = 0x01;
expand_mac.write(&end_octet, 1);
return expand_mac.read(buf,16);
}
TemporaryExposureKey::TemporaryExposureKey(const::std::string& prefix) {
// Validation period
uint32_t cur_interval = getENIntervalNumber();
valid_from = (cur_interval / TEKRollingPeriod) * TEKRollingPeriod;
// Load or generate key
std::stringstream ss(prefix);
ss << valid_from << ".tek";
std::ifstream inf(ss.str());
if (inf) {
inf.read((char*)key, 16);
inf.close();
} else {
gcry_randomize(key, 16, GCRY_VERY_STRONG_RANDOM);
std::ofstream outf(ss.str(),std::ofstream::out|std::ofstream::binary);
outf.write((const char*)key, 16);
outf.close();
}
// Generate RPI key
HKDF(key, 16, NULL, 0, (const uint8_t*)"EN-RPIK", 7, rpi_key, 16);
// Generate AEM key
HKDF(key, 16, NULL, 0, (const uint8_t*)"EN-AEMK", 7, aem_key, 16);
}
bool TemporaryExposureKey::is_still_valid() {
uint32_t cur_interval = getENIntervalNumber();
return cur_interval < (valid_from + TEKRollingPeriod);
}
std::vector<uint8_t> TemporaryExposureKey::make_rpi(uint32_t intervalNumber) {
uint8_t inblock[16] = { 'E','N','-','R','P','I' };
*(uint32_t*)(inblock+12) = htole32(intervalNumber);
gcry_cipher_hd_t handle;
gcry_cipher_open(&handle, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, 0);
gcry_cipher_setkey(handle,rpi_key,16);
gcry_cipher_encrypt(handle, inblock, 16, NULL, 0);
gcry_cipher_close(handle);
return std::vector<uint8_t>(inblock, inblock+16);
}
std::vector<uint8_t> TemporaryExposureKey::encrypt_aem(const std::vector<uint8_t>& rpi, const std::vector<uint8_t>& metadata) {
gcry_cipher_hd_t handle;
gcry_cipher_open(&handle, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, 0);
gcry_cipher_setkey(handle,aem_key,16);
gcry_cipher_setctr(handle,rpi.data(),rpi.size());
std::vector<uint8_t> out(metadata.size());
gcry_cipher_encrypt(handle, out.data(), out.size(), metadata.data(), metadata.size());
gcry_cipher_close(handle);
return out;
}