(this might be a resend).
On Fri, 24 Apr 1998, Hal Finney wrote:
V3 keys can switch to using the new iterated/salted passphrase hashing,
which is a major security improvement.
The spec says V4 uses the new, V3 uses the old. Note that there are only
two differences between V3 and V4 secret key packets, and the other is the
version number at the head of the packet. It would be easy to modify
things to use V4 S2K protection on V3 keys, but the spec should say this
is permitted on a V3 key.
Does the spec say that V3 keys cannot use string-to-key specifiers,
and/or that it must use only the Simple S2K? I don't see that, but maybe
I am not looking in the right place. Neither 3.6.X nor 5.5.3 say that.
5.5.3 describes the difference in terms of what is encrypted, but doesn't
prevent you from using the new S2K packets. Is there someplace else
where it is mentioned?
Not directly, but the reason for using V3 keys is for backwards
compatibility. When I import them, they will be in the old passphrase
format if they are encrypted. If in needed to export them, and wanted to
retain the passphrase protection, they would need to be in the old format.
I can use the new S2K passphrase protection with a V3, but is there then
any reason to still leave it as a V3 key (other than keyid issues)? If I
am going to use V4 passphrase encryption is there any reason I would not
want to change the version number to 4?
One thing I keep getting stuck on is that there are many places I can keep
V3 as V3, but add extensions, when it seems to make more sense simply to
jump to V4. Otherwise you create a PGP 2.6.2-plus implicit within OpenPGP
and I think this is a bad idea. When there is a V3 way of doing things,
it should meet the old RFC completely since the single reason to do things
that way is to be backward compatible. Otherwise things should be done
using purely V4 methods.
I can hack V3 keyids of new keys (LSBs of the public_key parts of
DSA/DSS). I can use a one pass signature prefix with a V3 format
signature. And I can go on. But these shouldn't be done unless there are
plans to extend some version of PGP 2.6.2 to PGP 2.7.x that might
incorporate some Open PGP features. Since a PGP 2.7 would be undesirable,
I would think doing anything to extend V3 instead of moving to V4 would be
equally undesirable.
Get a copy of the PKCS-1 spec and try writing something from it. Without
looking at the preformatted number I challenge you to determine the other
bytes in the packet. Even given SSLeay's ASN1 support it takes about 10
lines (optimizing more than is proper). Unless I haven't seen a good
version of the spec (is there one beyond that on RSA.com?).
It is true that you have to be able to read ASN.1 to understand this part
of PKCS-1. The actual code requirements are very simple, and perhaps we
should put them into the spec as you suggest. Our SHA-1 prefix looks like:
(ASN1 breakout deleted - I assume you don't know ASN.1 by heart and
copied it from the source).
You follow this by the 20 digest bytes, then pad it with block type
1 from PKCS-1 section 8.1. We could take out the comments and it would
be pretty concise:
0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 43, 14, 3, 2, 26, 0x05, 0x00, 0x04, 0x14
Similar structures could be provided for the other hashes. This might
be a better way to do it.
Or if you have SSLeay 0.9.X:
#include <stdio.h>
#include <asn1.h>
#include <objects.h>
int main(int argc, char *argv[])
{
unsigned char buf[4096], *bp;
int i, j;
ASN1_OCTET_STRING s;
s.data = "0123456789ABCDEFGHIJ"; /* replace with actual hash */
s.length = 20;
bp = &buf[4];
i2d_ASN1_OBJECT(OBJ_nid2obj(OBJ_sn2nid( "SHA1" )), &bp);
ASN1_put_object(&bp, 0, 0, V_ASN1_NULL, V_ASN1_UNIVERSAL);
j = bp - buf - 4;
i2d_ASN1_OCTET_STRING(&s, &bp);
i = bp - buf - 2;
bp = &buf[2];
ASN1_put_object(&bp, 1, j, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
bp = buf;
ASN1_put_object(&bp, 1, i, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
i += 2;
for (j = 0; j < i - 20; j++)
if ((j & 7) == 7)
fprintf(stderr, "0x%02x,\n", buf[j]);
else
fprintf(stderr, "0x%02x, ", buf[j]);
fprintf(stderr, "\n");
#if 1
fwrite(buf, 1, i, stdout);
#endif
return 0;
}
But this code is as obscure as the description.
The fwrite to stdout allows piping to "asn1parse -inform DER"
Change the "SHA1" to MD5, RIPEMD160, or MD2 (no oid for HAVAL yet), and
change the s.length as needed. Because the above code is far longer and
more complex than the tables, I didn't do the objects that way.
I have a fuller version that writes out the tail of hasher.c (maybe I
should do that as a .h file, but I only need run it once).
12.7
But implementors might also want to import secret V3 keys, so will need
the general algorithm. And I don't use any of the FR, FRE or other
registers described. I simply copy the last 8 bytes (actually the cipher
block size, but all are 8 so far) of cyphertext into the IV and set the
IVcount to zero.
Yes, I wrote up that long description because I thought you were asking
how it worked, and Jon put it in the spec as an explicit example of
how the feedback works. I think the description in the earlier part
of the spec was OK but if we do want this kind of long description then
perhaps we should also do one (or two for the two cases) for the secret
key encryption as well.
Or at least put a note that it would not be a good idea to hardcode parts
of the method. The example gives symmetric encryption header specific
stuff instead of being a general description. Were I reading it I might
use fixed values.
--- reply to tzeruch - at - ceddec - dot - com ---