/* encrypt the contents of the input buffer, and return the mem structure */ pgp_memory_t * pgp_encrypt_buf(pgp_io_t *io, const void *input, const size_t insize, const pgp_key_t *pubkey, const unsigned use_armour, const char *cipher) { pgp_output_t *output; pgp_memory_t *outmem; __PGP_USED(io); if (input == NULL) { (void) fprintf(io->errs, "pgp_encrypt_buf: null memory\n"); return 0; } pgp_setup_memory_write(&output, &outmem, insize); /* set armoured/not armoured here */ if (use_armour) { pgp_writer_push_armor_msg(output); } /* Push the encrypted writer */ pgp_push_enc_se_ip(output, pubkey, cipher); /* This does the writing */ pgp_write(output, input, (unsigned)insize); /* tidy up */ pgp_writer_close(output); pgp_output_delete(output); return outmem; }
/** \ingroup HighLevel_Sign \brief Signs a buffer \param input Input text to be signed \param input_len Length of input text \param sig_type Signature type \param seckey Secret Key \param armored Write armoured text, if set \return New pgp_memory_t struct containing signed text \note It is the caller's responsibility to call pgp_memory_free(me) */ pgp_memory_t * pgp_sign_buf(pgp_io_t *io, const void *input, const size_t insize, const pgp_seckey_t *seckey, const int64_t from, const uint64_t duration, const char *hashname, const unsigned armored, const unsigned cleartext) { pgp_litdata_enum ld_type; pgp_create_sig_t *sig; pgp_sig_type_t sig_type; pgp_hash_alg_t hash_alg; pgp_output_t *output; pgp_memory_t *mem; uint8_t keyid[PGP_KEY_ID_SIZE]; pgp_hash_t *hash; unsigned ret; sig = NULL; sig_type = PGP_SIG_BINARY; output = NULL; mem = pgp_memory_new(); hash = NULL; ret = 0; hash_alg = pgp_str_to_hash_alg(hashname); if (hash_alg == PGP_HASH_UNKNOWN) { (void) fprintf(io->errs, "pgp_sign_buf: unknown hash algorithm: \"%s\"\n", hashname); return NULL; } /* setup literal data packet type */ ld_type = (cleartext) ? PGP_LDT_TEXT : PGP_LDT_BINARY; if (input == NULL) { (void) fprintf(io->errs, "pgp_sign_buf: null input\n"); return NULL; } /* set up signature */ if ((sig = pgp_create_sig_new()) == NULL) { return NULL; } pgp_start_sig(sig, seckey, hash_alg, sig_type); /* setup writer */ pgp_setup_memory_write(&output, &mem, insize); if (cleartext) { /* Do the signing */ /* add signature with subpackets: */ /* - creation time */ /* - key id */ ret = pgp_writer_push_clearsigned(output, sig) && pgp_write(output, input, (unsigned)insize) && pgp_writer_use_armored_sig(output) && pgp_add_time(sig, from, "birth") && pgp_add_time(sig, (int64_t)duration, "expiration"); if (ret == 0) { return NULL; } pgp_output_delete(output); } else { /* set armoured/not armoured here */ if (armored) { pgp_writer_push_armor_msg(output); } if (pgp_get_debug_level(__FILE__)) { fprintf(io->errs, "** Writing out one pass sig\n"); } /* write one_pass_sig */ pgp_write_one_pass_sig(output, seckey, hash_alg, sig_type); /* hash memory */ hash = pgp_sig_get_hash(sig); hash->add(hash, input, (unsigned)insize); /* output file contents as Literal Data packet */ if (pgp_get_debug_level(__FILE__)) { (void) fprintf(stderr, "** Writing out data now\n"); } pgp_write_litdata(output, input, (const int)insize, ld_type); if (pgp_get_debug_level(__FILE__)) { fprintf(stderr, "** After Writing out data now\n"); } /* add creation time to signature */ pgp_add_time(sig, from, "birth"); pgp_add_time(sig, (int64_t)duration, "expiration"); /* add key id to signature */ pgp_keyid(keyid, PGP_KEY_ID_SIZE, &seckey->pubkey, hash_alg); pgp_add_issuer_keyid(sig, keyid); pgp_end_hashed_subpkts(sig); /* write out sig */ pgp_write_sig(output, sig, &seckey->pubkey, seckey); /* tidy up */ pgp_writer_close(output); pgp_create_sig_delete(sig); } return mem; }
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; }
/* decrypt an area of memory */ pgp_memory_t * pgp_decrypt_buf(pgp_io_t *io, const void *input, const size_t insize, pgp_keyring_t *secring, pgp_keyring_t *pubring, const unsigned use_armour, const unsigned sshkeys, void *passfp, int numtries, pgp_cbfunc_t *getpassfunc) { pgp_stream_t *parse = NULL; pgp_memory_t *outmem; pgp_memory_t *inmem; const int printerrors = 1; if (input == NULL) { (void) fprintf(io->errs, "pgp_encrypt_buf: null memory\n"); return 0; } inmem = pgp_memory_new(); pgp_memory_add(inmem, input, insize); /* set up to read from memory */ pgp_setup_memory_read(io, &parse, inmem, NULL, write_parsed_cb, 0); /* setup for writing decrypted contents to given output file */ pgp_setup_memory_write(&parse->cbinfo.output, &outmem, insize); /* setup keyring and passphrase callback */ parse->cbinfo.cryptinfo.secring = secring; parse->cbinfo.cryptinfo.pubring = pubring; parse->cbinfo.passfp = passfp; parse->cbinfo.cryptinfo.getpassphrase = getpassfunc; parse->cbinfo.sshseckey = (sshkeys) ? &secring->keys[0].key.seckey : NULL; parse->cbinfo.numtries = numtries; /* Set up armour/passphrase options */ if (use_armour) { pgp_reader_push_dearmour(parse); } /* Do it */ pgp_parse(parse, printerrors); /* Unsetup */ if (use_armour) { pgp_reader_pop_dearmour(parse); } /* tidy up */ pgp_teardown_memory_read(parse, inmem); pgp_writer_close(parse->cbinfo.output); pgp_output_delete(parse->cbinfo.output); /* if we didn't get the passphrase, return NULL */ return (parse->cbinfo.gotpass) ? outmem : NULL; }
/** \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 1 if key generated successfully; otherwise 0 \note It is the caller's responsibility to call pgp_keydata_free(keydata) */ static unsigned rsa_generate_keypair(pgp_key_t *keydata, const int numbits, const unsigned long e, const char *hashalg, const char *cipher) { pgp_seckey_t *seckey; RSA *rsa; BN_CTX *ctx; pgp_output_t *output; pgp_memory_t *mem; ctx = BN_CTX_new(); pgp_keydata_init(keydata, PGP_PTAG_CT_SECRET_KEY); seckey = pgp_get_writable_seckey(keydata); /* generate the key pair */ rsa = RSA_generate_key(numbits, e, NULL, NULL); /* populate pgp key from ssl key */ seckey->pubkey.version = PGP_V4; seckey->pubkey.birthtime = time(NULL); seckey->pubkey.days_valid = 0; seckey->pubkey.alg = PGP_PKA_RSA; seckey->pubkey.key.rsa.n = BN_dup(rsa->n); seckey->pubkey.key.rsa.e = BN_dup(rsa->e); seckey->s2k_usage = PGP_S2KU_ENCRYPTED_AND_HASHED; seckey->s2k_specifier = PGP_S2KS_SALTED; /* seckey->s2k_specifier=PGP_S2KS_SIMPLE; */ if ((seckey->hash_alg = pgp_str_to_hash_alg(hashalg)) == PGP_HASH_UNKNOWN) { seckey->hash_alg = PGP_HASH_SHA1; } seckey->alg = pgp_str_to_cipher(cipher); seckey->octetc = 0; seckey->checksum = 0; seckey->key.rsa.d = BN_dup(rsa->d); seckey->key.rsa.p = BN_dup(rsa->p); seckey->key.rsa.q = BN_dup(rsa->q); seckey->key.rsa.u = BN_mod_inverse(NULL, rsa->p, rsa->q, ctx); if (seckey->key.rsa.u == NULL) { (void) fprintf(stderr, "seckey->key.rsa.u is NULL\n"); return 0; } BN_CTX_free(ctx); RSA_free(rsa); pgp_keyid(keydata->sigid, PGP_KEY_ID_SIZE, &keydata->key.seckey.pubkey, seckey->hash_alg); pgp_fingerprint(&keydata->sigfingerprint, &keydata->key.seckey.pubkey, seckey->hash_alg); /* Generate checksum */ output = NULL; mem = NULL; pgp_setup_memory_write(&output, &mem, 128); pgp_push_checksum_writer(output, seckey); switch (seckey->pubkey.alg) { case PGP_PKA_DSA: return pgp_write_mpi(output, seckey->key.dsa.x); case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: case PGP_PKA_RSA_SIGN_ONLY: if (!pgp_write_mpi(output, seckey->key.rsa.d) || !pgp_write_mpi(output, seckey->key.rsa.p) || !pgp_write_mpi(output, seckey->key.rsa.q) || !pgp_write_mpi(output, seckey->key.rsa.u)) { return 0; } break; case PGP_PKA_ELGAMAL: return pgp_write_mpi(output, seckey->key.elgamal.x); default: (void) fprintf(stderr, "Bad seckey->pubkey.alg\n"); return 0; } /* close rather than pop, since its the only one on the stack */ pgp_writer_close(output); pgp_teardown_memory_write(output, mem); /* should now have checksum in seckey struct */ /* test */ if (pgp_get_debug_level(__FILE__)) { test_seckey(seckey); } return 1; }