Skip to content

Commit 62cd873

Browse files
authored
Merge pull request #451 from libtom/pr/wycheproof-gcm
Wycheproof failing GCM test - invalid/modified tag
2 parents 60eb5d0 + 7d85676 commit 62cd873

7 files changed

+97
-8
lines changed

doc/crypt.tex

+6
Original file line numberDiff line numberDiff line change
@@ -2305,6 +2305,9 @@ \subsection{One--Shot Packet}
23052305
This will initialize the GCM state with the given key, IV and AAD value then proceed to encrypt or decrypt the message text and store the final
23062306
message tag. The definition of the variables is the same as it is for all the manual functions.
23072307

2308+
IMPORTANT NOTICE: for \textit{direction == GCM\_DECRYPT} the caller has to fill \textit{tag} and \textit{taglen} with expected
2309+
tag value. The \textit{gcm\_memory} in decrypt mode validates the \textit{tag} value and returns \textit{CRYPT\_ERROR} on mismatch.
2310+
23082311
If you are processing many packets under the same key you shouldn't use this function as it invokes the pre--computation with each call.
23092312

23102313
\subsection{Example Usage}
@@ -2515,6 +2518,9 @@ \subsection{One--Shot Packet}
25152518
\textbf{CHACHA20POLY1305\_DECRYPT}) the message text and store the final message tag. The definition of the
25162519
variables is the same as it is for all the manual functions.
25172520

2521+
IMPORTANT NOTICE: for \textit{direction == CHACHA20POLY1305\_DECRYPT} the caller has to fill \textit{tag} and \textit{taglen} with expected
2522+
tag value. The \textit{chacha20poly1305\_memory} in decrypt mode validates the \textit{tag} value and returns \textit{CRYPT\_ERROR} on mismatch.
2523+
25182524
\chapter{One-Way Cryptographic Hash Functions}
25192525
\mysection{Core Functions}
25202526
Like the ciphers, there are hash core functions and a universal data type to hold the hash state called \textit{hash\_state}. To initialize hash

src/encauth/chachapoly/chacha20poly1305_decrypt.c

