aboutsummaryrefslogtreecommitdiffstats
path: root/g10/seskey.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2011-01-21 11:00:57 +0000
committerWerner Koch <[email protected]>2011-01-21 11:00:57 +0000
commit90b0ff23b7e51332592668e4034967c1aac1c593 (patch)
treea3ef4cbd4c679a954a2cceba218b54cc2e2e9be5 /g10/seskey.c
parentAdd ignore file (diff)
downloadgnupg-90b0ff23b7e51332592668e4034967c1aac1c593.tar.gz
gnupg-90b0ff23b7e51332592668e4034967c1aac1c593.zip
Editorial changes and allow building with old libgcrypts.
Changed order of some conditional to make to put the special case into the true branch. Indentation changes. Minor other changes to make the ECC code more similar to the rest of our code. It builds but many sefltests still fail. Need to fix that before using it with an ECDH enabled libgcrypt. [/] 2011-01-21 Werner Koch <[email protected]> * configure.ac: Need Libgcrypt 1.4.6 due to AESWRAP. (HAVE_GCRY_PK_ECDH): Add new test. [agent/] 2011-01-21 Werner Koch <[email protected]> * cvt-openpgp.c (GCRY_PK_ECDH) [!HAVE_GCRY_PK_ECDH]: New. [include/] 2011-01-21 Werner Koch <[email protected]> * cipher.h (GCRY_PK_USAGE_CERT): Remove compatibility macros because we now require libgcrypt 1.4.6. (GCRY_PK_ECDH): Add replacement.
Diffstat (limited to 'g10/seskey.c')
-rw-r--r--g10/seskey.c279
1 files changed, 152 insertions, 127 deletions
diff --git a/g10/seskey.c b/g10/seskey.c
index e50cf5c02..fa6765dc6 100644
--- a/g10/seskey.c
+++ b/g10/seskey.c
@@ -1,6 +1,6 @@
/* seskey.c - make sesssion keys etc.
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- * 2006, 2009 Free Software Foundation, Inc.
+ * 2006, 2009, 2010 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -76,109 +76,125 @@ make_session_key( DEK *dek )
gcry_mpi_t
encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits)
{
- size_t nframe = (nbits+7) / 8;
- byte *p;
- byte *frame;
- int i,n;
- u16 csum = 0;
- gcry_mpi_t a;
-
- if( DBG_CIPHER )
- log_debug("encode_session_key: encoding %d byte DEK", dek->keylen);
-
- for( p = dek->key, i=0; i < dek->keylen; i++ )
- csum += *p++;
-
- /* Shortcut for ECDH. It's padding is minimal to simply make the output be a multiple of 8 bytes. */
- if( openpgp_pk_algo == PUBKEY_ALGO_ECDH ) {
- /* pad to 8 byte granulatiry; the padding byte is the number of padded bytes.
- * A DEK(k bytes) CSUM(2 bytes) 0x 0x 0x 0x ... 0x
- * +---- x times ---+
- */
- nframe = ( 1 + dek->keylen + 2 /* the value so far is always odd */ + 7 ) & (~7);
- assert( !(nframe%8) && nframe > 1 + dek->keylen + 2 ); /* alg+key+csum fit and the size is congruent to 8 */
- frame = xmalloc_secure( nframe );
- n = 0;
- frame[n++] = dek->algo;
- memcpy( frame+n, dek->key, dek->keylen ); n += dek->keylen;
- frame[n++] = csum >>8;
- frame[n++] = csum;
- i = nframe - n; /* number padded bytes */
- memset( frame+n, i, i );/* use it as the value of each padded byte */
- assert( n+i == nframe );
-
- if( DBG_CIPHER )
- log_debug("encode_session_key: [%d] %02x %02x %02x ... %02x %02x %02x", nframe, frame[0],frame[1],frame[2], frame[nframe-3],frame[nframe-2],frame[nframe-1]);
-
- if (gcry_mpi_scan( &a, GCRYMPI_FMT_USG, frame, nframe, &nframe))
- BUG();
- xfree(frame);
- return a;
+ size_t nframe = (nbits+7) / 8;
+ byte *p;
+ byte *frame;
+ int i,n;
+ u16 csum;
+ gcry_mpi_t a;
+
+ if (DBG_CIPHER)
+ log_debug ("encode_session_key: encoding %d byte DEK", dek->keylen);
+
+ csum = 0;
+ for (p = dek->key, i=0; i < dek->keylen; i++)
+ csum += *p++;
+
+ /* Shortcut for ECDH. It's padding is minimal to simply make the
+ output be a multiple of 8 bytes. */
+ if (openpgp_pk_algo == PUBKEY_ALGO_ECDH)
+ {
+ /* Pad to 8 byte granulatiry; the padding byte is the number of
+ * padded bytes.
+ *
+ * A DEK(k bytes) CSUM(2 bytes) 0x 0x 0x 0x ... 0x
+ * +---- x times ---+
+ */
+ nframe = (( 1 + dek->keylen + 2 /* The value so far is always odd. */
+ + 7 ) & (~7));
+
+ /* alg+key+csum fit and the size is congruent to 8. */
+ assert (!(nframe%8) && nframe > 1 + dek->keylen + 2 );
+
+ frame = xmalloc_secure (nframe);
+ n = 0;
+ frame[n++] = dek->algo;
+ memcpy (frame+n, dek->key, dek->keylen);
+ n += dek->keylen;
+ frame[n++] = csum >> 8;
+ frame[n++] = csum;
+ i = nframe - n; /* Number of padded bytes. */
+ memset (frame+n, i, i); /* Use it as the value of each padded byte. */
+ assert (n+i == nframe);
+
+ if (DBG_CIPHER)
+ log_debug ("encode_session_key: "
+ "[%d] %02x %02x %02x ... %02x %02x %02x\n",
+ nframe, frame[0], frame[1], frame[2],
+ frame[nframe-3], frame[nframe-2], frame[nframe-1]);
+
+ if (gcry_mpi_scan (&a, GCRYMPI_FMT_USG, frame, nframe, &nframe))
+ BUG();
+ xfree(frame);
+ return a;
}
-
- /* The current limitation is that we can only use a session key
- * whose length is a multiple of BITS_PER_MPI_LIMB
- * I think we can live with that.
- */
- if( dek->keylen + 7 > nframe || !nframe )
- log_bug("can't encode a %d bit key in a %d bits frame\n",
- dek->keylen*8, nbits );
-
- /* We encode the session key in this way:
- *
- * 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes)
- *
- * (But how can we store the leading 0 - the external representaion
- * of MPIs doesn't allow leading zeroes =:-)
- *
- * RND are non-zero random bytes.
- * A is the cipher algorithm
- * DEK is the encryption key (session key) length k depends on the
- * cipher algorithm (20 is used with blowfish160).
- * CSUM is the 16 bit checksum over the DEK
- */
-
- frame = xmalloc_secure( nframe );
- n = 0;
- frame[n++] = 0;
- frame[n++] = 2;
- i = nframe - 6 - dek->keylen;
- assert( i > 0 );
- p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM);
- /* Replace zero bytes by new values. */
- for(;;) {
- int j, k;
- byte *pp;
-
- /* count the zero bytes */
- for(j=k=0; j < i; j++ )
- if( !p[j] )
- k++;
- if( !k )
- break; /* okay: no zero bytes */
- k += k/128 + 3; /* better get some more */
- pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM);
- for(j=0; j < i && k ;) {
- if( !p[j] )
- p[j] = pp[--k];
- if (p[j])
- j++;
+
+ /* The current limitation is that we can only use a session key
+ * whose length is a multiple of BITS_PER_MPI_LIMB
+ * I think we can live with that.
+ */
+ if (dek->keylen + 7 > nframe || !nframe)
+ log_bug ("can't encode a %d bit key in a %d bits frame\n",
+ dek->keylen*8, nbits );
+
+ /* We encode the session key in this way:
+ *
+ * 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes)
+ *
+ * (But how can we store the leading 0 - the external representaion
+ * of MPIs doesn't allow leading zeroes =:-)
+ *
+ * RND are non-zero random bytes.
+ * A is the cipher algorithm
+ * DEK is the encryption key (session key) length k depends on the
+ * cipher algorithm (20 is used with blowfish160).
+ * CSUM is the 16 bit checksum over the DEK
+ */
+
+ frame = xmalloc_secure( nframe );
+ n = 0;
+ frame[n++] = 0;
+ frame[n++] = 2;
+ i = nframe - 6 - dek->keylen;
+ assert( i > 0 );
+ p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM);
+ /* Replace zero bytes by new values. */
+ for (;;)
+ {
+ int j, k;
+ byte *pp;
+
+ /* Count the zero bytes. */
+ for (j=k=0; j < i; j++ )
+ if (!p[j])
+ k++;
+ if (!k)
+ break; /* Okay: no zero bytes. */
+ k += k/128 + 3; /* Better get some more. */
+ pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM);
+ for (j=0; j < i && k ;)
+ {
+ if (!p[j])
+ p[j] = pp[--k];
+ if (p[j])
+ j++;
}
- xfree(pp);
+ xfree (pp);
}
- memcpy( frame+n, p, i );
- xfree(p);
- n += i;
- frame[n++] = 0;
- frame[n++] = dek->algo;
- memcpy( frame+n, dek->key, dek->keylen ); n += dek->keylen;
- frame[n++] = csum >>8;
- frame[n++] = csum;
- assert( n == nframe );
- if (gcry_mpi_scan( &a, GCRYMPI_FMT_USG, frame, n, &nframe))
- BUG();
- xfree(frame);
- return a;
+ memcpy (frame+n, p, i);
+ xfree (p);
+ n += i;
+ frame[n++] = 0;
+ frame[n++] = dek->algo;
+ memcpy (frame+n, dek->key, dek->keylen );
+ n += dek->keylen;
+ frame[n++] = csum >>8;
+ frame[n++] = csum;
+ assert (n == nframe);
+ if (gcry_mpi_scan( &a, GCRYMPI_FMT_USG, frame, n, &nframe))
+ BUG();
+ xfree (frame);
+ return a;
}
@@ -192,8 +208,8 @@ do_encode_md( gcry_md_hd_t md, int algo, size_t len, unsigned nbits,
gcry_mpi_t a;
if( len + asnlen + 4 > nframe )
- log_bug("can't encode a %d bit MD into a %d bits frame, algo=%d\n",
- (int)(len*8), (int)nbits, algo);
+ log_bug ("can't encode a %d bit MD into a %d bits frame, algo=%d\n",
+ (int)(len*8), (int)nbits, algo);
/* We encode the MD in this way:
*
@@ -240,26 +256,27 @@ gcry_mpi_t
encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo)
{
gcry_mpi_t frame;
- int gcry_pkalgo;
+ int pkalgo;
assert (hash_algo);
assert (pk);
- gcry_pkalgo = map_pk_openpgp_to_gcry( pk->pubkey_algo );
+ pkalgo = map_pk_openpgp_to_gcry (pk->pubkey_algo);
- if (gcry_pkalgo == GCRY_PK_DSA || gcry_pkalgo == GCRY_PK_ECDSA )
+ if (pkalgo == GCRY_PK_DSA || pkalgo == GCRY_PK_ECDSA)
{
- /* It's a DSA signature, so find out the size of q. */
+ /* It's a DSA signature, so find out the size of q. */
size_t qbytes = gcry_mpi_get_nbits (pk->pkey[1]);
- /* pkey[1] is Q for ECDSA, which is an uncompressed point, i.e. 04 <x> <y> */
- if( gcry_pkalgo==GCRY_PK_ECDSA )
- qbytes = ecdsa_qbits_from_Q( qbytes );
-
+ /* pkey[1] is Q for ECDSA, which is an uncompressed point,
+ i.e. 04 <x> <y> */
+ if (pkalgo == GCRY_PK_ECDSA)
+ qbytes = ecdsa_qbits_from_Q (qbytes);
+
/* Make sure it is a multiple of 8 bits. */
-
- if(qbytes%8)
+
+ if (qbytes%8)
{
log_error(_("DSA requires the hash length to be a"
" multiple of 8 bits\n"));
@@ -275,30 +292,38 @@ encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo)
if (qbytes < 160)
{
log_error (_("%s key %s uses an unsafe (%zu bit) hash\n"),
- gcry_pk_algo_name( gcry_pkalgo ),
- keystr_from_pk (pk), qbytes);
+ gcry_pk_algo_name (pkalgo), keystr_from_pk (pk), qbytes);
return NULL;
}
-
+
qbytes /= 8;
/* Check if we're too short. Too long is safe as we'll
- automatically left-truncate. */
- /* This checks would require the use of SHA512 with ECDSA 512. I think this is overkill to fail in this case.
- * Therefore, relax the check, but only for ECDSA keys. We may need to adjust it later for general case.
- * ( Note that the check will never pass for ECDSA 521 anyway as the only hash that intended to match it is SHA 512, but 512 < 521 ).
- */
- if (gcry_md_get_algo_dlen (hash_algo) < ((gcry_pkalgo==GCRY_PK_ECDSA && qbytes>(521)/8) ? 512/8 : qbytes) )
+ automatically left-truncate.
+
+ FIXME: Check against FIPS.
+ This checks would require the use of SHA512 with ECDSA 512. I
+ think this is overkill to fail in this case. Therefore,
+ relax the check, but only for ECDSA keys. We may need to
+ adjust it later for general case. (Note that the check will
+ never pass for ECDSA 521 anyway as the only hash that
+ intended to match it is SHA 512, but 512 < 521). */
+ if (gcry_md_get_algo_dlen (hash_algo)
+ < ((pkalgo == GCRY_PK_ECDSA && qbytes > (521)/8) ? 512/8 : qbytes))
{
- log_error (_("%s key %s requires a %zu bit or larger hash, used hash-algo=%d\n"),
- gcry_pk_algo_name( gcry_pkalgo ),
- keystr_from_pk(pk), qbytes*8, hash_algo);
+ log_error (_("%s key %s requires a %zu bit or larger hash "
+ "(hash is %s\n"),
+ gcry_pk_algo_name (pkalgo),
+ keystr_from_pk(pk), qbytes*8,
+ gcry_md_algo_name (hash_algo));
return NULL;
}
- /* Note that in case of ECDSA 521 hash is always smaller than the key size */
+ /* Note that in case of ECDSA 521 hash is always smaller than
+ the key size. */
if (gcry_mpi_scan (&frame, GCRYMPI_FMT_USG,
- gcry_md_read (md, hash_algo), gcry_md_get_algo_dlen (hash_algo), &qbytes))
+ gcry_md_read (md, hash_algo),
+ gcry_md_get_algo_dlen (hash_algo), &qbytes))
BUG();
}
else