Page MenuHome GnuPG

libgcrypt | gcry_cipher_setkey: 3DES-CBC key returns GPG_ERR_WEAK even with GCRYCTL_SET_ALLOW_WEAK_KEY
Closed, ResolvedPublic

Description

System

Debian 11 amd64

Tools

CMake project
GCC 10.2.1 x86_64-linux-gnu

Library version

libgcrypt 1.10.1

Compilation options

no-thread no-shared

Description

When I use the gcry_cipher_setkey function to set a 3DES-CBC key, it returns an GPG_ERR_WEAK.

I tried to use gcry_cipher_ctl, with the parameter GCRYCTL_SET_ALLOW_WEAK_KEY, which enables code execution to enter the condition at line 766 of cipher.c.

But the subsequent switch has no case for CBC mode, and the function returns an error.

Key third portion is equal to 0, so I think that's the reason why it triggers an error.

I tried with a key with size = 16 bytes, but gcry_cipher_setkey needs a keylen of 24 bytes.

Expected result

gcry_cipher_setkey should set my key without error.

dec_payload should read 45 de ae ae e1 f4 6a 29 (see pastebin).

Step to reproduce

Here: https://pastebin.com/8Fri9HKW

Thank you :)

Details

Version
1.10.1

Event Timeline

werner added a subscriber: werner.

Thanks for the report. Fix is easy. I only wonder why you want to use a weak DES key.

Reading the commit rC5beadf201312: Add gcry_cipher_ctl command to allow weak keys in testing use-cases,
The test code in basic.c assumes that it is an application responsibility to confirm&ignore GPG_ERR_WEAK_KEY error when using GCRYCTL_SET_ALLOW_WEAK_KEY.

That's right. With GCRYCTL_SET_ALLOW_WEAK_KEY, setkey still returns GPG_ERR_WEAK_KEY when weak key is detected. However, cipher handle can still be used as if setkey succeeded.

tests/basic now actually fail because setkey not returning GPG_ERR_WEAK_KEY for weak keys with GCRYCTL_SET_ALLOW_WEAK_KEY.

I'll add documentation about GCRYCTL_SET_ALLOW_WEAK_KEY which was missing from be original commit.

Thank you for you responses! :)

With that problem solved, I still cannot get the result I want (see my pastebin).

With:

  • 3DES key = "\x16\xfe\x05\xf7\x3b\x57\xde\xb4\xeb\xb8\x79\xd6\xd0\x4c\xf0\x64\x00\x00\x00\x00\x00\x00\x00\x00"

(16 fe 05 f7 3b 57 de b4 eb b8 79 d6 d0 4c f0 64 00 00 00 00 00 00 00 00)

  • IV is 0
  • Encrypted payload = "\x2b\x98\xca\xaa\x29\xb3\xfe\x2e" (2b 98 ca aa 29 b3 fe 2e)

I should get:

  • Decrypted payload = "\x45\xde\xae\xae\xe1\xf4\x6a\x29" (45 de ae ae e1 f4 6a 29)

But I have "\xf9\xb4\x42\x67\x2e\x18\x68\x3e". (f9 b4 42 67 2e 18 68 3e)

I tried to move weak key from third position to first like:

  • 3DES key = "\x00\x00\x00\x00\x00\x00\x00\x00\x16\xfe\x05\xf7\x3b\x57\xde\xb4\xeb\xb8\x79\xd6\xd0\x4c\xf0\x64"

(00 00 00 00 00 00 00 00 16 fe 05 f7 3b 57 de b4 eb b8 79 d6 d0 4c f0 64)
But I have another wrong result that is "\x53\xce\xc0\xea\x8d\xb2\x45\x20". (53 ce c0 ea 8d b2 45 20)

I know it should work because I have logs from a commercial application that returns 45 de ae ae e1 f4 6a 29 with the same parameters I use above (key, IV, payload).

Also, I have the same result with a web application:


Source : http://tripledes.online-domain-tools.com/ (dont know if it is a safe website, but it gives a good result)

Thanks again

Reading the commit rC5beadf201312: Add gcry_cipher_ctl command to allow weak keys in testing use-cases,
The test code in basic.c assumes that it is an application responsibility to confirm&ignore GPG_ERR_WEAK_KEY error when using GCRYCTL_SET_ALLOW_WEAK_KEY.

You are right. However, when using any of the modern modes that error is reset anyway. That is a bit surprising although that I doubt that weak keys are an issue with modern ciphers which are commonly required for the modern modes. Given that gpg has this code for ages:

rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen);
if (gpg_err_code (rc) == GPG_ERR_WEAK_KEY)
  {
    log_info (_("WARNING: message was encrypted with"
                " a weak key in the symmetric cipher.\n"));
    rc = 0;
  }

I better revert my change and let the caller handle it.

Ok sorry, my bad, I have to use DES Keying option 2 to have 45 de ae ae e1 f4 6a 29, problem solved.

One last question, with 3DES, in my pastebin, gcry_cipher_setkey does not return 43 (GPG_ERR_WEAK_KEY), it returns value 536870955.

Is it a normal behavior ?

About error code. You need to use gcry_err_code(error_code) to get the GPG_ERR_WEAK_KEY value.

Here's patches I plan to push to master (revert + documentation):

Ok for 1.10 branch too?

@jukivili Yes, please go ahead for both branches. Thank you.

There is still a buglet because in some modes the weak key error can be swallowed by other errors. A fix would be something like:

           case GCRY_CIPHER_MODE_CMAC:
-          rc = _gcry_cipher_cmac_set_subkeys (c);
+          rc2 = _gcry_cipher_cmac_set_subkeys (c);
+          if (!rc && rc2)
+            rc = rc2;
           break;

Here's fix for mode specific setkey clearing error code:

jukivili claimed this task.