openwall / john

John the Ripper jumbo - advanced offline password cracker, which supports hundreds of hash and cipher types, and runs on many operating systems, CPUs, GPUs, and even some FPGAs
https://www.openwall.com/john/
Other
10.27k stars 2.1k forks source link

Add support for cracking very old GPG keys #3273

Open kholia opened 6 years ago

kholia commented 6 years ago

Links,

Quick notes,

On CentOS 7,

$ gpg --homedir . --s2k-cipher-algo idea --s2k-mode 0 --simple-sk-checksum --gen-key

$ pgpdump secring.gpg
...
Old: Secret Key Packet(tag 5)(931 bytes)
    Ver 4 - new
    Public key creation time - Tue Jun 19 15:04:57 IST 2018
    Pub alg - RSA Encrypt or Sign(pub 1)
    RSA n(2048 bits) - ...
    RSA e(17 bits) - ...
    Sym alg - IDEA(sym 1)
    Simple string-to-key(s2k 0):
        Hash alg - SHA1(hash 2

$ pgpdump newold.asc
Old: Secret Key Packet(tag 5)(928 bytes)
    Ver 3 - old
    Public key creation time - Tue Jun 19 00:59:57 IST 2018
    Valid days - 0[0 is forever]
    Pub alg - RSA Encrypt or Sign(pub 1)
    RSA n(2048 bits) - ...
    RSA e(5 bits) - ...
    Sym alg - IDEA(sym 1)
    Simple string-to-key for IDEA
    IV - 4c 24 29 7b 7d fe f2 3d
    Encrypted RSA d(2046 bits) - ...
    Encrypted RSA p(1024 bits) - ...
    Encrypted RSA q(1024 bits) - ...
    Encrypted RSA u(1022 bits) - ...
    Checksum - 52 27

It seems that we don't support this (i.e. Simple string-to-key for IDEA) S2K yet.

Note: Rejecting such keys and avoiding false negatives would be helpful for now.

CC @solardiz.

solardiz commented 6 years ago

Thanks, Dhiru. I think "Rejecting such keys and avoiding false negatives" is very important, and the current behavior is a bug - so fixing that aspect of this issue is more than just an "enhancement".

Our current reporting of out-of-range hash type 0 is also a bug. The code appears to treat 0 as SHA-1. It should probably "upgrade" it to 1, which is MD5. And it should certainly not report it as 0 while also printing a list of hash types and their numbers that doesn't include 0.

kholia commented 6 years ago

Ack on the bug label part.

kholia commented 6 years ago

Ideas for fixing this,

diff --git a/src/gpg2john.c b/src/gpg2john.c
index 16f24bbc8..de99a07f4 100644
--- a/src/gpg2john.c
+++ b/src/gpg2john.c
@@ -2570,6 +2570,10 @@ encrypted_Secret_Key(int len, int sha1)
                        MEM_FREE(last_hash);
                        last_hash = mem_alloc(len*2 + 512 + (n_bits + 7) / 4);
                        cp = last_hash;
+                       if (m_usage == 1) {
+                               puts("[ERROR] We don't support 'Simple string-to-key for IDEA' S2K type yet.");
+                               return;
+                       }
                        cp += sprintf(cp, "$gpg$*%d*%d*%d*", m_algorithm, len, n_bits);
                        cp += print_hex(m_data, len, cp);
                        cp += sprintf(cp, "*%d*%d*%d*%d*%d*", m_spec, m_usage, m_hashAlgorithm, m_cipherAlgorithm, bs);

With this patch applied,

$ ../run/gpg2john very-old-key.gpg 

File very-old-key.gpg
[ERROR] We don't support 'Simple string-to-key for IDEA' S2K type yet.
Error: No hash was generated for very-old-key.gpg, ensure that the input file contains a single private key only.

Format patch,

diff --git a/src/gpg_common_plug.c b/src/gpg_common_plug.c
index 0cbfb36b8..e733eeae9 100644
--- a/src/gpg_common_plug.c
+++ b/src/gpg_common_plug.c
@@ -271,7 +271,7 @@ int gpg_common_valid(char *ciphertext, struct fmt_main *self, int is_CPU_format)
                goto err;
        usage = atoi(p);
        if (!symmetric_mode) {
-               if (usage != 0 && usage != 254 && usage != 255 && usage != 1)
+               if (usage != 0 && usage != 254 && usage != 255) // && usage != 1)
                        goto err;
        } else {
                if (usage != 9 && usage != 18) // https://tools.ietf.org/html/rfc4880
kholia commented 6 years ago

Based on https://www.autistici.org/crypto/index.php/remository/GPG-PGP/linux/pgp-2.6.3-(linux)/, the KDF seems to be,

void hashpass (char *keystring, int keylen, byte *hash)
{
        struct MD5Context mdContext;

        /* Calculate the hash */
        MD5Init(&mdContext);
        MD5Update(&mdContext, (unsigned char *) keystring, keylen);
        MD5Final(hash, &mdContext);
} /* hashpass */
kholia commented 6 years ago

See readkeypacket in keymgmt.c for the decryption verification part. The following branch (within this function) is interesting and quite similar to the existing verification code in our GPG format.

if (is_secret_key(ctb)) {
    fread(&alg, 1, 1, f);
    if (alg && version_error(alg, IDEA_ALGORITHM_BYTE))
            SKIP_RETURN(-6);    /* Unknown version */

    if (!cfb && alg) 
            /* Don't bother trying if hidekey is false and alg is true */
            SKIP_RETURN(-5);

    if (alg) {          /* if secret components are encrypted... */
            /* process encrypted CFB IV before reading secret components */
            count = fread(iv, 1, 8, f);
            if (count < 8)
                    return -4;  /* data corrupted, error return */

            ideaCfbDecrypt(cfb, iv, iv, 8); 
            cert_length -= 8;   /* take IV length into account */
    }       
    /* Reset checksum before these reads */
    mpi_checksum = 0;

    if (read_mpi(d, f, FALSE, cfb) < 0)
            return -4;          /* data corrupted, error return */
    if (read_mpi(p, f, FALSE, cfb) < 0)
            return -4;          /* data corrupted, error return */
    if (read_mpi(q, f, FALSE, cfb) < 0)
            return -4;
kholia commented 6 years ago

Test data,

$ cat ~/.pgp/secring.pgp | base64
lQABA2L2WlsAAAECAHS6w9amqeYsAHe+96vlha98chNn095MP+ZkQC+br3vxXM1gaVBvSsSCiVBI
1QOy1w5tV33InUXccAQpERWisQYABQABOwbKrsoZ1xcB/9DkbZVIIvpQjK2KfWkNWHakz4xJCxuH
v7gqOwc96Wc63OMN5bXTVWBxVNtbOFQnYeoN1JkgepIQK0yEg7TZ+uQBAMUCujTH6fXBNUE9GIHh
Rzz5qF2WWNIiuEKkRGjbRYqnAQCZKciwoakzZaE/+uY4eD+Fi4QEynUzxLoKO6H/kk1TKwEAEYRw
NZO5HBFvrleOjfDIVfv+m29cg5Im6JM3/mP1hd93T7QFaGVsbG8=
$ pgpdump ~/.pgp/secring.pgp     
Old: Secret Key Packet(tag 5)(1 bytes)
    Ver 3 - old
    Public key creation time - Fri Aug 12 19:19:15 IST 2022
    Valid days - 0[0 is forever]
    Pub alg - RSA Encrypt or Sign(pub 1)
    RSA n(512 bits) - ...
    RSA e(5 bits) - ...
    Sym alg - IDEA(sym 1)
    Simple string-to-key for IDEA
    IV - 3b 06 ca ae ca 19 d7 17 
    Encrypted RSA d(511 bits) - ...
    Encrypted RSA p(256 bits) - ...
    Encrypted RSA q(256 bits) - ...
    Encrypted RSA u(256 bits) - ...
    Checksum - 77 4f 
Old: User ID Packet(tag 13)(5 bytes)
    User ID - hello