Пример #1
0
/**
\ingroup Core_Create
\brief implementation of EME-PKCS1-v1_5-ENCODE, as defined in OpenPGP RFC
\param M
\param mLen
\param pubkey
\param EM
\return 1 if OK; else 0
*/
unsigned 
encode_m_buf(const uint8_t *M, size_t mLen, const pgp_pubkey_t * pubkey,
	     uint8_t *EM)
{
	unsigned    k;
	unsigned        i;

	/* implementation of EME-PKCS1-v1_5-ENCODE, as defined in OpenPGP RFC */
	switch (pubkey->alg) {
	case PGP_PKA_RSA:
		k = (unsigned)BN_num_bytes(pubkey->key.rsa.n);
		if (mLen > k - 11) {
			(void) fprintf(stderr, "encode_m_buf: message too long\n");
			return 0;
		}
		break;
	case PGP_PKA_DSA:
	case PGP_PKA_ELGAMAL:
		k = (unsigned)BN_num_bytes(pubkey->key.elgamal.p);
		if (mLen > k - 11) {
			(void) fprintf(stderr, "encode_m_buf: message too long\n");
			return 0;
		}
		break;
	default:
		(void) fprintf(stderr, "encode_m_buf: pubkey algorithm\n");
		return 0;
	}
	/* these two bytes defined by RFC */
	EM[0] = 0x00;
	EM[1] = 0x02;
	/* add non-zero random bytes of length k - mLen -3 */
	for (i = 2; i < (k - mLen) - 1; ++i) {
		do {
			pgp_random(EM + i, 1);
		} while (EM[i] == 0);
	}
	if (i < 8 + 2) {
		(void) fprintf(stderr, "encode_m_buf: bad i len\n");
		return 0;
	}
	EM[i++] = 0;
	(void) memcpy(EM + i, M, mLen);
	if (pgp_get_debug_level(__FILE__)) {
		hexdump(stderr, "Encoded Message:", EM, mLen);
	}
	return 1;
}
Пример #2
0
/**
 \ingroup Core_Create
\brief Creates an pgp_pk_sesskey_t struct from keydata
\param key Keydata to use
\return pgp_pk_sesskey_t struct
\note It is the caller's responsiblity to free the returned pointer
\note Currently hard-coded to use CAST5
\note Currently hard-coded to use RSA
*/
pgp_pk_sesskey_t *
pgp_create_pk_sesskey(const pgp_key_t *key, const char *ciphername)
{
	/*
         * Creates a random session key and encrypts it for the given key
         *
         * Encryption used is PK,
         * can be any, we're hardcoding RSA for now
         */

	const pgp_pubkey_t	*pubkey;
	pgp_pk_sesskey_t	*sesskey;
	pgp_symm_alg_t	 cipher;
	const uint8_t		*id;
	pgp_crypt_t		 cipherinfo;
	uint8_t			*unencoded_m_buf;
	uint8_t			*encoded_m_buf;
	size_t			 sz_encoded_m_buf;

	if (memcmp(key->encid, "\0\0\0\0\0\0\0\0", 8) == 0) {
		pubkey = pgp_get_pubkey(key);
		id = key->sigid;
	} else {
		pubkey = &key->enckey;
		id = key->encid;
	}
	/* allocate unencoded_m_buf here */
	(void) memset(&cipherinfo, 0x0, sizeof(cipherinfo));
	pgp_crypt_any(&cipherinfo,
		cipher = pgp_str_to_cipher((ciphername) ? ciphername : "cast5"));
	unencoded_m_buf = calloc(1, cipherinfo.keysize + 1 + 2);
	if (unencoded_m_buf == NULL) {
		(void) fprintf(stderr,
			"pgp_create_pk_sesskey: can't allocate\n");
		return NULL;
	}
	switch(pubkey->alg) {
	case PGP_PKA_RSA:
		sz_encoded_m_buf = BN_num_bytes(pubkey->key.rsa.n);
		break;
	case PGP_PKA_DSA:
	case PGP_PKA_ELGAMAL:
		sz_encoded_m_buf = BN_num_bytes(pubkey->key.elgamal.p);
		break;
	default:
		sz_encoded_m_buf = 0;
		break;
	}
	if ((encoded_m_buf = calloc(1, sz_encoded_m_buf)) == NULL) {
		(void) fprintf(stderr,
			"pgp_create_pk_sesskey: can't allocate\n");
		free(unencoded_m_buf);
		return NULL;
	}
	if ((sesskey = calloc(1, sizeof(*sesskey))) == NULL) {
		(void) fprintf(stderr,
			"pgp_create_pk_sesskey: can't allocate\n");
		free(unencoded_m_buf);
		free(encoded_m_buf);
		return NULL;
	}
	if (key->type != PGP_PTAG_CT_PUBLIC_KEY) {
		(void) fprintf(stderr,
			"pgp_create_pk_sesskey: bad type\n");
		free(unencoded_m_buf);
		free(encoded_m_buf);
		free(sesskey);
		return NULL;
	}
	sesskey->version = PGP_PKSK_V3;
	(void) memcpy(sesskey->key_id, id, sizeof(sesskey->key_id));

	if (pgp_get_debug_level(__FILE__)) {
		hexdump(stderr, "Encrypting for keyid", id, sizeof(sesskey->key_id));
	}
	switch (pubkey->alg) {
	case PGP_PKA_RSA:
	case PGP_PKA_DSA:
	case PGP_PKA_ELGAMAL:
		break;
	default:
		(void) fprintf(stderr,
			"pgp_create_pk_sesskey: bad pubkey algorithm\n");
		free(unencoded_m_buf);
		free(encoded_m_buf);
		free(sesskey);
		return NULL;
	}
	sesskey->alg = pubkey->alg;

	sesskey->symm_alg = cipher;
	pgp_random(sesskey->key, cipherinfo.keysize);

	if (pgp_get_debug_level(__FILE__)) {
		hexdump(stderr, "sesskey created", sesskey->key,
			cipherinfo.keysize + 1 + 2);
	}
	if (create_unencoded_m_buf(sesskey, &cipherinfo, &unencoded_m_buf[0]) == 0) {
		free(unencoded_m_buf);
		free(encoded_m_buf);
		free(sesskey);
		return NULL;
	}
	if (pgp_get_debug_level(__FILE__)) {
		hexdump(stderr, "uuencoded m buf", unencoded_m_buf, cipherinfo.keysize + 1 + 2);
	}
	encode_m_buf(unencoded_m_buf, cipherinfo.keysize + 1 + 2, pubkey, encoded_m_buf);

	/* and encrypt it */
	switch (key->key.pubkey.alg) {
	case PGP_PKA_RSA:
		if (!pgp_rsa_encrypt_mpi(encoded_m_buf, sz_encoded_m_buf, pubkey,
				&sesskey->params)) {
			free(unencoded_m_buf);
			free(encoded_m_buf);
			free(sesskey);
			return NULL;
		}
		break;
	case PGP_PKA_DSA:
	case PGP_PKA_ELGAMAL:
		if (!pgp_elgamal_encrypt_mpi(encoded_m_buf, sz_encoded_m_buf, pubkey,
				&sesskey->params)) {
			free(unencoded_m_buf);
			free(encoded_m_buf);
			free(sesskey);
			return NULL;
		}
		break;
	default:
		/* will not get here - for lint only */
		break;
	}
	free(unencoded_m_buf);
	free(encoded_m_buf);
	return sesskey;
}
Пример #3
0
/*
 * Note that we support v3 keys here because they're needed for
 * verification.
 */
