-
Notifications
You must be signed in to change notification settings - Fork 2
/
crypto.h
195 lines (175 loc) · 6.17 KB
/
crypto.h
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#pragma once
#include "mbedtls/cipher.h"
#include "mbedtls/config.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/entropy.h"
#include "mbedtls/gcm.h"
#include "mbedtls/pk.h"
#include "mbedtls/rsa.h"
#include "mbedtls/sha256.h"
// All sizes are in bytes
#define CIPHER_KEY_SIZE 32
#define CIPHER_IV_SIZE 12
#define CIPHER_TAG_SIZE 16
#define SHA_DIGEST_SIZE 32
#define RSA_MOD_SIZE 256
#define RSA_EXPONENT 65537
// https://datatracker.ietf.org/doc/html/rfc8017#section-7.1.1
#define RSA_MAX_MESSAGE_SIZE RSA_MOD_SIZE - 2 * SHA_DIGEST_SIZE - 2
// The PEM encoding size of an RSA key with a modulus of 2048 bits
// and exponent 65537
#define CIPHER_PK_SIZE 452
class Crypto {
private:
mbedtls_ctr_drbg_context m_ctr_drbg_context;
mbedtls_entropy_context m_entropy_context;
mbedtls_pk_context m_pk_context;
bool m_initialized;
size_t rsa_modulus_size;
public:
Crypto();
~Crypto();
// Ensure only a single Crypto object exists to avoid insecure behavior
// with the RNG
Crypto(Crypto const&) = delete;
void operator=(Crypto const&) = delete;
/*
* Return the required size of a buffer to be used for asymmetric
* signing. This assumes that the RSA key has a modulus of size
* RSA_MOD_SIZE.
*/
size_t AsymEncSize(size_t data_size);
/*
* Return the required size of a buffer to be used for asymmetric
* decryption. This assumes that the RSA key has a modulus of size
* RSA_MOD_SIZE.
*/
size_t AsymDecSize(size_t enc_data_size);
/*
* Return the required size of a buffer to be used for asymmetric
* signing (`RSA_MOD_SIZE`).
*/
size_t AsymSignSize();
/*
* Return the required size of a buffer to be used for symmetric
* encryption: `data_size + CIPHER_IV_SIZE + CIPHER_TAG_SIZE`
*/
size_t SymEncSize(size_t data_size);
/*
* Return the required size of a buffer to be used for symmetric
* encryption: `enc_data_size - CIPHER_IV_SIZE - CIPHER_TAG_SIZE`
*/
size_t SymDecSize(size_t enc_data_size);
/**
* Copy the enclave public key into `buf`.
*/
int WritePublicKey(uint8_t (&buf)[CIPHER_PK_SIZE]);
/**
* Fill `buf` with random bytes
*/
int RandGen(uint8_t* buf, size_t buf_len);
/**
* Encrypt `data` using RSA encryption with .pem-formatted public key
* `pem_public_key`.
*
* The resulting ciphertext is stored in the `enc_data` buffer which
* must have at least `AsymEncSize(data_size)` bytes allocated.
*
* If `data_size` > RSA_MAX_MESSAGE_SIZE then `enc_data` will hold multiple
* ciphertexts. In order to mitigate re-ordering attacks, a counter
* is included in the label section of each ciphertext.
*/
int AsymEnc(const uint8_t* pem_public_key,
const uint8_t* data,
uint8_t* enc_data,
size_t data_size);
/**
* Decrypt `enc_data` using RSA encryption with internal private key.
* Resulting plaintext is stored in `data`.
*
* The resulting data is stored in the `data` buffer which must have
* at least `enc_data_size` bytes allocated. The final plaintext size
* (which may be less than `enc_data_size`) is stored in `data_size`.
*/
int AsymDec(const uint8_t* enc_data,
uint8_t* data,
size_t enc_data_size,
size_t* data_size);
/**
* Encrypt `data` using GCM encryption with symmetric key `sym_key`.
*
* Additional information can be placed in `aad` and will be used in
* generating the ciphertext tag but _not_ included in the ciphertext
* itself (i.e. the decryptor must also know this information to validate
* the tag)
*
* The resulting ciphertext is stored in `enc_data` buffer which must have
* at least CIPHER_IV_SIZE + CIPHER_TAG_SIZE + `data_size` bytes allocated.
*
* The ciphertext has the following structure:
*
* IV || TAG || ENCRYPTED DATA
*/
int SymEnc(const uint8_t* sym_key,
const uint8_t* data,
const uint8_t* aad,
uint8_t* enc_data,
size_t data_size,
size_t aad_size);
/*
* Decrypt `enc_data` using GCM decryption with symmetric key `sym_key` and
* additional authenticated data `aad`.
*
* The resulting data is stored in the `data` buffer which must have at
* least `enc_data_size` - CIPHER_IV_SIZE - CIPHER_TAG_SIZE bytes allocated.
*/
int SymDec(const uint8_t* sym_key,
const uint8_t* enc_data,
const uint8_t* aad,
uint8_t* data,
size_t enc_data_size,
size_t aad_size);
/*
* Output the SHA256 hash of `data` into `output`
*/
int Hash(const uint8_t* data,
uint8_t (&output)[SHA_DIGEST_SIZE],
size_t data_size);
/*
* Generate an RSA signature of `data` using the internal private key.
*
* The resulting signature is stored in the `sig` buffer which must have
* at least `RSA_MOD_SIZE` bytes allocated.
*/
int Sign(const uint8_t* data, uint8_t* sig, size_t data_size);
#ifdef HOST
/*
* Generate an RSA signature of `data` using the private key located at
* `keyfile` which must be an RSA key with modulus size `RSA_MOD_SIZE`.
*
* The resulting signature is stored in the `sig` buffer which must have
* at least `RSA_MOD_SIZE` bytes allocated.
*/
int SignUsingKeyfile(const char* keyfile,
const uint8_t* data,
uint8_t* sig,
size_t data_size);
#endif
/*
* Verify an RSA signature `sig` over `data` using .pem-formatted public key
* `pem_public_key`.
*/
int Verify(const uint8_t* pem_public_key,
const uint8_t* data,
const uint8_t* sig,
size_t data_size);
private:
/*
* Helper function to consolidate the shared computation of `Sign` and
* `SignUsingKeyfile`
*/
int sign_helper(mbedtls_pk_context* pk,
const uint8_t* data,
uint8_t* sig,
size_t data_size);
};