See ChangeLog: Mon Jan 24 13:04:28 CET 2000 Werner Koch
[gnupg.git] / g10 / seckey-cert.c
index 03cf3f2..10f7092 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
+
+#include <gcrypt.h>
 #include "util.h"
-#include "memory.h"
 #include "packet.h"
-#include "mpi.h"
 #include "keydb.h"
-#include "cipher.h"
 #include "main.h"
 #include "options.h"
 #include "i18n.h"
@@ -46,12 +45,12 @@ do_check( PKT_secret_key *sk )
     if( sk->is_protected ) { /* remove the protection */
        DEK *dek = NULL;
        u32 keyid[4]; /* 4! because we need two of them */
-       CIPHER_HANDLE cipher_hd=NULL;
+       GCRY_CIPHER_HD cipher_hd=NULL;
        PKT_secret_key *save_sk;
 
-       if( sk->protect.algo == CIPHER_ALGO_NONE )
+       if( sk->protect.algo == GCRY_CIPHER_NONE )
            BUG();
-       if( check_cipher_algo( sk->protect.algo ) ) {
+       if( openpgp_cipher_test_algo( sk->protect.algo ) ) {
            log_info(_("protection algorithm %d is not supported\n"),
                        sk->protect.algo );
            return G10ERR_CIPHER_ALGO;
@@ -59,30 +58,41 @@ do_check( PKT_secret_key *sk )
        keyid_from_sk( sk, keyid );
        keyid[2] = keyid[3] = 0;
        if( !sk->is_primary ) {
-           PKT_secret_key *sk2 = m_alloc_clear( sizeof *sk2 );
+           PKT_secret_key *sk2 = gcry_xcalloc( 1, sizeof *sk2 );
            if( !get_primary_seckey( sk2, keyid ) )
                keyid_from_sk( sk2, keyid+2 );
            free_secret_key( sk2 );
        }
-       dek = passphrase_to_dek( keyid, sk->protect.algo,
+       dek = passphrase_to_dek( keyid, sk->pubkey_algo, sk->protect.algo,
                                 &sk->protect.s2k, 0 );
-       cipher_hd = cipher_open( sk->protect.algo,
-                                CIPHER_MODE_AUTO_CFB, 1);
-       cipher_setkey( cipher_hd, dek->key, dek->keylen );
-       m_free(dek);
+       if( !(cipher_hd = gcry_cipher_open( sk->protect.algo,
+                                     GCRY_CIPHER_MODE_CFB,
+                                     GCRY_CIPHER_SECURE
+                                     | (sk->protect.algo >= 100 ?
+                                          0 : GCRY_CIPHER_ENABLE_SYNC) ) )
+                                   ) {
+           BUG();
+       }
+
+       if( gcry_cipher_setkey( cipher_hd, dek->key, dek->keylen ) )
+           log_fatal("set key failed: %s\n", gcry_strerror(-1) );
+       gcry_free(dek);
        save_sk = copy_secret_key( NULL, sk );
-       cipher_setiv( cipher_hd, sk->protect.iv, sk->protect.ivlen );
+       if( gcry_cipher_setiv( cipher_hd, sk->protect.iv, sk->protect.ivlen ))
+           log_fatal("set IV failed: %s\n", gcry_strerror(-1) );
        csum = 0;
        if( sk->version >= 4 ) {
-           int ndata;
+           size_t ndata;
+           unsigned int ndatabits;
            byte *p, *data;
 
            i = pubkey_get_npkey(sk->pubkey_algo);
-           assert( mpi_is_opaque( sk->skey[i] ) );
-           p = mpi_get_opaque( sk->skey[i], &ndata );
-           data = m_alloc_secure( ndata );
-           cipher_decrypt( cipher_hd, data, p, ndata );
-           mpi_free( sk->skey[i] ); sk->skey[i] = NULL ;
+           assert( gcry_mpi_get_flag( sk->skey[i], GCRYMPI_FLAG_OPAQUE ) );
+           p = gcry_mpi_get_opaque( sk->skey[i], &ndatabits );
+           ndata = (ndatabits+7)/8;
+           data = gcry_xmalloc_secure( ndata );
+           gcry_cipher_decrypt( cipher_hd, data, ndata, p, ndata );
+           mpi_release( sk->skey[i] ); sk->skey[i] = NULL ;
            p = data;
            if( ndata < 2 ) {
                log_error("not enough bytes for checksum\n");
@@ -94,34 +104,47 @@ do_check( PKT_secret_key *sk )
                sk->csum = data[ndata-2] << 8 | data[ndata-1];
            }
            /* must check it here otherwise the mpi_read_xx would fail
-            * because the length das an abritary value */
+            * because the length may have an arbitrary value */
            if( sk->csum == csum ) {
                for( ; i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
                    nbytes = ndata;
-                   sk->skey[i] = mpi_read_from_buffer(p, &nbytes, 1 );
+                   assert( gcry_is_secure( p ) );
+                   res = gcry_mpi_scan( &sk->skey[i], GCRYMPI_FMT_PGP,
+                                                            p, &nbytes);
+                   if( res )
+                       log_bug("gcry_mpi_scan failed in do_check: rc=%d\n", res);
+
                    ndata -= nbytes;
                    p += nbytes;
                }
            }
-           m_free(data);
+           gcry_free(data);
        }
        else {
            for(i=pubkey_get_npkey(sk->pubkey_algo);
                    i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
-               buffer = mpi_get_secure_buffer( sk->skey[i], &nbytes, NULL );
-               cipher_sync( cipher_hd );
-               assert( mpi_is_protected(sk->skey[i]) );
-               cipher_decrypt( cipher_hd, buffer, buffer, nbytes );
-               mpi_set_buffer( sk->skey[i], buffer, nbytes, 0 );
-               mpi_clear_protect_flag( sk->skey[i] );
+               size_t ndata;
+               unsigned int ndatabits;
+               byte *p, *data;
+
+               assert( gcry_mpi_get_flag( sk->skey[i], GCRYMPI_FLAG_OPAQUE ) );
+               p = gcry_mpi_get_opaque( sk->skey[i], &ndatabits );
+               ndata = (ndatabits+7)/8;
+               data = gcry_xmalloc_secure( ndata );
+               gcry_cipher_sync( cipher_hd );
+               gcry_cipher_decrypt( cipher_hd, data, ndata, p, ndata );
+               mpi_release( sk->skey[i] ); sk->skey[i] = NULL ;
+
+               res = gcry_mpi_scan( &sk->skey[i], GCRYMPI_FMT_USG,
+                                    data, &ndata );
+               if( res )
+                   log_bug("gcry_mpi_scan failed in do_check: rc=%d\n", res);
+
                csum += checksum_mpi( sk->skey[i] );
-               m_free( buffer );
-           }
-           if( opt.emulate_bugs & EMUBUG_GPGCHKSUM ) {
-              csum = sk->csum;
+               gcry_free( buffer );
            }
        }
-       cipher_close( cipher_hd );
+       gcry_cipher_close( cipher_hd );
        /* now let's see whether we have used the right passphrase */
        if( csum != sk->csum ) {
            copy_secret_key( sk, save_sk );
@@ -164,7 +187,7 @@ check_secret_key( PKT_secret_key *sk, int n )
     int i;
 
     if( n < 1 )
-       n = 3; /* use the default value */
+       n = opt.batch? 1 : 3; /* use the default value */
 
     for(i=0; i < n && rc == G10ERR_BAD_PASS; i++ ) {
        if( i )
@@ -215,25 +238,45 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek )
        return 0;
 
     if( !sk->is_protected ) { /* okay, apply the protection */
-       CIPHER_HANDLE cipher_hd=NULL;
+       GCRY_CIPHER_HD cipher_hd=NULL;
 
-       if( check_cipher_algo( sk->protect.algo ) )
+       if( openpgp_cipher_test_algo( sk->protect.algo ) )
            rc = G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
        else {
            print_cipher_algo_note( sk->protect.algo );
-           cipher_hd = cipher_open( sk->protect.algo,
-                                    CIPHER_MODE_AUTO_CFB, 1 );
-           if( cipher_setkey( cipher_hd, dek->key, dek->keylen ) )
+           if( !(cipher_hd = gcry_cipher_open( sk->protect.algo,
+                                         GCRY_CIPHER_MODE_CFB,
+                                         GCRY_CIPHER_SECURE
+                                         | (sk->protect.algo >= 100 ?
+                                             0 : GCRY_CIPHER_ENABLE_SYNC) ))
+                                        ) {
+               BUG();
+           }
+
+
+           rc = gcry_cipher_setkey( cipher_hd, dek->key, dek->keylen );
+           if( rc == GCRYERR_WEAK_KEY ) {
                log_info(_("WARNING: Weak key detected"
                           " - please change passphrase again.\n"));
-           sk->protect.ivlen = cipher_get_blocksize( sk->protect.algo );
+               rc = 0;
+           }
+           else if( rc )
+               BUG();
+
+           /* set the IV length */
+           {   int blocksize = gcry_cipher_get_algo_blklen( sk->protect.algo );
+               if( blocksize != 8 && blocksize != 16 )
+                   log_fatal("unsupported blocksize %d\n", blocksize );
+               sk->protect.ivlen = blocksize;
+           }
+
            assert( sk->protect.ivlen <= DIM(sk->protect.iv) );
-           if( sk->protect.ivlen != 8 && sk->protect.ivlen != 16 )
-               BUG(); /* yes, we are very careful */
-           randomize_buffer(sk->protect.iv, sk->protect.ivlen, 1);
-           cipher_setiv( cipher_hd, sk->protect.iv, sk->protect.ivlen );
+           gcry_randomize(sk->protect.iv, sk->protect.ivlen,
+                                                       GCRY_STRONG_RANDOM);
+           gcry_cipher_setiv( cipher_hd, sk->protect.iv, sk->protect.ivlen );
+           #warning FIXME: replace set/get buffer
            if( sk->version >= 4 ) {
-             #define NMPIS (PUBKEY_MAX_NSKEY - PUBKEY_MAX_NPKEY)
+             #define NMPIS (GNUPG_MAX_NSKEY - GNUPG_MAX_NPKEY)
                byte *bufarr[NMPIS];
                unsigned narr[NMPIS];
                unsigned nbits[NMPIS];
@@ -242,16 +285,20 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek )
 
                for(j=0, i = pubkey_get_npkey(sk->pubkey_algo);
                        i < pubkey_get_nskey(sk->pubkey_algo); i++, j++ ) {
-                   assert( !mpi_is_opaque( sk->skey[i] ) );
-                   bufarr[j] = mpi_get_buffer( sk->skey[i], &narr[j], NULL );
-                   nbits[j]  = mpi_get_nbits( sk->skey[i] );
+                   assert( !gcry_mpi_get_flag( sk->skey[i], GCRYMPI_FLAG_OPAQUE ) );
+
+                   if( gcry_mpi_aprint( GCRYMPI_FMT_USG, (char*)bufarr+j,
+                                                         narr+j, sk->skey[i]))
+                       BUG();
+
+                   nbits[j]  = gcry_mpi_get_nbits( sk->skey[i] );
                    ndata += narr[j] + 2;
                }
                for( ; j < NMPIS; j++ )
                    bufarr[j] = NULL;
                ndata += 2; /* for checksum */
 
-               data = m_alloc_secure( ndata );
+               data = gcry_xmalloc_secure( ndata );
                p = data;
                for(j=0; j < NMPIS && bufarr[j]; j++ ) {
                    p[0] = nbits[j] >> 8 ;
@@ -259,7 +306,7 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek )
                    p += 2;
                    memcpy(p, bufarr[j], narr[j] );
                    p += narr[j];
-                   m_free(bufarr[j]);
+                   gcry_free(bufarr[j]);
                }
              #undef NMPIS
                csum = checksum( data, ndata-2);
@@ -267,34 +314,42 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek )
                *p++ =  csum >> 8;
                *p++ =  csum;
                assert( p == data+ndata );
-               cipher_encrypt( cipher_hd, data, data, ndata );
+               gcry_cipher_encrypt( cipher_hd, data, ndata, NULL, 0 );
                for(i = pubkey_get_npkey(sk->pubkey_algo);
                        i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
-                   mpi_free( sk->skey[i] );
+                   mpi_release( sk->skey[i] );
                    sk->skey[i] = NULL;
                }
                i = pubkey_get_npkey(sk->pubkey_algo);
-               sk->skey[i] = mpi_set_opaque(NULL, data, ndata );
+               sk->skey[i] = gcry_mpi_set_opaque(NULL, data, ndata*8 );
            }
            else {
                /* NOTE: we always recalculate the checksum because there
                 * are some test releases which calculated it wrong */
+              #warning FIXME:  Replace this code
                csum = 0;
                for(i=pubkey_get_npkey(sk->pubkey_algo);
                        i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
-                   csum += checksum_mpi_counted_nbits( sk->skey[i] );
-                   buffer = mpi_get_buffer( sk->skey[i], &nbytes, NULL );
-                   cipher_sync( cipher_hd );
-                   assert( !mpi_is_protected(sk->skey[i]) );
-                   cipher_encrypt( cipher_hd, buffer, buffer, nbytes );
-                   mpi_set_buffer( sk->skey[i], buffer, nbytes, 0 );
-                   mpi_set_protect_flag( sk->skey[i] );
-                   m_free( buffer );
+                   csum += checksum_mpi( sk->skey[i] );
+
+                   if( gcry_mpi_aprint( GCRYMPI_FMT_USG,
+                                        &buffer, &nbytes, sk->skey[i] ) )
+                       BUG();
+
+                   gcry_cipher_sync( cipher_hd );
+                   assert( !gcry_mpi_get_flag( sk->skey[i], GCRYMPI_FLAG_OPAQUE ) );
+                   gcry_cipher_encrypt( cipher_hd, buffer, nbytes, NULL, 0 );
+                   gcry_mpi_release( sk->skey[i] );
+                   if( gcry_mpi_scan( &sk->skey[i], GCRYMPI_FMT_USG,
+                                      buffer,&nbytes ) )
+                       BUG();
+
+                   gcry_free( buffer );
                }
                sk->csum = csum;
            }
            sk->is_protected = 1;
-           cipher_close( cipher_hd );
+           gcry_cipher_close( cipher_hd );
        }
     }
     return rc;