static unsigned 
write_seckey_body(const pgp_seckey_t *key,
		      const uint8_t *passphrase,
		      const size_t pplen,
		      pgp_output_t *output)
{
	/* RFC4880 Section 5.5.3 Secret-Key Packet Formats */

	pgp_crypt_t   crypted;
	pgp_hash_t    hash;
	unsigned	done = 0;
	unsigned	i = 0;
	uint8_t		*hashed;
	uint8_t		sesskey[CAST_KEY_LENGTH];

	if (!write_pubkey_body(&key->pubkey, output)) {
		return 0;
	}
	if (key->s2k_usage != PGP_S2KU_ENCRYPTED_AND_HASHED) {
		(void) fprintf(stderr, "write_seckey_body: s2k usage\n");
		return 0;
	}
	if (!pgp_write_scalar(output, (unsigned)key->s2k_usage, 1)) {
		return 0;
	}

	if (key->alg != PGP_SA_CAST5) {
		(void) fprintf(stderr, "write_seckey_body: algorithm\n");
		return 0;
	}
	if (!pgp_write_scalar(output, (unsigned)key->alg, 1)) {
		return 0;
	}

	if (key->s2k_specifier != PGP_S2KS_SIMPLE &&
	    key->s2k_specifier != PGP_S2KS_SALTED) {
		/* = 1 \todo could also be iterated-and-salted */
		(void) fprintf(stderr, "write_seckey_body: s2k spec\n");
		return 0;
	}
	if (!pgp_write_scalar(output, (unsigned)key->s2k_specifier, 1)) {
		return 0;
	}
	if (!pgp_write_scalar(output, (unsigned)key->hash_alg, 1)) {
		return 0;
	}

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

	case PGP_S2KS_SALTED:
		/* 8-octet salt value */
		pgp_random(__UNCONST(&key->salt[0]), PGP_SALT_SIZE);
		if (!pgp_write(output, key->salt, PGP_SALT_SIZE)) {
			return 0;
		}
		break;

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

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

	if (!pgp_write(output, &key->iv[0], pgp_block_size(key->alg))) {
		return 0;
	}

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

	switch (key->s2k_specifier) {
	case PGP_S2KS_SIMPLE:
	case PGP_S2KS_SALTED:
		/* RFC4880: section 3.7.1.1 and 3.7.1.2 */

		for (done = 0, i = 0; done < CAST_KEY_LENGTH; i++) {
			unsigned 	hashsize;
			unsigned 	j;
			unsigned	needed;
			unsigned	size;
			uint8_t		zero = 0;

			/* Hard-coded SHA1 for session key */
			pgp_hash_any(&hash, PGP_HASH_SHA1);
			hashsize = pgp_hash_size(key->hash_alg);
			needed = CAST_KEY_LENGTH - done;
			size = MIN(needed, hashsize);
			if ((hashed = calloc(1, hashsize)) == NULL) {
				(void) fprintf(stderr, "write_seckey_body: bad alloc\n");
				return 0;
			}
			if (!hash.init(&hash)) {
				(void) fprintf(stderr, "write_seckey_body: bad alloc\n");
				return 0;
			}

			/* 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 == PGP_S2KS_SALTED) {
				hash.add(&hash, key->salt, PGP_SALT_SIZE);
			}
			hash.add(&hash, passphrase, (unsigned)pplen);
			hash.finish(&hash, hashed);

			/*
			 * if more in hash than is needed by session key, use
			 * the leftmost octets
			 */
			(void) memcpy(&sesskey[i * hashsize],
					hashed, (unsigned)size);
			done += (unsigned)size;
			if (done > CAST_KEY_LENGTH) {
				(void) fprintf(stderr,
					"write_seckey_body: short add\n");
				return 0;
			}
		}

		break;

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

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

	/* use this session key to encrypt */

	pgp_crypt_any(&crypted, key->alg);
	crypted.set_iv(&crypted, key->iv);
	crypted.set_crypt_key(&crypted, sesskey);
	pgp_encrypt_init(&crypted);

	if (pgp_get_debug_level(__FILE__)) {
		hexdump(stderr, "writing: iv=", key->iv, pgp_block_size(key->alg));
		hexdump(stderr, "key= ", sesskey, CAST_KEY_LENGTH);
		(void) fprintf(stderr, "\nturning encryption on...\n");
	}
	pgp_push_enc_crypt(output, &crypted);

	switch (key->pubkey.alg) {
	case PGP_PKA_RSA:
	case PGP_PKA_RSA_ENCRYPT_ONLY:
	case PGP_PKA_RSA_SIGN_ONLY:
		if (!pgp_write_mpi(output, key->key.rsa.d) ||
		    !pgp_write_mpi(output, key->key.rsa.p) ||
		    !pgp_write_mpi(output, key->key.rsa.q) ||
		    !pgp_write_mpi(output, key->key.rsa.u)) {
			if (pgp_get_debug_level(__FILE__)) {
				(void) fprintf(stderr,
					"4 x mpi not written - problem\n");
			}
			return 0;
		}
		break;
	case PGP_PKA_DSA:
		return pgp_write_mpi(output, key->key.dsa.x);
	case PGP_PKA_ELGAMAL:
		return pgp_write_mpi(output, key->key.elgamal.x);
	default:
		return 0;
	}

	if (!pgp_write(output, key->checkhash, PGP_CHECKHASH_SIZE)) {
		return 0;
	}

	pgp_writer_pop(output);

	return 1;
}
Пример #4
0
int dc_pgp_symm_encrypt(dc_context_t* context,
                        const char* passphrase,
                        const void* plain, size_t plain_bytes,
                        char** ret_ctext_armored)
{
	int                    success = 0;
	uint8_t                salt[PGP_SALT_SIZE];
	pgp_crypt_t            crypt_info;
	uint8_t*               key = NULL;

	pgp_output_t*          payload_output = NULL;
	pgp_memory_t*          payload_mem = NULL;

	pgp_output_t*          encr_output = NULL;
	pgp_memory_t*          encr_mem = NULL;

	if (context==NULL || passphrase==NULL || plain==NULL || plain_bytes==0
	 || ret_ctext_armored==NULL ) {
		goto cleanup;
	}

	//printf("\n~~~~~~~~~~~~~~~~~~~~SETUP-PAYLOAD~~~~~~~~~~~~~~~~~~~~\n%s~~~~~~~~~~~~~~~~~~~~/SETUP-PAYLOAD~~~~~~~~~~~~~~~~~~~~\n",key_asc); // DEBUG OUTPUT

	/* put the payload into a literal data packet which will be encrypted then, see RFC 4880, 5.7 :
	"When it has been decrypted, it contains other packets (usually a literal data packet or compressed data
	packet, but in theory other Symmetrically Encrypted Data packets or sequences of packets that form whole OpenPGP messages)" */

	pgp_setup_memory_write(&payload_output, &payload_mem, 128);
	pgp_write_litdata(payload_output, (const uint8_t*)plain, plain_bytes, PGP_LDT_BINARY);

	/* create salt for the key */
	pgp_random(salt, PGP_SALT_SIZE);

	/* S2K */
	#define SYMM_ALGO PGP_SA_AES_128
	if (!pgp_crypt_any(&crypt_info, SYMM_ALGO)) {
		goto cleanup;
	}

	int s2k_spec = PGP_S2KS_ITERATED_AND_SALTED; // 0=simple, 1=salted, 3=salted+iterated
	int s2k_iter_id = 96; // 0=1024 iterations, 96=65536 iterations
	#define HASH_ALG  PGP_HASH_SHA256
	if ((key = pgp_s2k_do(passphrase, crypt_info.keysize, s2k_spec, HASH_ALG, salt, s2k_iter_id))==NULL) {
		goto cleanup;
	}

	/* encrypt the payload using the key using AES-128 and put it into
	OpenPGP's "Symmetric-Key Encrypted Session Key" (Tag 3, https://tools.ietf.org/html/rfc4880#section-5.3) followed by
	OpenPGP's "Symmetrically Encrypted Data Packet" (Tag 18, https://tools.ietf.org/html/rfc4880#section-5.13 , better than Tag 9) */

	pgp_setup_memory_write(&encr_output, &encr_mem, 128);
	pgp_writer_push_armor_msg(encr_output);

	/* Tag 3 - PGP_PTAG_CT_SK_SESSION_KEY */
	pgp_write_ptag     (encr_output, PGP_PTAG_CT_SK_SESSION_KEY);
	pgp_write_length   (encr_output, 1/*version*/
	                               + 1/*symm. algo*/
	                               + 1/*s2k_spec*/
	                               + 1/*S2 hash algo*/
	                               + ((s2k_spec==PGP_S2KS_SALTED || s2k_spec==PGP_S2KS_ITERATED_AND_SALTED)? PGP_SALT_SIZE : 0)/*the salt*/
	                               + ((s2k_spec==PGP_S2KS_ITERATED_AND_SALTED)? 1 : 0)/*number of iterations*/);

	pgp_write_scalar   (encr_output, 4, 1);                  // 1 octet: version
	pgp_write_scalar   (encr_output, SYMM_ALGO, 1);          // 1 octet: symm. algo

	pgp_write_scalar   (encr_output, s2k_spec, 1);           // 1 octet: s2k_spec
	pgp_write_scalar   (encr_output, HASH_ALG, 1);           // 1 octet: S2 hash algo
	if (s2k_spec==PGP_S2KS_SALTED || s2k_spec==PGP_S2KS_ITERATED_AND_SALTED) {
	  pgp_write        (encr_output, salt, PGP_SALT_SIZE);   // 8 octets: the salt
	}
	if (s2k_spec==PGP_S2KS_ITERATED_AND_SALTED) {
	  pgp_write_scalar (encr_output, s2k_iter_id, 1);        // 1 octet: number of iterations
	}

	// for(int j=0; j<AES_KEY_LENGTH; j++) { printf("%02x", key[j]); } printf("\n----------------\n");

	/* Tag 18 - PGP_PTAG_CT_SE_IP_DATA */
	//pgp_write_symm_enc_data((const uint8_t*)payload_mem->buf, payload_mem->length, PGP_SA_AES_128, key, encr_output); //-- would generate Tag 9
	{
		uint8_t* iv = calloc(1, crypt_info.blocksize); if (iv==NULL) { goto cleanup; }
		crypt_info.set_iv(&crypt_info, iv);
		free(iv);

		crypt_info.set_crypt_key(&crypt_info, &key[0]);
		pgp_encrypt_init(&crypt_info);

		pgp_write_se_ip_pktset(encr_output, payload_mem->buf, payload_mem->length, &crypt_info);

		crypt_info.decrypt_finish(&crypt_info);
	}

	/* done with symmetric key block */
	pgp_writer_close(encr_output);
	*ret_ctext_armored = dc_null_terminate((const char*)encr_mem->buf, encr_mem->length);

	//printf("\n~~~~~~~~~~~~~~~~~~~~SYMMETRICALLY ENCRYPTED~~~~~~~~~~~~~~~~~~~~\n%s~~~~~~~~~~~~~~~~~~~~/SYMMETRICALLY ENCRYPTED~~~~~~~~~~~~~~~~~~~~\n",encr_string); // DEBUG OUTPUT

	success = 1;

cleanup:
	if (payload_output) { pgp_output_delete(payload_output); }
	if (payload_mem) { pgp_memory_free(payload_mem); }
	if (encr_output) { pgp_output_delete(encr_output); }
	if (encr_mem) { pgp_memory_free(encr_mem); }
	free(key);
	return success;
}