gpg: Remove MDC options
[gnupg.git] / g10 / cipher.c
1 /* cipher.c - En-/De-ciphering filter
2  * Copyright (C) 1998-2003, 2006, 2009 Free Software Foundation, Inc.
3  * Copyright (C) 1998-2003, 2006, 2009, 2017 Werner koch
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <https://www.gnu.org/licenses/>.
19  * SPDX-License-Identifier: GPL-3.0+
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27
28 #include "gpg.h"
29 #include "../common/status.h"
30 #include "../common/iobuf.h"
31 #include "../common/util.h"
32 #include "filter.h"
33 #include "packet.h"
34 #include "options.h"
35 #include "main.h"
36 #include "../common/i18n.h"
37 #include "../common/status.h"
38
39
40 #define MIN_PARTIAL_SIZE 512
41
42
43 static void
44 write_header (cipher_filter_context_t *cfx, iobuf_t a)
45 {
46   gcry_error_t err;
47   PACKET pkt;
48   PKT_encrypted ed;
49   byte temp[18];
50   unsigned int blocksize;
51   unsigned int nprefix;
52
53   blocksize = openpgp_cipher_get_algo_blklen (cfx->dek->algo);
54   if ( blocksize < 8 || blocksize > 16 )
55     log_fatal ("unsupported blocksize %u\n", blocksize);
56
57   memset (&ed, 0, sizeof ed);
58   ed.len = cfx->datalen;
59   ed.extralen = blocksize + 2;
60   ed.new_ctb = !ed.len;
61   if (cfx->dek->use_mdc)
62     {
63       ed.mdc_method = DIGEST_ALGO_SHA1;
64       gcry_md_open (&cfx->mdc_hash, DIGEST_ALGO_SHA1, 0);
65       if (DBG_HASHING)
66         gcry_md_debug (cfx->mdc_hash, "creatmdc");
67     }
68   else
69     {
70       log_info (_("WARNING: "
71                   "encrypting without integrity protection is dangerous\n"));
72       log_info (_("Hint: Do not use option %s\n"), "--rfc2440");
73     }
74
75   write_status_printf (STATUS_BEGIN_ENCRYPTION, "%d %d",
76                        ed.mdc_method, cfx->dek->algo);
77
78   init_packet (&pkt);
79   pkt.pkttype = cfx->dek->use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED;
80   pkt.pkt.encrypted = &ed;
81   if (build_packet( a, &pkt))
82     log_bug ("build_packet(ENCR_DATA) failed\n");
83   nprefix = blocksize;
84   gcry_randomize (temp, nprefix, GCRY_STRONG_RANDOM );
85   temp[nprefix] = temp[nprefix-2];
86   temp[nprefix+1] = temp[nprefix-1];
87   print_cipher_algo_note (cfx->dek->algo);
88   err = openpgp_cipher_open (&cfx->cipher_hd,
89                              cfx->dek->algo,
90                              GCRY_CIPHER_MODE_CFB,
91                              (GCRY_CIPHER_SECURE
92                               | ((cfx->dek->use_mdc || cfx->dek->algo >= 100)?
93                                  0 : GCRY_CIPHER_ENABLE_SYNC)));
94   if (err)
95     {
96       /* We should never get an error here cause we already checked,
97        * that the algorithm is available.  */
98       BUG();
99     }
100
101   /* log_hexdump ("thekey", cfx->dek->key, cfx->dek->keylen); */
102   gcry_cipher_setkey (cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen);
103   gcry_cipher_setiv (cfx->cipher_hd, NULL, 0);
104   /* log_hexdump ("prefix", temp, nprefix+2); */
105   if (cfx->mdc_hash) /* Hash the "IV". */
106     gcry_md_write (cfx->mdc_hash, temp, nprefix+2 );
107   gcry_cipher_encrypt (cfx->cipher_hd, temp, nprefix+2, NULL, 0);
108   gcry_cipher_sync (cfx->cipher_hd);
109   iobuf_write (a, temp, nprefix+2);
110
111   cfx->short_blklen_warn = (blocksize < 16);
112   cfx->short_blklen_count = nprefix+2;
113
114   cfx->wrote_header = 1;
115 }
116
117
118 /*
119  * This filter is used to en/de-cipher data with a symmetric algorithm
120  */
121 int
122 cipher_filter (void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len)
123 {
124   cipher_filter_context_t *cfx = opaque;
125   size_t size = *ret_len;
126   int rc = 0;
127
128   if (control == IOBUFCTRL_UNDERFLOW) /* decrypt */
129     {
130       rc = -1; /* not yet used */
131     }
132   else if (control == IOBUFCTRL_FLUSH) /* encrypt */
133     {
134       log_assert (a);
135       if (!cfx->wrote_header)
136         write_header (cfx, a);
137       if (cfx->mdc_hash)
138         gcry_md_write (cfx->mdc_hash, buf, size);
139       gcry_cipher_encrypt (cfx->cipher_hd, buf, size, NULL, 0);
140       if (cfx->short_blklen_warn)
141         {
142           cfx->short_blklen_count += size;
143           if (cfx->short_blklen_count > (150 * 1024 * 1024))
144             {
145               log_info ("WARNING: encrypting more than %d MiB with algorithm "
146                         "%s should be avoided\n", 150,
147                         openpgp_cipher_algo_name (cfx->dek->algo));
148               cfx->short_blklen_warn = 0; /* Don't show again.  */
149             }
150         }
151
152       rc = iobuf_write (a, buf, size);
153     }
154   else if (control == IOBUFCTRL_FREE)
155     {
156       if (cfx->mdc_hash)
157         {
158           byte *hash;
159           int hashlen = gcry_md_get_algo_dlen (gcry_md_get_algo(cfx->mdc_hash));
160           byte temp[22];
161
162           log_assert (hashlen == 20);
163           /* We must hash the prefix of the MDC packet here. */
164           temp[0] = 0xd3;
165           temp[1] = 0x14;
166           gcry_md_putc (cfx->mdc_hash, temp[0]);
167           gcry_md_putc (cfx->mdc_hash, temp[1]);
168
169           gcry_md_final (cfx->mdc_hash);
170           hash = gcry_md_read (cfx->mdc_hash, 0);
171           memcpy(temp+2, hash, 20);
172           gcry_cipher_encrypt (cfx->cipher_hd, temp, 22, NULL, 0);
173           gcry_md_close (cfx->mdc_hash); cfx->mdc_hash = NULL;
174           if (iobuf_write( a, temp, 22))
175             log_error ("writing MDC packet failed\n");
176         }
177
178       gcry_cipher_close (cfx->cipher_hd);
179     }
180   else if (control == IOBUFCTRL_DESC)
181     {
182       mem2str (buf, "cipher_filter", *ret_len);
183     }
184
185   return rc;
186 }