Example #1
0
/* Note that we support v3 keys here because they're needed for
 * for verification - the writer doesn't allow them, though */
static ops_boolean_t write_public_key_body(const ops_public_key_t *key,
					   ops_create_info_t *info)
{
	if(!(ops_write_scalar(key->version,1,info) && ops_write_scalar(key->creation_time,4,info)))
		return ops_false;

	if(key->version != 4 && !ops_write_scalar(key->days_valid,2,info))
		return ops_false;

	if(!ops_write_scalar(key->algorithm,1,info))
		return ops_false;

	switch(key->algorithm)
	{
		case OPS_PKA_DSA:
			return ops_write_mpi(key->key.dsa.p,info)
				&& ops_write_mpi(key->key.dsa.q,info)
				&& ops_write_mpi(key->key.dsa.g,info)
				&& ops_write_mpi(key->key.dsa.y,info);

		case OPS_PKA_RSA:
		case OPS_PKA_RSA_ENCRYPT_ONLY:
		case OPS_PKA_RSA_SIGN_ONLY:
			return ops_write_mpi(key->key.rsa.n,info)
				&& ops_write_mpi(key->key.rsa.e,info);

		case OPS_PKA_ELGAMAL:
			return ops_write_mpi(key->key.elgamal.p,info)
				&& ops_write_mpi(key->key.elgamal.g,info)
				&& ops_write_mpi(key->key.elgamal.y,info);

		default:
			fprintf(stderr, "Unknown algorithm %d\n", key->algorithm);
			assert(0);
			break;
	}

	/* not reached */
	return ops_false;
}
Example #2
0
/**
\ingroup Core_WritePackets
\brief Writes Public Key Session Key packet
\param info Write settings
\param pksk Public Key Session Key to write out
\return ops_true if OK; else ops_false
*/
ops_boolean_t ops_write_pk_session_key(ops_create_info_t *info,
				       ops_pk_session_key_t *pksk)
    {
    assert(pksk);
    assert(pksk->algorithm == OPS_PKA_RSA);

    return ops_write_ptag(OPS_PTAG_CT_PK_SESSION_KEY, info)
	&& ops_write_length(1 + 8 + 1
			    + BN_num_bytes(pksk->parameters.rsa.encrypted_m)
			    + 2, info)
	&& ops_write_scalar(pksk->version, 1, info)
	&& ops_write(pksk->key_id, 8, info)
	&& ops_write_scalar(pksk->algorithm, 1, info)
	&& ops_write_mpi(pksk->parameters.rsa.encrypted_m, info)
        //??	&& ops_write_scalar(0, 2, info);
        ;
    }
