int poly1305_test(void) { #ifndef LTC_TEST return CRYPT_NOP; #else /* https://tools.ietf.org/html/rfc7539#section-2.5.2 */ unsigned char k[] = { 0x85, 0xd6, 0xbe, 0x78, 0x57, 0x55, 0x6d, 0x33, 0x7f, 0x44, 0x52, 0xfe, 0x42, 0xd5, 0x06, 0xa8, 0x01, 0x03, 0x80, 0x8a, 0xfb, 0x0d, 0xb2, 0xfd, 0x4a, 0xbf, 0xf6, 0xaf, 0x41, 0x49, 0xf5, 0x1b }; unsigned char tag[] = { 0xA8, 0x06, 0x1D, 0xC1, 0x30, 0x51, 0x36, 0xC6, 0xC2, 0x2B, 0x8B, 0xAF, 0x0C, 0x01, 0x27, 0xA9 }; char m[] = "Cryptographic Forum Research Group"; unsigned long len = 16, mlen = strlen(m); unsigned char out[1000]; poly1305_state st; int err; /* process piece by piece */ if ((err = poly1305_init(&st, k, 32)) != CRYPT_OK) return err; if ((err = poly1305_process(&st, (unsigned char*)m, 5)) != CRYPT_OK) return err; if ((err = poly1305_process(&st, (unsigned char*)m + 5, 4)) != CRYPT_OK) return err; if ((err = poly1305_process(&st, (unsigned char*)m + 9, 3)) != CRYPT_OK) return err; if ((err = poly1305_process(&st, (unsigned char*)m + 12, 2)) != CRYPT_OK) return err; if ((err = poly1305_process(&st, (unsigned char*)m + 14, 1)) != CRYPT_OK) return err; if ((err = poly1305_process(&st, (unsigned char*)m + 15, mlen - 15)) != CRYPT_OK) return err; if ((err = poly1305_done(&st, out, &len)) != CRYPT_OK) return err; if (compare_testvector(out, len, tag, sizeof(tag), "POLY1305-TV1", 1) != 0) return CRYPT_FAIL_TESTVECTOR; /* process in one go */ if ((err = poly1305_init(&st, k, 32)) != CRYPT_OK) return err; if ((err = poly1305_process(&st, (unsigned char*)m, mlen)) != CRYPT_OK) return err; if ((err = poly1305_done(&st, out, &len)) != CRYPT_OK) return err; if (compare_testvector(out, len, tag, sizeof(tag), "POLY1305-TV2", 1) != 0) return CRYPT_FAIL_TESTVECTOR; return CRYPT_OK; #endif }
/** POLY1305 a file @param fname The name of the file you wish to POLY1305 @param key The secret key @param keylen The length of the secret key @param mac [out] The POLY1305 authentication tag @param maclen [in/out] The max size and resulting size of the authentication tag @return CRYPT_OK if successful, CRYPT_NOP if file support has been disabled */ int poly1305_file(const char *fname, const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen) { #ifdef LTC_NO_FILE LTC_UNUSED_PARAM(fname); LTC_UNUSED_PARAM(key); LTC_UNUSED_PARAM(keylen); LTC_UNUSED_PARAM(mac); LTC_UNUSED_PARAM(maclen); return CRYPT_NOP; #else poly1305_state st; FILE *in; unsigned char *buf; size_t x; int err; LTC_ARGCHK(fname != NULL); LTC_ARGCHK(key != NULL); LTC_ARGCHK(mac != NULL); LTC_ARGCHK(maclen != NULL); if ((buf = XMALLOC(LTC_FILE_READ_BUFSIZE)) == NULL) { return CRYPT_MEM; } if ((err = poly1305_init(&st, key, keylen)) != CRYPT_OK) { goto LBL_ERR; } in = fopen(fname, "rb"); if (in == NULL) { err = CRYPT_FILE_NOTFOUND; goto LBL_ERR; } do { x = fread(buf, 1, LTC_FILE_READ_BUFSIZE, in); if ((err = poly1305_process(&st, buf, (unsigned long)x)) != CRYPT_OK) { fclose(in); goto LBL_CLEANBUF; } } while (x == LTC_FILE_READ_BUFSIZE); if (fclose(in) != 0) { err = CRYPT_ERROR; goto LBL_CLEANBUF; } err = poly1305_done(&st, mac, maclen); LBL_CLEANBUF: zeromem(buf, LTC_FILE_READ_BUFSIZE); LBL_ERR: #ifdef LTC_CLEAN_STACK zeromem(&st, sizeof(poly1305_state)); #endif XFREE(buf); return err; #endif }
/** POLY1305 multiple blocks of memory to produce the authentication tag @param key The secret key @param keylen The length of the secret key (octets) @param mac [out] Destination of the authentication tag @param maclen [in/out] Max size and resulting size of authentication tag @param in The data to POLY1305 @param inlen The length of the data to POLY1305 (octets) @param ... tuples of (data,len) pairs to POLY1305, terminated with a (NULL,x) (x=don't care) @return CRYPT_OK if successful */ int poly1305_memory_multi(const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen, const unsigned char *in, unsigned long inlen, ...) { poly1305_state st; int err; va_list args; const unsigned char *curptr; unsigned long curlen; LTC_ARGCHK(key != NULL); LTC_ARGCHK(in != NULL); LTC_ARGCHK(mac != NULL); LTC_ARGCHK(maclen != NULL); va_start(args, inlen); curptr = in; curlen = inlen; if ((err = poly1305_init(&st, key, keylen)) != CRYPT_OK) { goto LBL_ERR; } for (;;) { if ((err = poly1305_process(&st, curptr, curlen)) != CRYPT_OK) { goto LBL_ERR; } curptr = va_arg(args, const unsigned char*); if (curptr == NULL) break; curlen = va_arg(args, unsigned long); } err = poly1305_done(&st, mac, maclen); LBL_ERR: #ifdef LTC_CLEAN_STACK zeromem(&st, sizeof(poly1305_state)); #endif va_end(args); return err; }
/** Terminate a ChaCha20Poly1305 stream @param st The ChaCha20Poly1305 state @param tag [out] The destination for the MAC tag @param taglen [in/out] The length of the MAC tag @return CRYPT_OK on success */ int chacha20poly1305_done(chacha20poly1305_state *st, unsigned char *tag, unsigned long *taglen) { unsigned char padzero[16] = { 0 }; unsigned long padlen; unsigned char buf[16]; int err; LTC_ARGCHK(st != NULL); padlen = 16 - (unsigned long)(st->ctlen % 16); if (padlen < 16) { if ((err = poly1305_process(&st->poly, padzero, padlen)) != CRYPT_OK) return err; } STORE64L(st->aadlen, buf); STORE64L(st->ctlen, buf + 8); if ((err = poly1305_process(&st->poly, buf, 16)) != CRYPT_OK) return err; if ((err = poly1305_done(&st->poly, tag, taglen)) != CRYPT_OK) return err; if ((err = chacha_done(&st->chacha)) != CRYPT_OK) return err; return CRYPT_OK; }