blob: ca7a3e7dc6b8574b0c58b54bfe6c1de1910fb913 [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 {
Bram Moolenaarc667da52019-11-30 20:52: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
Christian Brabandtf573c6e2021-06-20 14:02:16 +020036 int seed_len; // length of seed, or 0 when not using seed
Christian Brabandtaae58342023-04-23 17:50:22 +010037 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
Bram Moolenaarc667da52019-11-30 20:52:27 +010040 int works_inplace; // encryption/decryption can be done in-place
Bram Moolenaar987411d2019-01-18 22:48:34 +010041#endif
Bram Moolenaarc667da52019-11-30 20:52: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.
Michael Jarvisbe9624e2023-04-19 20:28:48 +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.
Bram Moolenaar6ee96582019-04-27 22:06:37 +020048 int (* init_fn)(cryptstate_T *state, char_u *key,
Christian Brabandtaae58342023-04-23 17:50:22 +010049 crypt_arg_T *arg);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020050
Bram Moolenaarc667da52019-11-30 20:52:27 +010051 // Function pointers for encoding/decoding from one buffer into another.
52 // Optional, however, these or the _buffer ones should be configured.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020053 void (*encode_fn)(cryptstate_T *state, char_u *from, size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +020054 char_u *to, int last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020055 void (*decode_fn)(cryptstate_T *state, char_u *from, size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +020056 char_u *to, int last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020057
Bram Moolenaarc667da52019-11-30 20:52:27 +010058 // Function pointers for encoding and decoding, can buffer data if needed.
59 // Optional (however, these or the above should be configured).
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020060 long (*encode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +020061 char_u **newptr, int last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020062 long (*decode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +020063 char_u **newptr, int last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020064
Bram Moolenaarc667da52019-11-30 20:52:27 +010065 // Function pointers for in-place encoding and decoding, used for
66 // crypt_*_inplace(). "from" and "to" arguments will be equal.
67 // These may be the same as decode_fn and encode_fn above, however an
68 // algorithm may implement them in a way that is not interchangeable with
69 // the crypt_(en|de)code() interface (for example because it wishes to add
70 // padding to files).
71 // This method is used for swap and undo files which have a rigid format.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020072 void (*encode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +020073 char_u *p2, int last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020074 void (*decode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +020075 char_u *p2, int last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020076} cryptmethod_T;
77
Christian Brabandtaae58342023-04-23 17:50:22 +010078static int crypt_sodium_init_(cryptstate_T *state, char_u *key, crypt_arg_T *arg);
Yegappan Lakshmananee47eac2022-06-29 12:55:36 +010079static long crypt_sodium_buffer_decode(cryptstate_T *state, char_u *from, size_t len, char_u **buf_out, int last);
80static 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 +010081#if defined(FEAT_EVAL) && defined(FEAT_SODIUM)
82static 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);
83#endif
Yegappan Lakshmananee47eac2022-06-29 12:55:36 +010084
Bram Moolenaarc667da52019-11-30 20:52:27 +010085// index is method_nr of cryptstate_T, CRYPT_M_*
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020086static cryptmethod_T cryptmethods[CRYPT_M_COUNT] = {
Bram Moolenaarc667da52019-11-30 20:52:27 +010087 // PK_Zip; very weak
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020088 {
89 "zip",
90 "VimCrypt~01!",
91 0,
92 0,
Christian Brabandtaae58342023-04-23 17:50:22 +010093 0,
Bram Moolenaar987411d2019-01-18 22:48:34 +010094#ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020095 TRUE,
Bram Moolenaar987411d2019-01-18 22:48:34 +010096#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020097 FALSE,
98 NULL,
99 crypt_zip_init,
100 crypt_zip_encode, crypt_zip_decode,
101 NULL, NULL,
102 crypt_zip_encode, crypt_zip_decode,
103 },
104
Bram Moolenaarc667da52019-11-30 20:52:27 +0100105 // Blowfish/CFB + SHA-256 custom key derivation; implementation issues.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200106 {
107 "blowfish",
108 "VimCrypt~02!",
109 8,
110 8,
Christian Brabandtaae58342023-04-23 17:50:22 +0100111 0,
Bram Moolenaar987411d2019-01-18 22:48:34 +0100112#ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200113 TRUE,
Bram Moolenaar987411d2019-01-18 22:48:34 +0100114#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200115 FALSE,
116 blowfish_self_test,
117 crypt_blowfish_init,
118 crypt_blowfish_encode, crypt_blowfish_decode,
119 NULL, NULL,
120 crypt_blowfish_encode, crypt_blowfish_decode,
121 },
122
Bram Moolenaarc667da52019-11-30 20:52:27 +0100123 // Blowfish/CFB + SHA-256 custom key derivation; fixed.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200124 {
125 "blowfish2",
126 "VimCrypt~03!",
127 8,
128 8,
Christian Brabandtaae58342023-04-23 17:50:22 +0100129 0,
Bram Moolenaar987411d2019-01-18 22:48:34 +0100130#ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200131 TRUE,
Bram Moolenaar987411d2019-01-18 22:48:34 +0100132#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200133 TRUE,
134 blowfish_self_test,
135 crypt_blowfish_init,
136 crypt_blowfish_encode, crypt_blowfish_decode,
137 NULL, NULL,
138 crypt_blowfish_encode, crypt_blowfish_decode,
139 },
Bram Moolenaard23a8232018-02-10 18:45:26 +0100140
Christian Brabandtaae58342023-04-23 17:50:22 +0100141 // XChaCha20 using libsodium; implementation issues
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200142 {
143 "xchacha20",
144 "VimCrypt~04!",
145#ifdef FEAT_SODIUM
146 crypto_pwhash_argon2id_SALTBYTES, // 16
147#else
148 16,
149#endif
150 8,
Christian Brabandtaae58342023-04-23 17:50:22 +0100151 0,
152#ifdef CRYPT_NOT_INPLACE
153 FALSE,
154#endif
155 FALSE,
156 NULL,
157 crypt_sodium_init_,
158 NULL, NULL,
159 crypt_sodium_buffer_encode, crypt_sodium_buffer_decode,
160 NULL, NULL,
161 },
162 // XChaCha20 using libsodium; stores parameters in header
163 {
164 "xchacha20v2",
165 "VimCrypt~05!",
166#ifdef FEAT_SODIUM
167 crypto_pwhash_argon2id_SALTBYTES, // 16
168#else
169 16,
170#endif
171 8,
172 // sizeof(crypto_pwhash_OPSLIMIT_INTERACTIVE + crypto_pwhash_MEMLIMIT_INTERACTIVE + crypto_pwhash_ALG_DEFAULT)
173 20,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200174#ifdef CRYPT_NOT_INPLACE
175 FALSE,
176#endif
177 FALSE,
178 NULL,
K.Takataa8cdb4e2022-12-06 16:17:01 +0000179 crypt_sodium_init_,
Christian Brabandt226b28b2021-06-21 21:08:08 +0200180 NULL, NULL,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200181 crypt_sodium_buffer_encode, crypt_sodium_buffer_decode,
Christian Brabandt226b28b2021-06-21 21:08:08 +0200182 NULL, NULL,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200183 },
184
Bram Moolenaarc667da52019-11-30 20:52:27 +0100185 // NOTE: when adding a new method, use some random bytes for the magic key,
186 // to avoid that a text file is recognized as encrypted.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200187};
188
Yegappan Lakshmanana23a11b2023-02-21 14:27:41 +0000189#if defined(FEAT_SODIUM) || defined(PROTO)
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200190typedef struct {
191 size_t count;
192 unsigned char key[crypto_box_SEEDBYTES];
193 // 32, same as crypto_secretstream_xchacha20poly1305_KEYBYTES
194 crypto_secretstream_xchacha20poly1305_state
195 state;
196} sodium_state_T;
K.Takata1a8825d2022-01-19 13:32:57 +0000197
198
199# ifdef DYNAMIC_SODIUM
K.Takatad68b2fc2022-02-12 11:18:37 +0000200# ifdef MSWIN
201# define SODIUM_PROC FARPROC
202# define load_dll vimLoadLib
203# define symbol_from_dll GetProcAddress
204# define close_dll FreeLibrary
205# define load_dll_error GetWin32Error
206# else
207# error Dynamic loading of libsodium is not supported for now.
208//# define HINSTANCE void*
209//# define SODIUM_PROC void*
210//# define load_dll(n) dlopen((n), RTLD_LAZY|RTLD_GLOBAL)
211//# define symbol_from_dll dlsym
212//# define close_dll dlclose
213//# define load_dll_error dlerror
214# endif
215
K.Takata1a8825d2022-01-19 13:32:57 +0000216# define sodium_init load_sodium
217# define sodium_free dll_sodium_free
218# define sodium_malloc dll_sodium_malloc
219# define sodium_memzero dll_sodium_memzero
220# define sodium_mlock dll_sodium_mlock
221# define sodium_munlock dll_sodium_munlock
222# define crypto_secretstream_xchacha20poly1305_init_push \
223 dll_crypto_secretstream_xchacha20poly1305_init_push
224# define crypto_secretstream_xchacha20poly1305_push \
225 dll_crypto_secretstream_xchacha20poly1305_push
226# define crypto_secretstream_xchacha20poly1305_init_pull \
227 dll_crypto_secretstream_xchacha20poly1305_init_pull
228# define crypto_secretstream_xchacha20poly1305_pull \
229 dll_crypto_secretstream_xchacha20poly1305_pull
230# define crypto_pwhash dll_crypto_pwhash
231# define randombytes_buf dll_randombytes_buf
K.Takataa8cdb4e2022-12-06 16:17:01 +0000232# define randombytes_random dll_randombytes_random
K.Takata1a8825d2022-01-19 13:32:57 +0000233
234static int (*dll_sodium_init)(void) = NULL;
235static void (*dll_sodium_free)(void *) = NULL;
236static void *(*dll_sodium_malloc)(const size_t) = NULL;
237static void (*dll_sodium_memzero)(void * const, const size_t) = NULL;
238static int (*dll_sodium_mlock)(void * const, const size_t) = NULL;
239static int (*dll_sodium_munlock)(void * const, const size_t) = NULL;
240static int (*dll_crypto_secretstream_xchacha20poly1305_init_push)
241 (crypto_secretstream_xchacha20poly1305_state *state,
242 unsigned char [],
243 const unsigned char []) = NULL;
244static int (*dll_crypto_secretstream_xchacha20poly1305_push)
245 (crypto_secretstream_xchacha20poly1305_state *state,
246 unsigned char *c, unsigned long long *clen_p,
247 const unsigned char *m, unsigned long long mlen,
248 const unsigned char *ad, unsigned long long adlen, unsigned char tag)
249 = NULL;
250static int (*dll_crypto_secretstream_xchacha20poly1305_init_pull)
251 (crypto_secretstream_xchacha20poly1305_state *state,
252 const unsigned char [],
253 const unsigned char []) = NULL;
254static int (*dll_crypto_secretstream_xchacha20poly1305_pull)
255 (crypto_secretstream_xchacha20poly1305_state *state,
256 unsigned char *m, unsigned long long *mlen_p, unsigned char *tag_p,
257 const unsigned char *c, unsigned long long clen,
258 const unsigned char *ad, unsigned long long adlen) = NULL;
259static int (*dll_crypto_pwhash)(unsigned char * const out,
260 unsigned long long outlen,
261 const char * const passwd, unsigned long long passwdlen,
262 const unsigned char * const salt,
263 unsigned long long opslimit, size_t memlimit, int alg)
264 = NULL;
265static void (*dll_randombytes_buf)(void * const buf, const size_t size);
K.Takataa8cdb4e2022-12-06 16:17:01 +0000266static uint32_t (*dll_randombytes_random)(void);
K.Takata1a8825d2022-01-19 13:32:57 +0000267
268static struct {
269 const char *name;
K.Takatad68b2fc2022-02-12 11:18:37 +0000270 SODIUM_PROC *ptr;
K.Takata1a8825d2022-01-19 13:32:57 +0000271} sodium_funcname_table[] = {
K.Takatad68b2fc2022-02-12 11:18:37 +0000272 {"sodium_init", (SODIUM_PROC*)&dll_sodium_init},
273 {"sodium_free", (SODIUM_PROC*)&dll_sodium_free},
274 {"sodium_malloc", (SODIUM_PROC*)&dll_sodium_malloc},
275 {"sodium_memzero", (SODIUM_PROC*)&dll_sodium_memzero},
276 {"sodium_mlock", (SODIUM_PROC*)&dll_sodium_mlock},
277 {"sodium_munlock", (SODIUM_PROC*)&dll_sodium_munlock},
278 {"crypto_secretstream_xchacha20poly1305_init_push", (SODIUM_PROC*)&dll_crypto_secretstream_xchacha20poly1305_init_push},
279 {"crypto_secretstream_xchacha20poly1305_push", (SODIUM_PROC*)&dll_crypto_secretstream_xchacha20poly1305_push},
280 {"crypto_secretstream_xchacha20poly1305_init_pull", (SODIUM_PROC*)&dll_crypto_secretstream_xchacha20poly1305_init_pull},
281 {"crypto_secretstream_xchacha20poly1305_pull", (SODIUM_PROC*)&dll_crypto_secretstream_xchacha20poly1305_pull},
282 {"crypto_pwhash", (SODIUM_PROC*)&dll_crypto_pwhash},
283 {"randombytes_buf", (SODIUM_PROC*)&dll_randombytes_buf},
K.Takataa8cdb4e2022-12-06 16:17:01 +0000284 {"randombytes_random", (SODIUM_PROC*)&dll_randombytes_random},
K.Takata1a8825d2022-01-19 13:32:57 +0000285 {NULL, NULL}
286};
287
288 static int
K.Takatad68b2fc2022-02-12 11:18:37 +0000289sodium_runtime_link_init(int verbose)
K.Takata1a8825d2022-01-19 13:32:57 +0000290{
K.Takatad68b2fc2022-02-12 11:18:37 +0000291 static HINSTANCE hsodium = NULL;
K.Takatad8f86292022-03-07 15:16:15 +0000292 const char *libname = DYNAMIC_SODIUM_DLL;
K.Takata1a8825d2022-01-19 13:32:57 +0000293 int i;
294
295 if (hsodium != NULL)
K.Takatad68b2fc2022-02-12 11:18:37 +0000296 return OK;
K.Takata1a8825d2022-01-19 13:32:57 +0000297
K.Takatad68b2fc2022-02-12 11:18:37 +0000298 hsodium = load_dll(libname);
K.Takata1a8825d2022-01-19 13:32:57 +0000299 if (hsodium == NULL)
300 {
K.Takatad68b2fc2022-02-12 11:18:37 +0000301 if (verbose)
302 semsg(_(e_could_not_load_library_str_str), libname, load_dll_error());
303 return FAIL;
K.Takata1a8825d2022-01-19 13:32:57 +0000304 }
305
306 for (i = 0; sodium_funcname_table[i].ptr; ++i)
307 {
K.Takatad68b2fc2022-02-12 11:18:37 +0000308 if ((*sodium_funcname_table[i].ptr = symbol_from_dll(hsodium,
K.Takata1a8825d2022-01-19 13:32:57 +0000309 sodium_funcname_table[i].name)) == NULL)
310 {
K.Takatad8f86292022-03-07 15:16:15 +0000311 close_dll(hsodium);
K.Takata1a8825d2022-01-19 13:32:57 +0000312 hsodium = NULL;
K.Takatad68b2fc2022-02-12 11:18:37 +0000313 if (verbose)
314 semsg(_(e_could_not_load_library_function_str), sodium_funcname_table[i].name);
315 return FAIL;
K.Takata1a8825d2022-01-19 13:32:57 +0000316 }
317 }
K.Takatad68b2fc2022-02-12 11:18:37 +0000318 return OK;
319}
320
321 static int
322load_sodium(void)
323{
324 if (sodium_runtime_link_init(TRUE) == FAIL)
325 return -1;
K.Takata1a8825d2022-01-19 13:32:57 +0000326 return dll_sodium_init();
327}
328# endif
K.Takatad68b2fc2022-02-12 11:18:37 +0000329
330# if defined(DYNAMIC_SODIUM) || defined(PROTO)
331 int
332sodium_enabled(int verbose)
333{
334 return sodium_runtime_link_init(verbose) == OK;
335}
336# endif
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200337#endif
338
Bram Moolenaarc667da52019-11-30 20:52:27 +0100339#define CRYPT_MAGIC_LEN 12 // cannot change
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200340static char crypt_magic_head[] = "VimCrypt~";
341
342/*
343 * Return int value for crypt method name.
344 * 0 for "zip", the old method. Also for any non-valid value.
345 * 1 for "blowfish".
346 * 2 for "blowfish2".
347 */
348 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100349crypt_method_nr_from_name(char_u *name)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200350{
351 int i;
352
353 for (i = 0; i < CRYPT_M_COUNT; ++i)
354 if (STRCMP(name, cryptmethods[i].name) == 0)
355 return i;
356 return 0;
357}
358
359/*
360 * Get the crypt method used for a file from "ptr[len]", the magic text at the
361 * start of the file.
362 * Returns -1 when no encryption used.
363 */
364 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100365crypt_method_nr_from_magic(char *ptr, int len)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200366{
367 int i;
368
369 if (len < CRYPT_MAGIC_LEN)
370 return -1;
371
372 for (i = 0; i < CRYPT_M_COUNT; i++)
373 if (memcmp(ptr, cryptmethods[i].magic, CRYPT_MAGIC_LEN) == 0)
374 return i;
375
376 i = (int)STRLEN(crypt_magic_head);
377 if (len >= i && memcmp(ptr, crypt_magic_head, i) == 0)
Bram Moolenaar9d00e4a2022-01-05 17:49:15 +0000378 emsg(_(e_file_is_encrypted_with_unknown_method));
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200379
380 return -1;
381}
382
Bram Moolenaar987411d2019-01-18 22:48:34 +0100383#ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200384/*
385 * Return TRUE if the crypt method for "method_nr" can be done in-place.
386 */
387 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100388crypt_works_inplace(cryptstate_T *state)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200389{
390 return cryptmethods[state->method_nr].works_inplace;
391}
Bram Moolenaar987411d2019-01-18 22:48:34 +0100392#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200393
394/*
395 * Get the crypt method for buffer "buf" as a number.
396 */
397 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100398crypt_get_method_nr(buf_T *buf)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200399{
400 return crypt_method_nr_from_name(*buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
401}
402
403/*
Christian Brabandtaae58342023-04-23 17:50:22 +0100404 * Returns True for Sodium Encryption.
405 */
406 int
407crypt_method_is_sodium(int method)
408{
409 return method == CRYPT_M_SOD || method == CRYPT_M_SOD2;
410}
411
412/*
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200413 * Return TRUE when the buffer uses an encryption method that encrypts the
414 * whole undo file, not only the text.
415 */
416 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100417crypt_whole_undofile(int method_nr)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200418{
419 return cryptmethods[method_nr].whole_undofile;
420}
421
422/*
Bram Moolenaar32aa1022019-11-02 22:54:41 +0100423 * Get crypt method specific length of the file header in bytes.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200424 */
425 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100426crypt_get_header_len(int method_nr)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200427{
428 return CRYPT_MAGIC_LEN
429 + cryptmethods[method_nr].salt_len
Christian Brabandtaae58342023-04-23 17:50:22 +0100430 + cryptmethods[method_nr].seed_len
431 + cryptmethods[method_nr].add_len;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200432}
433
Christian Brabandt226b28b2021-06-21 21:08:08 +0200434
Dominique Pelle748b3082022-01-08 12:41:16 +0000435#if defined(FEAT_SODIUM) || defined(PROTO)
Christian Brabandt226b28b2021-06-21 21:08:08 +0200436/*
437 * Get maximum crypt method specific length of the file header in bytes.
438 */
439 int
Yegappan Lakshmanana23a11b2023-02-21 14:27:41 +0000440crypt_get_max_header_len(void)
Christian Brabandt226b28b2021-06-21 21:08:08 +0200441{
442 int i;
443 int max = 0;
444 int temp = 0;
445
446 for (i = 0; i < CRYPT_M_COUNT; ++i)
447 {
448 temp = crypt_get_header_len(i);
449 if (temp > max)
450 max = temp;
451 }
452 return max;
453}
Dominique Pelle748b3082022-01-08 12:41:16 +0000454#endif
Christian Brabandt226b28b2021-06-21 21:08:08 +0200455
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200456/*
457 * Set the crypt method for buffer "buf" to "method_nr" using the int value as
458 * returned by crypt_method_nr_from_name().
459 */
460 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100461crypt_set_cm_option(buf_T *buf, int method_nr)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200462{
463 free_string_option(buf->b_p_cm);
464 buf->b_p_cm = vim_strsave((char_u *)cryptmethods[method_nr].name);
465}
466
467/*
468 * If the crypt method for the current buffer has a self-test, run it and
469 * return OK/FAIL.
470 */
471 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100472crypt_self_test(void)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200473{
474 int method_nr = crypt_get_method_nr(curbuf);
475
476 if (cryptmethods[method_nr].self_test_fn == NULL)
477 return OK;
478 return cryptmethods[method_nr].self_test_fn();
479}
480
481/*
482 * Allocate a crypt state and initialize it.
Bram Moolenaar6ee96582019-04-27 22:06:37 +0200483 * Return NULL for failure.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200484 */
485 cryptstate_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +0100486crypt_create(
487 int method_nr,
488 char_u *key,
Christian Brabandtaae58342023-04-23 17:50:22 +0100489 crypt_arg_T *crypt_arg)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200490{
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200491 cryptstate_T *state = ALLOC_ONE(cryptstate_T);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200492
Bram Moolenaar6ee96582019-04-27 22:06:37 +0200493 if (state == NULL)
494 return state;
495
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200496 state->method_nr = method_nr;
Christian Brabandtaae58342023-04-23 17:50:22 +0100497 if (cryptmethods[method_nr].init_fn(state, key, crypt_arg) == FAIL)
Bram Moolenaar6ee96582019-04-27 22:06:37 +0200498 {
Bram Moolenaar6ed545e2022-05-09 20:09:23 +0100499 vim_free(state);
500 return NULL;
Bram Moolenaar6ee96582019-04-27 22:06:37 +0200501 }
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200502 return state;
503}
504
505/*
506 * Allocate a crypt state from a file header and initialize it.
507 * Assumes that header contains at least the number of bytes that
508 * crypt_get_header_len() returns for "method_nr".
509 */
510 cryptstate_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +0100511crypt_create_from_header(
512 int method_nr,
513 char_u *key,
514 char_u *header)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200515{
Christian Brabandtaae58342023-04-23 17:50:22 +0100516 crypt_arg_T arg;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200517
Christian Brabandtaae58342023-04-23 17:50:22 +0100518 CLEAR_FIELD(arg);
519 arg.cat_init_from_file = TRUE;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200520
Christian Brabandtaae58342023-04-23 17:50:22 +0100521 arg.cat_salt_len = cryptmethods[method_nr].salt_len;
522 arg.cat_seed_len = cryptmethods[method_nr].seed_len;
523 arg.cat_add_len = cryptmethods[method_nr].add_len;
524 if (arg.cat_salt_len > 0)
525 arg.cat_salt = header + CRYPT_MAGIC_LEN;
526 if (arg.cat_seed_len > 0)
527 arg.cat_seed = header + CRYPT_MAGIC_LEN + arg.cat_salt_len;
528 if (arg.cat_add_len > 0)
529 arg.cat_add = header + CRYPT_MAGIC_LEN + arg.cat_salt_len + arg.cat_seed_len;
530
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)
607 arg.cat_add = *header + CRYPT_MAGIC_LEN + arg.cat_salt_len + arg.cat_seed_len;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200608
Bram Moolenaarc667da52019-11-30 20:52:27 +0100609 // TODO: Should this be crypt method specific? (Probably not worth
610 // it). sha2_seed is pretty bad for large amounts of entropy, so make
611 // that into something which is suitable for anything.
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200612#ifdef FEAT_SODIUM
613 if (sodium_init() >= 0)
614 {
Christian Brabandtaae58342023-04-23 17:50:22 +0100615 if (arg.cat_salt_len > 0)
616 randombytes_buf(arg.cat_salt, arg.cat_salt_len);
617 if (arg.cat_seed_len > 0)
618 randombytes_buf(arg.cat_seed, arg.cat_seed_len);
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200619 }
620 else
621#endif
Christian Brabandtaae58342023-04-23 17:50:22 +0100622 sha2_seed(arg.cat_salt, arg.cat_salt_len, arg.cat_seed, arg.cat_seed_len);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200623 }
Christian Brabandtaae58342023-04-23 17:50:22 +0100624 state = crypt_create(method_nr, key, &arg);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200625 if (state == NULL)
Bram Moolenaard23a8232018-02-10 18:45:26 +0100626 VIM_CLEAR(*header);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200627 return state;
628}
629
630/*
631 * Free the crypt state.
632 */
633 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100634crypt_free_state(cryptstate_T *state)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200635{
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200636#ifdef FEAT_SODIUM
Christian Brabandtaae58342023-04-23 17:50:22 +0100637 if (crypt_method_is_sodium(state->method_nr))
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200638 {
Bram Moolenaar131530a2021-07-29 20:37:49 +0200639 sodium_munlock(((sodium_state_T *)state->method_state)->key,
640 crypto_box_SEEDBYTES);
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200641 sodium_memzero(state->method_state, sizeof(sodium_state_T));
642 sodium_free(state->method_state);
643 }
644 else
645#endif
646 vim_free(state->method_state);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200647 vim_free(state);
648}
649
Bram Moolenaar987411d2019-01-18 22:48:34 +0100650#ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200651/*
652 * Encode "from[len]" and store the result in a newly allocated buffer, which
653 * is stored in "newptr".
654 * Return number of bytes in "newptr", 0 for need more or -1 on error.
655 */
656 long
Bram Moolenaar7454a062016-01-30 15:14:10 +0100657crypt_encode_alloc(
658 cryptstate_T *state,
659 char_u *from,
660 size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200661 char_u **newptr,
662 int last)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200663{
664 cryptmethod_T *method = &cryptmethods[state->method_nr];
665
666 if (method->encode_buffer_fn != NULL)
Bram Moolenaarc667da52019-11-30 20:52:27 +0100667 // Has buffer function, pass through.
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200668 return method->encode_buffer_fn(state, from, len, newptr, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200669 if (len == 0)
Bram Moolenaarc667da52019-11-30 20:52:27 +0100670 // Not buffering, just return EOF.
Bram Moolenaar9b8f0212014-08-13 22:05:53 +0200671 return (long)len;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200672
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200673 *newptr = alloc(len + 50);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200674 if (*newptr == NULL)
675 return -1;
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200676 method->encode_fn(state, from, len, *newptr, last);
Bram Moolenaar9b8f0212014-08-13 22:05:53 +0200677 return (long)len;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200678}
679
680/*
681 * Decrypt "ptr[len]" and store the result in a newly allocated buffer, which
682 * is stored in "newptr".
683 * Return number of bytes in "newptr", 0 for need more or -1 on error.
684 */
685 long
Bram Moolenaar7454a062016-01-30 15:14:10 +0100686crypt_decode_alloc(
687 cryptstate_T *state,
688 char_u *ptr,
689 long len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200690 char_u **newptr,
691 int last)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200692{
693 cryptmethod_T *method = &cryptmethods[state->method_nr];
694
695 if (method->decode_buffer_fn != NULL)
Bram Moolenaarc667da52019-11-30 20:52:27 +0100696 // Has buffer function, pass through.
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200697 return method->decode_buffer_fn(state, ptr, len, newptr, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200698
699 if (len == 0)
Bram Moolenaarc667da52019-11-30 20:52:27 +0100700 // Not buffering, just return EOF.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200701 return len;
702
703 *newptr = alloc(len);
704 if (*newptr == NULL)
705 return -1;
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200706 method->decode_fn(state, ptr, len, *newptr, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200707 return len;
708}
Bram Moolenaar987411d2019-01-18 22:48:34 +0100709#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200710
711/*
712 * Encrypting "from[len]" into "to[len]".
713 */
714 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100715crypt_encode(
716 cryptstate_T *state,
717 char_u *from,
718 size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200719 char_u *to,
720 int last)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200721{
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200722 cryptmethods[state->method_nr].encode_fn(state, from, len, to, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200723}
724
Bram Moolenaar987411d2019-01-18 22:48:34 +0100725#if 0 // unused
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200726/*
727 * decrypting "from[len]" into "to[len]".
728 */
729 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100730crypt_decode(
731 cryptstate_T *state,
732 char_u *from,
733 size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200734 char_u *to,
735 int last)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200736{
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200737 cryptmethods[state->method_nr].decode_fn(state, from, len, to, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200738}
Bram Moolenaar987411d2019-01-18 22:48:34 +0100739#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200740
741/*
742 * Simple inplace encryption, modifies "buf[len]" in place.
743 */
744 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100745crypt_encode_inplace(
746 cryptstate_T *state,
747 char_u *buf,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200748 size_t len,
Bram Moolenaar6ed545e2022-05-09 20:09:23 +0100749 int last)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200750{
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200751 cryptmethods[state->method_nr].encode_inplace_fn(state, buf, len,
752 buf, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200753}
754
755/*
756 * Simple inplace decryption, modifies "buf[len]" in place.
757 */
758 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100759crypt_decode_inplace(
760 cryptstate_T *state,
761 char_u *buf,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200762 size_t len,
763 int last)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200764{
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200765 cryptmethods[state->method_nr].decode_inplace_fn(state, buf, len,
766 buf, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200767}
768
769/*
770 * Free an allocated crypt key. Clear the text to make sure it doesn't stay
771 * in memory anywhere.
772 */
773 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100774crypt_free_key(char_u *key)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200775{
776 char_u *p;
777
778 if (key != NULL)
779 {
780 for (p = key; *p != NUL; ++p)
781 *p = 0;
782 vim_free(key);
783 }
784}
785
786/*
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100787 * Check the crypt method and give a warning if it's outdated.
788 */
789 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100790crypt_check_method(int method)
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100791{
Christian Brabandtaae58342023-04-23 17:50:22 +0100792 if (method < CRYPT_M_BF2 || method == CRYPT_M_SOD)
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100793 {
794 msg_scroll = TRUE;
Bram Moolenaar32526b32019-01-19 17:43:09 +0100795 msg(_("Warning: Using a weak encryption method; see :help 'cm'"));
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100796 }
Christian Brabandt226b28b2021-06-21 21:08:08 +0200797}
798
799#ifdef FEAT_SODIUM
800 static void
801crypt_check_swapfile_curbuf(void)
802{
803 int method = crypt_get_method_nr(curbuf);
Christian Brabandtaae58342023-04-23 17:50:22 +0100804 if (crypt_method_is_sodium(method))
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200805 {
806 // encryption uses padding and MAC, that does not work very well with
807 // swap and undo files, so disable them
808 mf_close_file(curbuf, TRUE); // remove the swap file
Bram Moolenaar31e5c602022-04-15 13:53:33 +0100809 set_option_value_give_err((char_u *)"swf", 0, NULL, OPT_LOCAL);
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200810 msg_scroll = TRUE;
Christian Brabandt8a4c8122021-07-25 14:36:05 +0200811 msg(_("Note: Encryption of swapfile not supported, disabling swap file"));
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200812 }
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100813}
Christian Brabandt226b28b2021-06-21 21:08:08 +0200814#endif
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100815
816 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100817crypt_check_current_method(void)
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100818{
819 crypt_check_method(crypt_get_method_nr(curbuf));
820}
821
822/*
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200823 * Ask the user for a crypt key.
824 * When "store" is TRUE, the new key is stored in the 'key' option, and the
825 * 'key' option value is returned: Don't free it.
826 * When "store" is FALSE, the typed key is returned in allocated memory.
827 * Returns NULL on failure.
828 */
829 char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +0100830crypt_get_key(
831 int store,
Bram Moolenaarc667da52019-11-30 20:52:27 +0100832 int twice) // Ask for the key twice.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200833{
834 char_u *p1, *p2 = NULL;
835 int round;
836
837 for (round = 0; ; ++round)
838 {
839 cmdline_star = TRUE;
840 cmdline_row = msg_row;
841 p1 = getcmdline_prompt(NUL, round == 0
842 ? (char_u *)_("Enter encryption key: ")
843 : (char_u *)_("Enter same key again: "), 0, EXPAND_NOTHING,
844 NULL);
845 cmdline_star = FALSE;
846
847 if (p1 == NULL)
848 break;
849
850 if (round == twice)
851 {
852 if (p2 != NULL && STRCMP(p1, p2) != 0)
853 {
Bram Moolenaar32526b32019-01-19 17:43:09 +0100854 msg(_("Keys don't match!"));
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200855 crypt_free_key(p1);
856 crypt_free_key(p2);
857 p2 = NULL;
Bram Moolenaarc667da52019-11-30 20:52:27 +0100858 round = -1; // do it again
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200859 continue;
860 }
861
862 if (store)
863 {
Bram Moolenaar31e5c602022-04-15 13:53:33 +0100864 set_option_value_give_err((char_u *)"key", 0L, p1, OPT_LOCAL);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200865 crypt_free_key(p1);
866 p1 = curbuf->b_p_key;
Christian Brabandt226b28b2021-06-21 21:08:08 +0200867#ifdef FEAT_SODIUM
868 crypt_check_swapfile_curbuf();
869#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200870 }
871 break;
872 }
873 p2 = p1;
874 }
875
Bram Moolenaarc667da52019-11-30 20:52:27 +0100876 // since the user typed this, no need to wait for return
Christian Brabandtaae58342023-04-23 17:50:22 +0100877 if (!crypt_method_is_sodium(crypt_get_method_nr(curbuf)))
Christian Brabandt226b28b2021-06-21 21:08:08 +0200878 {
879 if (msg_didout)
880 msg_putchar('\n');
881 need_wait_return = FALSE;
882 msg_didout = FALSE;
883 }
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200884
885 crypt_free_key(p2);
886 return p1;
887}
888
889
890/*
891 * Append a message to IObuff for the encryption/decryption method being used.
892 */
893 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100894crypt_append_msg(
895 buf_T *buf)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200896{
897 if (crypt_get_method_nr(buf) == 0)
898 STRCAT(IObuff, _("[crypted]"));
899 else
900 {
901 STRCAT(IObuff, "[");
902 STRCAT(IObuff, *buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
903 STRCAT(IObuff, "]");
904 }
905}
906
Yegappan Lakshmananee47eac2022-06-29 12:55:36 +0100907 static int
K.Takataa8cdb4e2022-12-06 16:17:01 +0000908crypt_sodium_init_(
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200909 cryptstate_T *state UNUSED,
910 char_u *key UNUSED,
Christian Brabandtaae58342023-04-23 17:50:22 +0100911 crypt_arg_T *arg UNUSED)
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200912{
913# ifdef FEAT_SODIUM
914 // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
915 unsigned char dkey[crypto_box_SEEDBYTES]; // 32
916 sodium_state_T *sd_state;
Bram Moolenaar131530a2021-07-29 20:37:49 +0200917 int retval = 0;
Christian Brabandtaae58342023-04-23 17:50:22 +0100918 unsigned long long opslimit;
919 size_t memlimit;
920 int alg;
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200921
922 if (sodium_init() < 0)
923 return FAIL;
924
925 sd_state = (sodium_state_T *)sodium_malloc(sizeof(sodium_state_T));
926 sodium_memzero(sd_state, sizeof(sodium_state_T));
927
Christian Brabandtaae58342023-04-23 17:50:22 +0100928 if ((state->method_nr == CRYPT_M_SOD2 && !arg->cat_init_from_file)
929 || state->method_nr == CRYPT_M_SOD)
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200930 {
Christian Brabandtaae58342023-04-23 17:50:22 +0100931 opslimit = crypto_pwhash_OPSLIMIT_INTERACTIVE;
932 memlimit = crypto_pwhash_MEMLIMIT_INTERACTIVE;
933 alg = crypto_pwhash_ALG_DEFAULT;
934
935#if 0
936 // For testing
937 if (state->method_nr == CRYPT_M_SOD2)
938 {
939 opslimit = crypto_pwhash_OPSLIMIT_MODERATE;
940 memlimit = crypto_pwhash_MEMLIMIT_MODERATE;
941 }
942#endif
943
944 // derive a key from the password
945 if (crypto_pwhash(dkey, sizeof(dkey), (const char *)key, STRLEN(key),
946 arg->cat_salt, opslimit, memlimit, alg) != 0)
947 {
948 // out of memory
949 sodium_free(sd_state);
950 return FAIL;
951 }
952 memcpy(sd_state->key, dkey, crypto_box_SEEDBYTES);
953
954 retval += sodium_mlock(sd_state->key, crypto_box_SEEDBYTES);
955 retval += sodium_mlock(key, STRLEN(key));
956
957 if (retval < 0)
958 {
959 emsg(_(e_encryption_sodium_mlock_failed));
960 sodium_free(sd_state);
961 return FAIL;
962 }
963 if (state->method_nr == CRYPT_M_SOD2)
964 {
965 memcpy(arg->cat_add, &opslimit, sizeof(opslimit));
966 arg->cat_add += sizeof(opslimit);
967
968 memcpy(arg->cat_add, &memlimit, sizeof(memlimit));
969 arg->cat_add += sizeof(memlimit);
970
971 memcpy(arg->cat_add, &alg, sizeof(alg));
972 arg->cat_add += sizeof(alg);
973 }
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200974 }
Christian Brabandtaae58342023-04-23 17:50:22 +0100975 else
Bram Moolenaar131530a2021-07-29 20:37:49 +0200976 {
Christian Brabandtaae58342023-04-23 17:50:22 +0100977 // Reading parameters from file
978 if (arg->cat_add_len
979 < (int)(sizeof(opslimit) + sizeof(memlimit) + sizeof(alg)))
980 {
981 sodium_free(sd_state);
982 return FAIL;
983 }
984
985 // derive the key from the file header
986 memcpy(&opslimit, arg->cat_add, sizeof(opslimit));
987 arg->cat_add += sizeof(opslimit);
988
989 memcpy(&memlimit, arg->cat_add, sizeof(memlimit));
990 arg->cat_add += sizeof(memlimit);
991
992 memcpy(&alg, arg->cat_add, sizeof(alg));
993 arg->cat_add += sizeof(alg);
994
995#ifdef FEAT_EVAL
996 crypt_sodium_report_hash_params(opslimit,
997 crypto_pwhash_OPSLIMIT_INTERACTIVE,
998 memlimit, crypto_pwhash_MEMLIMIT_INTERACTIVE,
999 alg, crypto_pwhash_ALG_DEFAULT);
1000#endif
1001
1002 if (crypto_pwhash(dkey, sizeof(dkey), (const char *)key, STRLEN(key),
1003 arg->cat_salt, opslimit, memlimit, alg) != 0)
1004 {
1005 // out of memory
1006 sodium_free(sd_state);
1007 return FAIL;
1008 }
1009 memcpy(sd_state->key, dkey, crypto_box_SEEDBYTES);
1010
1011 retval += sodium_mlock(sd_state->key, crypto_box_SEEDBYTES);
1012 retval += sodium_mlock(key, STRLEN(key));
1013
1014 if (retval < 0)
1015 {
1016 emsg(_(e_encryption_sodium_mlock_failed));
1017 sodium_free(sd_state);
1018 return FAIL;
1019 }
Bram Moolenaar131530a2021-07-29 20:37:49 +02001020 }
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001021 sd_state->count = 0;
1022 state->method_state = sd_state;
1023
1024 return OK;
1025# else
1026 emsg(e_libsodium_not_built_in);
1027 return FAIL;
1028# endif
1029}
1030
1031/*
1032 * Encrypt "from[len]" into "to[len]".
1033 * "from" and "to" can be equal to encrypt in place.
1034 * Call needs to ensure that there is enough space in to (for the header)
1035 */
Christian Brabandt226b28b2021-06-21 21:08:08 +02001036#if 0 // Currently unused
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001037 void
1038crypt_sodium_encode(
1039 cryptstate_T *state UNUSED,
1040 char_u *from UNUSED,
1041 size_t len UNUSED,
1042 char_u *to UNUSED,
1043 int last UNUSED)
1044{
1045# ifdef FEAT_SODIUM
1046 // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
1047 sodium_state_T *sod_st = state->method_state;
1048 unsigned char tag = last
1049 ? crypto_secretstream_xchacha20poly1305_TAG_FINAL : 0;
1050
1051 if (sod_st->count == 0)
1052 {
1053 if (len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES)
1054 {
1055 emsg(e_libsodium_cannot_encrypt_header);
1056 return;
1057 }
1058 crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state,
1059 to, sod_st->key);
1060 to += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1061 }
1062
1063 if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES)
1064 {
1065 emsg(e_libsodium_cannot_encrypt_buffer);
1066 return;
1067 }
1068
1069 crypto_secretstream_xchacha20poly1305_push(&sod_st->state, to, NULL,
1070 from, len, NULL, 0, tag);
1071
1072 sod_st->count++;
1073# endif
1074}
Christian Brabandt226b28b2021-06-21 21:08:08 +02001075#endif
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001076
Christian Brabandt226b28b2021-06-21 21:08:08 +02001077/*
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001078 * Decrypt "from[len]" into "to[len]".
1079 * "from" and "to" can be equal to encrypt in place.
1080 */
Christian Brabandt226b28b2021-06-21 21:08:08 +02001081#if 0 // Currently unused
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001082 void
1083crypt_sodium_decode(
1084 cryptstate_T *state UNUSED,
1085 char_u *from UNUSED,
1086 size_t len UNUSED,
1087 char_u *to UNUSED,
1088 int last UNUSED)
1089{
1090# ifdef FEAT_SODIUM
1091 // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
1092 sodium_state_T *sod_st = state->method_state;
1093 unsigned char tag;
1094 unsigned long long buf_len;
1095 char_u *p1 = from;
1096 char_u *p2 = to;
1097 char_u *buf_out;
1098
1099 if (sod_st->count == 0
1100 && len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES)
1101 {
1102 emsg(e_libsodium_cannot_decrypt_header);
1103 return;
1104 }
1105
1106 buf_out = (char_u *)alloc(len);
1107
1108 if (buf_out == NULL)
1109 {
1110 emsg(e_libsodium_cannot_allocate_buffer);
1111 return;
1112 }
1113 if (sod_st->count == 0)
1114 {
1115 if (crypto_secretstream_xchacha20poly1305_init_pull(
1116 &sod_st->state, from, sod_st->key) != 0)
1117 {
1118 emsg(e_libsodium_decryption_failed_header_incomplete);
1119 goto fail;
1120 }
1121
1122 from += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1123 len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1124
1125 if (p1 == p2)
1126 to += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1127 }
1128
1129 if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES)
1130 {
1131 emsg(e_libsodium_cannot_decrypt_buffer);
Dominique Pellecb54bc62021-06-21 20:15:37 +02001132 goto fail;
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001133 }
1134 if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state,
1135 buf_out, &buf_len, &tag, from, len, NULL, 0) != 0)
1136 {
Dominique Pellecb54bc62021-06-21 20:15:37 +02001137 emsg(e_libsodium_decryption_failed);
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001138 goto fail;
1139 }
1140 sod_st->count++;
1141
1142 if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last)
1143 {
Dominique Pellecb54bc62021-06-21 20:15:37 +02001144 emsg(e_libsodium_decryption_failed_premature);
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001145 goto fail;
1146 }
1147 if (p1 == p2)
1148 mch_memmove(p2, buf_out, buf_len);
1149
1150fail:
1151 vim_free(buf_out);
1152# endif
1153}
Christian Brabandt226b28b2021-06-21 21:08:08 +02001154#endif
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001155
1156/*
1157 * Encrypt "from[len]" into "to[len]".
1158 * "from" and "to" can be equal to encrypt in place.
1159 */
Yegappan Lakshmananee47eac2022-06-29 12:55:36 +01001160 static long
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001161crypt_sodium_buffer_encode(
1162 cryptstate_T *state UNUSED,
1163 char_u *from UNUSED,
1164 size_t len UNUSED,
1165 char_u **buf_out UNUSED,
1166 int last UNUSED)
1167{
1168# ifdef FEAT_SODIUM
1169 // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
1170 unsigned long long out_len;
1171 char_u *ptr;
1172 unsigned char tag = last
1173 ? crypto_secretstream_xchacha20poly1305_TAG_FINAL : 0;
1174 int length;
1175 sodium_state_T *sod_st = state->method_state;
1176 int first = (sod_st->count == 0);
1177
Christian Brabandt226b28b2021-06-21 21:08:08 +02001178 length = (int)len + crypto_secretstream_xchacha20poly1305_ABYTES
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001179 + (first ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0);
1180 *buf_out = alloc_clear(length);
1181 if (*buf_out == NULL)
1182 {
1183 emsg(e_libsodium_cannot_allocate_buffer);
1184 return -1;
1185 }
1186 ptr = *buf_out;
1187
1188 if (first)
1189 {
1190 crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state,
1191 ptr, sod_st->key);
1192 ptr += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1193 }
1194
1195 crypto_secretstream_xchacha20poly1305_push(&sod_st->state, ptr,
1196 &out_len, from, len, NULL, 0, tag);
1197
1198 sod_st->count++;
1199 return out_len + (first
1200 ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0);
1201# else
1202 return -1;
1203# endif
1204}
1205
1206/*
1207 * Decrypt "from[len]" into "to[len]".
1208 * "from" and "to" can be equal to encrypt in place.
1209 */
Yegappan Lakshmananee47eac2022-06-29 12:55:36 +01001210 static long
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001211crypt_sodium_buffer_decode(
1212 cryptstate_T *state UNUSED,
1213 char_u *from UNUSED,
1214 size_t len UNUSED,
1215 char_u **buf_out UNUSED,
1216 int last UNUSED)
1217{
1218# ifdef FEAT_SODIUM
1219 // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
1220 sodium_state_T *sod_st = state->method_state;
1221 unsigned char tag;
1222 unsigned long long out_len;
Christian Brabandtaae58342023-04-23 17:50:22 +01001223
1224 if (sod_st->count == 0
1225 && state->method_nr == CRYPT_M_SOD
1226 && len > WRITEBUFSIZE
1227 + crypto_secretstream_xchacha20poly1305_HEADERBYTES
1228 + crypto_secretstream_xchacha20poly1305_ABYTES)
1229 len -= cryptmethods[CRYPT_M_SOD2].add_len;
1230
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001231 *buf_out = alloc_clear(len);
1232 if (*buf_out == NULL)
1233 {
1234 emsg(e_libsodium_cannot_allocate_buffer);
1235 return -1;
1236 }
1237
1238 if (sod_st->count == 0)
1239 {
1240 if (crypto_secretstream_xchacha20poly1305_init_pull(&sod_st->state,
1241 from, sod_st->key) != 0)
1242 {
1243 emsg(e_libsodium_decryption_failed_header_incomplete);
1244 return -1;
1245 }
1246 from += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1247 len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1248 sod_st->count++;
1249 }
1250 if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state,
1251 *buf_out, &out_len, &tag, from, len, NULL, 0) != 0)
1252 {
Dominique Pellecb54bc62021-06-21 20:15:37 +02001253 emsg(e_libsodium_decryption_failed);
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001254 return -1;
1255 }
1256
1257 if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last)
Dominique Pellecb54bc62021-06-21 20:15:37 +02001258 emsg(e_libsodium_decryption_failed_premature);
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001259 return (long) out_len;
1260# else
1261 return -1;
1262# endif
1263}
1264
K.Takata1a8825d2022-01-19 13:32:57 +00001265# if defined(FEAT_SODIUM) || defined(PROTO)
1266 int
1267crypt_sodium_munlock(void *const addr, const size_t len)
1268{
1269 return sodium_munlock(addr, len);
1270}
1271
1272 void
1273crypt_sodium_randombytes_buf(void *const buf, const size_t size)
1274{
1275 randombytes_buf(buf, size);
1276}
K.Takataa8cdb4e2022-12-06 16:17:01 +00001277
1278 int
1279crypt_sodium_init(void)
1280{
1281 return sodium_init();
1282}
1283
1284 uint32_t
1285crypt_sodium_randombytes_random(void)
1286{
1287 return randombytes_random();
1288}
Christian Brabandtaae58342023-04-23 17:50:22 +01001289
1290#if defined(FEAT_EVAL) || defined(PROTO)
1291 static void
1292crypt_sodium_report_hash_params(
1293 unsigned long long opslimit,
1294 unsigned long long ops_def,
1295 size_t memlimit,
1296 size_t mem_def,
1297 int alg,
1298 int alg_def)
1299{
1300 if (p_verbose > 0)
1301 {
1302 verbose_enter();
1303 if (opslimit != ops_def)
1304 smsg(_("xchacha20v2: using custom opslimit \"%llu\" for Key derivation."), opslimit);
1305 else
1306 smsg(_("xchacha20v2: using default opslimit \"%llu\" for Key derivation."), opslimit);
1307 if (memlimit != mem_def)
1308 smsg(_("xchacha20v2: using custom memlimit \"%lu\" for Key derivation."), (unsigned long)memlimit);
1309 else
1310 smsg(_("xchacha20v2: using default memlimit \"%lu\" for Key derivation."), (unsigned long)memlimit);
1311 if (alg != alg_def)
1312 smsg(_("xchacha20v2: using custom algorithm \"%d\" for Key derivation."), alg);
1313 else
1314 smsg(_("xchacha20v2: using default algorithm \"%d\" for Key derivation."), alg);
1315 verbose_leave();
1316 }
1317}
1318#endif
K.Takata1a8825d2022-01-19 13:32:57 +00001319# endif
1320
Bram Moolenaarc667da52019-11-30 20:52:27 +01001321#endif // FEAT_CRYPT