Esempio n. 1
0
/* Return information about the given cipher algorithm ALGO.

   WHAT select the kind of information returned:

    GCRYCTL_GET_KEYLEN:
  	Return the length of the key.  If the algorithm ALGO
  	supports multiple key lengths, the maximum supported key length
  	is returned.  The key length is returned as number of octets.
  	BUFFER and NBYTES must be zero.

    GCRYCTL_GET_BLKLEN:
  	Return the blocklength of the algorithm ALGO counted in octets.
  	BUFFER and NBYTES must be zero.

    GCRYCTL_TEST_ALGO:
  	Returns 0 if the specified algorithm ALGO is available for use.
  	BUFFER and NBYTES must be zero.

   Note: Because this function is in most cases used to return an
   integer value, we can make it easier for the caller to just look at
   the return value.  The caller will in all cases consult the value
   and thereby detecting whether a error occurred or not (i.e. while
   checking the block size)
 */
gcry_err_code_t
_gcry_cipher_algo_info (int algo, int what, void *buffer, size_t *nbytes)
{
  gcry_err_code_t rc = 0;
  unsigned int ui;

  switch (what)
    {
    case GCRYCTL_GET_KEYLEN:
      if (buffer || (! nbytes))
	rc = GPG_ERR_CIPHER_ALGO;
      else
	{
	  ui = cipher_get_keylen (algo);
	  if ((ui > 0) && (ui <= 512))
	    *nbytes = (size_t) ui / 8;
	  else
	    /* The only reason for an error is an invalid algo.  */
	    rc = GPG_ERR_CIPHER_ALGO;
	}
      break;

    case GCRYCTL_GET_BLKLEN:
      if (buffer || (! nbytes))
	rc = GPG_ERR_CIPHER_ALGO;
      else
	{
	  ui = cipher_get_blocksize (algo);
	  if ((ui > 0) && (ui < 10000))
	    *nbytes = ui;
	  else
            {
              /* The only reason is an invalid algo or a strange
                 blocksize.  */
              rc = GPG_ERR_CIPHER_ALGO;
            }
	}
      break;

    case GCRYCTL_TEST_ALGO:
      if (buffer || nbytes)
	rc = GPG_ERR_INV_ARG;
      else
	rc = check_cipher_algo (algo);
      break;

      default:
	rc = GPG_ERR_INV_OP;
    }

  return rc;
}
Esempio n. 2
0
/****************
 * Map a string to the cipher algo
 */
