Padding on the end of the encrypted data in OpenSSH key format was
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sat, 15 Jun 2002 16:31:22 +0000 (16:31 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sat, 15 Jun 2002 16:31:22 +0000 (16:31 +0000)
broken: the OpenSSL EVP layer specifies a very particular form of
padding, which I wasn't generating because it hadn't occurred to me
that it might be mandatory. Irritatingly this was causing our
exported OpenSSH keys to load perfectly happily back in through our
OpenSSH import routines, but to be rejected by OpenSSH proper. Sigh.

git-svn-id: svn://svn.tartarus.org/sgt/putty@1733 cda61777-01e9-0310-a592-d414129be87e

import.c

index 7ad09ac..e792651 100644 (file)
--- a/import.c
+++ b/import.c
@@ -777,14 +777,15 @@ int openssh_write(char *filename, struct ssh2_userkey *key, char *passphrase)
     seqlen = len;
     /* Now add on the SEQUENCE header. */
     len += ber_write_id_len(NULL, 16, seqlen, ASN1_CONSTRUCTED);
-    /* And round up to the cipher block size. */
+    /* Round up to the cipher block size, ensuring we have at least one
+     * byte of padding (see below). */
+    outlen = len;
     if (passphrase)
-       len = (len+7) &~ 7;
+       outlen = (outlen+8) &~ 7;
 
     /*
      * Now we know how big outblob needs to be. Allocate it.
      */
-    outlen = len;
     outblob = smalloc(outlen);
 
     /*
@@ -797,8 +798,27 @@ int openssh_write(char *filename, struct ssh2_userkey *key, char *passphrase)
        memcpy(outblob+pos, numbers[i].start, numbers[i].bytes);
        pos += numbers[i].bytes;
     }
+
+    /*
+     * Padding on OpenSSH keys is deterministic. The number of
+     * padding bytes is always more than zero, and always at most
+     * the cipher block length. The value of each padding byte is
+     * equal to the number of padding bytes. So a plaintext that's
+     * an exact multiple of the block size will be padded with 08
+     * 08 08 08 08 08 08 08 (assuming a 64-bit block cipher); a
+     * plaintext one byte less than a multiple of the block size
+     * will be padded with just 01.
+     * 
+     * This enables the OpenSSL key decryption function to strip
+     * off the padding algorithmically and return the unpadded
+     * plaintext to the next layer: it looks at the final byte, and
+     * then expects to find that many bytes at the end of the data
+     * with the same value. Those are all removed and the rest is
+     * returned.
+     */
+    assert(pos == len);
     while (pos < outlen) {
-       outblob[pos++] = random_byte();
+        outblob[pos++] = outlen - len;
     }
 
     /*