Example #3
0
/**
 \ingroup HighLevel_KeyGenerate
 \brief Generates an RSA keypair
 \param numbits Modulus size
 \param e Public Exponent
 \param keydata Pointer to keydata struct to hold new key
 \return ops_true if key generated successfully; otherwise ops_false
 \note It is the caller's responsibility to call ops_keydata_free(keydata)
*/
ops_boolean_t ops_rsa_generate_keypair(const int numbits, const unsigned long e,
				       ops_keydata_t* keydata)
    {
    ops_secret_key_t *skey=NULL;
    RSA *rsa=RSA_new();
    BN_CTX *ctx=BN_CTX_new();
    BIGNUM *ebn=BN_new();

    ops_keydata_init(keydata,OPS_PTAG_CT_SECRET_KEY);
    skey=ops_get_writable_secret_key_from_data(keydata);

    // generate the key pair

    BN_set_word(ebn,e);
    RSA_generate_key_ex(rsa,numbits,ebn,NULL);

    // populate ops key from ssl key

    skey->public_key.version=4;
    skey->public_key.creation_time=time(NULL);
    skey->public_key.days_valid=0;
    skey->public_key.algorithm= OPS_PKA_RSA;

    skey->public_key.key.rsa.n=BN_dup(rsa->n);
    skey->public_key.key.rsa.e=BN_dup(rsa->e);

    skey->s2k_usage=OPS_S2KU_ENCRYPTED_AND_HASHED;
    skey->s2k_specifier=OPS_S2KS_SALTED;
    //skey->s2k_specifier=OPS_S2KS_SIMPLE;
    skey->algorithm=OPS_SA_CAST5; // \todo make param
    skey->hash_algorithm=OPS_HASH_SHA1; // \todo make param
    skey->octet_count=0;
    skey->checksum=0;

    skey->key.rsa.d=BN_dup(rsa->d);
    skey->key.rsa.p=BN_dup(rsa->p);
    skey->key.rsa.q=BN_dup(rsa->q);
    skey->key.rsa.u=BN_mod_inverse(NULL,rsa->p, rsa->q, ctx);
    assert(skey->key.rsa.u);
    BN_CTX_free(ctx);

    RSA_free(rsa);

    ops_keyid(keydata->key_id, &keydata->key.skey.public_key);
    ops_fingerprint(&keydata->fingerprint, &keydata->key.skey.public_key);

    // Generate checksum

    ops_create_info_t *cinfo=NULL;
    ops_memory_t *mem=NULL;

    ops_setup_memory_write(&cinfo, &mem, 128);

    ops_push_skey_checksum_writer(cinfo, skey);

    switch(skey->public_key.algorithm)
	{
	//    case OPS_PKA_DSA:
	//	return ops_write_mpi(key->key.dsa.x,info);

    case OPS_PKA_RSA:
    case OPS_PKA_RSA_ENCRYPT_ONLY:
    case OPS_PKA_RSA_SIGN_ONLY:
	if(!ops_write_mpi(skey->key.rsa.d,cinfo)
	   || !ops_write_mpi(skey->key.rsa.p,cinfo)
	   || !ops_write_mpi(skey->key.rsa.q,cinfo)
	   || !ops_write_mpi(skey->key.rsa.u,cinfo))
	    return ops_false;
	break;

	//    case OPS_PKA_ELGAMAL:
	//	return ops_write_mpi(key->key.elgamal.x,info);

    default:
	assert(0);
	break;
	}

    // close rather than pop, since its the only one on the stack
    ops_writer_close(cinfo);
    ops_teardown_memory_write(cinfo, mem);

    // should now have checksum in skey struct

    // test
    if (debug)
        test_secret_key(skey);

    return ops_true;
    }
Example #4
0
/* Note that we support v3 keys here because they're needed for
 * for verification - the writer doesn't allow them, though */
