blob: a2740c98aa308dc32e796cce388954c5caf6bb3d [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
Bram Moolenaar987411d2019-01-18 22:48:34 +010037#ifdef CRYPT_NOT_INPLACE
Bram Moolenaarc667da52019-11-30 20:52:27 +010038 int works_inplace; // encryption/decryption can be done in-place
Bram Moolenaar987411d2019-01-18 22:48:34 +010039#endif
Bram Moolenaarc667da52019-11-30 20:52:27 +010040 int whole_undofile; // whole undo file is encrypted
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020041
Bram Moolenaarc667da52019-11-30 20:52:27 +010042 // Optional function pointer for a self-test.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020043 int (* self_test_fn)();
44
Bram Moolenaarad3ec762019-04-21 00:00:13 +020045 // Function pointer for initializing encryption/decryption.
Bram Moolenaar6ee96582019-04-27 22:06:37 +020046 int (* init_fn)(cryptstate_T *state, char_u *key,
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020047 char_u *salt, int salt_len, char_u *seed, int seed_len);
48
Bram Moolenaarc667da52019-11-30 20:52:27 +010049 // Function pointers for encoding/decoding from one buffer into another.
50 // Optional, however, these or the _buffer ones should be configured.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020051 void (*encode_fn)(cryptstate_T *state, char_u *from, size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +020052 char_u *to, int last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020053 void (*decode_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
Bram Moolenaarc667da52019-11-30 20:52:27 +010056 // Function pointers for encoding and decoding, can buffer data if needed.
57 // Optional (however, these or the above should be configured).
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020058 long (*encode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +020059 char_u **newptr, int last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020060 long (*decode_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
Bram Moolenaarc667da52019-11-30 20:52:27 +010063 // Function pointers for in-place encoding and decoding, used for
64 // crypt_*_inplace(). "from" and "to" arguments will be equal.
65 // These may be the same as decode_fn and encode_fn above, however an
66 // algorithm may implement them in a way that is not interchangeable with
67 // the crypt_(en|de)code() interface (for example because it wishes to add
68 // padding to files).
69 // This method is used for swap and undo files which have a rigid format.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020070 void (*encode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +020071 char_u *p2, int last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020072 void (*decode_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} cryptmethod_T;
75
K.Takataa8cdb4e2022-12-06 16:17:01 +000076static int crypt_sodium_init_(cryptstate_T *state, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len);
Yegappan Lakshmananee47eac2022-06-29 12:55:36 +010077static long crypt_sodium_buffer_decode(cryptstate_T *state, char_u *from, size_t len, char_u **buf_out, int last);
78static long crypt_sodium_buffer_encode(cryptstate_T *state, char_u *from, size_t len, char_u **buf_out, int last);
79
Bram Moolenaarc667da52019-11-30 20:52:27 +010080// index is method_nr of cryptstate_T, CRYPT_M_*
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020081static cryptmethod_T cryptmethods[CRYPT_M_COUNT] = {
Bram Moolenaarc667da52019-11-30 20:52:27 +010082 // PK_Zip; very weak
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020083 {
84 "zip",
85 "VimCrypt~01!",
86 0,
87 0,
Bram Moolenaar987411d2019-01-18 22:48:34 +010088#ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020089 TRUE,
Bram Moolenaar987411d2019-01-18 22:48:34 +010090#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +020091 FALSE,
92 NULL,
93 crypt_zip_init,
94 crypt_zip_encode, crypt_zip_decode,
95 NULL, NULL,
96 crypt_zip_encode, crypt_zip_decode,
97 },
98
Bram Moolenaarc667da52019-11-30 20:52:27 +010099 // Blowfish/CFB + SHA-256 custom key derivation; implementation issues.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200100 {
101 "blowfish",
102 "VimCrypt~02!",
103 8,
104 8,
Bram Moolenaar987411d2019-01-18 22:48:34 +0100105#ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200106 TRUE,
Bram Moolenaar987411d2019-01-18 22:48:34 +0100107#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200108 FALSE,
109 blowfish_self_test,
110 crypt_blowfish_init,
111 crypt_blowfish_encode, crypt_blowfish_decode,
112 NULL, NULL,
113 crypt_blowfish_encode, crypt_blowfish_decode,
114 },
115
Bram Moolenaarc667da52019-11-30 20:52:27 +0100116 // Blowfish/CFB + SHA-256 custom key derivation; fixed.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200117 {
118 "blowfish2",
119 "VimCrypt~03!",
120 8,
121 8,
Bram Moolenaar987411d2019-01-18 22:48:34 +0100122#ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200123 TRUE,
Bram Moolenaar987411d2019-01-18 22:48:34 +0100124#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200125 TRUE,
126 blowfish_self_test,
127 crypt_blowfish_init,
128 crypt_blowfish_encode, crypt_blowfish_decode,
129 NULL, NULL,
130 crypt_blowfish_encode, crypt_blowfish_decode,
131 },
Bram Moolenaard23a8232018-02-10 18:45:26 +0100132
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200133 // XChaCha20 using libsodium
134 {
135 "xchacha20",
136 "VimCrypt~04!",
137#ifdef FEAT_SODIUM
138 crypto_pwhash_argon2id_SALTBYTES, // 16
139#else
140 16,
141#endif
142 8,
143#ifdef CRYPT_NOT_INPLACE
144 FALSE,
145#endif
146 FALSE,
147 NULL,
K.Takataa8cdb4e2022-12-06 16:17:01 +0000148 crypt_sodium_init_,
Christian Brabandt226b28b2021-06-21 21:08:08 +0200149 NULL, NULL,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200150 crypt_sodium_buffer_encode, crypt_sodium_buffer_decode,
Christian Brabandt226b28b2021-06-21 21:08:08 +0200151 NULL, NULL,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200152 },
153
Bram Moolenaarc667da52019-11-30 20:52:27 +0100154 // NOTE: when adding a new method, use some random bytes for the magic key,
155 // to avoid that a text file is recognized as encrypted.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200156};
157
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200158#ifdef FEAT_SODIUM
159typedef struct {
160 size_t count;
161 unsigned char key[crypto_box_SEEDBYTES];
162 // 32, same as crypto_secretstream_xchacha20poly1305_KEYBYTES
163 crypto_secretstream_xchacha20poly1305_state
164 state;
165} sodium_state_T;
K.Takata1a8825d2022-01-19 13:32:57 +0000166
167
168# ifdef DYNAMIC_SODIUM
K.Takatad68b2fc2022-02-12 11:18:37 +0000169# ifdef MSWIN
170# define SODIUM_PROC FARPROC
171# define load_dll vimLoadLib
172# define symbol_from_dll GetProcAddress
173# define close_dll FreeLibrary
174# define load_dll_error GetWin32Error
175# else
176# error Dynamic loading of libsodium is not supported for now.
177//# define HINSTANCE void*
178//# define SODIUM_PROC void*
179//# define load_dll(n) dlopen((n), RTLD_LAZY|RTLD_GLOBAL)
180//# define symbol_from_dll dlsym
181//# define close_dll dlclose
182//# define load_dll_error dlerror
183# endif
184
K.Takata1a8825d2022-01-19 13:32:57 +0000185# define sodium_init load_sodium
186# define sodium_free dll_sodium_free
187# define sodium_malloc dll_sodium_malloc
188# define sodium_memzero dll_sodium_memzero
189# define sodium_mlock dll_sodium_mlock
190# define sodium_munlock dll_sodium_munlock
191# define crypto_secretstream_xchacha20poly1305_init_push \
192 dll_crypto_secretstream_xchacha20poly1305_init_push
193# define crypto_secretstream_xchacha20poly1305_push \
194 dll_crypto_secretstream_xchacha20poly1305_push
195# define crypto_secretstream_xchacha20poly1305_init_pull \
196 dll_crypto_secretstream_xchacha20poly1305_init_pull
197# define crypto_secretstream_xchacha20poly1305_pull \
198 dll_crypto_secretstream_xchacha20poly1305_pull
199# define crypto_pwhash dll_crypto_pwhash
200# define randombytes_buf dll_randombytes_buf
K.Takataa8cdb4e2022-12-06 16:17:01 +0000201# define randombytes_random dll_randombytes_random
K.Takata1a8825d2022-01-19 13:32:57 +0000202
203static int (*dll_sodium_init)(void) = NULL;
204static void (*dll_sodium_free)(void *) = NULL;
205static void *(*dll_sodium_malloc)(const size_t) = NULL;
206static void (*dll_sodium_memzero)(void * const, const size_t) = NULL;
207static int (*dll_sodium_mlock)(void * const, const size_t) = NULL;
208static int (*dll_sodium_munlock)(void * const, const size_t) = NULL;
209static int (*dll_crypto_secretstream_xchacha20poly1305_init_push)
210 (crypto_secretstream_xchacha20poly1305_state *state,
211 unsigned char [],
212 const unsigned char []) = NULL;
213static int (*dll_crypto_secretstream_xchacha20poly1305_push)
214 (crypto_secretstream_xchacha20poly1305_state *state,
215 unsigned char *c, unsigned long long *clen_p,
216 const unsigned char *m, unsigned long long mlen,
217 const unsigned char *ad, unsigned long long adlen, unsigned char tag)
218 = NULL;
219static int (*dll_crypto_secretstream_xchacha20poly1305_init_pull)
220 (crypto_secretstream_xchacha20poly1305_state *state,
221 const unsigned char [],
222 const unsigned char []) = NULL;
223static int (*dll_crypto_secretstream_xchacha20poly1305_pull)
224 (crypto_secretstream_xchacha20poly1305_state *state,
225 unsigned char *m, unsigned long long *mlen_p, unsigned char *tag_p,
226 const unsigned char *c, unsigned long long clen,
227 const unsigned char *ad, unsigned long long adlen) = NULL;
228static int (*dll_crypto_pwhash)(unsigned char * const out,
229 unsigned long long outlen,
230 const char * const passwd, unsigned long long passwdlen,
231 const unsigned char * const salt,
232 unsigned long long opslimit, size_t memlimit, int alg)
233 = NULL;
234static void (*dll_randombytes_buf)(void * const buf, const size_t size);
K.Takataa8cdb4e2022-12-06 16:17:01 +0000235static uint32_t (*dll_randombytes_random)(void);
K.Takata1a8825d2022-01-19 13:32:57 +0000236
237static struct {
238 const char *name;
K.Takatad68b2fc2022-02-12 11:18:37 +0000239 SODIUM_PROC *ptr;
K.Takata1a8825d2022-01-19 13:32:57 +0000240} sodium_funcname_table[] = {
K.Takatad68b2fc2022-02-12 11:18:37 +0000241 {"sodium_init", (SODIUM_PROC*)&dll_sodium_init},
242 {"sodium_free", (SODIUM_PROC*)&dll_sodium_free},
243 {"sodium_malloc", (SODIUM_PROC*)&dll_sodium_malloc},
244 {"sodium_memzero", (SODIUM_PROC*)&dll_sodium_memzero},
245 {"sodium_mlock", (SODIUM_PROC*)&dll_sodium_mlock},
246 {"sodium_munlock", (SODIUM_PROC*)&dll_sodium_munlock},
247 {"crypto_secretstream_xchacha20poly1305_init_push", (SODIUM_PROC*)&dll_crypto_secretstream_xchacha20poly1305_init_push},
248 {"crypto_secretstream_xchacha20poly1305_push", (SODIUM_PROC*)&dll_crypto_secretstream_xchacha20poly1305_push},
249 {"crypto_secretstream_xchacha20poly1305_init_pull", (SODIUM_PROC*)&dll_crypto_secretstream_xchacha20poly1305_init_pull},
250 {"crypto_secretstream_xchacha20poly1305_pull", (SODIUM_PROC*)&dll_crypto_secretstream_xchacha20poly1305_pull},
251 {"crypto_pwhash", (SODIUM_PROC*)&dll_crypto_pwhash},
252 {"randombytes_buf", (SODIUM_PROC*)&dll_randombytes_buf},
K.Takataa8cdb4e2022-12-06 16:17:01 +0000253 {"randombytes_random", (SODIUM_PROC*)&dll_randombytes_random},
K.Takata1a8825d2022-01-19 13:32:57 +0000254 {NULL, NULL}
255};
256
257 static int
K.Takatad68b2fc2022-02-12 11:18:37 +0000258sodium_runtime_link_init(int verbose)
K.Takata1a8825d2022-01-19 13:32:57 +0000259{
K.Takatad68b2fc2022-02-12 11:18:37 +0000260 static HINSTANCE hsodium = NULL;
K.Takatad8f86292022-03-07 15:16:15 +0000261 const char *libname = DYNAMIC_SODIUM_DLL;
K.Takata1a8825d2022-01-19 13:32:57 +0000262 int i;
263
264 if (hsodium != NULL)
K.Takatad68b2fc2022-02-12 11:18:37 +0000265 return OK;
K.Takata1a8825d2022-01-19 13:32:57 +0000266
K.Takatad68b2fc2022-02-12 11:18:37 +0000267 hsodium = load_dll(libname);
K.Takata1a8825d2022-01-19 13:32:57 +0000268 if (hsodium == NULL)
269 {
K.Takatad68b2fc2022-02-12 11:18:37 +0000270 if (verbose)
271 semsg(_(e_could_not_load_library_str_str), libname, load_dll_error());
272 return FAIL;
K.Takata1a8825d2022-01-19 13:32:57 +0000273 }
274
275 for (i = 0; sodium_funcname_table[i].ptr; ++i)
276 {
K.Takatad68b2fc2022-02-12 11:18:37 +0000277 if ((*sodium_funcname_table[i].ptr = symbol_from_dll(hsodium,
K.Takata1a8825d2022-01-19 13:32:57 +0000278 sodium_funcname_table[i].name)) == NULL)
279 {
K.Takatad8f86292022-03-07 15:16:15 +0000280 close_dll(hsodium);
K.Takata1a8825d2022-01-19 13:32:57 +0000281 hsodium = NULL;
K.Takatad68b2fc2022-02-12 11:18:37 +0000282 if (verbose)
283 semsg(_(e_could_not_load_library_function_str), sodium_funcname_table[i].name);
284 return FAIL;
K.Takata1a8825d2022-01-19 13:32:57 +0000285 }
286 }
K.Takatad68b2fc2022-02-12 11:18:37 +0000287 return OK;
288}
289
290 static int
291load_sodium(void)
292{
293 if (sodium_runtime_link_init(TRUE) == FAIL)
294 return -1;
K.Takata1a8825d2022-01-19 13:32:57 +0000295 return dll_sodium_init();
296}
297# endif
K.Takatad68b2fc2022-02-12 11:18:37 +0000298
299# if defined(DYNAMIC_SODIUM) || defined(PROTO)
300 int
301sodium_enabled(int verbose)
302{
303 return sodium_runtime_link_init(verbose) == OK;
304}
305# endif
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200306#endif
307
Bram Moolenaarc667da52019-11-30 20:52:27 +0100308#define CRYPT_MAGIC_LEN 12 // cannot change
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200309static char crypt_magic_head[] = "VimCrypt~";
310
311/*
312 * Return int value for crypt method name.
313 * 0 for "zip", the old method. Also for any non-valid value.
314 * 1 for "blowfish".
315 * 2 for "blowfish2".
316 */
317 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100318crypt_method_nr_from_name(char_u *name)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200319{
320 int i;
321
322 for (i = 0; i < CRYPT_M_COUNT; ++i)
323 if (STRCMP(name, cryptmethods[i].name) == 0)
324 return i;
325 return 0;
326}
327
328/*
329 * Get the crypt method used for a file from "ptr[len]", the magic text at the
330 * start of the file.
331 * Returns -1 when no encryption used.
332 */
333 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100334crypt_method_nr_from_magic(char *ptr, int len)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200335{
336 int i;
337
338 if (len < CRYPT_MAGIC_LEN)
339 return -1;
340
341 for (i = 0; i < CRYPT_M_COUNT; i++)
342 if (memcmp(ptr, cryptmethods[i].magic, CRYPT_MAGIC_LEN) == 0)
343 return i;
344
345 i = (int)STRLEN(crypt_magic_head);
346 if (len >= i && memcmp(ptr, crypt_magic_head, i) == 0)
Bram Moolenaar9d00e4a2022-01-05 17:49:15 +0000347 emsg(_(e_file_is_encrypted_with_unknown_method));
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200348
349 return -1;
350}
351
Bram Moolenaar987411d2019-01-18 22:48:34 +0100352#ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200353/*
354 * Return TRUE if the crypt method for "method_nr" can be done in-place.
355 */
356 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100357crypt_works_inplace(cryptstate_T *state)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200358{
359 return cryptmethods[state->method_nr].works_inplace;
360}
Bram Moolenaar987411d2019-01-18 22:48:34 +0100361#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200362
363/*
364 * Get the crypt method for buffer "buf" as a number.
365 */
366 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100367crypt_get_method_nr(buf_T *buf)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200368{
369 return crypt_method_nr_from_name(*buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
370}
371
372/*
373 * Return TRUE when the buffer uses an encryption method that encrypts the
374 * whole undo file, not only the text.
375 */
376 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100377crypt_whole_undofile(int method_nr)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200378{
379 return cryptmethods[method_nr].whole_undofile;
380}
381
382/*
Bram Moolenaar32aa1022019-11-02 22:54:41 +0100383 * Get crypt method specific length of the file header in bytes.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200384 */
385 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100386crypt_get_header_len(int method_nr)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200387{
388 return CRYPT_MAGIC_LEN
389 + cryptmethods[method_nr].salt_len
390 + cryptmethods[method_nr].seed_len;
391}
392
Christian Brabandt226b28b2021-06-21 21:08:08 +0200393
Dominique Pelle748b3082022-01-08 12:41:16 +0000394#if defined(FEAT_SODIUM) || defined(PROTO)
Christian Brabandt226b28b2021-06-21 21:08:08 +0200395/*
396 * Get maximum crypt method specific length of the file header in bytes.
397 */
398 int
399crypt_get_max_header_len()
400{
401 int i;
402 int max = 0;
403 int temp = 0;
404
405 for (i = 0; i < CRYPT_M_COUNT; ++i)
406 {
407 temp = crypt_get_header_len(i);
408 if (temp > max)
409 max = temp;
410 }
411 return max;
412}
Dominique Pelle748b3082022-01-08 12:41:16 +0000413#endif
Christian Brabandt226b28b2021-06-21 21:08:08 +0200414
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200415/*
416 * Set the crypt method for buffer "buf" to "method_nr" using the int value as
417 * returned by crypt_method_nr_from_name().
418 */
419 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100420crypt_set_cm_option(buf_T *buf, int method_nr)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200421{
422 free_string_option(buf->b_p_cm);
423 buf->b_p_cm = vim_strsave((char_u *)cryptmethods[method_nr].name);
424}
425
426/*
427 * If the crypt method for the current buffer has a self-test, run it and
428 * return OK/FAIL.
429 */
430 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100431crypt_self_test(void)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200432{
433 int method_nr = crypt_get_method_nr(curbuf);
434
435 if (cryptmethods[method_nr].self_test_fn == NULL)
436 return OK;
437 return cryptmethods[method_nr].self_test_fn();
438}
439
440/*
441 * Allocate a crypt state and initialize it.
Bram Moolenaar6ee96582019-04-27 22:06:37 +0200442 * Return NULL for failure.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200443 */
444 cryptstate_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +0100445crypt_create(
446 int method_nr,
447 char_u *key,
448 char_u *salt,
449 int salt_len,
450 char_u *seed,
451 int seed_len)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200452{
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200453 cryptstate_T *state = ALLOC_ONE(cryptstate_T);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200454
Bram Moolenaar6ee96582019-04-27 22:06:37 +0200455 if (state == NULL)
456 return state;
457
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200458 state->method_nr = method_nr;
Bram Moolenaar6ee96582019-04-27 22:06:37 +0200459 if (cryptmethods[method_nr].init_fn(
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200460 state, key, salt, salt_len, seed, seed_len) == FAIL)
Bram Moolenaar6ee96582019-04-27 22:06:37 +0200461 {
Bram Moolenaar6ed545e2022-05-09 20:09:23 +0100462 vim_free(state);
463 return NULL;
Bram Moolenaar6ee96582019-04-27 22:06:37 +0200464 }
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200465 return state;
466}
467
468/*
469 * Allocate a crypt state from a file header and initialize it.
470 * Assumes that header contains at least the number of bytes that
471 * crypt_get_header_len() returns for "method_nr".
472 */
473 cryptstate_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +0100474crypt_create_from_header(
475 int method_nr,
476 char_u *key,
477 char_u *header)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200478{
479 char_u *salt = NULL;
480 char_u *seed = NULL;
481 int salt_len = cryptmethods[method_nr].salt_len;
482 int seed_len = cryptmethods[method_nr].seed_len;
483
484 if (salt_len > 0)
485 salt = header + CRYPT_MAGIC_LEN;
486 if (seed_len > 0)
487 seed = header + CRYPT_MAGIC_LEN + salt_len;
488
489 return crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
490}
491
492/*
493 * Read the crypt method specific header data from "fp".
494 * Return an allocated cryptstate_T or NULL on error.
495 */
496 cryptstate_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +0100497crypt_create_from_file(FILE *fp, char_u *key)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200498{
499 int method_nr;
500 int header_len;
501 char magic_buffer[CRYPT_MAGIC_LEN];
502 char_u *buffer;
503 cryptstate_T *state;
504
505 if (fread(magic_buffer, CRYPT_MAGIC_LEN, 1, fp) != 1)
506 return NULL;
507 method_nr = crypt_method_nr_from_magic(magic_buffer, CRYPT_MAGIC_LEN);
508 if (method_nr < 0)
509 return NULL;
510
511 header_len = crypt_get_header_len(method_nr);
512 if ((buffer = alloc(header_len)) == NULL)
513 return NULL;
514 mch_memmove(buffer, magic_buffer, CRYPT_MAGIC_LEN);
515 if (header_len > CRYPT_MAGIC_LEN
516 && fread(buffer + CRYPT_MAGIC_LEN,
517 header_len - CRYPT_MAGIC_LEN, 1, fp) != 1)
518 {
519 vim_free(buffer);
520 return NULL;
521 }
522
523 state = crypt_create_from_header(method_nr, key, buffer);
524 vim_free(buffer);
525 return state;
526}
527
528/*
529 * Allocate a cryptstate_T for writing and initialize it with "key".
530 * Allocates and fills in the header and stores it in "header", setting
531 * "header_len". The header may include salt and seed, depending on
532 * cryptmethod. Caller must free header.
533 * Returns the state or NULL on failure.
534 */
535 cryptstate_T *
Bram Moolenaar7454a062016-01-30 15:14:10 +0100536crypt_create_for_writing(
537 int method_nr,
538 char_u *key,
539 char_u **header,
540 int *header_len)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200541{
542 int len = crypt_get_header_len(method_nr);
543 char_u *salt = NULL;
544 char_u *seed = NULL;
545 int salt_len = cryptmethods[method_nr].salt_len;
546 int seed_len = cryptmethods[method_nr].seed_len;
547 cryptstate_T *state;
548
549 *header_len = len;
550 *header = alloc(len);
551 if (*header == NULL)
552 return NULL;
553
554 mch_memmove(*header, cryptmethods[method_nr].magic, CRYPT_MAGIC_LEN);
555 if (salt_len > 0 || seed_len > 0)
556 {
557 if (salt_len > 0)
558 salt = *header + CRYPT_MAGIC_LEN;
559 if (seed_len > 0)
560 seed = *header + CRYPT_MAGIC_LEN + salt_len;
561
Bram Moolenaarc667da52019-11-30 20:52:27 +0100562 // TODO: Should this be crypt method specific? (Probably not worth
563 // it). sha2_seed is pretty bad for large amounts of entropy, so make
564 // that into something which is suitable for anything.
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200565#ifdef FEAT_SODIUM
566 if (sodium_init() >= 0)
567 {
Christian Brabandt226b28b2021-06-21 21:08:08 +0200568 if (salt_len > 0)
569 randombytes_buf(salt, salt_len);
570 if (seed_len > 0)
571 randombytes_buf(seed, seed_len);
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200572 }
573 else
574#endif
575 sha2_seed(salt, salt_len, seed, seed_len);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200576 }
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200577 state = crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
578 if (state == NULL)
Bram Moolenaard23a8232018-02-10 18:45:26 +0100579 VIM_CLEAR(*header);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200580 return state;
581}
582
583/*
584 * Free the crypt state.
585 */
586 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100587crypt_free_state(cryptstate_T *state)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200588{
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200589#ifdef FEAT_SODIUM
590 if (state->method_nr == CRYPT_M_SOD)
591 {
Bram Moolenaar131530a2021-07-29 20:37:49 +0200592 sodium_munlock(((sodium_state_T *)state->method_state)->key,
593 crypto_box_SEEDBYTES);
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200594 sodium_memzero(state->method_state, sizeof(sodium_state_T));
595 sodium_free(state->method_state);
596 }
597 else
598#endif
599 vim_free(state->method_state);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200600 vim_free(state);
601}
602
Bram Moolenaar987411d2019-01-18 22:48:34 +0100603#ifdef CRYPT_NOT_INPLACE
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200604/*
605 * Encode "from[len]" and store the result in a newly allocated buffer, which
606 * is stored in "newptr".
607 * Return number of bytes in "newptr", 0 for need more or -1 on error.
608 */
609 long
Bram Moolenaar7454a062016-01-30 15:14:10 +0100610crypt_encode_alloc(
611 cryptstate_T *state,
612 char_u *from,
613 size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200614 char_u **newptr,
615 int last)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200616{
617 cryptmethod_T *method = &cryptmethods[state->method_nr];
618
619 if (method->encode_buffer_fn != NULL)
Bram Moolenaarc667da52019-11-30 20:52:27 +0100620 // Has buffer function, pass through.
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200621 return method->encode_buffer_fn(state, from, len, newptr, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200622 if (len == 0)
Bram Moolenaarc667da52019-11-30 20:52:27 +0100623 // Not buffering, just return EOF.
Bram Moolenaar9b8f0212014-08-13 22:05:53 +0200624 return (long)len;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200625
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200626 *newptr = alloc(len + 50);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200627 if (*newptr == NULL)
628 return -1;
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200629 method->encode_fn(state, from, len, *newptr, last);
Bram Moolenaar9b8f0212014-08-13 22:05:53 +0200630 return (long)len;
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200631}
632
633/*
634 * Decrypt "ptr[len]" and store the result in a newly allocated buffer, which
635 * is stored in "newptr".
636 * Return number of bytes in "newptr", 0 for need more or -1 on error.
637 */
638 long
Bram Moolenaar7454a062016-01-30 15:14:10 +0100639crypt_decode_alloc(
640 cryptstate_T *state,
641 char_u *ptr,
642 long len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200643 char_u **newptr,
644 int last)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200645{
646 cryptmethod_T *method = &cryptmethods[state->method_nr];
647
648 if (method->decode_buffer_fn != NULL)
Bram Moolenaarc667da52019-11-30 20:52:27 +0100649 // Has buffer function, pass through.
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200650 return method->decode_buffer_fn(state, ptr, len, newptr, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200651
652 if (len == 0)
Bram Moolenaarc667da52019-11-30 20:52:27 +0100653 // Not buffering, just return EOF.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200654 return len;
655
656 *newptr = alloc(len);
657 if (*newptr == NULL)
658 return -1;
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200659 method->decode_fn(state, ptr, len, *newptr, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200660 return len;
661}
Bram Moolenaar987411d2019-01-18 22:48:34 +0100662#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200663
664/*
665 * Encrypting "from[len]" into "to[len]".
666 */
667 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100668crypt_encode(
669 cryptstate_T *state,
670 char_u *from,
671 size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200672 char_u *to,
673 int last)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200674{
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200675 cryptmethods[state->method_nr].encode_fn(state, from, len, to, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200676}
677
Bram Moolenaar987411d2019-01-18 22:48:34 +0100678#if 0 // unused
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200679/*
680 * decrypting "from[len]" into "to[len]".
681 */
682 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100683crypt_decode(
684 cryptstate_T *state,
685 char_u *from,
686 size_t len,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200687 char_u *to,
688 int last)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200689{
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200690 cryptmethods[state->method_nr].decode_fn(state, from, len, to, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200691}
Bram Moolenaar987411d2019-01-18 22:48:34 +0100692#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200693
694/*
695 * Simple inplace encryption, modifies "buf[len]" in place.
696 */
697 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100698crypt_encode_inplace(
699 cryptstate_T *state,
700 char_u *buf,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200701 size_t len,
Bram Moolenaar6ed545e2022-05-09 20:09:23 +0100702 int last)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200703{
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200704 cryptmethods[state->method_nr].encode_inplace_fn(state, buf, len,
705 buf, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200706}
707
708/*
709 * Simple inplace decryption, modifies "buf[len]" in place.
710 */
711 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100712crypt_decode_inplace(
713 cryptstate_T *state,
714 char_u *buf,
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200715 size_t len,
716 int last)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200717{
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200718 cryptmethods[state->method_nr].decode_inplace_fn(state, buf, len,
719 buf, last);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200720}
721
722/*
723 * Free an allocated crypt key. Clear the text to make sure it doesn't stay
724 * in memory anywhere.
725 */
726 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100727crypt_free_key(char_u *key)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200728{
729 char_u *p;
730
731 if (key != NULL)
732 {
733 for (p = key; *p != NUL; ++p)
734 *p = 0;
735 vim_free(key);
736 }
737}
738
739/*
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100740 * Check the crypt method and give a warning if it's outdated.
741 */
742 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100743crypt_check_method(int method)
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100744{
745 if (method < CRYPT_M_BF2)
746 {
747 msg_scroll = TRUE;
Bram Moolenaar32526b32019-01-19 17:43:09 +0100748 msg(_("Warning: Using a weak encryption method; see :help 'cm'"));
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100749 }
Christian Brabandt226b28b2021-06-21 21:08:08 +0200750}
751
752#ifdef FEAT_SODIUM
753 static void
754crypt_check_swapfile_curbuf(void)
755{
756 int method = crypt_get_method_nr(curbuf);
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200757 if (method == CRYPT_M_SOD)
758 {
759 // encryption uses padding and MAC, that does not work very well with
760 // swap and undo files, so disable them
761 mf_close_file(curbuf, TRUE); // remove the swap file
Bram Moolenaar31e5c602022-04-15 13:53:33 +0100762 set_option_value_give_err((char_u *)"swf", 0, NULL, OPT_LOCAL);
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200763 msg_scroll = TRUE;
Christian Brabandt8a4c8122021-07-25 14:36:05 +0200764 msg(_("Note: Encryption of swapfile not supported, disabling swap file"));
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200765 }
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100766}
Christian Brabandt226b28b2021-06-21 21:08:08 +0200767#endif
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100768
769 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100770crypt_check_current_method(void)
Bram Moolenaar3a0c9082014-11-12 15:15:42 +0100771{
772 crypt_check_method(crypt_get_method_nr(curbuf));
773}
774
775/*
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200776 * Ask the user for a crypt key.
777 * When "store" is TRUE, the new key is stored in the 'key' option, and the
778 * 'key' option value is returned: Don't free it.
779 * When "store" is FALSE, the typed key is returned in allocated memory.
780 * Returns NULL on failure.
781 */
782 char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +0100783crypt_get_key(
784 int store,
Bram Moolenaarc667da52019-11-30 20:52:27 +0100785 int twice) // Ask for the key twice.
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200786{
787 char_u *p1, *p2 = NULL;
788 int round;
789
790 for (round = 0; ; ++round)
791 {
792 cmdline_star = TRUE;
793 cmdline_row = msg_row;
794 p1 = getcmdline_prompt(NUL, round == 0
795 ? (char_u *)_("Enter encryption key: ")
796 : (char_u *)_("Enter same key again: "), 0, EXPAND_NOTHING,
797 NULL);
798 cmdline_star = FALSE;
799
800 if (p1 == NULL)
801 break;
802
803 if (round == twice)
804 {
805 if (p2 != NULL && STRCMP(p1, p2) != 0)
806 {
Bram Moolenaar32526b32019-01-19 17:43:09 +0100807 msg(_("Keys don't match!"));
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200808 crypt_free_key(p1);
809 crypt_free_key(p2);
810 p2 = NULL;
Bram Moolenaarc667da52019-11-30 20:52:27 +0100811 round = -1; // do it again
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200812 continue;
813 }
814
815 if (store)
816 {
Bram Moolenaar31e5c602022-04-15 13:53:33 +0100817 set_option_value_give_err((char_u *)"key", 0L, p1, OPT_LOCAL);
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200818 crypt_free_key(p1);
819 p1 = curbuf->b_p_key;
Christian Brabandt226b28b2021-06-21 21:08:08 +0200820#ifdef FEAT_SODIUM
821 crypt_check_swapfile_curbuf();
822#endif
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200823 }
824 break;
825 }
826 p2 = p1;
827 }
828
Bram Moolenaarc667da52019-11-30 20:52:27 +0100829 // since the user typed this, no need to wait for return
Christian Brabandt226b28b2021-06-21 21:08:08 +0200830 if (crypt_get_method_nr(curbuf) != CRYPT_M_SOD)
831 {
832 if (msg_didout)
833 msg_putchar('\n');
834 need_wait_return = FALSE;
835 msg_didout = FALSE;
836 }
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200837
838 crypt_free_key(p2);
839 return p1;
840}
841
842
843/*
844 * Append a message to IObuff for the encryption/decryption method being used.
845 */
846 void
Bram Moolenaar7454a062016-01-30 15:14:10 +0100847crypt_append_msg(
848 buf_T *buf)
Bram Moolenaar8f4ac012014-08-10 13:38:34 +0200849{
850 if (crypt_get_method_nr(buf) == 0)
851 STRCAT(IObuff, _("[crypted]"));
852 else
853 {
854 STRCAT(IObuff, "[");
855 STRCAT(IObuff, *buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
856 STRCAT(IObuff, "]");
857 }
858}
859
Yegappan Lakshmananee47eac2022-06-29 12:55:36 +0100860 static int
K.Takataa8cdb4e2022-12-06 16:17:01 +0000861crypt_sodium_init_(
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200862 cryptstate_T *state UNUSED,
863 char_u *key UNUSED,
864 char_u *salt UNUSED,
865 int salt_len UNUSED,
866 char_u *seed UNUSED,
867 int seed_len UNUSED)
868{
869# ifdef FEAT_SODIUM
870 // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
871 unsigned char dkey[crypto_box_SEEDBYTES]; // 32
872 sodium_state_T *sd_state;
Bram Moolenaar131530a2021-07-29 20:37:49 +0200873 int retval = 0;
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200874
875 if (sodium_init() < 0)
876 return FAIL;
877
878 sd_state = (sodium_state_T *)sodium_malloc(sizeof(sodium_state_T));
879 sodium_memzero(sd_state, sizeof(sodium_state_T));
880
881 // derive a key from the password
882 if (crypto_pwhash(dkey, sizeof(dkey), (const char *)key, STRLEN(key), salt,
883 crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE,
884 crypto_pwhash_ALG_DEFAULT) != 0)
885 {
886 // out of memory
887 sodium_free(sd_state);
888 return FAIL;
889 }
890 memcpy(sd_state->key, dkey, crypto_box_SEEDBYTES);
Bram Moolenaar131530a2021-07-29 20:37:49 +0200891
892 retval += sodium_mlock(sd_state->key, crypto_box_SEEDBYTES);
893 retval += sodium_mlock(key, STRLEN(key));
894
895 if (retval < 0)
896 {
897 emsg(_(e_encryption_sodium_mlock_failed));
898 sodium_free(sd_state);
899 return FAIL;
900 }
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200901 sd_state->count = 0;
902 state->method_state = sd_state;
903
904 return OK;
905# else
906 emsg(e_libsodium_not_built_in);
907 return FAIL;
908# endif
909}
910
911/*
912 * Encrypt "from[len]" into "to[len]".
913 * "from" and "to" can be equal to encrypt in place.
914 * Call needs to ensure that there is enough space in to (for the header)
915 */
Christian Brabandt226b28b2021-06-21 21:08:08 +0200916#if 0 // Currently unused
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200917 void
918crypt_sodium_encode(
919 cryptstate_T *state UNUSED,
920 char_u *from UNUSED,
921 size_t len UNUSED,
922 char_u *to UNUSED,
923 int last UNUSED)
924{
925# ifdef FEAT_SODIUM
926 // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
927 sodium_state_T *sod_st = state->method_state;
928 unsigned char tag = last
929 ? crypto_secretstream_xchacha20poly1305_TAG_FINAL : 0;
930
931 if (sod_st->count == 0)
932 {
933 if (len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES)
934 {
935 emsg(e_libsodium_cannot_encrypt_header);
936 return;
937 }
938 crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state,
939 to, sod_st->key);
940 to += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
941 }
942
943 if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES)
944 {
945 emsg(e_libsodium_cannot_encrypt_buffer);
946 return;
947 }
948
949 crypto_secretstream_xchacha20poly1305_push(&sod_st->state, to, NULL,
950 from, len, NULL, 0, tag);
951
952 sod_st->count++;
953# endif
954}
Christian Brabandt226b28b2021-06-21 21:08:08 +0200955#endif
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200956
Christian Brabandt226b28b2021-06-21 21:08:08 +0200957/*
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200958 * Decrypt "from[len]" into "to[len]".
959 * "from" and "to" can be equal to encrypt in place.
960 */
Christian Brabandt226b28b2021-06-21 21:08:08 +0200961#if 0 // Currently unused
Christian Brabandtf573c6e2021-06-20 14:02:16 +0200962 void
963crypt_sodium_decode(
964 cryptstate_T *state UNUSED,
965 char_u *from UNUSED,
966 size_t len UNUSED,
967 char_u *to UNUSED,
968 int last UNUSED)
969{
970# ifdef FEAT_SODIUM
971 // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
972 sodium_state_T *sod_st = state->method_state;
973 unsigned char tag;
974 unsigned long long buf_len;
975 char_u *p1 = from;
976 char_u *p2 = to;
977 char_u *buf_out;
978
979 if (sod_st->count == 0
980 && len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES)
981 {
982 emsg(e_libsodium_cannot_decrypt_header);
983 return;
984 }
985
986 buf_out = (char_u *)alloc(len);
987
988 if (buf_out == NULL)
989 {
990 emsg(e_libsodium_cannot_allocate_buffer);
991 return;
992 }
993 if (sod_st->count == 0)
994 {
995 if (crypto_secretstream_xchacha20poly1305_init_pull(
996 &sod_st->state, from, sod_st->key) != 0)
997 {
998 emsg(e_libsodium_decryption_failed_header_incomplete);
999 goto fail;
1000 }
1001
1002 from += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1003 len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1004
1005 if (p1 == p2)
1006 to += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1007 }
1008
1009 if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES)
1010 {
1011 emsg(e_libsodium_cannot_decrypt_buffer);
Dominique Pellecb54bc62021-06-21 20:15:37 +02001012 goto fail;
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001013 }
1014 if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state,
1015 buf_out, &buf_len, &tag, from, len, NULL, 0) != 0)
1016 {
Dominique Pellecb54bc62021-06-21 20:15:37 +02001017 emsg(e_libsodium_decryption_failed);
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001018 goto fail;
1019 }
1020 sod_st->count++;
1021
1022 if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last)
1023 {
Dominique Pellecb54bc62021-06-21 20:15:37 +02001024 emsg(e_libsodium_decryption_failed_premature);
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001025 goto fail;
1026 }
1027 if (p1 == p2)
1028 mch_memmove(p2, buf_out, buf_len);
1029
1030fail:
1031 vim_free(buf_out);
1032# endif
1033}
Christian Brabandt226b28b2021-06-21 21:08:08 +02001034#endif
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001035
1036/*
1037 * Encrypt "from[len]" into "to[len]".
1038 * "from" and "to" can be equal to encrypt in place.
1039 */
Yegappan Lakshmananee47eac2022-06-29 12:55:36 +01001040 static long
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001041crypt_sodium_buffer_encode(
1042 cryptstate_T *state UNUSED,
1043 char_u *from UNUSED,
1044 size_t len UNUSED,
1045 char_u **buf_out UNUSED,
1046 int last UNUSED)
1047{
1048# ifdef FEAT_SODIUM
1049 // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
1050 unsigned long long out_len;
1051 char_u *ptr;
1052 unsigned char tag = last
1053 ? crypto_secretstream_xchacha20poly1305_TAG_FINAL : 0;
1054 int length;
1055 sodium_state_T *sod_st = state->method_state;
1056 int first = (sod_st->count == 0);
1057
Christian Brabandt226b28b2021-06-21 21:08:08 +02001058 length = (int)len + crypto_secretstream_xchacha20poly1305_ABYTES
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001059 + (first ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0);
1060 *buf_out = alloc_clear(length);
1061 if (*buf_out == NULL)
1062 {
1063 emsg(e_libsodium_cannot_allocate_buffer);
1064 return -1;
1065 }
1066 ptr = *buf_out;
1067
1068 if (first)
1069 {
1070 crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state,
1071 ptr, sod_st->key);
1072 ptr += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1073 }
1074
1075 crypto_secretstream_xchacha20poly1305_push(&sod_st->state, ptr,
1076 &out_len, from, len, NULL, 0, tag);
1077
1078 sod_st->count++;
1079 return out_len + (first
1080 ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0);
1081# else
1082 return -1;
1083# endif
1084}
1085
1086/*
1087 * Decrypt "from[len]" into "to[len]".
1088 * "from" and "to" can be equal to encrypt in place.
1089 */
Yegappan Lakshmananee47eac2022-06-29 12:55:36 +01001090 static long
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001091crypt_sodium_buffer_decode(
1092 cryptstate_T *state UNUSED,
1093 char_u *from UNUSED,
1094 size_t len UNUSED,
1095 char_u **buf_out UNUSED,
1096 int last UNUSED)
1097{
1098# ifdef FEAT_SODIUM
1099 // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
1100 sodium_state_T *sod_st = state->method_state;
1101 unsigned char tag;
1102 unsigned long long out_len;
1103 *buf_out = alloc_clear(len);
1104 if (*buf_out == NULL)
1105 {
1106 emsg(e_libsodium_cannot_allocate_buffer);
1107 return -1;
1108 }
1109
1110 if (sod_st->count == 0)
1111 {
1112 if (crypto_secretstream_xchacha20poly1305_init_pull(&sod_st->state,
1113 from, sod_st->key) != 0)
1114 {
1115 emsg(e_libsodium_decryption_failed_header_incomplete);
1116 return -1;
1117 }
1118 from += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1119 len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES;
1120 sod_st->count++;
1121 }
1122 if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state,
1123 *buf_out, &out_len, &tag, from, len, NULL, 0) != 0)
1124 {
Dominique Pellecb54bc62021-06-21 20:15:37 +02001125 emsg(e_libsodium_decryption_failed);
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001126 return -1;
1127 }
1128
1129 if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last)
Dominique Pellecb54bc62021-06-21 20:15:37 +02001130 emsg(e_libsodium_decryption_failed_premature);
Christian Brabandtf573c6e2021-06-20 14:02:16 +02001131 return (long) out_len;
1132# else
1133 return -1;
1134# endif
1135}
1136
K.Takata1a8825d2022-01-19 13:32:57 +00001137# if defined(FEAT_SODIUM) || defined(PROTO)
1138 int
1139crypt_sodium_munlock(void *const addr, const size_t len)
1140{
1141 return sodium_munlock(addr, len);
1142}
1143
1144 void
1145crypt_sodium_randombytes_buf(void *const buf, const size_t size)
1146{
1147 randombytes_buf(buf, size);
1148}
K.Takataa8cdb4e2022-12-06 16:17:01 +00001149
1150 int
1151crypt_sodium_init(void)
1152{
1153 return sodium_init();
1154}
1155
1156 uint32_t
1157crypt_sodium_randombytes_random(void)
1158{
1159 return randombytes_random();
1160}
K.Takata1a8825d2022-01-19 13:32:57 +00001161# endif
1162
Bram Moolenaarc667da52019-11-30 20:52:27 +01001163#endif // FEAT_CRYPT