libgcrypt integration into OSS-Fuzz differential cryptography fuzzer

Guido Vranken guidovranken at gmail.com
Thu May 9 13:52:35 CEST 2019


It found a difference with Veracrypt's Stribog. This is libgcrypt with the
carry overflow bug fix incorporated (commit
da6cd4fea30f79cf9d8f9b2f1c6daf3aea39fa9c)

Operation:
operation name: Digest
digest: STREEBOG-256
cleartext: {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
 0xff, 0xff, 0xff, 0x80, 0xbc, 0x6b, 0xa8, 0xb3, 0x68, 0xb9, 0x68, 0xbb,
0x53, 0x80, 0xe1, 0x06,
 0x90} (65 bytes)

Module libgcrypt result:

{0x0f, 0xbe, 0x0b, 0x3f, 0x89, 0x8d, 0x49, 0x22, 0xe8, 0x77, 0xc5, 0x1f,
0xfd, 0x4b, 0xef, 0x76,
 0xc6, 0x34, 0x03, 0x04, 0x00, 0xd0, 0x0c, 0x43, 0x06, 0x5a, 0xed, 0xc5,
0x74, 0x72, 0x34, 0x7b} (32 bytes)

Module Veracrypt result:

{0xbf, 0x49, 0x33, 0x72, 0x84, 0x00, 0x45, 0xa6, 0x9f, 0x21, 0xff, 0xc7,
0xa2, 0x07, 0x02, 0x99,
 0x8d, 0x76, 0x62, 0xf0, 0xb7, 0x2c, 0x02, 0x19, 0x9e, 0xf6, 0x72, 0xf8,
0x4b, 0x14, 0xc8, 0xb3} (32 bytes)


----------------------

On Thu, May 9, 2019 at 3:08 AM Guido Vranken <guidovranken at gmail.com> wrote:

