wolf SSL / wolfSSL-TLS13-Beta

Fork of wolfSSL by wolf SSL

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers poly1305.c Source File

poly1305.c

00001 /* poly1305.c
00002  *
00003  * Copyright (C) 2006-2016 wolfSSL Inc.
00004  *
00005  * This file is part of wolfSSL.
00006  *
00007  * wolfSSL is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * wolfSSL is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
00020  */
00021 
00022 /*
00023  * Based off the public domain implementations by Andrew Moon
00024  * and Daniel J. Bernstein
00025  */
00026 
00027 #ifdef HAVE_CONFIG_H
00028     #include <config.h>
00029 #endif
00030 
00031 #include <wolfssl/wolfcrypt/settings.h>
00032 
00033 #ifdef HAVE_POLY1305
00034 #include <wolfssl/wolfcrypt/poly1305.h>
00035 #include <wolfssl/wolfcrypt/error-crypt.h>
00036 #include <wolfssl/wolfcrypt/logging.h>
00037 #ifdef NO_INLINE
00038     #include <wolfssl/wolfcrypt/misc.h>
00039 #else
00040     #define WOLFSSL_MISC_INCLUDED
00041     #include <wolfcrypt/src/misc.c>
00042 #endif
00043 #ifdef CHACHA_AEAD_TEST
00044     #include <stdio.h>
00045 #endif
00046 
00047 #ifdef _MSC_VER
00048     /* 4127 warning constant while(1)  */
00049     #pragma warning(disable: 4127)
00050 #endif
00051 
00052 #if defined(POLY130564)
00053 
00054     #if defined(_MSC_VER)
00055         #define POLY1305_NOINLINE __declspec(noinline)
00056     #elif defined(__GNUC__)
00057         #define POLY1305_NOINLINE __attribute__((noinline))
00058     #else
00059         #define POLY1305_NOINLINE
00060     #endif
00061 
00062     #if defined(_MSC_VER)
00063         #include <intrin.h>
00064 
00065         typedef struct word128 {
00066             word64 lo;
00067             word64 hi;
00068         } word128;
00069 
00070         #define MUL(out, x, y) out.lo = _umul128((x), (y), &out.hi)
00071         #define ADD(out, in) { word64 t = out.lo; out.lo += in.lo; \
00072                                out.hi += (out.lo < t) + in.hi; }
00073         #define ADDLO(out, in) { word64 t = out.lo; out.lo += in; \
00074                                  out.hi += (out.lo < t); }
00075         #define SHR(in, shift) (__shiftright128(in.lo, in.hi, (shift)))
00076         #define LO(in) (in.lo)
00077 
00078     #elif defined(__GNUC__)
00079         #if defined(__SIZEOF_INT128__)
00080             typedef unsigned __int128 word128;
00081         #else
00082             typedef unsigned word128 __attribute__((mode(TI)));
00083         #endif
00084 
00085         #define MUL(out, x, y) out = ((word128)x * y)
00086         #define ADD(out, in) out += in
00087         #define ADDLO(out, in) out += in
00088         #define SHR(in, shift) (word64)(in >> (shift))
00089         #define LO(in) (word64)(in)
00090     #endif
00091 
00092     static word64 U8TO64(const byte* p) {
00093         return
00094             (((word64)(p[0] & 0xff)      ) |
00095              ((word64)(p[1] & 0xff) <<  8) |
00096              ((word64)(p[2] & 0xff) << 16) |
00097              ((word64)(p[3] & 0xff) << 24) |
00098              ((word64)(p[4] & 0xff) << 32) |
00099              ((word64)(p[5] & 0xff) << 40) |
00100              ((word64)(p[6] & 0xff) << 48) |
00101              ((word64)(p[7] & 0xff) << 56));
00102     }
00103 
00104     static void U64TO8(byte* p, word64 v) {
00105         p[0] = (v      ) & 0xff;
00106         p[1] = (v >>  8) & 0xff;
00107         p[2] = (v >> 16) & 0xff;
00108         p[3] = (v >> 24) & 0xff;
00109         p[4] = (v >> 32) & 0xff;
00110         p[5] = (v >> 40) & 0xff;
00111         p[6] = (v >> 48) & 0xff;
00112         p[7] = (v >> 56) & 0xff;
00113     }
00114 
00115 #else /* if not 64 bit then use 32 bit */
00116 
00117     static word32 U8TO32(const byte *p) {
00118         return
00119             (((word32)(p[0] & 0xff)      ) |
00120              ((word32)(p[1] & 0xff) <<  8) |
00121              ((word32)(p[2] & 0xff) << 16) |
00122              ((word32)(p[3] & 0xff) << 24));
00123     }
00124 
00125     static void U32TO8(byte *p, word32 v) {
00126         p[0] = (v      ) & 0xff;
00127         p[1] = (v >>  8) & 0xff;
00128         p[2] = (v >> 16) & 0xff;
00129         p[3] = (v >> 24) & 0xff;
00130     }
00131 #endif
00132 
00133 
00134 static void U32TO64(word32 v, byte* p) {
00135     XMEMSET(p, 0, 8);
00136     p[0] = (v & 0xFF);
00137     p[1] = (v >>  8) & 0xFF;
00138     p[2] = (v >> 16) & 0xFF;
00139     p[3] = (v >> 24) & 0xFF;
00140 }
00141 
00142 
00143 static void poly1305_blocks(Poly1305* ctx, const unsigned char *m,
00144                             size_t bytes) {
00145 
00146 #ifdef POLY130564
00147 
00148     const word64 hibit = (ctx->final) ? 0 : ((word64)1 << 40); /* 1 << 128 */
00149     word64 r0,r1,r2;
00150     word64 s1,s2;
00151     word64 h0,h1,h2;
00152     word64 c;
00153     word128 d0,d1,d2,d;
00154 
00155 #else
00156 
00157     const word32 hibit = (ctx->final) ? 0 : (1 << 24); /* 1 << 128 */
00158     word32 r0,r1,r2,r3,r4;
00159     word32 s1,s2,s3,s4;
00160     word32 h0,h1,h2,h3,h4;
00161     word64 d0,d1,d2,d3,d4;
00162     word32 c;
00163 
00164 #endif
00165 
00166 #ifdef POLY130564
00167 
00168     r0 = ctx->r[0];
00169     r1 = ctx->r[1];
00170     r2 = ctx->r[2];
00171 
00172     h0 = ctx->h[0];
00173     h1 = ctx->h[1];
00174     h2 = ctx->h[2];
00175 
00176     s1 = r1 * (5 << 2);
00177     s2 = r2 * (5 << 2);
00178 
00179     while (bytes >= POLY1305_BLOCK_SIZE) {
00180         word64 t0,t1;
00181 
00182         /* h += m[i] */
00183         t0 = U8TO64(&m[0]);
00184         t1 = U8TO64(&m[8]);
00185 
00186         h0 += (( t0                    ) & 0xfffffffffff);
00187         h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
00188         h2 += (((t1 >> 24)             ) & 0x3ffffffffff) | hibit;
00189 
00190         /* h *= r */
00191         MUL(d0, h0, r0); MUL(d, h1, s2); ADD(d0, d); MUL(d, h2, s1); ADD(d0, d);
00192         MUL(d1, h0, r1); MUL(d, h1, r0); ADD(d1, d); MUL(d, h2, s2); ADD(d1, d);
00193         MUL(d2, h0, r2); MUL(d, h1, r1); ADD(d2, d); MUL(d, h2, r0); ADD(d2, d);
00194 
00195         /* (partial) h %= p */
00196                       c = SHR(d0, 44); h0 = LO(d0) & 0xfffffffffff;
00197         ADDLO(d1, c); c = SHR(d1, 44); h1 = LO(d1) & 0xfffffffffff;
00198         ADDLO(d2, c); c = SHR(d2, 42); h2 = LO(d2) & 0x3ffffffffff;
00199         h0  += c * 5; c = (h0 >> 44);  h0 =    h0  & 0xfffffffffff;
00200         h1  += c;
00201 
00202         m += POLY1305_BLOCK_SIZE;
00203         bytes -= POLY1305_BLOCK_SIZE;
00204     }
00205 
00206     ctx->h[0] = h0;
00207     ctx->h[1] = h1;
00208     ctx->h[2] = h2;
00209 
00210 #else /* if not 64 bit then use 32 bit */
00211 
00212     r0 = ctx->r[0];
00213     r1 = ctx->r[1];
00214     r2 = ctx->r[2];
00215     r3 = ctx->r[3];
00216     r4 = ctx->r[4];
00217 
00218     s1 = r1 * 5;
00219     s2 = r2 * 5;
00220     s3 = r3 * 5;
00221     s4 = r4 * 5;
00222 
00223     h0 = ctx->h[0];
00224     h1 = ctx->h[1];
00225     h2 = ctx->h[2];
00226     h3 = ctx->h[3];
00227     h4 = ctx->h[4];
00228 
00229     while (bytes >= POLY1305_BLOCK_SIZE) {
00230         /* h += m[i] */
00231         h0 += (U8TO32(m+ 0)     ) & 0x3ffffff;
00232         h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff;
00233         h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff;
00234         h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff;
00235         h4 += (U8TO32(m+12) >> 8) | hibit;
00236 
00237         /* h *= r */
00238         d0 = ((word64)h0 * r0) + ((word64)h1 * s4) + ((word64)h2 * s3) +
00239              ((word64)h3 * s2) + ((word64)h4 * s1);
00240         d1 = ((word64)h0 * r1) + ((word64)h1 * r0) + ((word64)h2 * s4) +
00241              ((word64)h3 * s3) + ((word64)h4 * s2);
00242         d2 = ((word64)h0 * r2) + ((word64)h1 * r1) + ((word64)h2 * r0) +
00243              ((word64)h3 * s4) + ((word64)h4 * s3);
00244         d3 = ((word64)h0 * r3) + ((word64)h1 * r2) + ((word64)h2 * r1) +
00245              ((word64)h3 * r0) + ((word64)h4 * s4);
00246         d4 = ((word64)h0 * r4) + ((word64)h1 * r3) + ((word64)h2 * r2) +
00247              ((word64)h3 * r1) + ((word64)h4 * r0);
00248 
00249         /* (partial) h %= p */
00250                       c = (word32)(d0 >> 26); h0 = (word32)d0 & 0x3ffffff;
00251         d1 += c;      c = (word32)(d1 >> 26); h1 = (word32)d1 & 0x3ffffff;
00252         d2 += c;      c = (word32)(d2 >> 26); h2 = (word32)d2 & 0x3ffffff;
00253         d3 += c;      c = (word32)(d3 >> 26); h3 = (word32)d3 & 0x3ffffff;
00254         d4 += c;      c = (word32)(d4 >> 26); h4 = (word32)d4 & 0x3ffffff;
00255         h0 += c * 5;  c =  (h0 >> 26); h0 =                h0 & 0x3ffffff;
00256         h1 += c;
00257 
00258         m += POLY1305_BLOCK_SIZE;
00259         bytes -= POLY1305_BLOCK_SIZE;
00260     }
00261 
00262     ctx->h[0] = h0;
00263     ctx->h[1] = h1;
00264     ctx->h[2] = h2;
00265     ctx->h[3] = h3;
00266     ctx->h[4] = h4;
00267 
00268 #endif /* end of 64 bit cpu blocks or 32 bit cpu */
00269 }
00270 
00271 
00272 int wc_Poly1305SetKey(Poly1305* ctx, const byte* key, word32 keySz) {
00273 
00274 #if defined(POLY130564)
00275     word64 t0,t1;
00276 #endif
00277 
00278 #ifdef CHACHA_AEAD_TEST
00279     word32 k;
00280     printf("Poly key used:\n");
00281     for (k = 0; k < keySz; k++) {
00282         printf("%02x", key[k]);
00283         if ((k+1) % 8 == 0)
00284             printf("\n");
00285     }
00286     printf("\n");
00287 #endif
00288 
00289     if (keySz != 32 || ctx == NULL)
00290         return BAD_FUNC_ARG;
00291 
00292 #if defined(POLY130564)
00293 
00294     /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
00295     t0 = U8TO64(key + 0);
00296     t1 = U8TO64(key + 8);
00297 
00298     ctx->r[0] = ( t0                    ) & 0xffc0fffffff;
00299     ctx->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
00300     ctx->r[2] = ((t1 >> 24)             ) & 0x00ffffffc0f;
00301 
00302     /* h (accumulator) = 0 */
00303     ctx->h[0] = 0;
00304     ctx->h[1] = 0;
00305     ctx->h[2] = 0;
00306 
00307     /* save pad for later */
00308     ctx->pad[0] = U8TO64(key + 16);
00309     ctx->pad[1] = U8TO64(key + 24);
00310 
00311 #else /* if not 64 bit then use 32 bit */
00312 
00313     /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
00314     ctx->r[0] = (U8TO32(key +  0)     ) & 0x3ffffff;
00315     ctx->r[1] = (U8TO32(key +  3) >> 2) & 0x3ffff03;
00316     ctx->r[2] = (U8TO32(key +  6) >> 4) & 0x3ffc0ff;
00317     ctx->r[3] = (U8TO32(key +  9) >> 6) & 0x3f03fff;
00318     ctx->r[4] = (U8TO32(key + 12) >> 8) & 0x00fffff;
00319 
00320     /* h = 0 */
00321     ctx->h[0] = 0;
00322     ctx->h[1] = 0;
00323     ctx->h[2] = 0;
00324     ctx->h[3] = 0;
00325     ctx->h[4] = 0;
00326 
00327     /* save pad for later */
00328     ctx->pad[0] = U8TO32(key + 16);
00329     ctx->pad[1] = U8TO32(key + 20);
00330     ctx->pad[2] = U8TO32(key + 24);
00331     ctx->pad[3] = U8TO32(key + 28);
00332 
00333 #endif
00334 
00335     ctx->leftover = 0;
00336     ctx->final = 0;
00337 
00338     return 0;
00339 }
00340 
00341 
00342 int wc_Poly1305Final(Poly1305* ctx, byte* mac) {
00343 
00344 #if defined(POLY130564)
00345 
00346     word64 h0,h1,h2,c;
00347     word64 g0,g1,g2;
00348     word64 t0,t1;
00349 
00350 #else
00351 
00352     word32 h0,h1,h2,h3,h4,c;
00353     word32 g0,g1,g2,g3,g4;
00354     word64 f;
00355     word32 mask;
00356 
00357 #endif
00358 
00359     if (ctx == NULL)
00360         return BAD_FUNC_ARG;
00361 
00362 #if defined(POLY130564)
00363 
00364     /* process the remaining block */
00365     if (ctx->leftover) {
00366         size_t i = ctx->leftover;
00367         ctx->buffer[i] = 1;
00368         for (i = i + 1; i < POLY1305_BLOCK_SIZE; i++)
00369             ctx->buffer[i] = 0;
00370         ctx->final = 1;
00371         poly1305_blocks(ctx, ctx->buffer, POLY1305_BLOCK_SIZE);
00372     }
00373 
00374     /* fully carry h */
00375     h0 = ctx->h[0];
00376     h1 = ctx->h[1];
00377     h2 = ctx->h[2];
00378 
00379                  c = (h1 >> 44); h1 &= 0xfffffffffff;
00380     h2 += c;     c = (h2 >> 42); h2 &= 0x3ffffffffff;
00381     h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff;
00382     h1 += c;     c = (h1 >> 44); h1 &= 0xfffffffffff;
00383     h2 += c;     c = (h2 >> 42); h2 &= 0x3ffffffffff;
00384     h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff;
00385     h1 += c;
00386 
00387     /* compute h + -p */
00388     g0 = h0 + 5; c = (g0 >> 44); g0 &= 0xfffffffffff;
00389     g1 = h1 + c; c = (g1 >> 44); g1 &= 0xfffffffffff;
00390     g2 = h2 + c - ((word64)1 << 42);
00391 
00392     /* select h if h < p, or h + -p if h >= p */
00393     c = (g2 >> ((sizeof(word64) * 8) - 1)) - 1;
00394     g0 &= c;
00395     g1 &= c;
00396     g2 &= c;
00397     c = ~c;
00398     h0 = (h0 & c) | g0;
00399     h1 = (h1 & c) | g1;
00400     h2 = (h2 & c) | g2;
00401 
00402     /* h = (h + pad) */
00403     t0 = ctx->pad[0];
00404     t1 = ctx->pad[1];
00405 
00406     h0 += (( t0                    ) & 0xfffffffffff)    ;
00407     c = (h0 >> 44); h0 &= 0xfffffffffff;
00408     h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c;
00409     c = (h1 >> 44); h1 &= 0xfffffffffff;
00410     h2 += (((t1 >> 24)             ) & 0x3ffffffffff) + c;
00411     h2 &= 0x3ffffffffff;
00412 
00413     /* mac = h % (2^128) */
00414     h0 = ((h0      ) | (h1 << 44));
00415     h1 = ((h1 >> 20) | (h2 << 24));
00416 
00417     U64TO8(mac + 0, h0);
00418     U64TO8(mac + 8, h1);
00419 
00420     /* zero out the state */
00421     ctx->h[0] = 0;
00422     ctx->h[1] = 0;
00423     ctx->h[2] = 0;
00424     ctx->r[0] = 0;
00425     ctx->r[1] = 0;
00426     ctx->r[2] = 0;
00427     ctx->pad[0] = 0;
00428     ctx->pad[1] = 0;
00429 
00430 #else /* if not 64 bit then use 32 bit */
00431 
00432     /* process the remaining block */
00433     if (ctx->leftover) {
00434         size_t i = ctx->leftover;
00435         ctx->buffer[i++] = 1;
00436         for (; i < POLY1305_BLOCK_SIZE; i++)
00437             ctx->buffer[i] = 0;
00438         ctx->final = 1;
00439         poly1305_blocks(ctx, ctx->buffer, POLY1305_BLOCK_SIZE);
00440     }
00441 
00442     /* fully carry h */
00443     h0 = ctx->h[0];
00444     h1 = ctx->h[1];
00445     h2 = ctx->h[2];
00446     h3 = ctx->h[3];
00447     h4 = ctx->h[4];
00448 
00449                  c = h1 >> 26; h1 = h1 & 0x3ffffff;
00450     h2 +=     c; c = h2 >> 26; h2 = h2 & 0x3ffffff;
00451     h3 +=     c; c = h3 >> 26; h3 = h3 & 0x3ffffff;
00452     h4 +=     c; c = h4 >> 26; h4 = h4 & 0x3ffffff;
00453     h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff;
00454     h1 +=     c;
00455 
00456     /* compute h + -p */
00457     g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff;
00458     g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff;
00459     g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff;
00460     g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff;
00461     g4 = h4 + c - (1 << 26);
00462 
00463     /* select h if h < p, or h + -p if h >= p */
00464     mask = (g4 >> ((sizeof(word32) * 8) - 1)) - 1;
00465     g0 &= mask;
00466     g1 &= mask;
00467     g2 &= mask;
00468     g3 &= mask;
00469     g4 &= mask;
00470     mask = ~mask;
00471     h0 = (h0 & mask) | g0;
00472     h1 = (h1 & mask) | g1;
00473     h2 = (h2 & mask) | g2;
00474     h3 = (h3 & mask) | g3;
00475     h4 = (h4 & mask) | g4;
00476 
00477     /* h = h % (2^128) */
00478     h0 = ((h0      ) | (h1 << 26)) & 0xffffffff;
00479     h1 = ((h1 >>  6) | (h2 << 20)) & 0xffffffff;
00480     h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
00481     h3 = ((h3 >> 18) | (h4 <<  8)) & 0xffffffff;
00482 
00483     /* mac = (h + pad) % (2^128) */
00484     f = (word64)h0 + ctx->pad[0]            ; h0 = (word32)f;
00485     f = (word64)h1 + ctx->pad[1] + (f >> 32); h1 = (word32)f;
00486     f = (word64)h2 + ctx->pad[2] + (f >> 32); h2 = (word32)f;
00487     f = (word64)h3 + ctx->pad[3] + (f >> 32); h3 = (word32)f;
00488 
00489     U32TO8(mac + 0, h0);
00490     U32TO8(mac + 4, h1);
00491     U32TO8(mac + 8, h2);
00492     U32TO8(mac + 12, h3);
00493 
00494     /* zero out the state */
00495     ctx->h[0] = 0;
00496     ctx->h[1] = 0;
00497     ctx->h[2] = 0;
00498     ctx->h[3] = 0;
00499     ctx->h[4] = 0;
00500     ctx->r[0] = 0;
00501     ctx->r[1] = 0;
00502     ctx->r[2] = 0;
00503     ctx->r[3] = 0;
00504     ctx->r[4] = 0;
00505     ctx->pad[0] = 0;
00506     ctx->pad[1] = 0;
00507     ctx->pad[2] = 0;
00508     ctx->pad[3] = 0;
00509 
00510 #endif
00511 
00512     return 0;
00513 }
00514 
00515 
00516 int wc_Poly1305Update(Poly1305* ctx, const byte* m, word32 bytes) {
00517 
00518     size_t i;
00519 
00520 #ifdef CHACHA_AEAD_TEST
00521     word32 k;
00522     printf("Raw input to poly:\n");
00523     for (k = 0; k < bytes; k++) {
00524         printf("%02x", m[k]);
00525         if ((k+1) % 16 == 0)
00526             printf("\n");
00527     }
00528     printf("\n");
00529 #endif
00530 
00531     if (ctx == NULL)
00532         return BAD_FUNC_ARG;
00533 
00534     /* handle leftover */
00535     if (ctx->leftover) {
00536         size_t want = (POLY1305_BLOCK_SIZE - ctx->leftover);
00537         if (want > bytes)
00538             want = bytes;
00539         for (i = 0; i < want; i++)
00540             ctx->buffer[ctx->leftover + i] = m[i];
00541         bytes -= (word32)want;
00542         m += want;
00543         ctx->leftover += want;
00544         if (ctx->leftover < POLY1305_BLOCK_SIZE)
00545             return 0;
00546         poly1305_blocks(ctx, ctx->buffer, POLY1305_BLOCK_SIZE);
00547         ctx->leftover = 0;
00548     }
00549 
00550     /* process full blocks */
00551     if (bytes >= POLY1305_BLOCK_SIZE) {
00552         size_t want = (bytes & ~(POLY1305_BLOCK_SIZE - 1));
00553         poly1305_blocks(ctx, m, want);
00554         m += want;
00555         bytes -= (word32)want;
00556     }
00557 
00558     /* store leftover */
00559     if (bytes) {
00560         for (i = 0; i < bytes; i++)
00561             ctx->buffer[ctx->leftover + i] = m[i];
00562         ctx->leftover += bytes;
00563     }
00564     return 0;
00565 }
00566 
00567 
00568 /*  Takes in an initialized Poly1305 struct that has a key loaded and creates
00569     a MAC (tag) using recent TLS AEAD padding scheme.
00570     ctx        : Initialized Poly1305 struct to use
00571     additional : Additional data to use
00572     addSz      : Size of additional buffer
00573     input      : Input buffer to create tag from
00574     sz         : Size of input buffer
00575     tag        : Buffer to hold created tag
00576     tagSz      : Size of input tag buffer (must be at least
00577                  WC_POLY1305_MAC_SZ(16))
00578  */
00579 int wc_Poly1305_MAC(Poly1305* ctx, byte* additional, word32 addSz,
00580                     byte* input, word32 sz, byte* tag, word32 tagSz)
00581 {
00582     int ret;
00583     byte padding[WC_POLY1305_PAD_SZ - 1];
00584     word32 paddingLen;
00585     byte little64[8];
00586 
00587     XMEMSET(padding, 0, sizeof(padding));
00588 
00589     /* sanity check on arguments */
00590     if (ctx == NULL || input == NULL || tag == NULL ||
00591                                                    tagSz < WC_POLY1305_MAC_SZ) {
00592         return BAD_FUNC_ARG;
00593     }
00594 
00595     /* additional allowed to be 0 */
00596     if (addSz > 0) {
00597         if (additional == NULL)
00598             return BAD_FUNC_ARG;
00599 
00600         /* additional data plus padding */
00601         if ((ret = wc_Poly1305Update(ctx, additional, addSz)) != 0) {
00602             return ret;
00603         }
00604         paddingLen = -((int)addSz) & (WC_POLY1305_PAD_SZ - 1);
00605         if (paddingLen) {
00606             if ((ret = wc_Poly1305Update(ctx, padding, paddingLen)) != 0) {
00607                 return ret;
00608             }
00609         }
00610     }
00611 
00612     /* input plus padding */
00613     if ((ret = wc_Poly1305Update(ctx, input, sz)) != 0) {
00614         return ret;
00615     }
00616     paddingLen = -((int)sz) & (WC_POLY1305_PAD_SZ - 1);
00617     if (paddingLen) {
00618         if ((ret = wc_Poly1305Update(ctx, padding, paddingLen)) != 0) {
00619             return ret;
00620         }
00621     }
00622 
00623     /* size of additional data and input as little endian 64 bit types */
00624     U32TO64(addSz, little64);
00625     ret = wc_Poly1305Update(ctx, little64, sizeof(little64));
00626     if (ret)
00627     {
00628         return ret;
00629     }
00630 
00631     U32TO64(sz, little64);
00632     ret = wc_Poly1305Update(ctx, little64, sizeof(little64));
00633     if (ret)
00634     {
00635         return ret;
00636     }
00637 
00638     /* Finalize the auth tag */
00639     ret = wc_Poly1305Final(ctx, tag);
00640 
00641     return ret;
00642 
00643 }
00644 #endif /* HAVE_POLY1305 */
00645 
00646