1 /* 2 * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the OpenSSL license (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include <sys/libkern.h> 11 #include <sys/malloc.h> 12 13 #include <opencrypto/cryptodev.h> 14 #include <opencrypto/xform_auth.h> 15 16 #include <crypto/openssl/ossl.h> 17 #include <crypto/openssl/ossl_poly1305.h> 18 19 #define POLY1305_ASM 20 21 /* From crypto/poly1305/poly1305.c */ 22 23 /* pick 32-bit unsigned integer in little endian order */ 24 static unsigned int U8TOU32(const unsigned char *p) 25 { 26 return (((unsigned int)(p[0] & 0xff)) | 27 ((unsigned int)(p[1] & 0xff) << 8) | 28 ((unsigned int)(p[2] & 0xff) << 16) | 29 ((unsigned int)(p[3] & 0xff) << 24)); 30 } 31 32 /* 33 * Implementations can be classified by amount of significant bits in 34 * words making up the multi-precision value, or in other words radix 35 * or base of numerical representation, e.g. base 2^64, base 2^32, 36 * base 2^26. Complementary characteristic is how wide is the result of 37 * multiplication of pair of digits, e.g. it would take 128 bits to 38 * accommodate multiplication result in base 2^64 case. These are used 39 * interchangeably. To describe implementation that is. But interface 40 * is designed to isolate this so that low-level primitives implemented 41 * in assembly can be self-contained/self-coherent. 42 */ 43 int poly1305_init(void *ctx, const unsigned char key[16], void *func); 44 void poly1305_blocks(void *ctx, const unsigned char *inp, size_t len, 45 unsigned int padbit); 46 void poly1305_emit(void *ctx, unsigned char mac[16], 47 const unsigned int nonce[4]); 48 49 void Poly1305_Init(POLY1305 *ctx, const unsigned char key[32]) 50 { 51 ctx->nonce[0] = U8TOU32(&key[16]); 52 ctx->nonce[1] = U8TOU32(&key[20]); 53 ctx->nonce[2] = U8TOU32(&key[24]); 54 ctx->nonce[3] = U8TOU32(&key[28]); 55 56 /* 57 * Unlike reference poly1305_init assembly counterpart is expected 58 * to return a value: non-zero if it initializes ctx->func, and zero 59 * otherwise. Latter is to simplify assembly in cases when there no 60 * multiple code paths to switch between. 61 */ 62 if (!poly1305_init(ctx->opaque, key, &ctx->func)) { 63 ctx->func.blocks = poly1305_blocks; 64 ctx->func.emit = poly1305_emit; 65 } 66 67 ctx->num = 0; 68 69 } 70 71 #ifdef POLY1305_ASM 72 /* 73 * This "eclipses" poly1305_blocks and poly1305_emit, but it's 74 * conscious choice imposed by -Wshadow compiler warnings. 75 */ 76 # define poly1305_blocks (*poly1305_blocks_p) 77 # define poly1305_emit (*poly1305_emit_p) 78 #endif 79 80 void Poly1305_Update(POLY1305 *ctx, const unsigned char *inp, size_t len) 81 { 82 #ifdef POLY1305_ASM 83 /* 84 * As documented, poly1305_blocks is never called with input 85 * longer than single block and padbit argument set to 0. This 86 * property is fluently used in assembly modules to optimize 87 * padbit handling on loop boundary. 88 */ 89 poly1305_blocks_f poly1305_blocks_p = ctx->func.blocks; 90 #endif 91 size_t rem, num; 92 93 if ((num = ctx->num)) { 94 rem = POLY1305_BLOCK_SIZE - num; 95 if (len >= rem) { 96 memcpy(ctx->data + num, inp, rem); 97 poly1305_blocks(ctx->opaque, ctx->data, POLY1305_BLOCK_SIZE, 1); 98 inp += rem; 99 len -= rem; 100 } else { 101 /* Still not enough data to process a block. */ 102 memcpy(ctx->data + num, inp, len); 103 ctx->num = num + len; 104 return; 105 } 106 } 107 108 rem = len % POLY1305_BLOCK_SIZE; 109 len -= rem; 110 111 if (len >= POLY1305_BLOCK_SIZE) { 112 poly1305_blocks(ctx->opaque, inp, len, 1); 113 inp += len; 114 } 115 116 if (rem) 117 memcpy(ctx->data, inp, rem); 118 119 ctx->num = rem; 120 } 121 122 void Poly1305_Final(POLY1305 *ctx, unsigned char mac[16]) 123 { 124 #ifdef POLY1305_ASM 125 poly1305_blocks_f poly1305_blocks_p = ctx->func.blocks; 126 poly1305_emit_f poly1305_emit_p = ctx->func.emit; 127 #endif 128 size_t num; 129 130 if ((num = ctx->num)) { 131 ctx->data[num++] = 1; /* pad bit */ 132 while (num < POLY1305_BLOCK_SIZE) 133 ctx->data[num++] = 0; 134 poly1305_blocks(ctx->opaque, ctx->data, POLY1305_BLOCK_SIZE, 0); 135 } 136 137 poly1305_emit(ctx->opaque, mac, ctx->nonce); 138 139 /* zero out the state */ 140 OPENSSL_cleanse(ctx, sizeof(*ctx)); 141 } 142 143 static void 144 ossl_poly1305_init(void *vctx) 145 { 146 } 147 148 static void 149 ossl_poly1305_setkey(void *vctx, const uint8_t *key, u_int klen) 150 { 151 MPASS(klen == 32); 152 Poly1305_Init(vctx, key); 153 } 154 155 int 156 ossl_poly1305_update(void *vctx, const void *buf, u_int len) 157 { 158 Poly1305_Update(vctx, buf, len); 159 return (0); 160 } 161 162 static void 163 ossl_poly1305_final(uint8_t *digest, void *vctx) 164 { 165 Poly1305_Final(vctx, digest); 166 } 167 168 struct auth_hash ossl_hash_poly1305 = { 169 .type = CRYPTO_POLY1305, 170 .name = "OpenSSL-Poly1305", 171 .hashsize = POLY1305_HASH_LEN, 172 .ctxsize = sizeof(struct poly1305_context), 173 .blocksize = POLY1305_BLOCK_SIZE, 174 .Init = ossl_poly1305_init, 175 .Setkey = ossl_poly1305_setkey, 176 .Update = ossl_poly1305_update, 177 .Final = ossl_poly1305_final, 178 }; 179 180 _Static_assert(sizeof(struct poly1305_context) <= 181 sizeof(struct ossl_hash_context), "ossl_hash_context too small"); 182