1*0957b409SSimon J. Gerraty /* 2*0957b409SSimon J. Gerraty * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org> 3*0957b409SSimon J. Gerraty * 4*0957b409SSimon J. Gerraty * Permission is hereby granted, free of charge, to any person obtaining 5*0957b409SSimon J. Gerraty * a copy of this software and associated documentation files (the 6*0957b409SSimon J. Gerraty * "Software"), to deal in the Software without restriction, including 7*0957b409SSimon J. Gerraty * without limitation the rights to use, copy, modify, merge, publish, 8*0957b409SSimon J. Gerraty * distribute, sublicense, and/or sell copies of the Software, and to 9*0957b409SSimon J. Gerraty * permit persons to whom the Software is furnished to do so, subject to 10*0957b409SSimon J. Gerraty * the following conditions: 11*0957b409SSimon J. Gerraty * 12*0957b409SSimon J. Gerraty * The above copyright notice and this permission notice shall be 13*0957b409SSimon J. Gerraty * included in all copies or substantial portions of the Software. 14*0957b409SSimon J. Gerraty * 15*0957b409SSimon J. Gerraty * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16*0957b409SSimon J. Gerraty * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17*0957b409SSimon J. Gerraty * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18*0957b409SSimon J. Gerraty * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19*0957b409SSimon J. Gerraty * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20*0957b409SSimon J. Gerraty * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21*0957b409SSimon J. Gerraty * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22*0957b409SSimon J. Gerraty * SOFTWARE. 23*0957b409SSimon J. Gerraty */ 24*0957b409SSimon J. Gerraty 25*0957b409SSimon J. Gerraty #include "inner.h" 26*0957b409SSimon J. Gerraty 27*0957b409SSimon J. Gerraty /* 28*0957b409SSimon J. Gerraty * GCM initialisation. This does everything except setting the vtable, 29*0957b409SSimon J. Gerraty * which depends on whether this is a context for encrypting or for 30*0957b409SSimon J. Gerraty * decrypting. 31*0957b409SSimon J. Gerraty */ 32*0957b409SSimon J. Gerraty static void 33*0957b409SSimon J. Gerraty gen_gcm_init(br_sslrec_gcm_context *cc, 34*0957b409SSimon J. Gerraty const br_block_ctr_class *bc_impl, 35*0957b409SSimon J. Gerraty const void *key, size_t key_len, 36*0957b409SSimon J. Gerraty br_ghash gh_impl, 37*0957b409SSimon J. Gerraty const void *iv) 38*0957b409SSimon J. Gerraty { 39*0957b409SSimon J. Gerraty unsigned char tmp[12]; 40*0957b409SSimon J. Gerraty 41*0957b409SSimon J. Gerraty cc->seq = 0; 42*0957b409SSimon J. Gerraty bc_impl->init(&cc->bc.vtable, key, key_len); 43*0957b409SSimon J. Gerraty cc->gh = gh_impl; 44*0957b409SSimon J. Gerraty memcpy(cc->iv, iv, sizeof cc->iv); 45*0957b409SSimon J. Gerraty memset(cc->h, 0, sizeof cc->h); 46*0957b409SSimon J. Gerraty memset(tmp, 0, sizeof tmp); 47*0957b409SSimon J. Gerraty bc_impl->run(&cc->bc.vtable, tmp, 0, cc->h, sizeof cc->h); 48*0957b409SSimon J. Gerraty } 49*0957b409SSimon J. Gerraty 50*0957b409SSimon J. Gerraty static void 51*0957b409SSimon J. Gerraty in_gcm_init(br_sslrec_gcm_context *cc, 52*0957b409SSimon J. Gerraty const br_block_ctr_class *bc_impl, 53*0957b409SSimon J. Gerraty const void *key, size_t key_len, 54*0957b409SSimon J. Gerraty br_ghash gh_impl, 55*0957b409SSimon J. Gerraty const void *iv) 56*0957b409SSimon J. Gerraty { 57*0957b409SSimon J. Gerraty cc->vtable.in = &br_sslrec_in_gcm_vtable; 58*0957b409SSimon J. Gerraty gen_gcm_init(cc, bc_impl, key, key_len, gh_impl, iv); 59*0957b409SSimon J. Gerraty } 60*0957b409SSimon J. Gerraty 61*0957b409SSimon J. Gerraty static int 62*0957b409SSimon J. Gerraty gcm_check_length(const br_sslrec_gcm_context *cc, size_t rlen) 63*0957b409SSimon J. Gerraty { 64*0957b409SSimon J. Gerraty /* 65*0957b409SSimon J. Gerraty * GCM adds a fixed overhead: 66*0957b409SSimon J. Gerraty * 8 bytes for the nonce_explicit (before the ciphertext) 67*0957b409SSimon J. Gerraty * 16 bytes for the authentication tag (after the ciphertext) 68*0957b409SSimon J. Gerraty */ 69*0957b409SSimon J. Gerraty (void)cc; 70*0957b409SSimon J. Gerraty return rlen >= 24 && rlen <= (16384 + 24); 71*0957b409SSimon J. Gerraty } 72*0957b409SSimon J. Gerraty 73*0957b409SSimon J. Gerraty /* 74*0957b409SSimon J. Gerraty * Compute the authentication tag. The value written in 'tag' must still 75*0957b409SSimon J. Gerraty * be CTR-encrypted. 76*0957b409SSimon J. Gerraty */ 77*0957b409SSimon J. Gerraty static void 78*0957b409SSimon J. Gerraty do_tag(br_sslrec_gcm_context *cc, 79*0957b409SSimon J. Gerraty int record_type, unsigned version, 80*0957b409SSimon J. Gerraty void *data, size_t len, void *tag) 81*0957b409SSimon J. Gerraty { 82*0957b409SSimon J. Gerraty unsigned char header[13]; 83*0957b409SSimon J. Gerraty unsigned char footer[16]; 84*0957b409SSimon J. Gerraty 85*0957b409SSimon J. Gerraty /* 86*0957b409SSimon J. Gerraty * Compute authentication tag. Three elements must be injected in 87*0957b409SSimon J. Gerraty * sequence, each possibly 0-padded to reach a length multiple 88*0957b409SSimon J. Gerraty * of the block size: the 13-byte header (sequence number, record 89*0957b409SSimon J. Gerraty * type, protocol version, record length), the cipher text, and 90*0957b409SSimon J. Gerraty * the word containing the encodings of the bit lengths of the two 91*0957b409SSimon J. Gerraty * other elements. 92*0957b409SSimon J. Gerraty */ 93*0957b409SSimon J. Gerraty br_enc64be(header, cc->seq ++); 94*0957b409SSimon J. Gerraty header[8] = (unsigned char)record_type; 95*0957b409SSimon J. Gerraty br_enc16be(header + 9, version); 96*0957b409SSimon J. Gerraty br_enc16be(header + 11, len); 97*0957b409SSimon J. Gerraty br_enc64be(footer, (uint64_t)(sizeof header) << 3); 98*0957b409SSimon J. Gerraty br_enc64be(footer + 8, (uint64_t)len << 3); 99*0957b409SSimon J. Gerraty memset(tag, 0, 16); 100*0957b409SSimon J. Gerraty cc->gh(tag, cc->h, header, sizeof header); 101*0957b409SSimon J. Gerraty cc->gh(tag, cc->h, data, len); 102*0957b409SSimon J. Gerraty cc->gh(tag, cc->h, footer, sizeof footer); 103*0957b409SSimon J. Gerraty } 104*0957b409SSimon J. Gerraty 105*0957b409SSimon J. Gerraty /* 106*0957b409SSimon J. Gerraty * Do CTR encryption. This also does CTR encryption of a single block at 107*0957b409SSimon J. Gerraty * address 'xortag' with the counter value appropriate for the final 108*0957b409SSimon J. Gerraty * processing of the authentication tag. 109*0957b409SSimon J. Gerraty */ 110*0957b409SSimon J. Gerraty static void 111*0957b409SSimon J. Gerraty do_ctr(br_sslrec_gcm_context *cc, const void *nonce, void *data, size_t len, 112*0957b409SSimon J. Gerraty void *xortag) 113*0957b409SSimon J. Gerraty { 114*0957b409SSimon J. Gerraty unsigned char iv[12]; 115*0957b409SSimon J. Gerraty 116*0957b409SSimon J. Gerraty memcpy(iv, cc->iv, 4); 117*0957b409SSimon J. Gerraty memcpy(iv + 4, nonce, 8); 118*0957b409SSimon J. Gerraty cc->bc.vtable->run(&cc->bc.vtable, iv, 2, data, len); 119*0957b409SSimon J. Gerraty cc->bc.vtable->run(&cc->bc.vtable, iv, 1, xortag, 16); 120*0957b409SSimon J. Gerraty } 121*0957b409SSimon J. Gerraty 122*0957b409SSimon J. Gerraty static unsigned char * 123*0957b409SSimon J. Gerraty gcm_decrypt(br_sslrec_gcm_context *cc, 124*0957b409SSimon J. Gerraty int record_type, unsigned version, void *data, size_t *data_len) 125*0957b409SSimon J. Gerraty { 126*0957b409SSimon J. Gerraty unsigned char *buf; 127*0957b409SSimon J. Gerraty size_t len, u; 128*0957b409SSimon J. Gerraty uint32_t bad; 129*0957b409SSimon J. Gerraty unsigned char tag[16]; 130*0957b409SSimon J. Gerraty 131*0957b409SSimon J. Gerraty buf = (unsigned char *)data + 8; 132*0957b409SSimon J. Gerraty len = *data_len - 24; 133*0957b409SSimon J. Gerraty do_tag(cc, record_type, version, buf, len, tag); 134*0957b409SSimon J. Gerraty do_ctr(cc, data, buf, len, tag); 135*0957b409SSimon J. Gerraty 136*0957b409SSimon J. Gerraty /* 137*0957b409SSimon J. Gerraty * Compare the computed tag with the value from the record. It 138*0957b409SSimon J. Gerraty * is possibly useless to do a constant-time comparison here, 139*0957b409SSimon J. Gerraty * but it does not hurt. 140*0957b409SSimon J. Gerraty */ 141*0957b409SSimon J. Gerraty bad = 0; 142*0957b409SSimon J. Gerraty for (u = 0; u < 16; u ++) { 143*0957b409SSimon J. Gerraty bad |= tag[u] ^ buf[len + u]; 144*0957b409SSimon J. Gerraty } 145*0957b409SSimon J. Gerraty if (bad) { 146*0957b409SSimon J. Gerraty return NULL; 147*0957b409SSimon J. Gerraty } 148*0957b409SSimon J. Gerraty *data_len = len; 149*0957b409SSimon J. Gerraty return buf; 150*0957b409SSimon J. Gerraty } 151*0957b409SSimon J. Gerraty 152*0957b409SSimon J. Gerraty /* see bearssl_ssl.h */ 153*0957b409SSimon J. Gerraty const br_sslrec_in_gcm_class br_sslrec_in_gcm_vtable = { 154*0957b409SSimon J. Gerraty { 155*0957b409SSimon J. Gerraty sizeof(br_sslrec_gcm_context), 156*0957b409SSimon J. Gerraty (int (*)(const br_sslrec_in_class *const *, size_t)) 157*0957b409SSimon J. Gerraty &gcm_check_length, 158*0957b409SSimon J. Gerraty (unsigned char *(*)(const br_sslrec_in_class **, 159*0957b409SSimon J. Gerraty int, unsigned, void *, size_t *)) 160*0957b409SSimon J. Gerraty &gcm_decrypt 161*0957b409SSimon J. Gerraty }, 162*0957b409SSimon J. Gerraty (void (*)(const br_sslrec_in_gcm_class **, 163*0957b409SSimon J. Gerraty const br_block_ctr_class *, const void *, size_t, 164*0957b409SSimon J. Gerraty br_ghash, const void *)) 165*0957b409SSimon J. Gerraty &in_gcm_init 166*0957b409SSimon J. Gerraty }; 167*0957b409SSimon J. Gerraty 168*0957b409SSimon J. Gerraty static void 169*0957b409SSimon J. Gerraty out_gcm_init(br_sslrec_gcm_context *cc, 170*0957b409SSimon J. Gerraty const br_block_ctr_class *bc_impl, 171*0957b409SSimon J. Gerraty const void *key, size_t key_len, 172*0957b409SSimon J. Gerraty br_ghash gh_impl, 173*0957b409SSimon J. Gerraty const void *iv) 174*0957b409SSimon J. Gerraty { 175*0957b409SSimon J. Gerraty cc->vtable.out = &br_sslrec_out_gcm_vtable; 176*0957b409SSimon J. Gerraty gen_gcm_init(cc, bc_impl, key, key_len, gh_impl, iv); 177*0957b409SSimon J. Gerraty } 178*0957b409SSimon J. Gerraty 179*0957b409SSimon J. Gerraty static void 180*0957b409SSimon J. Gerraty gcm_max_plaintext(const br_sslrec_gcm_context *cc, 181*0957b409SSimon J. Gerraty size_t *start, size_t *end) 182*0957b409SSimon J. Gerraty { 183*0957b409SSimon J. Gerraty size_t len; 184*0957b409SSimon J. Gerraty 185*0957b409SSimon J. Gerraty (void)cc; 186*0957b409SSimon J. Gerraty *start += 8; 187*0957b409SSimon J. Gerraty len = *end - *start - 16; 188*0957b409SSimon J. Gerraty if (len > 16384) { 189*0957b409SSimon J. Gerraty len = 16384; 190*0957b409SSimon J. Gerraty } 191*0957b409SSimon J. Gerraty *end = *start + len; 192*0957b409SSimon J. Gerraty } 193*0957b409SSimon J. Gerraty 194*0957b409SSimon J. Gerraty static unsigned char * 195*0957b409SSimon J. Gerraty gcm_encrypt(br_sslrec_gcm_context *cc, 196*0957b409SSimon J. Gerraty int record_type, unsigned version, void *data, size_t *data_len) 197*0957b409SSimon J. Gerraty { 198*0957b409SSimon J. Gerraty unsigned char *buf; 199*0957b409SSimon J. Gerraty size_t u, len; 200*0957b409SSimon J. Gerraty unsigned char tmp[16]; 201*0957b409SSimon J. Gerraty 202*0957b409SSimon J. Gerraty buf = (unsigned char *)data; 203*0957b409SSimon J. Gerraty len = *data_len; 204*0957b409SSimon J. Gerraty memset(tmp, 0, sizeof tmp); 205*0957b409SSimon J. Gerraty br_enc64be(buf - 8, cc->seq); 206*0957b409SSimon J. Gerraty do_ctr(cc, buf - 8, buf, len, tmp); 207*0957b409SSimon J. Gerraty do_tag(cc, record_type, version, buf, len, buf + len); 208*0957b409SSimon J. Gerraty for (u = 0; u < 16; u ++) { 209*0957b409SSimon J. Gerraty buf[len + u] ^= tmp[u]; 210*0957b409SSimon J. Gerraty } 211*0957b409SSimon J. Gerraty len += 24; 212*0957b409SSimon J. Gerraty buf -= 13; 213*0957b409SSimon J. Gerraty buf[0] = (unsigned char)record_type; 214*0957b409SSimon J. Gerraty br_enc16be(buf + 1, version); 215*0957b409SSimon J. Gerraty br_enc16be(buf + 3, len); 216*0957b409SSimon J. Gerraty *data_len = len + 5; 217*0957b409SSimon J. Gerraty return buf; 218*0957b409SSimon J. Gerraty } 219*0957b409SSimon J. Gerraty 220*0957b409SSimon J. Gerraty /* see bearssl_ssl.h */ 221*0957b409SSimon J. Gerraty const br_sslrec_out_gcm_class br_sslrec_out_gcm_vtable = { 222*0957b409SSimon J. Gerraty { 223*0957b409SSimon J. Gerraty sizeof(br_sslrec_gcm_context), 224*0957b409SSimon J. Gerraty (void (*)(const br_sslrec_out_class *const *, 225*0957b409SSimon J. Gerraty size_t *, size_t *)) 226*0957b409SSimon J. Gerraty &gcm_max_plaintext, 227*0957b409SSimon J. Gerraty (unsigned char *(*)(const br_sslrec_out_class **, 228*0957b409SSimon J. Gerraty int, unsigned, void *, size_t *)) 229*0957b409SSimon J. Gerraty &gcm_encrypt 230*0957b409SSimon J. Gerraty }, 231*0957b409SSimon J. Gerraty (void (*)(const br_sslrec_out_gcm_class **, 232*0957b409SSimon J. Gerraty const br_block_ctr_class *, const void *, size_t, 233*0957b409SSimon J. Gerraty br_ghash, const void *)) 234*0957b409SSimon J. Gerraty &out_gcm_init 235*0957b409SSimon J. Gerraty }; 236