int
string_to_cipher_algo( const char *string )
{
    int i;
    const char *s;

    /* kludge to alias RIJNDAEL to AES */
    if ( *string == 'R' || *string == 'r')
    {
        if (!ascii_strcasecmp (string, "RIJNDAEL"))
            string = "AES";
        else if (!ascii_strcasecmp (string, "RIJNDAEL192"))
            string = "AES192";
        else if (!ascii_strcasecmp (string, "RIJNDAEL256"))
            string = "AES256";
    }

    do
    {
        for(i=0; (s=cipher_table[i].name); i++ )
        {
            if( !ascii_strcasecmp( s, string ) )
                return cipher_table[i].algo;
        }
    } while( load_cipher_modules() );

    /* Didn't find it, so try the Sx format */
    if(string[0]=='S' || string[0]=='s')
    {
        long val;
        char *endptr;

        string++;

        val=strtol(string,&endptr,10);
        if(*string!='\0' && *endptr=='\0' && check_cipher_algo(val)==0)
            return val;
    }

    return 0;
}
int
algo_available( preftype_t preftype, int algo, const union pref_hint *hint )
{
  if( preftype == PREFTYPE_SYM )
    {
      if(PGP6 && (algo != CIPHER_ALGO_IDEA
		  && algo != CIPHER_ALGO_3DES
		  && algo != CIPHER_ALGO_CAST5))
	return 0;
      
      if(PGP7 && (algo != CIPHER_ALGO_IDEA
		  && algo != CIPHER_ALGO_3DES
		  && algo != CIPHER_ALGO_CAST5
		  && algo != CIPHER_ALGO_AES
		  && algo != CIPHER_ALGO_AES192
		  && algo != CIPHER_ALGO_AES256
		  && algo != CIPHER_ALGO_TWOFISH))
	return 0;

      /* PGP8 supports all the ciphers we do.. */

      return algo && !check_cipher_algo( algo );
    }
  else if( preftype == PREFTYPE_HASH )
    {
      if(hint && hint->digest_length)
	{
	  if(hint->digest_length!=20 || opt.flags.dsa2)
	    {
	      /* If --enable-dsa2 is set or the hash isn't 160 bits
		 (which implies DSA2), then we'll accept a hash that
		 is larger than we need.  Otherwise we won't accept
		 any hash that isn't exactly the right size. */
	      if(hint->digest_length > md_digest_length(algo))
		return 0;
	    }
	  else if(hint->digest_length != md_digest_length(algo))
	    return 0;
	}

      if((PGP6 || PGP7) && (algo != DIGEST_ALGO_MD5
			    && algo != DIGEST_ALGO_SHA1
			    && algo != DIGEST_ALGO_RMD160))
	return 0;


      if(PGP8 && (algo != DIGEST_ALGO_MD5
		  && algo != DIGEST_ALGO_SHA1
		  && algo != DIGEST_ALGO_RMD160
		  && algo != DIGEST_ALGO_SHA256))
	return 0;

      return algo && !check_digest_algo( algo );
    }
  else if( preftype == PREFTYPE_ZIP )
    {
      if((PGP6 || PGP7) && (algo != COMPRESS_ALGO_NONE
			    && algo != COMPRESS_ALGO_ZIP))
	return 0;

      /* PGP8 supports all the compression algos we do */

      return !check_compress_algo( algo );
    }
  else
    return 0;
}
static int
get_it( PKT_pubkey_enc *enc, DEK *dek, PKT_secret_key *sk, u32 *keyid )
{
  int rc;
  MPI plain_dek  = NULL;
  byte *frame = NULL;
  unsigned n, nframe;
  u16 csum, csum2;
  
  int card = 0;

  if (sk->is_protected && sk->protect.s2k.mode == 1002)
    { /* Note, that we only support RSA for now. */
#ifdef ENABLE_CARD_SUPPORT
      unsigned char *rbuf;
      size_t rbuflen;
      char *snbuf;
      unsigned char *indata = NULL;
      unsigned int indatalen;

      snbuf = serialno_and_fpr_from_sk (sk->protect.iv, sk->protect.ivlen, sk);

      indata = mpi_get_buffer (enc->data[0], &indatalen, NULL);
      if (!indata)
        BUG ();

      rc = agent_scd_pkdecrypt (snbuf, indata, indatalen, &rbuf, &rbuflen);
      xfree (snbuf);
      xfree (indata);
      if (rc)
        goto leave;

      frame = rbuf;
      nframe = rbuflen;
      card = 1;
#else
      rc = G10ERR_UNSUPPORTED;
      goto leave;
#endif /*!ENABLE_CARD_SUPPORT*/
    }
  else
    {
      rc = pubkey_decrypt(sk->pubkey_algo, &plain_dek, enc->data, sk->skey );
      if( rc )
	goto leave;
      frame = mpi_get_buffer( plain_dek, &nframe, NULL );
      mpi_free( plain_dek ); plain_dek = NULL;
    }

    /* Now get the DEK (data encryption key) from the frame
     *
     * Old versions encode the DEK in in this format (msb is left):
     *
     *	   0  1  DEK(16 bytes)	CSUM(2 bytes)  0  RND(n bytes) 2
     *
     * Later versions encode the DEK like this:
     *
     *	   0  2  RND(n bytes)  0  A  DEK(k bytes)  CSUM(2 bytes)
     *
     * (mpi_get_buffer already removed the leading zero).
     *
     * RND are non-zero randow bytes.
     * A   is the cipher algorithm
     * DEK is the encryption key (session key) with length k
     * CSUM
     */
    if( DBG_CIPHER )
	log_hexdump("DEK frame:", frame, nframe );
    n=0;
    if (!card)
      {
        if( n + 7 > nframe )
          { rc = G10ERR_WRONG_SECKEY; goto leave; }
        if( frame[n] == 1 && frame[nframe-1] == 2 ) {
          log_info(_("old encoding of the DEK is not supported\n"));
          rc = G10ERR_CIPHER_ALGO;
          goto leave;
        }
        if( frame[n] != 2 )  /* somethink is wrong */
          { rc = G10ERR_WRONG_SECKEY; goto leave; }
        for(n++; n < nframe && frame[n]; n++ ) /* skip the random bytes */
          ;
        n++; /* and the zero byte */
      }

    if( n + 4 > nframe )
	{ rc = G10ERR_WRONG_SECKEY; goto leave; }

    dek->keylen = nframe - (n+1) - 2;
    dek->algo = frame[n++];
    if( dek->algo ==  CIPHER_ALGO_IDEA )
	write_status(STATUS_RSA_OR_IDEA);
    rc = check_cipher_algo( dek->algo );
    if( rc ) {
	if( !opt.quiet && rc == G10ERR_CIPHER_ALGO ) {
	    log_info(_("cipher algorithm %d%s is unknown or disabled\n"),
                     dek->algo, dek->algo == CIPHER_ALGO_IDEA? " (IDEA)":"");
	    if(dek->algo==CIPHER_ALGO_IDEA)
	      idea_cipher_warn(0);
	}
	dek->algo = 0;
	goto leave;
    }
    if( (dek->keylen*8) != cipher_get_keylen( dek->algo ) ) {
	rc = G10ERR_WRONG_SECKEY;
	goto leave;
    }

    /* copy the key to DEK and compare the checksum */
    csum  = frame[nframe-2] << 8;
    csum |= frame[nframe-1];
    memcpy( dek->key, frame+n, dek->keylen );
    for( csum2=0, n=0; n < dek->keylen; n++ )
	csum2 += dek->key[n];
    if( csum != csum2 ) {
	rc = G10ERR_WRONG_SECKEY;
	goto leave;
    }
    if( DBG_CIPHER )
	log_hexdump("DEK is:", dek->key, dek->keylen );
    /* check that the algo is in the preferences and whether it has expired */
    {
	PKT_public_key *pk = NULL;
        KBNODE pkb = get_pubkeyblock (keyid);

	if( !pkb ) {
            rc = -1;
	    log_error("oops: public key not found for preference check\n");
        }
	else if(pkb->pkt->pkt.public_key->selfsigversion > 3
		&& dek->algo != CIPHER_ALGO_3DES
		&& !opt.quiet
		&& !is_algo_in_prefs( pkb, PREFTYPE_SYM, dek->algo ))
	  log_info(_("WARNING: cipher algorithm %s not found in recipient"
		     " preferences\n"),cipher_algo_to_string(dek->algo));
        if (!rc) {
            KBNODE k;
            
            for (k=pkb; k; k = k->next) {
                if (k->pkt->pkttype == PKT_PUBLIC_KEY 
                    || k->pkt->pkttype == PKT_PUBLIC_SUBKEY){
                    u32 aki[2];
        	    keyid_from_pk(k->pkt->pkt.public_key, aki);

                    if (aki[0]==keyid[0] && aki[1]==keyid[1]) {
                        pk = k->pkt->pkt.public_key;
                        break;
                    }
                }
            }
            if (!pk)
                BUG ();
            if ( pk->expiredate && pk->expiredate <= make_timestamp() ) {
                log_info(_("NOTE: secret key %s expired at %s\n"),
                         keystr(keyid), asctimestamp( pk->expiredate) );
            }
        }

        if ( pk &&  pk->is_revoked ) {
            log_info( _("NOTE: key has been revoked") );
            putc( '\n', log_stream() );
            show_revocation_reason( pk, 1 );
        }

	release_kbnode (pkb);
	rc = 0;
    }


  leave:
    mpi_free(plain_dek);
    xfree(frame);
    return rc;
}
Esempio n. 5
0
static int
get_it( PKT_pubkey_enc *k, DEK *dek, PKT_secret_key *sk, u32 *keyid )
{
    int rc;
    MPI plain_dek  = NULL;
    byte *frame = NULL;
    unsigned n, nframe;
    u16 csum, csum2;

    rc = pubkey_decrypt(sk->pubkey_algo, &plain_dek, k->data, sk->skey );
    if( rc )
	goto leave;
    frame = mpi_get_buffer( plain_dek, &nframe, NULL );
    mpi_free( plain_dek ); plain_dek = NULL;

    /* Now get the DEK (data encryption key) from the frame
     *
     * Old versions encode the DEK in in this format (msb is left):
     *
     *	   0  1  DEK(16 bytes)	CSUM(2 bytes)  0  RND(n bytes) 2
     *
     * Later versions encode the DEK like this:
     *
     *	   0  2  RND(n bytes)  0  A  DEK(k bytes)  CSUM(2 bytes)
     *
     * (mpi_get_buffer already removed the leading zero).
     *
     * RND are non-zero randow bytes.
     * A   is the cipher algorithm
     * DEK is the encryption key (session key) with length k
     * CSUM
     */
    if( DBG_CIPHER )
	log_hexdump("DEK frame:", frame, nframe );
    n=0;
    if( n + 7 > nframe )
	{ rc = G10ERR_WRONG_SECKEY; goto leave; }
    if( frame[n] == 1 && frame[nframe-1] == 2 ) {
	log_info(_("old encoding of the DEK is not supported\n"));
	rc = G10ERR_CIPHER_ALGO;
	goto leave;
    }
    if( frame[n] != 2 )  /* somethink is wrong */
	{ rc = G10ERR_WRONG_SECKEY; goto leave; }
    for(n++; n < nframe && frame[n]; n++ ) /* skip the random bytes */
	;
    n++; /* and the zero byte */
    if( n + 4 > nframe )
	{ rc = G10ERR_WRONG_SECKEY; goto leave; }

    dek->keylen = nframe - (n+1) - 2;
    dek->algo = frame[n++];
    if( dek->algo ==  CIPHER_ALGO_IDEA )
	write_status(STATUS_RSA_OR_IDEA);
    rc = check_cipher_algo( dek->algo );
    if( rc ) {
	if( !opt.quiet && rc == G10ERR_CIPHER_ALGO ) {
	    log_info(_("cipher algorithm %d is unknown or disabled\n"),
							    dek->algo);
	}
	dek->algo = 0;
	goto leave;
    }
    if( (dek->keylen*8) != cipher_get_keylen( dek->algo ) ) {
	rc = G10ERR_WRONG_SECKEY;
	goto leave;
    }

    /* copy the key to DEK and compare the checksum */
    csum  = frame[nframe-2] << 8;
    csum |= frame[nframe-1];
    memcpy( dek->key, frame+n, dek->keylen );
    for( csum2=0, n=0; n < dek->keylen; n++ )
	csum2 += dek->key[n];
    if( csum != csum2 ) {
	rc = G10ERR_WRONG_SECKEY;
	goto leave;
    }
    if( DBG_CIPHER )
	log_hexdump("DEK is:", dek->key, dek->keylen );
    /* check that the algo is in the preferences and whether it has expired */
    {
	PKT_public_key *pk = m_alloc_clear( sizeof *pk );
	if( (rc = get_pubkey( pk, keyid )) )
	    log_error("public key problem: %s\n", g10_errstr(rc) );
	else if( !pk->local_id && query_trust_record(pk) )
	    log_error("can't check algorithm against preferences\n");
	else if( dek->algo != CIPHER_ALGO_3DES
	    && !is_algo_in_prefs( pk->local_id, PREFTYPE_SYM, dek->algo ) ) {
	    /* Don't print a note while we are not on verbose mode,
	     * the cipher is blowfish and the preferences have twofish
	     * listed */
	    if( opt.verbose || dek->algo != CIPHER_ALGO_BLOWFISH
		|| !is_algo_in_prefs( pk->local_id, PREFTYPE_SYM,
						    CIPHER_ALGO_TWOFISH ) )
		log_info(_(
		    "NOTE: cipher algorithm %d not found in preferences\n"),
								 dek->algo );
	}


	if( !rc && pk->expiredate && pk->expiredate <= make_timestamp() ) {
	    log_info(_("NOTE: secret key %08lX expired at %s\n"),
			   (ulong)keyid[1], asctimestamp( pk->expiredate) );
	}

	/* FIXME: check wheter the key has been revoked and display
	 * the revocation reason.  Actually the user should know this himself,
	 * but the sender might not know already and therefor the user
	 * should get a notice that an revoked key has been used to decode
	 * the message.  The user can than watch out for snakes send by
	 * one of those Eves outside his paradise :-)
	 */
	free_public_key( pk );
	rc = 0;
    }


  leave:
    mpi_free(plain_dek);
    m_free(frame);
    return rc;
}