ops_boolean_t ops_write_transferable_secret_key_from_packet_data(const ops_keydata_t *keydata, ops_boolean_t armoured, ops_create_info_t *info) { ops_boolean_t rtn = ops_true; unsigned int i=0; if(keydata->type != OPS_PTAG_CT_ENCRYPTED_SECRET_KEY) { fprintf(stderr,"Can only output encrypted secret keys from raw packet data. Current type is %d\n",keydata->type) ; return ops_false ; } if (armoured) { ops_writer_push_armoured(info, OPS_PGP_PRIVATE_KEY_BLOCK); } for(i=0;i<keydata->npackets;++i) if(!ops_write(keydata->packets[i].raw, keydata->packets[i].length, info)) return ops_false ; if (armoured) { writer_info_finalise(&info->errors, &info->winfo); ops_writer_pop(info); } return rtn; }
/** * \ingroup Core_WritePackets * \brief Writes a User Id packet * \param id * \param info * \return ops_true if OK, otherwise ops_false */ ops_boolean_t ops_write_struct_user_id(ops_user_id_t *id, ops_create_info_t *info) { return ops_write_ptag(OPS_PTAG_CT_USER_ID,info) && ops_write_length(strlen((char *)id->user_id),info) && ops_write(id->user_id,strlen((char *)id->user_id),info); }
ops_boolean_t ops_write_mdc(const unsigned char *hashed, ops_create_info_t* info) { // write it out return ops_write_ptag(OPS_PTAG_CT_MDC, info) && ops_write_length(OPS_SHA1_HASH_SIZE,info) && ops_write(hashed, OPS_SHA1_HASH_SIZE, info); }
/** \ingroup HighLevel_Crypto Encrypt a file \param input_filename Name of file to be encrypted \param output_filename Name of file to write to. If NULL, name is constructed from input_filename \param pub_key Public Key to encrypt file for \param use_armour Write armoured text, if set \param allow_overwrite Allow output file to be overwrwritten if it exists \return ops_true if OK; else ops_false */ ops_boolean_t ops_encrypt_file(const char* input_filename, const char* output_filename, const ops_keydata_t *pub_key, const ops_boolean_t use_armour, const ops_boolean_t allow_overwrite) { int fd_in=0; int fd_out=0; ops_create_info_t *cinfo; #ifdef WIN32 fd_in=ops_open(input_filename, O_RDONLY | O_BINARY, 0); #else fd_in=ops_open(input_filename, O_RDONLY, 0); #endif if(fd_in < 0) { perror(input_filename); return ops_false; } fd_out=ops_setup_file_write(&cinfo, output_filename, allow_overwrite); if (fd_out < 0) return ops_false; // set armoured/not armoured here if (use_armour) ops_writer_push_armoured_message(cinfo); // Push the encrypted writer ops_writer_push_stream_encrypt_se_ip(cinfo, pub_key); ops_writer_push_literal(cinfo); // Do the writing unsigned buffer[10240]; for (;;) { int n=0; n=read(fd_in, buffer, sizeof buffer); if (!n) break; if(n < 0) return ops_false ; // FIXME: apparently writing can't fail. ops_write(buffer, n, cinfo); } // tidy up close(fd_in); ops_teardown_file_write(cinfo, fd_out); return ops_true; }
ops_boolean_t ops_write_transferable_public_key(const ops_keydata_t *keydata, ops_boolean_t armoured, ops_create_info_t *info) { ops_boolean_t rtn; unsigned int i=0,j=0; if (armoured) { ops_writer_push_armoured(info, OPS_PGP_PUBLIC_KEY_BLOCK); } // public key rtn=ops_write_struct_public_key(&keydata->key.skey.public_key,info); if (rtn!=ops_true) return rtn; // TODO: revocation signatures go here // user ids and corresponding signatures for (i=0; i<keydata->nuids; i++) { ops_user_id_t* uid=&keydata->uids[i]; rtn=ops_write_struct_user_id(uid, info); if (!rtn) return rtn; // find signature for this packet if it exists for (j=0; j<keydata->nsigs; j++) { sigpacket_t* sig=&keydata->sigs[i]; if (!strcmp((char *)sig->userid->user_id, (char *)uid->user_id)) { rtn=ops_write(sig->packet->raw, sig->packet->length, info); if (!rtn) return !rtn; } } } // TODO: user attributes and corresponding signatures // subkey packets and corresponding signatures and optional revocation if (armoured) { writer_info_finalise(&info->errors, &info->winfo); ops_writer_pop(info); } return rtn; }
ops_boolean_t ops_write_literal_data_from_file(const char *filename, const ops_literal_data_type_t type, ops_create_info_t *info) { size_t initial_size=1024; int fd=0; ops_boolean_t rtn; unsigned char buf[1024]; ops_memory_t* mem=NULL; size_t len=0; fd=ops_open(filename,O_RDONLY | O_BINARY, 0); if (fd < 0) return ops_false; mem=ops_memory_new(); ops_memory_init(mem,initial_size); for (;;) { ssize_t n=0; n=read(fd,buf,1024); if (!n) break; if (n == -1) { close(fd); ops_memory_free(mem); return ops_false; } ops_memory_add(mem, &buf[0], n); } close(fd); // \todo do we need to check text data for <cr><lf> line endings ? len=ops_memory_get_length(mem); rtn=ops_write_ptag(OPS_PTAG_CT_LITERAL_DATA, info) && ops_write_length(1+1+4+len,info) && ops_write_scalar(type, 1, info) && ops_write_scalar(0, 1, info) // filename && ops_write_scalar(0, 4, info) // date && ops_write(ops_memory_get_data(mem), len, info); ops_memory_free(mem); return rtn; }
/** \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); ; }
/** \ingroup Core_WritePackets \brief Writes Literal Data packet from buffer \param data Buffer to write out \param maxlen Max length of buffer \param type Literal Data Type \param info Write settings \return ops_true if OK; else ops_false */ ops_boolean_t ops_write_literal_data_from_buf(const unsigned char *data, const int maxlen, const ops_literal_data_type_t type, ops_create_info_t *info) { /* * RFC4880 does not specify a meaning for filename or date. * It is implementation-dependent. * We will not implement them. */ // \todo do we need to check text data for <cr><lf> line endings ? return ops_write_ptag(OPS_PTAG_CT_LITERAL_DATA, info) && ops_write_length(1+1+4+maxlen,info) && ops_write_scalar(type, 1, info) && ops_write_scalar(0, 1, info) && ops_write_scalar(0, 4, info) && ops_write(data, maxlen, info); }
/** \ingroup Core_WritePackets \brief Write a One Pass Signature packet \param skey Secret Key to use \param hash_alg Hash Algorithm to use \param sig_type Signature type \param info Write settings \return ops_true if OK; else ops_false */ ops_boolean_t ops_write_one_pass_sig(const ops_secret_key_t* skey, const ops_hash_algorithm_t hash_alg, const ops_sig_type_t sig_type, ops_create_info_t* info) { unsigned char keyid[OPS_KEY_ID_SIZE]; if (debug) fprintf(stderr, "calling ops_keyid in write_one_pass_sig: " "this calls sha1_init\n"); ops_keyid(keyid,&skey->public_key); return ops_write_ptag(OPS_PTAG_CT_ONE_PASS_SIGNATURE, info) && ops_write_length(1+1+1+1+8+1, info) && ops_write_scalar (3, 1, info) // version && ops_write_scalar (sig_type, 1, info) && ops_write_scalar (hash_alg, 1, info) && ops_write_scalar (skey->public_key.algorithm, 1, info) && ops_write(keyid, 8, info) && ops_write_scalar (1, 1, info); }
ops_boolean_t ops_write_transferable_public_key_from_packet_data(const ops_keydata_t *keydata, ops_boolean_t armoured, ops_create_info_t *info) { ops_boolean_t rtn = ops_true; unsigned int i=0; if (armoured) { ops_writer_push_armoured(info, OPS_PGP_PUBLIC_KEY_BLOCK); } for(i=0;i<keydata->npackets;++i) if(!ops_write(keydata->packets[i].raw, keydata->packets[i].length, info)) return ops_false ; if (armoured) { writer_info_finalise(&info->errors, &info->winfo); ops_writer_pop(info); } return rtn; }
ops_parse_cb_return_t callback_literal_data(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo) { ops_parser_content_union_t* content=(ops_parser_content_union_t *)&content_->content; OPS_USED(cbinfo); // ops_print_packet(content_); // Read data from packet into static buffer switch(content_->tag) { case OPS_PTAG_CT_LITERAL_DATA_BODY: // if writer enabled, use it if (cbinfo->cinfo) { ops_write(content->literal_data_body.data, content->literal_data_body.length, cbinfo->cinfo); } /* ops_memory_add(mem_literal_data, content->literal_data_body.data, content->literal_data_body.length); */ break; case OPS_PTAG_CT_LITERAL_DATA_HEADER: // ignore break; default: // return callback_general(content_,cbinfo); break; } return OPS_RELEASE_MEMORY; }
/** \ingroup Core_WritePackets \brief Write Symmetrically Encrypted packet \param data Data to encrypt \param len Length of data \param info Write settings \return ops_true if OK; else ops_false \note Hard-coded to use AES256 */ ops_boolean_t ops_write_symmetrically_encrypted_data(const unsigned char *data, const int len, ops_create_info_t *info) { int done=0; ops_crypt_t crypt_info; int encrypted_sz=0;// size of encrypted data unsigned char *encrypted=NULL; // buffer to write encrypted data to // \todo assume AES256 for now ops_crypt_any(&crypt_info, OPS_SA_AES_256); ops_encrypt_init(&crypt_info); encrypted_sz=len+crypt_info.blocksize+2; encrypted=ops_mallocz(encrypted_sz); done=ops_encrypt_se(&crypt_info, encrypted, data, len); assert(done==len); // printf("len=%d, done: %d\n", len, done); return ops_write_ptag(OPS_PTAG_CT_SE_DATA, info) && ops_write_length(1+encrypted_sz,info) && ops_write(data, len, info); }
/* 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; }