master uint/magnolia / source / net / mc_crypto.c
  1#include <stdlib.h>
  2#include <string.h>
  3
  4#include "mc_internal.h"
  5#include "mgrandom.h"
  6
  7/* naive der parser */
  8typedef struct {
  9	const u8* data;
 10	size_t    size;
 11	size_t    cursor;
 12} DERReader;
 13
 14static u8   cipher_byte(MCCipher* cipher);
 15static i8   der_length(DERReader* reader, size_t* length);
 16static i8   der_value(DERReader* reader, u8 tag, DERReader* value);
 17static i8   rsa_public_key(const u8* der, size_t der_size, br_rsa_public_key* key, char* error, size_t error_size);
 18static void twos_complement(u8* data, size_t size);
 19
 20/* generate next cipher stream byte
 21   returns cipher byte */
 22static u8 cipher_byte(MCCipher* cipher)
 23{
 24	u8 zero_iv[16] = { 0 };
 25	u8 block[16];
 26	memcpy(block, cipher->state, 16);
 27	br_aes_ct_cbcenc_run(&cipher->key, zero_iv, block, sizeof(block));
 28	return block[0];
 29}
 30
 31/* read DER length
 32   returns 1 on success, 0 on failure */
 33static i8 der_length(DERReader* reader, size_t* length)
 34{
 35	u8     first;
 36	size_t value = 0;
 37	u32    count;
 38	u32    i;
 39
 40	if (reader->cursor >= reader->size)
 41		return 0;
 42	first = reader->data[reader->cursor++];
 43	if (!(first & 0x80)) {
 44		*length = first;
 45		return *length <= reader->size - reader->cursor;
 46	}
 47	count = first & 0x7f;
 48	if (count == 0 || count > sizeof(size_t) || count > reader->size - reader->cursor)
 49		return 0;
 50	for (i = 0; i < count; ++i)
 51		value = (value << 8) | reader->data[reader->cursor++];
 52	if (value > reader->size - reader->cursor)
 53		return 0;
 54	*length = value;
 55	return 1;
 56}
 57
 58/* read DER value by tag
 59   returns 1 on success, 0 on failure */
 60static i8 der_value(DERReader* reader, u8 tag, DERReader* value)
 61{
 62	size_t length;
 63	if (reader->cursor >= reader->size || reader->data[reader->cursor++] != tag || !der_length(reader, &length))
 64		return 0;
 65	value->data = reader->data + reader->cursor;
 66	value->size = length;
 67	value->cursor = 0;
 68	reader->cursor += length;
 69	return 1;
 70}
 71
 72/* parse the server's X.509 RSA pubkey for BearSSL
 73   returns 1 on success, 0 on failure */
 74static i8 rsa_public_key(const u8* der, size_t der_size, br_rsa_public_key* key, char* error, size_t error_size)
 75{
 76	DERReader root = { der, der_size, 0 };
 77	DERReader spki;
 78	DERReader algorithm;
 79	DERReader bits;
 80	DERReader rsa;
 81	DERReader modulus;
 82	DERReader exponent;
 83
 84	if (!der_value(&root, 0x30, &spki) || !der_value(&spki, 0x30, &algorithm) || !der_value(&spki, 0x03, &bits) ||
 85	    bits.size < 1 || bits.data[0] != 0) {
 86		mc_set_error(MC_EC_INVALID_PUBLIC_KEY, error, error_size, "invalid X.509 RSA public key");
 87		return 0;
 88	}
 89	bits.cursor = 1;
 90	if (!der_value(&bits, 0x30, &rsa) || !der_value(&rsa, 0x02, &modulus) || !der_value(&rsa, 0x02, &exponent)) {
 91		mc_set_error(MC_EC_INVALID_PUBLIC_KEY, error, error_size, "invalid RSA public key integers");
 92		return 0;
 93	}
 94	while (modulus.size > 1 && modulus.data[0] == 0) {
 95		++modulus.data;
 96		--modulus.size;
 97	}
 98	while (exponent.size > 1 && exponent.data[0] == 0) {
 99		++exponent.data;
100		--exponent.size;
101	}
102	key->n = (unsigned char*)modulus.data;
103	key->nlen = modulus.size;
104	key->e = (unsigned char*)exponent.data;
105	key->elen = exponent.size;
106	return key->nlen >= 64 && key->elen > 0;
107}
108
109/* convert bytes to twos complement in place */
110static void twos_complement(u8* data, size_t size)
111{
112	size_t i = size;
113	u32    carry = 1;
114	while (i > 0) {
115		u32 value;
116		--i;
117		value = (u32)(data[i] ^ 0xff) + carry;
118		data[i] = (u8)value;
119		carry = value >> 8;
120	}
121}
122
123void mc_cipher_init(MCCipher* cipher, const u8 key[16])
124{
125	br_aes_ct_cbcenc_init(&cipher->key, key, 16);
126	memcpy(cipher->state, key, 16);
127}
128
129void mc_cipher_encrypt(MCCipher* cipher, u8* data, size_t size)
130{
131	size_t i;
132	for (i = 0; i < size; ++i) {
133		u8 encrypted = data[i] ^ cipher_byte(cipher);
134		memmove(cipher->state, cipher->state + 1, 15);
135		cipher->state[15] = encrypted;
136		data[i] = encrypted;
137	}
138}
139
140void mc_cipher_decrypt(MCCipher* cipher, u8* data, size_t size)
141{
142	size_t i;
143	for (i = 0; i < size; ++i) {
144		u8 encrypted = data[i];
145		data[i] ^= cipher_byte(cipher);
146		memmove(cipher->state, cipher->state + 1, 15);
147		cipher->state[15] = encrypted;
148	}
149}
150
151i8 mc_rsa_encrypt(const u8* public_key, size_t public_key_size, const u8* message, size_t message_size, u8** encrypted,
152                  size_t* encrypted_size, char* error, size_t error_size)
153{
154	br_rsa_public_key key;
155	br_rsa_public     rsa;
156	u8*               output;
157	size_t            padding_size;
158	size_t            i;
159
160	if (!rsa_public_key(public_key, public_key_size, &key, error, error_size))
161		return 0;
162	if (message_size + 11 > key.nlen) {
163		mc_set_error(MC_EC_RSA_MESSAGE_TOO_LARGE, error, error_size, "message is too large for server RSA key");
164		return 0;
165	}
166	output = (u8*)malloc(key.nlen);
167	if (!output) {
168		mc_set_error(MC_EC_OUT_OF_MEMORY, error, error_size, "out of memory encrypting login response");
169		return 0;
170	}
171	padding_size = key.nlen - message_size - 3;
172	output[0] = 0;
173	output[1] = 2;
174	/* PKCS#1 v1.5 encryption padding requires every padding byte to be
175	   nonzero */
176	if (!mg_random_bytes(output + 2, padding_size)) {
177		free(output);
178		mc_set_error(MC_EC_RANDOM, error, error_size, "could not obtain secure random bytes");
179		return 0;
180	}
181	for (i = 0; i < padding_size; ++i) {
182		while (output[2 + i] == 0) {
183			if (!mg_random_bytes(output + 2 + i, 1)) {
184				free(output);
185				mc_set_error(MC_EC_RANDOM, error, error_size, "could not obtain secure random bytes");
186				return 0;
187			}
188		}
189	}
190	output[2 + padding_size] = 0;
191	memcpy(output + 3 + padding_size, message, message_size);
192
193	rsa = br_rsa_public_get_default();
194	if (!rsa || !rsa(output, key.nlen, &key)) {
195		free(output);
196		mc_set_error(MC_EC_RSA_ENCRYPT, error, error_size, "BearSSL RSA encryption failed");
197		return 0;
198	}
199	*encrypted = output;
200	*encrypted_size = key.nlen;
201	return 1;
202}
203
204void mc_server_hash(const char* server_id, const u8 shared_secret[16], const u8* public_key, size_t public_key_size,
205                    char output[42])
206{
207	static const char hex[] = "0123456789abcdef";
208	br_sha1_context   sha;
209	u8                digest[20];
210	size_t            first = 0;
211	size_t            i;
212	size_t            out = 0;
213	i8                negative;
214
215	br_sha1_init(&sha);
216	br_sha1_update(&sha, server_id, strlen(server_id));
217	br_sha1_update(&sha, shared_secret, 16);
218	br_sha1_update(&sha, public_key, public_key_size);
219	br_sha1_out(&sha, digest);
220	/* mc puts sha-1 digest as a signed twos-complement int */
221	negative = (digest[0] & 0x80) != 0;
222	if (negative)
223		twos_complement(digest, sizeof(digest));
224	while (first < sizeof(digest) && digest[first] == 0)
225		++first;
226	if (negative)
227		output[out++] = '-';
228	if (first == sizeof(digest)) {
229		output[out++] = '0';
230	}
231	else {
232		output[out++] = hex[digest[first] >> 4];
233		output[out++] = hex[digest[first] & 15];
234		for (i = first + 1; i < sizeof(digest); ++i) {
235			output[out++] = hex[digest[i] >> 4];
236			output[out++] = hex[digest[i] & 15];
237		}
238		if (output[negative ? 1 : 0] == '0') {
239			memmove(output + (negative ? 1 : 0), output + (negative ? 2 : 1), out - (negative ? 2 : 1));
240			--out;
241		}
242	}
243	output[out] = '\0';
244}