1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-02 22:46:30 +02:00
The following works:
   gpg2 --gen-key (ECC)
   gpg2 --list-keys
   gpg2 --list-packets ~/.gnupg/pubring.gpg
   gpg2 --list-packets <private key from http://sites.google.com/site/brainhub/pgpecckeys>

ECDH doesn't work yet as the code must be re-written to adjust for gpg-agent refactoring.
This commit is contained in:
Andrey Jivsov 2011-01-05 17:33:17 -08:00
parent 7bbc07fde0
commit e0972d3d96
34 changed files with 1497 additions and 176 deletions

View file

@ -27,6 +27,7 @@
#include "gpg.h"
#include "util.h"
#include "cipher.h"
#include "options.h"
#include "main.h"
#include "i18n.h"
@ -73,15 +74,48 @@ make_session_key( DEK *dek )
* returns: A mpi with the session key (caller must free)
*/
gcry_mpi_t
encode_session_key (DEK *dek, unsigned int nbits)
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;
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;
}
/* 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.
@ -103,9 +137,6 @@ encode_session_key (DEK *dek, unsigned int nbits)
* cipher algorithm (20 is used with blowfish160).
* CSUM is the 16 bit checksum over the DEK
*/
csum = 0;
for( p = dek->key, i=0; i < dek->keylen; i++ )
csum += *p++;
frame = xmalloc_secure( nframe );
n = 0;
@ -161,8 +192,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\n",
(int)(len*8), (int)nbits);
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:
*
@ -209,16 +240,23 @@ 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;
assert (hash_algo);
assert (pk);
if (pk->pubkey_algo == GCRY_PK_DSA)
gcry_pkalgo = map_pk_openpgp_to_gcry( pk->pubkey_algo );
if (gcry_pkalgo == GCRY_PK_DSA || gcry_pkalgo == GCRY_PK_ECDSA )
{
/* 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 );
/* Make sure it is a multiple of 8 bits. */
if(qbytes%8)
@ -236,7 +274,8 @@ encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo)
DSA. ;) */
if (qbytes < 160)
{
log_error (_("DSA key %s uses an unsafe (%zu bit) hash\n"),
log_error (_("%s key %s uses an unsafe (%zu bit) hash\n"),
gcry_pk_algo_name( gcry_pkalgo ),
keystr_from_pk (pk), qbytes);
return NULL;
}
@ -245,10 +284,16 @@ encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo)
/* Check if we're too short. Too long is safe as we'll
automatically left-truncate. */
if (gcry_md_get_algo_dlen (hash_algo) < qbytes)
/* 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) < qbytes )
if (gcry_md_get_algo_dlen (hash_algo) < ((gcry_pkalgo==GCRY_PK_ECDSA && qbytes>(521)/8) ? 512/8 : qbytes) )
{
log_error (_("DSA key %s requires a %zu bit or larger hash\n"),
keystr_from_pk(pk), qbytes*8);
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);
return NULL;
}