static ops_boolean_t write_secret_key_body(const ops_secret_key_t *key,
                                           const unsigned char* passphrase,
                                           const size_t pplen,
					   ops_create_info_t *info)
{
	/* RFC4880 Section 5.5.3 Secret-Key Packet Formats */

	ops_crypt_t crypt;
	ops_hash_t hash;
	unsigned char hashed[OPS_SHA1_HASH_SIZE];
	unsigned char session_key[CAST_KEY_LENGTH];
	unsigned int done=0;
	unsigned int i=0;

	if(!write_public_key_body(&key->public_key,info))
		return ops_false;

	assert(key->s2k_usage==OPS_S2KU_ENCRYPTED_AND_HASHED); /* = 254 */
	if(!ops_write_scalar(key->s2k_usage,1,info))
		return ops_false;

	assert(key->algorithm==OPS_SA_CAST5);
	if (!ops_write_scalar(key->algorithm,1,info))
		return ops_false;

	assert(key->s2k_specifier==OPS_S2KS_SIMPLE
			|| key->s2k_specifier==OPS_S2KS_SALTED); // = 1 \todo could also be iterated-and-salted
	if (!ops_write_scalar(key->s2k_specifier,1,info))
		return ops_false;

	assert(key->hash_algorithm==OPS_HASH_SHA1);
	if (!ops_write_scalar(key->hash_algorithm,1,info))
		return ops_false;

	switch(key->s2k_specifier)
	{
		case OPS_S2KS_SIMPLE:
			// nothing more to do
			break;

		case OPS_S2KS_SALTED:
			// 8-octet salt value
			ops_random((void *)&key->salt[0],OPS_SALT_SIZE);
			if (!ops_write(key->salt, OPS_SALT_SIZE, info))
				return ops_false;
			break;

			/* \todo
				case OPS_S2KS_ITERATED_AND_SALTED:
			// 8-octet salt value
			// 1-octet count
			break;
			 */

		default:
			fprintf(stderr,"invalid/unsupported s2k specifier %d\n",
					key->s2k_specifier);
			assert(0);
	}

	if (!ops_write(&key->iv[0],ops_block_size(key->algorithm),info))
		return ops_false;

	/* create the session key for encrypting the algorithm-specific fields */

	switch(key->s2k_specifier)
	{
		case OPS_S2KS_SIMPLE:
		case OPS_S2KS_SALTED:
			// RFC4880: section 3.7.1.1 and 3.7.1.2

			done=0;
			for (i=0; done<CAST_KEY_LENGTH; i++ )
			{
				unsigned int j=0;
				unsigned char zero=0;
				int needed=CAST_KEY_LENGTH-done;
				int use= needed < SHA_DIGEST_LENGTH ? needed : SHA_DIGEST_LENGTH;

				ops_hash_any(&hash, key->hash_algorithm);
				hash.init(&hash);

				// preload if iterating 
				for (j=0; j<i; j++)
				{
					/* 
						Coverity shows a DEADCODE error on this line.
						This is expected since the hardcoded use of
						SHA1 and CAST5 means that it will not used.
						This will change however when other algorithms are
						supported.
					 */
					hash.add(&hash, &zero, 1);
				}

				if (key->s2k_specifier==OPS_S2KS_SALTED)
				{ hash.add(&hash, key->salt, OPS_SALT_SIZE); }

				hash.add(&hash, passphrase, pplen);
				hash.finish(&hash, hashed);

				// if more in hash than is needed by session key, use the
				// leftmost octets
				memcpy(session_key+(i*SHA_DIGEST_LENGTH), hashed, use);
				done += use;
				assert(done<=CAST_KEY_LENGTH);
			}

			break;

			/* \todo
				case OPS_S2KS_ITERATED_AND_SALTED:
			// 8-octet salt value
			// 1-octet count
			break;
			 */

		default:
			fprintf(stderr,"invalid/unsupported s2k specifier %d\n",
					key->s2k_specifier);
			assert(0);
	}

	/* use this session key to encrypt */

	ops_crypt_any(&crypt,key->algorithm);
	crypt.set_iv(&crypt, key->iv);
	crypt.set_key(&crypt, session_key);
	ops_encrypt_init(&crypt);

	if (debug)
	{
		unsigned int i=0;
		fprintf(stderr,"\nWRITING:\niv=");
		for (i=0; i<ops_block_size(key->algorithm); i++)
		{
			fprintf(stderr, "%02x ", key->iv[i]);
		}
		fprintf(stderr,"\n");

		fprintf(stderr,"key=");
		for (i=0; i<CAST_KEY_LENGTH; i++)
		{
			fprintf(stderr, "%02x ", session_key[i]);
		}
		fprintf(stderr,"\n");

		//ops_print_secret_key(OPS_PTAG_CT_SECRET_KEY,key);

		fprintf(stderr,"turning encryption on...\n");
	}

	ops_writer_push_encrypt_crypt(info, &crypt);

	switch(key->public_key.algorithm)
	{
		case OPS_PKA_DSA:
			return ops_write_mpi(key->key.dsa.x,info);

		case OPS_PKA_RSA:
		case OPS_PKA_RSA_ENCRYPT_ONLY:
		case OPS_PKA_RSA_SIGN_ONLY:

			if(!ops_write_mpi(key->key.rsa.d,info)
					|| !ops_write_mpi(key->key.rsa.p,info)
					|| !ops_write_mpi(key->key.rsa.q,info)
					|| !ops_write_mpi(key->key.rsa.u,info))
			{
				if (debug)
				{ fprintf(stderr,"4 x mpi not written - problem\n"); }
				return ops_false;
			}

			break;

			//    case OPS_PKA_ELGAMAL:
			//	return ops_write_mpi(key->key.elgamal.x,info);

		default:
			assert(0);
			break;
	}

	if(!ops_write(key->checkhash, OPS_CHECKHASH_SIZE, info))
		return ops_false;

	ops_writer_pop(info);

	free(crypt.encrypt_key) ;
	free(crypt.decrypt_key) ;

	return ops_true;
}