blob: 9f0f68a2d4858f4b176dc1b179a7c0ad83f24b86 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar8f4ac012014-08-10 13:38:34 +02002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * crypt.c: Generic encryption support.
12 */
13#include "vim.h"
14
15#if defined(FEAT_CRYPT) || defined(PROTO)
16/*
17 * Optional encryption support.
18 * Mohsin Ahmed, mosh@sasi.com, 1998-09-24
19 * Based on zip/crypt sources.
20 * Refactored by David Leadbeater, 2014.
21 *
22 * NOTE FOR USA: Since 2000 exporting this code from the USA is allowed to
23 * most countries. There are a few exceptions, but that still should not be a
24 * problem since this code was originally created in Europe and India.
25 *
26 * Blowfish addition originally made by Mohsin Ahmed,
27 * http://www.cs.albany.edu/~mosh 2010-03-14
28 * Based on blowfish by Bruce Schneier (http://www.schneier.com/blowfish.html)
29 * and sha256 by Christophe Devine.
30 */
31
32typedef struct {
ichizok35a2ec12023-04-25 15:27:27 +010033 char *name; // encryption name as used in 'cryptmethod'
34 char *magic; // magic bytes stored in file header
35 int salt_len; // length of salt, or 0 when not using salt
36 int seed_len; // length of seed, or 0 when not using seed
37 int add_len; // additional length in the header needed for storing
38 // custom data
Bram Moolenaar987411d2019-01-18 22:48:34 +010039#ifdef CRYPT_NOT_INPLACE
ichizok35a2ec12023-04-25 15:27:27 +010040 int works_inplace; // encryption/decryption can be done in-place
Bram Moolenaar987411d2019-01-18 22:48:34 +010041#endif
ichizok35a2ec12023-04-25 15:27:27 +010042 int whole_undofile; // whole undo file is encrypted
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020043
Bram Moolenaarc667da52019-11-30 20:52:27 +010044 // Optional function pointer for a self-test.
ichizok35a2ec12023-04-25 15:27:27 +010045 int (*self_test_fn)(void);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020046
Bram Moolenaarad3ec762019-04-21 00:00:13 +020047 // Function pointer for initializing encryption/decryption.
ichizok35a2ec12023-04-25 15:27:27 +010048 int (* init_fn)(cryptstate_T *state, char_u *key, crypt_arg_T *arg);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020049
Bram Moolenaarc667da52019-11-30 20:52:27 +010050 // Function pointers for encoding/decoding from one buffer into another.
51 // Optional, however, these or the _buffer ones should be configured.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020052 void (*encode_fn)(cryptstate_T *state, char_u *from, size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +020053 char_u *to, int last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020054 void (*decode_fn)(cryptstate_T *state, char_u *from, size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +020055 char_u *to, int last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020056
Bram Moolenaarc667da52019-11-30 20:52:27 +010057 // Function pointers for encoding and decoding, can buffer data if needed.
58 // Optional (however, these or the above should be configured).
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020059 long (*encode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +020060 char_u **newptr, int last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020061 long (*decode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +020062 char_u **newptr, int last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020063
Bram Moolenaarc667da52019-11-30 20:52:27 +010064 // Function pointers for in-place encoding and decoding, used for
65 // crypt_*_inplace(). "from" and "to" arguments will be equal.
66 // These may be the same as decode_fn and encode_fn above, however an
67 // algorithm may implement them in a way that is not interchangeable with
68 // the crypt_(en|de)code() interface (for example because it wishes to add
69 // padding to files).
70 // This method is used for swap and undo files which have a rigid format.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020071 void (*encode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +020072 char_u *p2, int last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020073 void (*decode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +020074 char_u *p2, int last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020075} cryptmethod_T;
76
Christian Brabandtaae58342023-04-23 17:50:22 +010077static int crypt_sodium_init_(cryptstate_T *state, char_u *key, crypt_arg_T *arg);
Yegappan Lakshmananee47eac2022-06-29 12:55:36 +010078static long crypt_sodium_buffer_decode(cryptstate_T *state, char_u *from, size_t len, char_u **buf_out, int last);
79static long crypt_sodium_buffer_encode(cryptstate_T *state, char_u *from, size_t len, char_u **buf_out, int last);
Christian Brabandtaae58342023-04-23 17:50:22 +010080#if defined(FEAT_EVAL) && defined(FEAT_SODIUM)
ichizok35a2ec12023-04-25 15:27:27 +010081static void crypt_sodium_report_hash_params(unsigned long long opslimit, unsigned long long ops_def, size_t memlimit, size_t mem_def, int alg, int alg_def);
Christian Brabandtaae58342023-04-23 17:50:22 +010082#endif
Yegappan Lakshmananee47eac2022-06-29 12:55:36 +010083
Bram Moolenaarc667da52019-11-30 20:52:27 +010084// index is method_nr of cryptstate_T, CRYPT_M_*
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020085static cryptmethod_T cryptmethods[CRYPT_M_COUNT] = {
Bram Moolenaarc667da52019-11-30 20:52:27 +010086 // PK_Zip; very weak
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020087 {
88 "zip",
89 "VimCrypt~01!",
90 0,
91 0,
Christian Brabandtaae58342023-04-23 17:50:22 +010092 0,
Bram Moolenaar987411d2019-01-18 22:48:34 +010093#ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020094 TRUE,
Bram Moolenaar987411d2019-01-18 22:48:34 +010095#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020096 FALSE,
97 NULL,
98 crypt_zip_init,
99 crypt_zip_encode, crypt_zip_decode,
100 NULL, NULL,
101 crypt_zip_encode, crypt_zip_decode,
102 },
103
Bram Moolenaarc667da52019-11-30 20:52:27 +0100104 // Blowfish/CFB + SHA-256 custom key derivation; implementation issues.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200105 {
106 "blowfish",
107 "VimCrypt~02!",
108 8,
109 8,
Christian Brabandtaae58342023-04-23 17:50:22 +0100110 0,
Bram Moolenaar987411d2019-01-18 22:48:34 +0100111#ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200112 TRUE,
Bram Moolenaar987411d2019-01-18 22:48:34 +0100113#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200114 FALSE,
115 blowfish_self_test,
116 crypt_blowfish_init,
117 crypt_blowfish_encode, crypt_blowfish_decode,
118 NULL, NULL,
119 crypt_blowfish_encode, crypt_blowfish_decode,
120 },
121
Bram Moolenaarc667da52019-11-30 20:52:27 +0100122 // Blowfish/CFB + SHA-256 custom key derivation; fixed.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200123 {
124 "blowfish2",
125 "VimCrypt~03!",
126 8,
127 8,
Christian Brabandtaae58342023-04-23 17:50:22 +0100128 0,
Bram Moolenaar987411d2019-01-18 22:48:34 +0100129#ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200130 TRUE,
Bram Moolenaar987411d2019-01-18 22:48:34 +0100131#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200132 TRUE,
133 blowfish_self_test,
134 crypt_blowfish_init,
135 crypt_blowfish_encode, crypt_blowfish_decode,
136 NULL, NULL,
137 crypt_blowfish_encode, crypt_blowfish_decode,
138 },
Bram Moolenaard23a8232018-02-10 18:45:26 +0100139
Christian Brabandtaae58342023-04-23 17:50:22 +0100140 // XChaCha20 using libsodium; implementation issues
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200141 {
142 "xchacha20",
143 "VimCrypt~04!",
144#ifdef FEAT_SODIUM
145 crypto_pwhash_argon2id_SALTBYTES, // 16
146#else
147 16,
148#endif
149 8,
Christian Brabandtaae58342023-04-23 17:50:22 +0100150 0,
151#ifdef CRYPT_NOT_INPLACE
152 FALSE,
153#endif
154 FALSE,
155 NULL,
156 crypt_sodium_init_,
157 NULL, NULL,
158 crypt_sodium_buffer_encode, crypt_sodium_buffer_decode,
159 NULL, NULL,
160 },
161 // XChaCha20 using libsodium; stores parameters in header
162 {
163 "xchacha20v2",
164 "VimCrypt~05!",
165#ifdef FEAT_SODIUM
166 crypto_pwhash_argon2id_SALTBYTES, // 16
167#else
168 16,
169#endif
170 8,
171 // sizeof(crypto_pwhash_OPSLIMIT_INTERACTIVE + crypto_pwhash_MEMLIMIT_INTERACTIVE + crypto_pwhash_ALG_DEFAULT)
172 20,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200173#ifdef CRYPT_NOT_INPLACE
174 FALSE,
175#endif
176 FALSE,
177 NULL,
K.Takataa8cdb4e2022-12-06 16:17:01 +0000178 crypt_sodium_init_,
Christian Brabandt226b28b2021-06-21 21:08:08 +0200179 NULL, NULL,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200180 crypt_sodium_buffer_encode, crypt_sodium_buffer_decode,
Christian Brabandt226b28b2021-06-21 21:08:08 +0200181 NULL, NULL,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200182 },
183
Bram Moolenaarc667da52019-11-30 20:52:27 +0100184 // NOTE: when adding a new method, use some random bytes for the magic key,
185 // to avoid that a text file is recognized as encrypted.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200186};
187
Yegappan Lakshmanana23a11b2023-02-21 14:27:41 +0000188#if defined(FEAT_SODIUM) || defined(PROTO)
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200189typedef struct {
190 size_t count;
191 unsigned char key[crypto_box_SEEDBYTES];
192 // 32, same as crypto_secretstream_xchacha20poly1305_KEYBYTES
193 crypto_secretstream_xchacha20poly1305_state
194 state;
195} sodium_state_T;
K.Takata1a8825d2022-01-19 13:32:57 +0000196
197
198# ifdef DYNAMIC_SODIUM
K.Takatad68b2fc2022-02-12 11:18:37 +0000199# ifdef MSWIN
200# define SODIUM_PROC FARPROC
201# define load_dll vimLoadLib
202# define symbol_from_dll GetProcAddress
203# define close_dll FreeLibrary
204# define load_dll_error GetWin32Error
205# else
206# error Dynamic loading of libsodium is not supported for now.
207//# define HINSTANCE void*
208//# define SODIUM_PROC void*
209//# define load_dll(n) dlopen((n), RTLD_LAZY|RTLD_GLOBAL)
210//# define symbol_from_dll dlsym
211//# define close_dll dlclose
212//# define load_dll_error dlerror
213# endif
214
K.Takata1a8825d2022-01-19 13:32:57 +0000215# define sodium_init load_sodium
216# define sodium_free dll_sodium_free
217# define sodium_malloc dll_sodium_malloc
218# define sodium_memzero dll_sodium_memzero
219# define sodium_mlock dll_sodium_mlock
220# define sodium_munlock dll_sodium_munlock
221# define crypto_secretstream_xchacha20poly1305_init_push \
222 dll_crypto_secretstream_xchacha20poly1305_init_push
223# define crypto_secretstream_xchacha20poly1305_push \
224 dll_crypto_secretstream_xchacha20poly1305_push
225# define crypto_secretstream_xchacha20poly1305_init_pull \
226 dll_crypto_secretstream_xchacha20poly1305_init_pull
227# define crypto_secretstream_xchacha20poly1305_pull \
228 dll_crypto_secretstream_xchacha20poly1305_pull
229# define crypto_pwhash dll_crypto_pwhash
230# define randombytes_buf dll_randombytes_buf
K.Takataa8cdb4e2022-12-06 16:17:01 +0000231# define randombytes_random dll_randombytes_random
K.Takata1a8825d2022-01-19 13:32:57 +0000232
233static int (*dll_sodium_init)(void) = NULL;
234static void (*dll_sodium_free)(void *) = NULL;
235static void *(*dll_sodium_malloc)(const size_t) = NULL;
236static void (*dll_sodium_memzero)(void * const, const size_t) = NULL;
237static int (*dll_sodium_mlock)(void * const, const size_t) = NULL;
238static int (*dll_sodium_munlock)(void * const, const size_t) = NULL;
239static int (*dll_crypto_secretstream_xchacha20poly1305_init_push)
240 (crypto_secretstream_xchacha20poly1305_state *state,
241 unsigned char [],
242 const unsigned char []) = NULL;
243static int (*dll_crypto_secretstream_xchacha20poly1305_push)
244 (crypto_secretstream_xchacha20poly1305_state *state,
245 unsigned char *c, unsigned long long *clen_p,
246 const unsigned char *m, unsigned long long mlen,
247 const unsigned char *ad, unsigned long long adlen, unsigned char tag)
248 = NULL;
249static int (*dll_crypto_secretstream_xchacha20poly1305_init_pull)
250 (crypto_secretstream_xchacha20poly1305_state *state,
251 const unsigned char [],
252 const unsigned char []) = NULL;
253static int (*dll_crypto_secretstream_xchacha20poly1305_pull)
254 (crypto_secretstream_xchacha20poly1305_state *state,
255 unsigned char *m, unsigned long long *mlen_p, unsigned char *tag_p,
256 const unsigned char *c, unsigned long long clen,
257 const unsigned char *ad, unsigned long long adlen) = NULL;
258static int (*dll_crypto_pwhash)(unsigned char * const out,
259 unsigned long long outlen,
260 const char * const passwd, unsigned long long passwdlen,
261 const unsigned char * const salt,
262 unsigned long long opslimit, size_t memlimit, int alg)
263 = NULL;
264static void (*dll_randombytes_buf)(void * const buf, const size_t size);
K.Takataa8cdb4e2022-12-06 16:17:01 +0000265static uint32_t (*dll_randombytes_random)(void);
K.Takata1a8825d2022-01-19 13:32:57 +0000266
267static struct {
268 const char *name;
K.Takatad68b2fc2022-02-12 11:18:37 +0000269 SODIUM_PROC *ptr;
K.Takata1a8825d2022-01-19 13:32:57 +0000270} sodium_funcname_table[] = {
K.Takatad68b2fc2022-02-12 11:18:37 +0000271 {"sodium_init", (SODIUM_PROC*)&dll_sodium_init},
272 {"sodium_free", (SODIUM_PROC*)&dll_sodium_free},
273 {"sodium_malloc", (SODIUM_PROC*)&dll_sodium_malloc},
274 {"sodium_memzero", (SODIUM_PROC*)&dll_sodium_memzero},
275 {"sodium_mlock", (SODIUM_PROC*)&dll_sodium_mlock},
276 {"sodium_munlock", (SODIUM_PROC*)&dll_sodium_munlock},
277 {"crypto_secretstream_xchacha20poly1305_init_push", (SODIUM_PROC*)&dll_crypto_secretstream_xchacha20poly1305_init_push},
278 {"crypto_secretstream_xchacha20poly1305_push", (SODIUM_PROC*)&dll_crypto_secretstream_xchacha20poly1305_push},
279 {"crypto_secretstream_xchacha20poly1305_init_pull", (SODIUM_PROC*)&dll_crypto_secretstream_xchacha20poly1305_init_pull},
280 {"crypto_secretstream_xchacha20poly1305_pull", (SODIUM_PROC*)&dll_crypto_secretstream_xchacha20poly1305_pull},
281 {"crypto_pwhash", (SODIUM_PROC*)&dll_crypto_pwhash},
282 {"randombytes_buf", (SODIUM_PROC*)&dll_randombytes_buf},
K.Takataa8cdb4e2022-12-06 16:17:01 +0000283 {"randombytes_random", (SODIUM_PROC*)&dll_randombytes_random},
K.Takata1a8825d2022-01-19 13:32:57 +0000284 {NULL, NULL}
285};
286
287 static int
K.Takatad68b2fc2022-02-12 11:18:37 +0000288sodium_runtime_link_init(int verbose)
K.Takata1a8825d2022-01-19 13:32:57 +0000289{
K.Takatad68b2fc2022-02-12 11:18:37 +0000290 static HINSTANCE hsodium = NULL;
K.Takatad8f86292022-03-07 15:16:15 +0000291 const char *libname = DYNAMIC_SODIUM_DLL;
K.Takata1a8825d2022-01-19 13:32:57 +0000292 int i;
293
294 if (hsodium != NULL)
K.Takatad68b2fc2022-02-12 11:18:37 +0000295 return OK;
K.Takata1a8825d2022-01-19 13:32:57 +0000296
K.Takatad68b2fc2022-02-12 11:18:37 +0000297 hsodium = load_dll(libname);
K.Takata1a8825d2022-01-19 13:32:57 +0000298 if (hsodium == NULL)
299 {
K.Takatad68b2fc2022-02-12 11:18:37 +0000300 if (verbose)
301 semsg(_(e_could_not_load_library_str_str), libname, load_dll_error());
302 return FAIL;
K.Takata1a8825d2022-01-19 13:32:57 +0000303 }
304
305 for (i = 0; sodium_funcname_table[i].ptr; ++i)
306 {
K.Takatad68b2fc2022-02-12 11:18:37 +0000307 if ((*sodium_funcname_table[i].ptr = symbol_from_dll(hsodium,
K.Takata1a8825d2022-01-19 13:32:57 +0000308 sodium_funcname_table[i].name)) == NULL)
309 {
K.Takatad8f86292022-03-07 15:16:15 +0000310 close_dll(hsodium);
K.Takata1a8825d2022-01-19 13:32:57 +0000311 hsodium = NULL;
K.Takatad68b2fc2022-02-12 11:18:37 +0000312 if (verbose)
313 semsg(_(e_could_not_load_library_function_str), sodium_funcname_table[i].name);
314 return FAIL;
K.Takata1a8825d2022-01-19 13:32:57 +0000315 }
316 }
K.Takatad68b2fc2022-02-12 11:18:37 +0000317 return OK;
318}
319
320 static int
321load_sodium(void)
322{
323 if (sodium_runtime_link_init(TRUE) == FAIL)
324 return -1;
K.Takata1a8825d2022-01-19 13:32:57 +0000325 return dll_sodium_init();
326}
327# endif
K.Takatad68b2fc2022-02-12 11:18:37 +0000328
329# if defined(DYNAMIC_SODIUM) || defined(PROTO)
330 int
331sodium_enabled(int verbose)
332{
333 return sodium_runtime_link_init(verbose) == OK;
334}
335# endif
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200336#endif
337
Bram Moolenaarc667da52019-11-30 20:52:27 +0100338#define CRYPT_MAGIC_LEN 12 // cannot change
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200339static char crypt_magic_head[] = "VimCrypt~";
340
341/*
342 * Return int value for crypt method name.
343 * 0 for "zip", the old method. Also for any non-valid value.
344 * 1 for "blowfish".
345 * 2 for "blowfish2".
346 */
347 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100348crypt_method_nr_from_name(char_u *name)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200349{
350 int i;
351
352 for (i = 0; i < CRYPT_M_COUNT; ++i)
353 if (STRCMP(name, cryptmethods[i].name) == 0)
354 return i;
355 return 0;
356}
357
358/*
359 * Get the crypt method used for a file from "ptr[len]", the magic text at the
360 * start of the file.
361 * Returns -1 when no encryption used.
362 */
363 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100364crypt_method_nr_from_magic(char *ptr, int len)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200365{
366 int i;
367
368 if (len < CRYPT_MAGIC_LEN)
369 return -1;
370
371 for (i = 0; i < CRYPT_M_COUNT; i++)
372 if (memcmp(ptr, cryptmethods[i].magic, CRYPT_MAGIC_LEN) == 0)
373 return i;
374
375 i = (int)STRLEN(crypt_magic_head);
376 if (len >= i && memcmp(ptr, crypt_magic_head, i) == 0)
Bram Moolenaar9d00e4a2022-01-05 17:49:15 +0000377 emsg(_(e_file_is_encrypted_with_unknown_method));
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200378
379 return -1;
380}
381
Bram Moolenaar987411d2019-01-18 22:48:34 +0100382#ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200383/*
384 * Return TRUE if the crypt method for "method_nr" can be done in-place.
385 */
386 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100387crypt_works_inplace(cryptstate_T *state)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200388{
389 return cryptmethods[state->method_nr].works_inplace;
390}
Bram Moolenaar987411d2019-01-18 22:48:34 +0100391#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200392
393/*
394 * Get the crypt method for buffer "buf" as a number.
395 */
396 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100397crypt_get_method_nr(buf_T *buf)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200398{
399 return crypt_method_nr_from_name(*buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
400}
401
402/*
Christian Brabandtaae58342023-04-23 17:50:22 +0100403 * Returns True for Sodium Encryption.
404 */
405 int
406crypt_method_is_sodium(int method)
407{
408 return method == CRYPT_M_SOD || method == CRYPT_M_SOD2;
409}
410
411/*
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200412 * Return TRUE when the buffer uses an encryption method that encrypts the
413 * whole undo file, not only the text.
414 */
415 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100416crypt_whole_undofile(int method_nr)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200417{
418 return cryptmethods[method_nr].whole_undofile;
419}
420
421/*
Bram Moolenaar32aa1022019-11-02 22:54:41 +0100422 * Get crypt method specific length of the file header in bytes.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200423 */
424 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100425crypt_get_header_len(int method_nr)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200426{
427 return CRYPT_MAGIC_LEN
428 + cryptmethods[method_nr].salt_len
Christian Brabandtaae58342023-04-23 17:50:22 +0100429 + cryptmethods[method_nr].seed_len
430 + cryptmethods[method_nr].add_len;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200431}
432
Christian Brabandt226b28b2021-06-21 21:08:08 +0200433
Dominique Pelle748b3082022-01-08 12:41:16 +0000434#if defined(FEAT_SODIUM) || defined(PROTO)
Christian Brabandt226b28b2021-06-21 21:08:08 +0200435/*
436 * Get maximum crypt method specific length of the file header in bytes.
437 */
438 int
Yegappan Lakshmanana23a11b2023-02-21 14:27:41 +0000439crypt_get_max_header_len(void)
Christian Brabandt226b28b2021-06-21 21:08:08 +0200440{
441 int i;
442 int max = 0;
443 int temp = 0;
444
445 for (i = 0; i < CRYPT_M_COUNT; ++i)
446 {
447 temp = crypt_get_header_len(i);
448 if (temp > max)
449 max = temp;
450 }
451 return max;
452}
Dominique Pelle748b3082022-01-08 12:41:16 +0000453#endif
Christian Brabandt226b28b2021-06-21 21:08:08 +0200454
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200455/*
456 * Set the crypt method for buffer "buf" to "method_nr" using the int value as
457 * returned by crypt_method_nr_from_name().
458 */
459 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100460crypt_set_cm_option(buf_T *buf, int method_nr)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200461{
462 free_string_option(buf->b_p_cm);
463 buf->b_p_cm = vim_strsave((char_u *)cryptmethods[method_nr].name);
464}
465
466/*
467 * If the crypt method for the current buffer has a self-test, run it and
468 * return OK/FAIL.
469 */
470 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100471crypt_self_test(void)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200472{
473 int method_nr = crypt_get_method_nr(curbuf);
474
475 if (cryptmethods[method_nr].self_test_fn == NULL)
476 return OK;
477 return cryptmethods[method_nr].self_test_fn();
478}
479
480/*
481 * Allocate a crypt state and initialize it.
Bram Moolenaar6ee96582019-04-27 22:06:37 +0200482 * Return NULL for failure.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200483 */
484 cryptstate_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +0100485crypt_create(
486 int method_nr,
487 char_u *key,
Christian Brabandtaae58342023-04-23 17:50:22 +0100488 crypt_arg_T *crypt_arg)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200489{
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200490 cryptstate_T *state = ALLOC_ONE(cryptstate_T);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200491
Bram Moolenaar6ee96582019-04-27 22:06:37 +0200492 if (state == NULL)
493 return state;
494
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200495 state->method_nr = method_nr;
Christian Brabandtaae58342023-04-23 17:50:22 +0100496 if (cryptmethods[method_nr].init_fn(state, key, crypt_arg) == FAIL)
Bram Moolenaar6ee96582019-04-27 22:06:37 +0200497 {
Bram Moolenaar6ed545e2022-05-09 20:09:23 +0100498 vim_free(state);
499 return NULL;
Bram Moolenaar6ee96582019-04-27 22:06:37 +0200500 }
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200501 return state;
502}
503
504/*
505 * Allocate a crypt state from a file header and initialize it.
506 * Assumes that header contains at least the number of bytes that
507 * crypt_get_header_len() returns for "method_nr".
508 */
509 cryptstate_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +0100510crypt_create_from_header(
511 int method_nr,
512 char_u *key,
513 char_u *header)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200514{
Christian Brabandtaae58342023-04-23 17:50:22 +0100515 crypt_arg_T arg;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200516
Christian Brabandtaae58342023-04-23 17:50:22 +0100517 CLEAR_FIELD(arg);
518 arg.cat_init_from_file = TRUE;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200519
Christian Brabandtaae58342023-04-23 17:50:22 +0100520 arg.cat_salt_len = cryptmethods[method_nr].salt_len;
521 arg.cat_seed_len = cryptmethods[method_nr].seed_len;
522 arg.cat_add_len = cryptmethods[method_nr].add_len;
523 if (arg.cat_salt_len > 0)
524 arg.cat_salt = header + CRYPT_MAGIC_LEN;
525 if (arg.cat_seed_len > 0)
526 arg.cat_seed = header + CRYPT_MAGIC_LEN + arg.cat_salt_len;
527 if (arg.cat_add_len > 0)
Bram Moolenaar3a2a60c2023-05-27 18:02:55 +0100528 arg.cat_add = header + CRYPT_MAGIC_LEN
529 + arg.cat_salt_len + arg.cat_seed_len;
Christian Brabandtaae58342023-04-23 17:50:22 +0100530
531 return crypt_create(method_nr, key, &arg);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200532}
533
534/*
535 * Read the crypt method specific header data from "fp".
536 * Return an allocated cryptstate_T or NULL on error.
537 */
538 cryptstate_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +0100539crypt_create_from_file(FILE *fp, char_u *key)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200540{
541 int method_nr;
542 int header_len;
543 char magic_buffer[CRYPT_MAGIC_LEN];
544 char_u *buffer;
545 cryptstate_T *state;
546
547 if (fread(magic_buffer, CRYPT_MAGIC_LEN, 1, fp) != 1)
548 return NULL;
549 method_nr = crypt_method_nr_from_magic(magic_buffer, CRYPT_MAGIC_LEN);
550 if (method_nr < 0)
551 return NULL;
552
553 header_len = crypt_get_header_len(method_nr);
554 if ((buffer = alloc(header_len)) == NULL)
555 return NULL;
556 mch_memmove(buffer, magic_buffer, CRYPT_MAGIC_LEN);
557 if (header_len > CRYPT_MAGIC_LEN
558 && fread(buffer + CRYPT_MAGIC_LEN,
559 header_len - CRYPT_MAGIC_LEN, 1, fp) != 1)
560 {
561 vim_free(buffer);
562 return NULL;
563 }
564
565 state = crypt_create_from_header(method_nr, key, buffer);
566 vim_free(buffer);
567 return state;
568}
569
570/*
571 * Allocate a cryptstate_T for writing and initialize it with "key".
572 * Allocates and fills in the header and stores it in "header", setting
573 * "header_len". The header may include salt and seed, depending on
574 * cryptmethod. Caller must free header.
575 * Returns the state or NULL on failure.
576 */
577 cryptstate_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +0100578crypt_create_for_writing(
579 int method_nr,
580 char_u *key,
581 char_u **header,
582 int *header_len)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200583{
584 int len = crypt_get_header_len(method_nr);
Christian Brabandtaae58342023-04-23 17:50:22 +0100585 crypt_arg_T arg;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200586 cryptstate_T *state;
587
Christian Brabandtaae58342023-04-23 17:50:22 +0100588 CLEAR_FIELD(arg);
589 arg.cat_salt_len = cryptmethods[method_nr].salt_len;
590 arg.cat_seed_len = cryptmethods[method_nr].seed_len;
591 arg.cat_add_len = cryptmethods[method_nr].add_len;
592 arg.cat_init_from_file = FALSE;
593
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200594 *header_len = len;
595 *header = alloc(len);
596 if (*header == NULL)
597 return NULL;
598
599 mch_memmove(*header, cryptmethods[method_nr].magic, CRYPT_MAGIC_LEN);
Christian Brabandtaae58342023-04-23 17:50:22 +0100600 if (arg.cat_salt_len > 0 || arg.cat_seed_len > 0 || arg.cat_add_len > 0)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200601 {
Christian Brabandtaae58342023-04-23 17:50:22 +0100602 if (arg.cat_salt_len > 0)
603 arg.cat_salt = *header + CRYPT_MAGIC_LEN;
604 if (arg.cat_seed_len > 0)
605 arg.cat_seed = *header + CRYPT_MAGIC_LEN + arg.cat_salt_len;
606 if (arg.cat_add_len > 0)
Bram Moolenaar3a2a60c2023-05-27 18:02:55 +0100607 arg.cat_add = *header + CRYPT_MAGIC_LEN
608 + arg.cat_salt_len + arg.cat_seed_len;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200609
Bram Moolenaarc667da52019-11-30 20:52:27 +0100610 // TODO: Should this be crypt method specific? (Probably not worth
611 // it). sha2_seed is pretty bad for large amounts of entropy, so make
612 // that into something which is suitable for anything.
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200613#ifdef FEAT_SODIUM
614 if (sodium_init() >= 0)
615 {
Christian Brabandtaae58342023-04-23 17:50:22 +0100616 if (arg.cat_salt_len > 0)
617 randombytes_buf(arg.cat_salt, arg.cat_salt_len);
618 if (arg.cat_seed_len > 0)
619 randombytes_buf(arg.cat_seed, arg.cat_seed_len);
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200620 }
621 else
622#endif
Christian Brabandtaae58342023-04-23 17:50:22 +0100623 sha2_seed(arg.cat_salt, arg.cat_salt_len, arg.cat_seed, arg.cat_seed_len);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200624 }
Christian Brabandtaae58342023-04-23 17:50:22 +0100625 state = crypt_create(method_nr, key, &arg);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200626 if (state == NULL)
Bram Moolenaard23a8232018-02-10 18:45:26 +0100627 VIM_CLEAR(*header);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200628 return state;
629}
630
631/*
632 * Free the crypt state.
633 */
634 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100635crypt_free_state(cryptstate_T *state)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200636{
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200637#ifdef FEAT_SODIUM
Christian Brabandtaae58342023-04-23 17:50:22 +0100638 if (crypt_method_is_sodium(state->method_nr))
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200639 {
Bram Moolenaar131530a2021-07-29 20:37:49 +0200640 sodium_munlock(((sodium_state_T *)state->method_state)->key,
641 crypto_box_SEEDBYTES);
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200642 sodium_memzero(state->method_state, sizeof(sodium_state_T));
643 sodium_free(state->method_state);
644 }
645 else
646#endif
647 vim_free(state->method_state);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200648 vim_free(state);
649}
650
Bram Moolenaar987411d2019-01-18 22:48:34 +0100651#ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200652/*
653 * Encode "from[len]" and store the result in a newly allocated buffer, which
654 * is stored in "newptr".
655 * Return number of bytes in "newptr", 0 for need more or -1 on error.
656 */
657 long
Bram Moolenaar7454a062016-01-30 15:14:10 +0100658crypt_encode_alloc(
659 cryptstate_T *state,
660 char_u *from,
661 size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200662 char_u **newptr,
663 int last)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200664{
665 cryptmethod_T *method = &cryptmethods[state->method_nr];
666
667 if (method->encode_buffer_fn != NULL)
Bram Moolenaarc667da52019-11-30 20:52:27 +0100668 // Has buffer function, pass through.
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200669 return method->encode_buffer_fn(state, from, len, newptr, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200670 if (len == 0)
Bram Moolenaarc667da52019-11-30 20:52:27 +0100671 // Not buffering, just return EOF.
Bram Moolenaar9b8f0212014-08-13 22:05:53 +0200672 return (long)len;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200673
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200674 *newptr = alloc(len + 50);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200675 if (*newptr == NULL)
676 return -1;
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200677 method->encode_fn(state, from, len, *newptr, last);
Bram Moolenaar9b8f0212014-08-13 22:05:53 +0200678 return (long)len;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200679}
680
681/*
682 * Decrypt "ptr[len]" and store the result in a newly allocated buffer, which
683 * is stored in "newptr".
684 * Return number of bytes in "newptr", 0 for need more or -1 on error.
685 */
686 long
Bram Moolenaar7454a062016-01-30 15:14:10 +0100687crypt_decode_alloc(
688 cryptstate_T *state,
689 char_u *ptr,
690 long len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200691 char_u **newptr,
692 int last)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200693{
694 cryptmethod_T *method = &cryptmethods[state->method_nr];
695
696 if (method->decode_buffer_fn != NULL)
Bram Moolenaarc667da52019-11-30 20:52:27 +0100697 // Has buffer function, pass through.
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200698 return method->decode_buffer_fn(state, ptr, len, newptr, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200699
700 if (len == 0)
Bram Moolenaarc667da52019-11-30 20:52:27 +0100701 // Not buffering, just return EOF.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200702 return len;
703
704 *newptr = alloc(len);
705 if (*newptr == NULL)
706 return -1;
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200707 method->decode_fn(state, ptr, len, *newptr, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200708 return len;
709}
Bram Moolenaar987411d2019-01-18 22:48:34 +0100710#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200711
712/*
713 * Encrypting "from[len]" into "to[len]".
714 */
715 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100716crypt_encode(
717 cryptstate_T *state,
718 char_u *from,
719 size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200720 char_u *to,
721 int last)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200722{
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200723 cryptmethods[state->method_nr].encode_fn(state, from, len, to, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200724}
725
Bram Moolenaar987411d2019-01-18 22:48:34 +0100726#if 0 // unused
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200727/*
728 * decrypting "from[len]" into "to[len]".
729 */
730 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100731crypt_decode(
732 cryptstate_T *state,
733 char_u *from,
734 size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200735 char_u *to,
736 int last)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200737{
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200738 cryptmethods[state->method_nr].decode_fn(state, from, len, to, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200739}
Bram Moolenaar987411d2019-01-18 22:48:34 +0100740#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200741
742/*
743 * Simple inplace encryption, modifies "buf[len]" in place.
744 */
745 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100746crypt_encode_inplace(
747 cryptstate_T *state,
748 char_u *buf,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200749 size_t len,
Bram Moolenaar6ed545e2022-05-09 20:09:23 +0100750 int last)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200751{
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200752 cryptmethods[state->method_nr].encode_inplace_fn(state, buf, len,
753 buf, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200754}
755
756/*
757 * Simple inplace decryption, modifies "buf[len]" in place.
758 */
759 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100760crypt_decode_inplace(
761 cryptstate_T *state,
762 char_u *buf,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200763 size_t len,
764 int last)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200765{
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200766 cryptmethods[state->method_nr].decode_inplace_fn(state, buf, len,
767 buf, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200768}
769
770/*
771 * Free an allocated crypt key. Clear the text to make sure it doesn't stay
772 * in memory anywhere.
773 */
774 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100775crypt_free_key(char_u *key)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200776{
777 char_u *p;
778
779 if (key != NULL)
780 {
781 for (p = key; *p != NUL; ++p)
782 *p = 0;
783 vim_free(key);
784 }
785}
786
787/*
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100788 * Check the crypt method and give a warning if it's outdated.
789 */
790 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100791crypt_check_method(int method)
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100792{
Christian Brabandtaae58342023-04-23 17:50:22 +0100793 if (method < CRYPT_M_BF2 || method == CRYPT_M_SOD)
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100794 {
795 msg_scroll = TRUE;
Bram Moolenaar32526b32019-01-19 17:43:09 +0100796 msg(_("Warning: Using a weak encryption method; see :help 'cm'"));
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100797 }
Christian Brabandt226b28b2021-06-21 21:08:08 +0200798}
799
Bram Moolenaar3a2a60c2023-05-27 18:02:55 +0100800/*
801 * If the crypt method for "curbuf" does not support encrypting the swap file
802 * then disable the swap file.
803 */
804 void
Christian Brabandt226b28b2021-06-21 21:08:08 +0200805crypt_check_swapfile_curbuf(void)
806{
Bram Moolenaar3a2a60c2023-05-27 18:02:55 +0100807#ifdef FEAT_SODIUM
Christian Brabandt226b28b2021-06-21 21:08:08 +0200808 int method = crypt_get_method_nr(curbuf);
Christian Brabandtaae58342023-04-23 17:50:22 +0100809 if (crypt_method_is_sodium(method))
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200810 {
811 // encryption uses padding and MAC, that does not work very well with
812 // swap and undo files, so disable them
813 mf_close_file(curbuf, TRUE); // remove the swap file
Bram Moolenaar31e5c602022-04-15 13:53:33 +0100814 set_option_value_give_err((char_u *)"swf", 0, NULL, OPT_LOCAL);
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200815 msg_scroll = TRUE;
Christian Brabandt8a4c8122021-07-25 14:36:05 +0200816 msg(_("Note: Encryption of swapfile not supported, disabling swap file"));
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200817 }
Christian Brabandt226b28b2021-06-21 21:08:08 +0200818#endif
Bram Moolenaar3a2a60c2023-05-27 18:02:55 +0100819}
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100820
821 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100822crypt_check_current_method(void)
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100823{
824 crypt_check_method(crypt_get_method_nr(curbuf));
825}
826
827/*
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200828 * Ask the user for a crypt key.
829 * When "store" is TRUE, the new key is stored in the 'key' option, and the
830 * 'key' option value is returned: Don't free it.
831 * When "store" is FALSE, the typed key is returned in allocated memory.
832 * Returns NULL on failure.
833 */
834 char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +0100835crypt_get_key(
836 int store,
Bram Moolenaarc667da52019-11-30 20:52:27 +0100837 int twice) // Ask for the key twice.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200838{
839 char_u *p1, *p2 = NULL;
840 int round;
841
842 for (round = 0; ; ++round)
843 {
844 cmdline_star = TRUE;
845 cmdline_row = msg_row;
846 p1 = getcmdline_prompt(NUL, round == 0
847 ? (char_u *)_("Enter encryption key: ")
848 : (char_u *)_("Enter same key again: "), 0, EXPAND_NOTHING,
849 NULL);
850 cmdline_star = FALSE;
851
852 if (p1 == NULL)
853 break;
854
855 if (round == twice)
856 {
857 if (p2 != NULL && STRCMP(p1, p2) != 0)
858 {
Bram Moolenaar32526b32019-01-19 17:43:09 +0100859 msg(_("Keys don't match!"));
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200860 crypt_free_key(p1);
861 crypt_free_key(p2);
862 p2 = NULL;
Bram Moolenaarc667da52019-11-30 20:52:27 +0100863 round = -1; // do it again
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200864 continue;
865 }
866
867 if (store)
868 {
Bram Moolenaar31e5c602022-04-15 13:53:33 +0100869 set_option_value_give_err((char_u *)"key", 0L, p1, OPT_LOCAL);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200870 crypt_free_key(p1);
871 p1 = curbuf->b_p_key;
Christian Brabandt226b28b2021-06-21 21:08:08 +0200872 crypt_check_swapfile_curbuf();
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200873 }
874 break;
875 }
876 p2 = p1;
877 }
878
Bram Moolenaarc667da52019-11-30 20:52:27 +0100879 // since the user typed this, no need to wait for return
Christian Brabandtaae58342023-04-23 17:50:22 +0100880 if (!crypt_method_is_sodium(crypt_get_method_nr(curbuf)))
Christian Brabandt226b28b2021-06-21 21:08:08 +0200881 {
882 if (msg_didout)
883 msg_putchar('\n');
884 need_wait_return = FALSE;
885 msg_didout = FALSE;
886 }
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200887
888 crypt_free_key(p2);
889 return p1;
890}
891
892
893/*
894 * Append a message to IObuff for the encryption/decryption method being used.
895 */
896 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100897crypt_append_msg(
898 buf_T *buf)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200899{
900 if (crypt_get_method_nr(buf) == 0)
901 STRCAT(IObuff, _("[crypted]"));
902 else
903 {
904 STRCAT(IObuff, "[");
905 STRCAT(IObuff, *buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
906 STRCAT(IObuff, "]");
907 }
908}
909
Yegappan Lakshmananee47eac2022-06-29 12:55:36 +0100910 static int
K.Takataa8cdb4e2022-12-06 16:17:01 +0000911crypt_sodium_init_(
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200912 cryptstate_T *state UNUSED,
913 char_u *key UNUSED,
Christian Brabandtaae58342023-04-23 17:50:22 +0100914 crypt_arg_T *arg UNUSED)
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200915{
916# ifdef FEAT_SODIUM
917 // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
918 unsigned char dkey[crypto_box_SEEDBYTES]; // 32
919 sodium_state_T *sd_state;
Bram Moolenaar131530a2021-07-29 20:37:49 +0200920 int retval = 0;
Christian Brabandtaae58342023-04-23 17:50:22 +0100921 unsigned long long opslimit;
ichizok35a2ec12023-04-25 15:27:27 +0100922 unsigned long long memlimit;
Christian Brabandtaae58342023-04-23 17:50:22 +0100923 int alg;
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200924
925 if (sodium_init() < 0)
926 return FAIL;
927
928 sd_state = (sodium_state_T *)sodium_malloc(sizeof(sodium_state_T));
929 sodium_memzero(sd_state, sizeof(sodium_state_T));
930
Christian Brabandtaae58342023-04-23 17:50:22 +0100931 if ((state->method_nr == CRYPT_M_SOD2 && !arg->cat_init_from_file)
932 || state->method_nr == CRYPT_M_SOD)
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200933 {
Christian Brabandtaae58342023-04-23 17:50:22 +0100934 opslimit = crypto_pwhash_OPSLIMIT_INTERACTIVE;
935 memlimit = crypto_pwhash_MEMLIMIT_INTERACTIVE;
936 alg = crypto_pwhash_ALG_DEFAULT;
937
938#if 0
939 // For testing
940 if (state->method_nr == CRYPT_M_SOD2)
941 {
942 opslimit = crypto_pwhash_OPSLIMIT_MODERATE;
943 memlimit = crypto_pwhash_MEMLIMIT_MODERATE;
944 }
945#endif
946
947 // derive a key from the password
948 if (crypto_pwhash(dkey, sizeof(dkey), (const char *)key, STRLEN(key),
ichizok35a2ec12023-04-25 15:27:27 +0100949 arg->cat_salt, opslimit, (size_t)memlimit, alg) != 0)
Christian Brabandtaae58342023-04-23 17:50:22 +0100950 {
951 // out of memory
952 sodium_free(sd_state);
953 return FAIL;
954 }
955 memcpy(sd_state->key, dkey, crypto_box_SEEDBYTES);
956
957 retval += sodium_mlock(sd_state->key, crypto_box_SEEDBYTES);
958 retval += sodium_mlock(key, STRLEN(key));
959
960 if (retval < 0)
961 {
962 emsg(_(e_encryption_sodium_mlock_failed));
963 sodium_free(sd_state);
964 return FAIL;
965 }
Bram Moolenaar3a2a60c2023-05-27 18:02:55 +0100966 // "cat_add" should not be NULL, check anyway for safety
967 if (state->method_nr == CRYPT_M_SOD2 && arg->cat_add != NULL)
Christian Brabandtaae58342023-04-23 17:50:22 +0100968 {
969 memcpy(arg->cat_add, &opslimit, sizeof(opslimit));
970 arg->cat_add += sizeof(opslimit);
971
972 memcpy(arg->cat_add, &memlimit, sizeof(memlimit));
973 arg->cat_add += sizeof(memlimit);
974
975 memcpy(arg->cat_add, &alg, sizeof(alg));
976 arg->cat_add += sizeof(alg);
977 }
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200978 }
Christian Brabandtaae58342023-04-23 17:50:22 +0100979 else
Bram Moolenaar131530a2021-07-29 20:37:49 +0200980 {
Christian Brabandtaae58342023-04-23 17:50:22 +0100981 // Reading parameters from file
982 if (arg->cat_add_len
983 < (int)(sizeof(opslimit) + sizeof(memlimit) + sizeof(alg)))
984 {
985 sodium_free(sd_state);
986 return FAIL;
987 }
988
989 // derive the key from the file header
990 memcpy(&opslimit, arg->cat_add, sizeof(opslimit));
991 arg->cat_add += sizeof(opslimit);
992
993 memcpy(&memlimit, arg->cat_add, sizeof(memlimit));
994 arg->cat_add += sizeof(memlimit);
995
996 memcpy(&alg, arg->cat_add, sizeof(alg));
997 arg->cat_add += sizeof(alg);
998
999#ifdef FEAT_EVAL
1000 crypt_sodium_report_hash_params(opslimit,
1001 crypto_pwhash_OPSLIMIT_INTERACTIVE,
ichizok35a2ec12023-04-25 15:27:27 +01001002 (size_t)memlimit, crypto_pwhash_MEMLIMIT_INTERACTIVE,
Christian Brabandtaae58342023-04-23 17:50:22 +01001003 alg, crypto_pwhash_ALG_DEFAULT);
1004#endif
1005
1006 if (crypto_pwhash(dkey, sizeof(dkey), (const char *)key, STRLEN(key),
ichizok35a2ec12023-04-25 15:27:27 +01001007 arg->cat_salt, opslimit, (size_t)memlimit, alg) != 0)
Christian Brabandtaae58342023-04-23 17:50:22 +01001008 {
1009 // out of memory
1010 sodium_free(sd_state);
1011 return FAIL;
1012 }
1013 memcpy(sd_state->key, dkey, crypto_box_SEEDBYTES);
1014
1015 retval += sodium_mlock(sd_state->key, crypto_box_SEEDBYTES);
1016 retval += sodium_mlock(key, STRLEN(key));
1017
1018 if (retval < 0)
1019 {
1020 emsg(_(e_encryption_sodium_mlock_failed));
1021 sodium_free(sd_state);
1022 return FAIL;
1023 }
Bram Moolenaar131530a2021-07-29 20:37:49 +02001024 }
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001025 sd_state->count = 0;
1026 state->method_state = sd_state;
1027
1028 return OK;
1029# else
Bram Moolenaar50809a42023-05-20 16:39:07 +01001030 emsg(_(e_libsodium_not_built_in));
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001031 return FAIL;
1032# endif
1033}
1034
1035/*
1036 * Encrypt "from[len]" into "to[len]".
1037 * "from" and "to" can be equal to encrypt in place.
1038 * Call needs to ensure that there is enough space in to (for the header)
1039 */
Christian Brabandt226b28b2021-06-21 21:08:08 +02001040#if 0 // Currently unused
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001041 void
1042crypt_sodium_encode(
1043 cryptstate_T *state UNUSED,
1044 char_u *from UNUSED,
1045 size_t len UNUSED,
1046 char_u *to UNUSED,
1047 int last UNUSED)
1048{
1049# ifdef FEAT_SODIUM
1050 // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
1051 sodium_state_T *sod_st = state->method_state;
1052 unsigned char tag = last
1053 ? crypto_secretstream_xchacha20poly1305_TAG_FINAL : 0;
1054
1055 if (sod_st->count == 0)
1056 {
1057 if (len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES)
1058 {
Bram Moolenaar50809a42023-05-20 16:39:07 +01001059 emsg(_(e_libsodium_cannot_encrypt_header));
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001060 return;
1061 }
1062 crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state,
1063 to, sod_st->key);
1064 to += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1065 }
1066
1067 if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES)
1068 {
Bram Moolenaar50809a42023-05-20 16:39:07 +01001069 emsg(_(e_libsodium_cannot_encrypt_buffer));
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001070 return;
1071 }
1072
1073 crypto_secretstream_xchacha20poly1305_push(&sod_st->state, to, NULL,
1074 from, len, NULL, 0, tag);
1075
1076 sod_st->count++;
1077# endif
1078}
Christian Brabandt226b28b2021-06-21 21:08:08 +02001079#endif
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001080
Christian Brabandt226b28b2021-06-21 21:08:08 +02001081/*
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001082 * Decrypt "from[len]" into "to[len]".
1083 * "from" and "to" can be equal to encrypt in place.
1084 */
Christian Brabandt226b28b2021-06-21 21:08:08 +02001085#if 0 // Currently unused
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001086 void
1087crypt_sodium_decode(
1088 cryptstate_T *state UNUSED,
1089 char_u *from UNUSED,
1090 size_t len UNUSED,
1091 char_u *to UNUSED,
1092 int last UNUSED)
1093{
1094# ifdef FEAT_SODIUM
1095 // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
1096 sodium_state_T *sod_st = state->method_state;
1097 unsigned char tag;
1098 unsigned long long buf_len;
1099 char_u *p1 = from;
1100 char_u *p2 = to;
1101 char_u *buf_out;
1102
1103 if (sod_st->count == 0
1104 && len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES)
1105 {
Bram Moolenaar50809a42023-05-20 16:39:07 +01001106 emsg(_(e_libsodium_cannot_decrypt_header));
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001107 return;
1108 }
1109
1110 buf_out = (char_u *)alloc(len);
1111
1112 if (buf_out == NULL)
1113 {
Bram Moolenaar50809a42023-05-20 16:39:07 +01001114 emsg(_(e_libsodium_cannot_allocate_buffer));
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001115 return;
1116 }
1117 if (sod_st->count == 0)
1118 {
1119 if (crypto_secretstream_xchacha20poly1305_init_pull(
1120 &sod_st->state, from, sod_st->key) != 0)
1121 {
Bram Moolenaar50809a42023-05-20 16:39:07 +01001122 emsg(_(e_libsodium_decryption_failed_header_incomplete));
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001123 goto fail;
1124 }
1125
1126 from += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1127 len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1128
1129 if (p1 == p2)
1130 to += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1131 }
1132
1133 if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES)
1134 {
Bram Moolenaar50809a42023-05-20 16:39:07 +01001135 emsg(_(e_libsodium_cannot_decrypt_buffer));
Dominique Pellecb54bc62021-06-21 20:15:37 +02001136 goto fail;
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001137 }
1138 if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state,
1139 buf_out, &buf_len, &tag, from, len, NULL, 0) != 0)
1140 {
Bram Moolenaar50809a42023-05-20 16:39:07 +01001141 emsg(_(e_libsodium_decryption_failed));
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001142 goto fail;
1143 }
1144 sod_st->count++;
1145
1146 if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last)
1147 {
Bram Moolenaar50809a42023-05-20 16:39:07 +01001148 emsg(_(e_libsodium_decryption_failed_premature));
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001149 goto fail;
1150 }
1151 if (p1 == p2)
1152 mch_memmove(p2, buf_out, buf_len);
1153
1154fail:
1155 vim_free(buf_out);
1156# endif
1157}
Christian Brabandt226b28b2021-06-21 21:08:08 +02001158#endif
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001159
1160/*
1161 * Encrypt "from[len]" into "to[len]".
1162 * "from" and "to" can be equal to encrypt in place.
1163 */
Yegappan Lakshmananee47eac2022-06-29 12:55:36 +01001164 static long
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001165crypt_sodium_buffer_encode(
1166 cryptstate_T *state UNUSED,
1167 char_u *from UNUSED,
1168 size_t len UNUSED,
1169 char_u **buf_out UNUSED,
1170 int last UNUSED)
1171{
1172# ifdef FEAT_SODIUM
1173 // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
1174 unsigned long long out_len;
1175 char_u *ptr;
1176 unsigned char tag = last
1177 ? crypto_secretstream_xchacha20poly1305_TAG_FINAL : 0;
1178 int length;
1179 sodium_state_T *sod_st = state->method_state;
1180 int first = (sod_st->count == 0);
1181
Christian Brabandt226b28b2021-06-21 21:08:08 +02001182 length = (int)len + crypto_secretstream_xchacha20poly1305_ABYTES
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001183 + (first ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0);
1184 *buf_out = alloc_clear(length);
1185 if (*buf_out == NULL)
1186 {
Bram Moolenaar50809a42023-05-20 16:39:07 +01001187 emsg(_(e_libsodium_cannot_allocate_buffer));
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001188 return -1;
1189 }
1190 ptr = *buf_out;
1191
1192 if (first)
1193 {
1194 crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state,
1195 ptr, sod_st->key);
1196 ptr += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1197 }
1198
1199 crypto_secretstream_xchacha20poly1305_push(&sod_st->state, ptr,
1200 &out_len, from, len, NULL, 0, tag);
1201
1202 sod_st->count++;
1203 return out_len + (first
1204 ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0);
1205# else
1206 return -1;
1207# endif
1208}
1209
1210/*
1211 * Decrypt "from[len]" into "to[len]".
1212 * "from" and "to" can be equal to encrypt in place.
1213 */
Yegappan Lakshmananee47eac2022-06-29 12:55:36 +01001214 static long
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001215crypt_sodium_buffer_decode(
1216 cryptstate_T *state UNUSED,
1217 char_u *from UNUSED,
1218 size_t len UNUSED,
1219 char_u **buf_out UNUSED,
1220 int last UNUSED)
1221{
1222# ifdef FEAT_SODIUM
1223 // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
1224 sodium_state_T *sod_st = state->method_state;
1225 unsigned char tag;
1226 unsigned long long out_len;
Christian Brabandtaae58342023-04-23 17:50:22 +01001227
1228 if (sod_st->count == 0
1229 && state->method_nr == CRYPT_M_SOD
1230 && len > WRITEBUFSIZE
1231 + crypto_secretstream_xchacha20poly1305_HEADERBYTES
1232 + crypto_secretstream_xchacha20poly1305_ABYTES)
1233 len -= cryptmethods[CRYPT_M_SOD2].add_len;
1234
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001235 *buf_out = alloc_clear(len);
1236 if (*buf_out == NULL)
1237 {
Bram Moolenaar50809a42023-05-20 16:39:07 +01001238 emsg(_(e_libsodium_cannot_allocate_buffer));
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001239 return -1;
1240 }
1241
1242 if (sod_st->count == 0)
1243 {
1244 if (crypto_secretstream_xchacha20poly1305_init_pull(&sod_st->state,
1245 from, sod_st->key) != 0)
1246 {
Bram Moolenaar50809a42023-05-20 16:39:07 +01001247 emsg(_(e_libsodium_decryption_failed_header_incomplete));
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001248 return -1;
1249 }
1250 from += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1251 len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1252 sod_st->count++;
1253 }
1254 if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state,
1255 *buf_out, &out_len, &tag, from, len, NULL, 0) != 0)
1256 {
Bram Moolenaar50809a42023-05-20 16:39:07 +01001257 emsg(_(e_libsodium_decryption_failed));
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001258 return -1;
1259 }
1260
1261 if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last)
Bram Moolenaar50809a42023-05-20 16:39:07 +01001262 emsg(_(e_libsodium_decryption_failed_premature));
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001263 return (long) out_len;
1264# else
1265 return -1;
1266# endif
1267}
1268
K.Takata1a8825d2022-01-19 13:32:57 +00001269# if defined(FEAT_SODIUM) || defined(PROTO)
Christian Brabandt19e6c4f2023-06-27 18:57:10 +01001270 void
1271crypt_sodium_lock_key(char_u *key)
1272{
1273 if (sodium_init() >= 0)
1274 sodium_mlock(key, STRLEN(key));
1275}
1276
K.Takata1a8825d2022-01-19 13:32:57 +00001277 int
1278crypt_sodium_munlock(void *const addr, const size_t len)
1279{
1280 return sodium_munlock(addr, len);
1281}
1282
1283 void
1284crypt_sodium_randombytes_buf(void *const buf, const size_t size)
1285{
1286 randombytes_buf(buf, size);
1287}
K.Takataa8cdb4e2022-12-06 16:17:01 +00001288
1289 int
1290crypt_sodium_init(void)
1291{
1292 return sodium_init();
1293}
1294
1295 uint32_t
1296crypt_sodium_randombytes_random(void)
1297{
1298 return randombytes_random();
1299}
Christian Brabandtaae58342023-04-23 17:50:22 +01001300
1301#if defined(FEAT_EVAL) || defined(PROTO)
1302 static void
1303crypt_sodium_report_hash_params(
1304 unsigned long long opslimit,
1305 unsigned long long ops_def,
1306 size_t memlimit,
1307 size_t mem_def,
1308 int alg,
1309 int alg_def)
1310{
1311 if (p_verbose > 0)
1312 {
1313 verbose_enter();
1314 if (opslimit != ops_def)
1315 smsg(_("xchacha20v2: using custom opslimit \"%llu\" for Key derivation."), opslimit);
1316 else
1317 smsg(_("xchacha20v2: using default opslimit \"%llu\" for Key derivation."), opslimit);
1318 if (memlimit != mem_def)
1319 smsg(_("xchacha20v2: using custom memlimit \"%lu\" for Key derivation."), (unsigned long)memlimit);
1320 else
1321 smsg(_("xchacha20v2: using default memlimit \"%lu\" for Key derivation."), (unsigned long)memlimit);
1322 if (alg != alg_def)
1323 smsg(_("xchacha20v2: using custom algorithm \"%d\" for Key derivation."), alg);
1324 else
1325 smsg(_("xchacha20v2: using default algorithm \"%d\" for Key derivation."), alg);
1326 verbose_leave();
1327 }
1328}
1329#endif
K.Takata1a8825d2022-01-19 13:32:57 +00001330# endif
1331
Bram Moolenaarc667da52019-11-30 20:52:27 +01001332#endif // FEAT_CRYPT