-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ int chacha20poly1305_decrypt(chacha20poly1305_state *st, const unsigned char *in
2525
unsigned long padlen;
2626
int err;
2727

28-
if (inlen == 0) return CRYPT_OK; /* nothing to do */
2928
LTC_ARGCHK(st != NULL);
3029

3130
if (st->aadflg) {

src/encauth/chachapoly/chacha20poly1305_encrypt.c

-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ int chacha20poly1305_encrypt(chacha20poly1305_state *st, const unsigned char *in
2525
unsigned long padlen;
2626
int err;
2727

28-
if (inlen == 0) return CRYPT_OK; /* nothing to do */
2928
LTC_ARGCHK(st != NULL);
3029

3130
if ((err = chacha_crypt(&st->chacha, in, inlen, out)) != CRYPT_OK) return err;

src/encauth/chachapoly/chacha20poly1305_memory.c

+9-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ int chacha20poly1305_memory(const unsigned char *key, unsigned long keylen,
4343
LTC_ARGCHK(in != NULL);
4444
LTC_ARGCHK(out != NULL);
4545
LTC_ARGCHK(tag != NULL);
46+
LTC_ARGCHK(taglen != NULL);
4647

4748
if ((err = chacha20poly1305_init(&st, key, keylen)) != CRYPT_OK) { goto LBL_ERR; }
4849
if ((err = chacha20poly1305_setiv(&st, iv, ivlen)) != CRYPT_OK) { goto LBL_ERR; }
@@ -51,15 +52,22 @@ int chacha20poly1305_memory(const unsigned char *key, unsigned long keylen,
5152
}
5253
if (direction == CHACHA20POLY1305_ENCRYPT) {
5354
if ((err = chacha20poly1305_encrypt(&st, in, inlen, out)) != CRYPT_OK) { goto LBL_ERR; }
55+
if ((err = chacha20poly1305_done(&st, tag, taglen)) != CRYPT_OK) { goto LBL_ERR; }
5456
}
5557
else if (direction == CHACHA20POLY1305_DECRYPT) {
58+
unsigned char buf[MAXBLOCKSIZE];
59+
unsigned long buflen = sizeof(buf);
5660
if ((err = chacha20poly1305_decrypt(&st, in, inlen, out)) != CRYPT_OK) { goto LBL_ERR; }
61+
if ((err = chacha20poly1305_done(&st, buf, &buflen)) != CRYPT_OK) { goto LBL_ERR; }
62+
if (buflen != *taglen || XMEM_NEQ(buf, tag, buflen) != 0) {
63+
err = CRYPT_ERROR;
64+
goto LBL_ERR;
65+
}
5766
}
5867
else {
5968
err = CRYPT_INVALID_ARG;
6069
goto LBL_ERR;
6170
}
62-
err = chacha20poly1305_done(&st, tag, taglen);
6371
LBL_ERR:
6472
#ifdef LTC_CLEAN_STACK
6573
zeromem(&st, sizeof(chacha20poly1305_state));

src/encauth/chachapoly/chacha20poly1305_test.c

+36-1
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@ int chacha20poly1305_test(void)
7777

7878
/* chacha20poly1305_memory - decrypt */
7979
len = sizeof(dmac);
80+
XMEMCPY(dmac, tag, sizeof(tag));
8081
if ((err = chacha20poly1305_memory(k, sizeof(k), i12, sizeof(i12), aad, sizeof(aad),
8182
ct, mlen, pt, dmac, &len, CHACHA20POLY1305_DECRYPT)) != CRYPT_OK) return err;
8283
if (compare_testvector(pt, mlen, m, mlen, "DEC-PT2", 3) != 0) return CRYPT_FAIL_TESTVECTOR;
83-
if (compare_testvector(dmac, len, tag, sizeof(tag), "DEC-TAG2", 4) != 0) return CRYPT_FAIL_TESTVECTOR;
8484

8585
/* encrypt - rfc7905 */
8686
if ((err = chacha20poly1305_init(&st1, k, sizeof(k))) != CRYPT_OK) return err;
@@ -123,6 +123,41 @@ int chacha20poly1305_test(void)
123123
if (compare_testvector(pt, mlen, m, mlen, "DEC-PT4", 1) != 0) return CRYPT_FAIL_TESTVECTOR;
124124
if (compare_testvector(dmac, len, emac, len, "DEC-TAG4", 2) != 0) return CRYPT_FAIL_TESTVECTOR;
125125

126+
/* wycheproof failing test - https://github.com/libtom/libtomcrypt/pull/451 */
127+
{
128+
unsigned char key[] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff,
129+
0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff };
130+
unsigned char iv[] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b };
131+
unsigned char valid_tag[] = { 0xa3,0xe3,0xfd,0xf9,0xfb,0xa6,0x86,0x1b,0x5a,0xd2,0x60,0x7f,0x40,0xb7,0xf4,0x47 };
132+
unsigned char invalid_tag[] = { 0xa2,0xe3,0xfd,0xf9,0xfb,0xa6,0x86,0x1b,0x5a,0xd2,0x60,0x7f,0x40,0xb7,0xf4,0x47 };
133+
unsigned char waad[] = { 0x61,0x61,0x64 };
134+
unsigned char wct[] = { 0x00 };
135+
unsigned char wpt[20] = { 0 };
136+
unsigned char wtag[20] = { 0 };
137+
unsigned long taglen;
138+
139+
/* encrypt */
140+
taglen = sizeof(wtag);
141+
err = chacha20poly1305_memory(key, sizeof(key), iv, sizeof(iv), waad, sizeof(waad),
142+
wpt, 0, wct, wtag, &taglen, CHACHA20POLY1305_ENCRYPT);
143+
if (err != CRYPT_OK) return CRYPT_FAIL_TESTVECTOR;
144+
if (compare_testvector(wtag, taglen, valid_tag, sizeof(valid_tag), "WYCH", 1) != 0) return CRYPT_FAIL_TESTVECTOR;
145+
146+
/* VALID tag */
147+
taglen = sizeof(valid_tag);
148+
err = chacha20poly1305_memory(key, sizeof(key), iv, sizeof(iv), waad, sizeof(waad),
149+
wpt, 0, wct, valid_tag, &taglen, CHACHA20POLY1305_DECRYPT);
150+
if (err != CRYPT_OK) return CRYPT_FAIL_TESTVECTOR;
151+
152+
/* INVALID tag */
153+
taglen = sizeof(invalid_tag);
154+
err = chacha20poly1305_memory(key, sizeof(key), iv, sizeof(iv), waad, sizeof(waad),
155+
wpt, 0, wct, invalid_tag, &taglen, CHACHA20POLY1305_DECRYPT);
156+
if (err == CRYPT_OK) {
157+
return CRYPT_FAIL_TESTVECTOR; /* should fail */
158+
}
159+
}
160+
126161
return CRYPT_OK;
127162
#endif
128163
}

src/encauth/gcm/gcm_memory.c

+18-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,24 @@ int gcm_memory( int cipher,
9393
if ((err = gcm_process(gcm, pt, ptlen, ct, direction)) != CRYPT_OK) {
9494
goto LTC_ERR;
9595
}
96-
err = gcm_done(gcm, tag, taglen);
96+
if (direction == GCM_ENCRYPT) {
97+
if ((err = gcm_done(gcm, tag, taglen)) != CRYPT_OK) {
98+
goto LTC_ERR;
99+
}
100+
}
101+
else if (direction == GCM_DECRYPT) {
102+
unsigned char buf[MAXBLOCKSIZE];
103+
unsigned long buflen = sizeof(buf);
104+
if ((err = gcm_done(gcm, buf, &buflen)) != CRYPT_OK) {
105+
goto LTC_ERR;
106+
}
107+
if (buflen != *taglen || XMEM_NEQ(buf, tag, buflen) != 0) {
108+
err = CRYPT_ERROR;
109+
}
110+
}
111+
else {
112+
err = CRYPT_INVALID_ARG;
113+
}
97114
LTC_ERR:
98115
XFREE(orig);
99116
return err;

src/encauth/gcm/gcm_test.c

+28-3
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ int gcm_test(void)
363363
}
364364

365365
y = sizeof(T[1]);
366+
XMEMCPY(T[1], tests[x].T, 16);
366367
if ((err = gcm_memory(idx, tests[x].K, tests[x].keylen,
367368
tests[x].IV, tests[x].IVlen,
368369
tests[x].A, tests[x].alen,
@@ -374,12 +375,36 @@ int gcm_test(void)
374375
if (compare_testvector(out[1], tests[x].ptlen, tests[x].P, tests[x].ptlen, "GCM PT", x)) {
375376
return CRYPT_FAIL_TESTVECTOR;
376377
}
378+
}
377379

378-
if (compare_testvector(T[1], y, tests[x].T, 16, "GCM Decrypt Tag", x)) {
379-
return CRYPT_FAIL_TESTVECTOR;
380-
}
380+
/* wycheproof failing test - https://github.com/libtom/libtomcrypt/pull/451 */
381+
{
382+
unsigned char key[] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f };
383+
unsigned char iv[] = { 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b };
384+
unsigned char valid_tag[] = { 0xd8,0x84,0x7d,0xbc,0x32,0x6a,0x06,0xe9,0x88,0xc7,0x7a,0xd3,0x86,0x3e,0x60,0x83 };
385+
unsigned char invalid_tag[] = { 0xd9,0x84,0x7d,0xbc,0x32,0x6a,0x06,0xe9,0x88,0xc7,0x7a,0xd3,0x86,0x3e,0x60,0x83 };
386+
unsigned char msg[] = { 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f };
387+
unsigned char ct[] = { 0xeb,0x15,0x6d,0x08,0x1e,0xd6,0xb6,0xb5,0x5f,0x46,0x12,0xf0,0x21,0xd8,0x7b,0x39 };
388+
unsigned char pt[20] = { 0 };
389+
unsigned long taglen;
390+
391+
/* VALID tag */
392+
taglen = sizeof(valid_tag);
393+
err = gcm_memory(idx, key, sizeof(key), iv, sizeof(iv), NULL, 0,
394+
pt, sizeof(ct), ct, valid_tag, &taglen, GCM_DECRYPT);
395+
if ((err != CRYPT_OK) || (XMEMCMP(msg, pt, sizeof(msg)) != 0)) {
396+
return CRYPT_FAIL_TESTVECTOR;
397+
}
381398

399+
/* INVALID tag */
400+
taglen = sizeof(invalid_tag);
401+
err = gcm_memory(idx, key, sizeof(key), iv, sizeof(iv), NULL, 0,
402+
pt, sizeof(ct), ct, invalid_tag, &taglen, GCM_DECRYPT);
403+
if (err == CRYPT_OK) {
404+
return CRYPT_FAIL_TESTVECTOR; /* should fail */
405+
}
382406
}
407+
383408
return CRYPT_OK;
384409
#endif
385410
}

0 commit comments

Comments
 (0)