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