static int write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek, iobuf_t out) { int rc, seskeylen = openpgp_cipher_get_algo_keylen (dek->algo); PKT_symkey_enc *enc; byte enckey[33]; PACKET pkt; enc=xmalloc_clear(sizeof(PKT_symkey_enc)+seskeylen+1); encrypt_seskey(symkey_dek,&dek,enckey); enc->version = 4; enc->cipher_algo = opt.s2k_cipher_algo; enc->s2k = *symkey_s2k; enc->seskeylen = seskeylen + 1; /* algo id */ memcpy( enc->seskey, enckey, seskeylen + 1 ); pkt.pkttype = PKT_SYMKEY_ENC; pkt.pkt.symkey_enc = enc; if ((rc=build_packet(out,&pkt))) log_error("build symkey_enc packet failed: %s\n",gpg_strerror (rc)); xfree(enc); return rc; }
static int write_symkey_enc (STRING2KEY *symkey_s2k, aead_algo_t aead_algo, DEK *symkey_dek, DEK *dek, iobuf_t out) { int rc; void *enckey; size_t enckeylen; PKT_symkey_enc *enc; PACKET pkt; rc = encrypt_seskey (symkey_dek, aead_algo, &dek, &enckey, &enckeylen); if (rc) return rc; enc = xtrycalloc (1, sizeof (PKT_symkey_enc) + enckeylen); if (!enc) { rc = gpg_error_from_syserror (); xfree (enckey); return rc; } enc->version = aead_algo? 5 : 4; enc->cipher_algo = opt.s2k_cipher_algo; enc->aead_algo = aead_algo; enc->s2k = *symkey_s2k; enc->seskeylen = enckeylen; memcpy (enc->seskey, enckey, enckeylen); xfree (enckey); pkt.pkttype = PKT_SYMKEY_ENC; pkt.pkt.symkey_enc = enc; if ((rc=build_packet(out,&pkt))) log_error("build symkey_enc packet failed: %s\n",gpg_strerror (rc)); xfree (enc); return rc; }
/* We don't want to use use_seskey yet because older gnupg versions can't handle it, and there isn't really any point unless we're making a message that can be decrypted by a public key or passphrase. */ static int encrypt_simple (const char *filename, int mode, int use_seskey) { iobuf_t inp, out; PACKET pkt; PKT_plaintext *pt = NULL; STRING2KEY *s2k = NULL; byte enckey[33]; int rc = 0; int seskeylen = 0; u32 filesize; cipher_filter_context_t cfx; armor_filter_context_t *afx = NULL; compress_filter_context_t zfx; text_filter_context_t tfx; progress_filter_context_t *pfx; int do_compress = !!default_compress_algo(); pfx = new_progress_context (); memset( &cfx, 0, sizeof cfx); memset( &zfx, 0, sizeof zfx); memset( &tfx, 0, sizeof tfx); init_packet(&pkt); /* Prepare iobufs. */ inp = iobuf_open(filename); if (inp) iobuf_ioctl (inp, IOBUF_IOCTL_NO_CACHE, 1, NULL); if (inp && is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; gpg_err_set_errno (EPERM); } if (!inp) { rc = gpg_error_from_syserror (); log_error(_("can't open '%s': %s\n"), filename? filename: "[stdin]", strerror(errno) ); release_progress_context (pfx); return rc; } handle_progress (pfx, inp, filename); if (opt.textmode) iobuf_push_filter( inp, text_filter, &tfx ); cfx.dek = NULL; if ( mode ) { int canceled; s2k = xmalloc_clear( sizeof *s2k ); s2k->mode = opt.s2k_mode; s2k->hash_algo = S2K_DIGEST_ALGO; cfx.dek = passphrase_to_dek (NULL, 0, default_cipher_algo(), s2k, 4, NULL, &canceled); if ( !cfx.dek || !cfx.dek->keylen ) { rc = gpg_error (canceled? GPG_ERR_CANCELED:GPG_ERR_INV_PASSPHRASE); xfree (cfx.dek); xfree (s2k); iobuf_close (inp); log_error (_("error creating passphrase: %s\n"), gpg_strerror (rc)); release_progress_context (pfx); return rc; } if (use_seskey && s2k->mode != 1 && s2k->mode != 3) { use_seskey = 0; log_info (_("can't use a symmetric ESK packet " "due to the S2K mode\n")); } if ( use_seskey ) { DEK *dek = NULL; seskeylen = openpgp_cipher_get_algo_keylen (default_cipher_algo ()); encrypt_seskey( cfx.dek, &dek, enckey ); xfree( cfx.dek ); cfx.dek = dek; } if (opt.verbose) log_info(_("using cipher %s\n"), openpgp_cipher_algo_name (cfx.dek->algo)); cfx.dek->use_mdc=use_mdc(NULL,cfx.dek->algo); } if (do_compress && cfx.dek && cfx.dek->use_mdc && is_file_compressed(filename, &rc)) { if (opt.verbose) log_info(_("'%s' already compressed\n"), filename); do_compress = 0; } if ( rc || (rc = open_outfile (-1, filename, opt.armor? 1:0, 0, &out ))) { iobuf_cancel (inp); xfree (cfx.dek); xfree (s2k); release_progress_context (pfx); return rc; } if ( opt.armor ) { afx = new_armor_context (); push_armor_filter (afx, out); } if ( s2k ) { PKT_symkey_enc *enc = xmalloc_clear( sizeof *enc + seskeylen + 1 ); enc->version = 4; enc->cipher_algo = cfx.dek->algo; enc->s2k = *s2k; if ( use_seskey && seskeylen ) { enc->seskeylen = seskeylen + 1; /* algo id */ memcpy (enc->seskey, enckey, seskeylen + 1 ); } pkt.pkttype = PKT_SYMKEY_ENC; pkt.pkt.symkey_enc = enc; if ((rc = build_packet( out, &pkt ))) log_error("build symkey packet failed: %s\n", gpg_strerror (rc) ); xfree (enc); } if (!opt.no_literal) pt = setup_plaintext_name (filename, inp); /* Note that PGP 5 has problems decrypting symmetrically encrypted data if the file length is in the inner packet. It works when only partial length headers are use. In the past, we always used partial body length here, but since PGP 2, PGP 6, and PGP 7 need the file length, and nobody should be using PGP 5 nowadays anyway, this is now set to the file length. Note also that this only applies to the RFC-1991 style symmetric messages, and not the RFC-2440 style. PGP 6 and 7 work with either partial length or fixed length with the new style messages. */ if ( !iobuf_is_pipe_filename (filename) && *filename && !opt.textmode ) { off_t tmpsize; int overflow; if ( !(tmpsize = iobuf_get_filelength(inp, &overflow)) && !overflow && opt.verbose) log_info(_("WARNING: '%s' is an empty file\n"), filename ); /* We can't encode the length of very large files because OpenPGP uses only 32 bit for file sizes. So if the the size of a file is larger than 2^32 minus some bytes for packet headers, we switch to partial length encoding. */ if ( tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) ) filesize = tmpsize; else filesize = 0; } else filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */ if (!opt.no_literal) { pt->timestamp = make_timestamp(); pt->mode = opt.textmode? 't' : 'b'; pt->len = filesize; pt->new_ctb = !pt->len; pt->buf = inp; pkt.pkttype = PKT_PLAINTEXT; pkt.pkt.plaintext = pt; cfx.datalen = filesize && !do_compress ? calc_packet_length( &pkt ) : 0; } else { cfx.datalen = filesize && !do_compress ? filesize : 0; pkt.pkttype = 0; pkt.pkt.generic = NULL; } /* Register the cipher filter. */ if (mode) iobuf_push_filter ( out, cipher_filter, &cfx ); /* Register the compress filter. */ if ( do_compress ) { if (cfx.dek && cfx.dek->use_mdc) zfx.new_ctb = 1; push_compress_filter (out, &zfx, default_compress_algo()); } /* Do the work. */ if (!opt.no_literal) { if ( (rc = build_packet( out, &pkt )) ) log_error("build_packet failed: %s\n", gpg_strerror (rc) ); } else { /* User requested not to create a literal packet, so we copy the plain data. */ byte copy_buffer[4096]; int bytes_copied; while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1) if ( (rc=iobuf_write(out, copy_buffer, bytes_copied)) ) { log_error ("copying input to output failed: %s\n", gpg_strerror (rc) ); break; } wipememory (copy_buffer, 4096); /* burn buffer */ } /* Finish the stuff. */ iobuf_close (inp); if (rc) iobuf_cancel(out); else { iobuf_close (out); /* fixme: check returncode */ if (mode) write_status ( STATUS_END_ENCRYPTION ); } if (pt) pt->buf = NULL; free_packet (&pkt); xfree (cfx.dek); xfree (s2k); release_armor_context (afx); release_progress_context (pfx); return rc; }