> Never mind, I've noticed my bug, please ignore :).
>
> On Thu, May 9, 2019 at 2:35 AM Guido Vranken <guidovranken at gmail.com>
> wrote:
>
>> Here's an example of different outputs with chunked input:
>>
>> #include <stdbool.h>
>> #include <stdint.h>
>> #include <gcrypt.h>
>>
>> #define CF_CHECK_EQ(expr, res) if ( (expr) != (res) ) { goto end; }
>>
>> int main(void)
>> {
>>     uint8_t out[1024];
>>     const uint8_t cleartext[16] = {0};
>>     const uint8_t iv[16] = {0};
>>     const uint8_t key[32] = {0};
>>     size_t idx = 0;
>>
>>     gcry_cipher_hd_t h;
>>     bool hOpen = false;
>>     CF_CHECK_EQ(gcry_cipher_open(&h, GCRY_CIPHER_CHACHA20,
>> GCRY_CIPHER_MODE_STREAM, 0), GPG_ERR_NO_ERROR);
>>     hOpen = true;
>>     CF_CHECK_EQ(gcry_cipher_setkey(h, key, sizeof(key)),
>> GPG_ERR_NO_ERROR);
>>     CF_CHECK_EQ(gcry_cipher_setiv(h, iv, sizeof(iv)), GPG_ERR_NO_ERROR);
>>
>> #if defined(CHUNKED)
>>     const int lengths[] = {1, 15};
>> #else
>>     const int lengths[] = {16};
>> #endif
>>
>>     for (size_t i = 0; i < sizeof(lengths) / sizeof(lengths[0]); i++) {
>>         CF_CHECK_EQ(gcry_cipher_encrypt(h, out, sizeof(out) - idx,
>> cleartext + idx, lengths[i]), GPG_ERR_NO_ERROR);
>>         idx += lengths[i];
>>     }
>>
>>     for (size_t i = 0; i < idx; i++) {
>>         printf("%02X ", out[i]);
>>     }
>>     printf("\n");
>>
>> end:
>>     if ( hOpen == true ) {
>>         gcry_cipher_close(h);
>>     }
>> }
>>
>> Compile with and without -DCHUNKED. Am I doing something wrong?
>>
>> 'make check' did not report any errors but I'll look into it further.
>>
>> Guido
>>
>> On Wed, May 8, 2019 at 10:53 PM Jussi Kivilinna <jussi.kivilinna at iki.fi>
>> wrote:
>>
>>> On 8.5.2019 22.58, Guido Vranken wrote:
>>> > While we're on the subject, can you comment on which ciphers/cipher
>>> modes allow for "chunked updating"? Eg. if you have a cleartext of 16
>>> bytes, when is it allowed to call gcry_cipher_encrypt with the first 10
>>> bytes, then another 3 bytes, then the final 3 bytes (for example)? I've
>>> been noticing a host of wrong outputs if I allow "chunked updating" with
>>> libgcrypt.
>>>
>>> Following modes should work with "chunked updating":
>>>     GCRY_CIPHER_MODE_STREAM
>>>     GCRY_CIPHER_MODE_OFB
>>>     GCRY_CIPHER_MODE_CTR
>>>     GCRY_CIPHER_MODE_CFB
>>>     GCRY_CIPHER_MODE_CCM
>>>     GCRY_CIPHER_MODE_GCM
>>>     GCRY_CIPHER_MODE_EAX
>>>     GCRY_CIPHER_MODE_POLY1305
>>>
>>> ECB and CBC require input length in multiples of cipher blocksize.
>>>
>>> For XTS input length can be from 16 to 16*2^20 bytes.
>>>
>>> OCB requires first N-1 input buffer lengths to be multiples of cipher
>>> blocksize. Before last input buffer 'gcry_cipher_final()' needs to be
>>> called and last Nth input buffer does not have restriction on input size.
>>>
>>> > The documentation states "Depending on the selected algorithms and
>>> encryption mode, the length of the buffers must be a multiple of the block
>>> size." but this doesn't make it clear when it is allowed exactly. And
>>> should the function not just fail if chunked input is attempted when full
>>> blocks are expected?
>>>
>>> Modes that do not accept chunked input return error.
>>>
>>> >
>>> > Also, I consistently get the error message "selftest for CFB failed -
>>> see syslog for details" both from git master and 1.8.4. Is this expected?
>>>
>>> That is not expected. Which compiler and what kind of configuration are
>>> you using? Do you get these errors when running libgcrypt build tests,
>>> "make check"?
>>>
>>> -Jussi
>>>
>>> >
>>> > Thanks
>>> >
>>> > Guido
>>> >
>>> > On Wed, May 8, 2019 at 9:48 PM Jussi Kivilinna <jussi.kivilinna at iki.fi
>>> <mailto:jussi.kivilinna at iki.fi>> wrote:
>>> >
>>> >     Hello,
>>> >
>>> >     On 8.5.2019 16.31, Guido Vranken wrote:
>>> >     > Hi,
>>> >     >
>>> >     > I've been building a differential cryptography fuzzer that has
>>> been finding some nice bugs in major cryptographic libraries:
>>> https://github.com/guidovranken/cryptofuzz#hall-of-fame
>>> >     > It's very effective as it can find the Whirlpool bug (before
>>> 1.60.0) and the recent Stribog bug instantly.
>>> >     >
>>> >     > It finds errors in message digests like RipeMD160 in the current
>>> master branch that are not present in 1.8.4. I still have to research the
>>> cause.. I can post demonstration code later.
>>> >
>>> >     Thanks! It looks like culprit commit is
>>> 46d7dbbc293fdc1e04656798b3e6f58873fee110 which breaks md4, md5 and rmd160.
>>> Quickly looking at code, this happens when input size is '64*nblks +
>>> 56..63'. Bug is at md4.c/md5.c/rmd160.c new code path "/* need one extra
>>> block */" and when writing bit count to buffer. Buffer offsets there should
>>> be "hd->bctx.buf + 56 + 64" and "hd->bctx.buf + 60 + 64". Other message
>>> digests modified in that commit appear to get this right.
>>> >
>>> >     Bigger issue here is that there is quite big cap in testing
>>> coverage for digest finalization functions.. fuzzing against different
>>> libraries would definitely help.
>>> >
>>> >     >
>>> >     > It's running 24/7 on Google's OSS-Fuzz. Are the libgcrypt
>>> maintainers interested in participating in the OSS-Fuzz project? This
>>> entails that results for message digests, HMACs, CMACs and symmetric
>>> ciphers are compared to other libraries, and if there is a mismatch,
>>> everyone gets an e-mail. At that point we have to find out which library is
>>> emitting the wrong result, and the bug has to be fixed.
>>> >     >
>>> >
>>> >     I'd be interested getting emails of such mismatches.
>>> >
>>> >     What do others think? Werner? Niibe?
>>> >
>>> >
>>> >     -Jussi
>>> >
>>>
>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.gnupg.org/pipermail/gcrypt-devel/attachments/20190509/825864c8/attachment-0001.html>


More information about the Gcrypt-devel mailing list