xref: /vim-8.2.3635/src/crypt.c (revision cb54bc65)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
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 #ifdef FEAT_SODIUM
16 # include <sodium.h>
17 #endif
18 
19 #if defined(FEAT_CRYPT) || defined(PROTO)
20 /*
21  * Optional encryption support.
22  * Mohsin Ahmed, [email protected], 1998-09-24
23  * Based on zip/crypt sources.
24  * Refactored by David Leadbeater, 2014.
25  *
26  * NOTE FOR USA: Since 2000 exporting this code from the USA is allowed to
27  * most countries.  There are a few exceptions, but that still should not be a
28  * problem since this code was originally created in Europe and India.
29  *
30  * Blowfish addition originally made by Mohsin Ahmed,
31  * http://www.cs.albany.edu/~mosh 2010-03-14
32  * Based on blowfish by Bruce Schneier (http://www.schneier.com/blowfish.html)
33  * and sha256 by Christophe Devine.
34  */
35 
36 typedef struct {
37     char    *name;	// encryption name as used in 'cryptmethod'
38     char    *magic;	// magic bytes stored in file header
39     int	    salt_len;	// length of salt, or 0 when not using salt
40     int	    seed_len;	// length of seed, or 0 when not using seed
41 #ifdef CRYPT_NOT_INPLACE
42     int	    works_inplace; // encryption/decryption can be done in-place
43 #endif
44     int	    whole_undofile; // whole undo file is encrypted
45 
46     // Optional function pointer for a self-test.
47     int (* self_test_fn)();
48 
49     // Function pointer for initializing encryption/decryption.
50     int (* init_fn)(cryptstate_T *state, char_u *key,
51 		      char_u *salt, int salt_len, char_u *seed, int seed_len);
52 
53     // Function pointers for encoding/decoding from one buffer into another.
54     // Optional, however, these or the _buffer ones should be configured.
55     void (*encode_fn)(cryptstate_T *state, char_u *from, size_t len,
56 							char_u *to, int last);
57     void (*decode_fn)(cryptstate_T *state, char_u *from, size_t len,
58 							char_u *to, int last);
59 
60     // Function pointers for encoding and decoding, can buffer data if needed.
61     // Optional (however, these or the above should be configured).
62     long (*encode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
63 						    char_u **newptr, int last);
64     long (*decode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
65 						    char_u **newptr, int last);
66 
67     // Function pointers for in-place encoding and decoding, used for
68     // crypt_*_inplace(). "from" and "to" arguments will be equal.
69     // These may be the same as decode_fn and encode_fn above, however an
70     // algorithm may implement them in a way that is not interchangeable with
71     // the crypt_(en|de)code() interface (for example because it wishes to add
72     // padding to files).
73     // This method is used for swap and undo files which have a rigid format.
74     void (*encode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
75 							char_u *p2, int last);
76     void (*decode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
77 							char_u *p2, int last);
78 } cryptmethod_T;
79 
80 // index is method_nr of cryptstate_T, CRYPT_M_*
81 static cryptmethod_T cryptmethods[CRYPT_M_COUNT] = {
82     // PK_Zip; very weak
83     {
84 	"zip",
85 	"VimCrypt~01!",
86 	0,
87 	0,
88 #ifdef CRYPT_NOT_INPLACE
89 	TRUE,
90 #endif
91 	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 
99     // Blowfish/CFB + SHA-256 custom key derivation; implementation issues.
100     {
101 	"blowfish",
102 	"VimCrypt~02!",
103 	8,
104 	8,
105 #ifdef CRYPT_NOT_INPLACE
106 	TRUE,
107 #endif
108 	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 
116     // Blowfish/CFB + SHA-256 custom key derivation; fixed.
117     {
118 	"blowfish2",
119 	"VimCrypt~03!",
120 	8,
121 	8,
122 #ifdef CRYPT_NOT_INPLACE
123 	TRUE,
124 #endif
125 	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     },
132 
133     // 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,
148 	crypt_sodium_init,
149 	crypt_sodium_encode, crypt_sodium_decode,
150 	crypt_sodium_buffer_encode, crypt_sodium_buffer_decode,
151 	crypt_sodium_encode, crypt_sodium_decode,
152     },
153 
154     // 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.
156 };
157 
158 #ifdef FEAT_SODIUM
159 typedef 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;
166 #endif
167 
168 #define CRYPT_MAGIC_LEN	12	// cannot change
169 static char	crypt_magic_head[] = "VimCrypt~";
170 
171 /*
172  * Return int value for crypt method name.
173  * 0 for "zip", the old method.  Also for any non-valid value.
174  * 1 for "blowfish".
175  * 2 for "blowfish2".
176  */
177     int
178 crypt_method_nr_from_name(char_u *name)
179 {
180     int i;
181 
182     for (i = 0; i < CRYPT_M_COUNT; ++i)
183 	if (STRCMP(name, cryptmethods[i].name) == 0)
184 	    return i;
185     return 0;
186 }
187 
188 /*
189  * Get the crypt method used for a file from "ptr[len]", the magic text at the
190  * start of the file.
191  * Returns -1 when no encryption used.
192  */
193     int
194 crypt_method_nr_from_magic(char *ptr, int len)
195 {
196     int i;
197 
198     if (len < CRYPT_MAGIC_LEN)
199 	return -1;
200 
201     for (i = 0; i < CRYPT_M_COUNT; i++)
202 	if (memcmp(ptr, cryptmethods[i].magic, CRYPT_MAGIC_LEN) == 0)
203 	    return i;
204 
205     i = (int)STRLEN(crypt_magic_head);
206     if (len >= i && memcmp(ptr, crypt_magic_head, i) == 0)
207 	emsg(_("E821: File is encrypted with unknown method"));
208 
209     return -1;
210 }
211 
212 #ifdef CRYPT_NOT_INPLACE
213 /*
214  * Return TRUE if the crypt method for "method_nr" can be done in-place.
215  */
216     int
217 crypt_works_inplace(cryptstate_T *state)
218 {
219     return cryptmethods[state->method_nr].works_inplace;
220 }
221 #endif
222 
223 /*
224  * Get the crypt method for buffer "buf" as a number.
225  */
226     int
227 crypt_get_method_nr(buf_T *buf)
228 {
229     return crypt_method_nr_from_name(*buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
230 }
231 
232 /*
233  * Return TRUE when the buffer uses an encryption method that encrypts the
234  * whole undo file, not only the text.
235  */
236     int
237 crypt_whole_undofile(int method_nr)
238 {
239     return cryptmethods[method_nr].whole_undofile;
240 }
241 
242 /*
243  * Get crypt method specific length of the file header in bytes.
244  */
245     int
246 crypt_get_header_len(int method_nr)
247 {
248     return CRYPT_MAGIC_LEN
249 	+ cryptmethods[method_nr].salt_len
250 	+ cryptmethods[method_nr].seed_len;
251 }
252 
253 /*
254  * Set the crypt method for buffer "buf" to "method_nr" using the int value as
255  * returned by crypt_method_nr_from_name().
256  */
257     void
258 crypt_set_cm_option(buf_T *buf, int method_nr)
259 {
260     free_string_option(buf->b_p_cm);
261     buf->b_p_cm = vim_strsave((char_u *)cryptmethods[method_nr].name);
262 }
263 
264 /*
265  * If the crypt method for the current buffer has a self-test, run it and
266  * return OK/FAIL.
267  */
268     int
269 crypt_self_test(void)
270 {
271     int method_nr = crypt_get_method_nr(curbuf);
272 
273     if (cryptmethods[method_nr].self_test_fn == NULL)
274 	return OK;
275     return cryptmethods[method_nr].self_test_fn();
276 }
277 
278 /*
279  * Allocate a crypt state and initialize it.
280  * Return NULL for failure.
281  */
282     cryptstate_T *
283 crypt_create(
284     int		method_nr,
285     char_u	*key,
286     char_u	*salt,
287     int		salt_len,
288     char_u	*seed,
289     int		seed_len)
290 {
291     cryptstate_T *state = ALLOC_ONE(cryptstate_T);
292 
293     if (state == NULL)
294 	return state;
295 
296     state->method_nr = method_nr;
297     if (cryptmethods[method_nr].init_fn(
298 	state, key, salt, salt_len, seed, seed_len) == FAIL)
299     {
300         vim_free(state);
301         return NULL;
302     }
303     return state;
304 }
305 
306 /*
307  * Allocate a crypt state from a file header and initialize it.
308  * Assumes that header contains at least the number of bytes that
309  * crypt_get_header_len() returns for "method_nr".
310  */
311     cryptstate_T *
312 crypt_create_from_header(
313     int		method_nr,
314     char_u	*key,
315     char_u	*header)
316 {
317     char_u	*salt = NULL;
318     char_u	*seed = NULL;
319     int		salt_len = cryptmethods[method_nr].salt_len;
320     int		seed_len = cryptmethods[method_nr].seed_len;
321 
322     if (salt_len > 0)
323 	salt = header + CRYPT_MAGIC_LEN;
324     if (seed_len > 0)
325 	seed = header + CRYPT_MAGIC_LEN + salt_len;
326 
327     return crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
328 }
329 
330 /*
331  * Read the crypt method specific header data from "fp".
332  * Return an allocated cryptstate_T or NULL on error.
333  */
334     cryptstate_T *
335 crypt_create_from_file(FILE *fp, char_u *key)
336 {
337     int		method_nr;
338     int		header_len;
339     char	magic_buffer[CRYPT_MAGIC_LEN];
340     char_u	*buffer;
341     cryptstate_T *state;
342 
343     if (fread(magic_buffer, CRYPT_MAGIC_LEN, 1, fp) != 1)
344 	return NULL;
345     method_nr = crypt_method_nr_from_magic(magic_buffer, CRYPT_MAGIC_LEN);
346     if (method_nr < 0)
347 	return NULL;
348 
349     header_len = crypt_get_header_len(method_nr);
350     if ((buffer = alloc(header_len)) == NULL)
351 	return NULL;
352     mch_memmove(buffer, magic_buffer, CRYPT_MAGIC_LEN);
353     if (header_len > CRYPT_MAGIC_LEN
354 	    && fread(buffer + CRYPT_MAGIC_LEN,
355 				    header_len - CRYPT_MAGIC_LEN, 1, fp) != 1)
356     {
357 	vim_free(buffer);
358 	return NULL;
359     }
360 
361     state = crypt_create_from_header(method_nr, key, buffer);
362     vim_free(buffer);
363     return state;
364 }
365 
366 /*
367  * Allocate a cryptstate_T for writing and initialize it with "key".
368  * Allocates and fills in the header and stores it in "header", setting
369  * "header_len".  The header may include salt and seed, depending on
370  * cryptmethod.  Caller must free header.
371  * Returns the state or NULL on failure.
372  */
373     cryptstate_T *
374 crypt_create_for_writing(
375     int	    method_nr,
376     char_u  *key,
377     char_u  **header,
378     int	    *header_len)
379 {
380     int	    len = crypt_get_header_len(method_nr);
381     char_u  *salt = NULL;
382     char_u  *seed = NULL;
383     int	    salt_len = cryptmethods[method_nr].salt_len;
384     int	    seed_len = cryptmethods[method_nr].seed_len;
385     cryptstate_T *state;
386 
387     *header_len = len;
388     *header = alloc(len);
389     if (*header == NULL)
390 	return NULL;
391 
392     mch_memmove(*header, cryptmethods[method_nr].magic, CRYPT_MAGIC_LEN);
393     if (salt_len > 0 || seed_len > 0)
394     {
395 	if (salt_len > 0)
396 	    salt = *header + CRYPT_MAGIC_LEN;
397 	if (seed_len > 0)
398 	    seed = *header + CRYPT_MAGIC_LEN + salt_len;
399 
400 	// TODO: Should this be crypt method specific? (Probably not worth
401 	// it).  sha2_seed is pretty bad for large amounts of entropy, so make
402 	// that into something which is suitable for anything.
403 #ifdef FEAT_SODIUM
404 	if (sodium_init() >= 0)
405 	{
406 	    randombytes_buf(salt, salt_len);
407 	    randombytes_buf(seed, seed_len);
408 	}
409 	else
410 #endif
411 	    sha2_seed(salt, salt_len, seed, seed_len);
412     }
413     state = crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
414     if (state == NULL)
415 	VIM_CLEAR(*header);
416     return state;
417 }
418 
419 /*
420  * Free the crypt state.
421  */
422     void
423 crypt_free_state(cryptstate_T *state)
424 {
425 #ifdef FEAT_SODIUM
426     if (state->method_nr == CRYPT_M_SOD)
427     {
428 	sodium_memzero(state->method_state, sizeof(sodium_state_T));
429 	sodium_free(state->method_state);
430     }
431     else
432 #endif
433 	vim_free(state->method_state);
434     vim_free(state);
435 }
436 
437 #ifdef CRYPT_NOT_INPLACE
438 /*
439  * Encode "from[len]" and store the result in a newly allocated buffer, which
440  * is stored in "newptr".
441  * Return number of bytes in "newptr", 0 for need more or -1 on error.
442  */
443     long
444 crypt_encode_alloc(
445     cryptstate_T *state,
446     char_u	*from,
447     size_t	len,
448     char_u	**newptr,
449     int		last)
450 {
451     cryptmethod_T *method = &cryptmethods[state->method_nr];
452 
453     if (method->encode_buffer_fn != NULL)
454 	// Has buffer function, pass through.
455 	return method->encode_buffer_fn(state, from, len, newptr, last);
456     if (len == 0)
457 	// Not buffering, just return EOF.
458 	return (long)len;
459 
460     *newptr = alloc(len + 50);
461     if (*newptr == NULL)
462 	return -1;
463     method->encode_fn(state, from, len, *newptr, last);
464     return (long)len;
465 }
466 
467 /*
468  * Decrypt "ptr[len]" and store the result in a newly allocated buffer, which
469  * is stored in "newptr".
470  * Return number of bytes in "newptr", 0 for need more or -1 on error.
471  */
472     long
473 crypt_decode_alloc(
474     cryptstate_T *state,
475     char_u	*ptr,
476     long	len,
477     char_u      **newptr,
478     int		last)
479 {
480     cryptmethod_T *method = &cryptmethods[state->method_nr];
481 
482     if (method->decode_buffer_fn != NULL)
483 	// Has buffer function, pass through.
484 	return method->decode_buffer_fn(state, ptr, len, newptr, last);
485 
486     if (len == 0)
487 	// Not buffering, just return EOF.
488 	return len;
489 
490     *newptr = alloc(len);
491     if (*newptr == NULL)
492 	return -1;
493     method->decode_fn(state, ptr, len, *newptr, last);
494     return len;
495 }
496 #endif
497 
498 /*
499  * Encrypting "from[len]" into "to[len]".
500  */
501     void
502 crypt_encode(
503     cryptstate_T *state,
504     char_u	*from,
505     size_t	len,
506     char_u	*to,
507     int		last)
508 {
509     cryptmethods[state->method_nr].encode_fn(state, from, len, to, last);
510 }
511 
512 #if 0  // unused
513 /*
514  * decrypting "from[len]" into "to[len]".
515  */
516     void
517 crypt_decode(
518     cryptstate_T *state,
519     char_u	*from,
520     size_t	len,
521     char_u	*to,
522     int		last)
523 {
524     cryptmethods[state->method_nr].decode_fn(state, from, len, to, last);
525 }
526 #endif
527 
528 /*
529  * Simple inplace encryption, modifies "buf[len]" in place.
530  */
531     void
532 crypt_encode_inplace(
533     cryptstate_T *state,
534     char_u	*buf,
535     size_t	len,
536     int         last)
537 {
538     cryptmethods[state->method_nr].encode_inplace_fn(state, buf, len,
539 								    buf, last);
540 }
541 
542 /*
543  * Simple inplace decryption, modifies "buf[len]" in place.
544  */
545     void
546 crypt_decode_inplace(
547     cryptstate_T *state,
548     char_u	*buf,
549     size_t	len,
550     int		last)
551 {
552     cryptmethods[state->method_nr].decode_inplace_fn(state, buf, len,
553 								    buf, last);
554 }
555 
556 /*
557  * Free an allocated crypt key.  Clear the text to make sure it doesn't stay
558  * in memory anywhere.
559  */
560     void
561 crypt_free_key(char_u *key)
562 {
563     char_u *p;
564 
565     if (key != NULL)
566     {
567 	for (p = key; *p != NUL; ++p)
568 	    *p = 0;
569 	vim_free(key);
570     }
571 }
572 
573 /*
574  * Check the crypt method and give a warning if it's outdated.
575  */
576     void
577 crypt_check_method(int method)
578 {
579     if (method < CRYPT_M_BF2)
580     {
581 	msg_scroll = TRUE;
582 	msg(_("Warning: Using a weak encryption method; see :help 'cm'"));
583     }
584     if (method == CRYPT_M_SOD)
585     {
586 	// encryption uses padding and MAC, that does not work very well with
587 	// swap and undo files, so disable them
588 	mf_close_file(curbuf, TRUE);	// remove the swap file
589 	set_option_value((char_u *)"swf", 0, NULL, OPT_LOCAL);
590 #ifdef FEAT_PERSISTENT_UNDO
591 	set_option_value((char_u *)"udf", 0, NULL, OPT_LOCAL);
592 #endif
593 
594 	msg_scroll = TRUE;
595 	msg(_("Note: Encryption of swapfile not supported, disabling swap- and undofile"));
596     }
597 }
598 
599     void
600 crypt_check_current_method(void)
601 {
602     crypt_check_method(crypt_get_method_nr(curbuf));
603 }
604 
605 /*
606  * Ask the user for a crypt key.
607  * When "store" is TRUE, the new key is stored in the 'key' option, and the
608  * 'key' option value is returned: Don't free it.
609  * When "store" is FALSE, the typed key is returned in allocated memory.
610  * Returns NULL on failure.
611  */
612     char_u *
613 crypt_get_key(
614     int		store,
615     int		twice)	    // Ask for the key twice.
616 {
617     char_u	*p1, *p2 = NULL;
618     int		round;
619 
620     for (round = 0; ; ++round)
621     {
622 	cmdline_star = TRUE;
623 	cmdline_row = msg_row;
624 	p1 = getcmdline_prompt(NUL, round == 0
625 		? (char_u *)_("Enter encryption key: ")
626 		: (char_u *)_("Enter same key again: "), 0, EXPAND_NOTHING,
627 		NULL);
628 	cmdline_star = FALSE;
629 
630 	if (p1 == NULL)
631 	    break;
632 
633 	if (round == twice)
634 	{
635 	    if (p2 != NULL && STRCMP(p1, p2) != 0)
636 	    {
637 		msg(_("Keys don't match!"));
638 		crypt_free_key(p1);
639 		crypt_free_key(p2);
640 		p2 = NULL;
641 		round = -1;		// do it again
642 		continue;
643 	    }
644 
645 	    if (store)
646 	    {
647 		set_option_value((char_u *)"key", 0L, p1, OPT_LOCAL);
648 		crypt_free_key(p1);
649 		p1 = curbuf->b_p_key;
650 	    }
651 	    break;
652 	}
653 	p2 = p1;
654     }
655 
656     // since the user typed this, no need to wait for return
657     if (msg_didout)
658 	msg_putchar('\n');
659     need_wait_return = FALSE;
660     msg_didout = FALSE;
661 
662     crypt_free_key(p2);
663     return p1;
664 }
665 
666 
667 /*
668  * Append a message to IObuff for the encryption/decryption method being used.
669  */
670     void
671 crypt_append_msg(
672     buf_T *buf)
673 {
674     if (crypt_get_method_nr(buf) == 0)
675 	STRCAT(IObuff, _("[crypted]"));
676     else
677     {
678 	STRCAT(IObuff, "[");
679 	STRCAT(IObuff, *buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
680 	STRCAT(IObuff, "]");
681     }
682 }
683 
684     int
685 crypt_sodium_init(
686     cryptstate_T	*state UNUSED,
687     char_u		*key UNUSED,
688     char_u		*salt UNUSED,
689     int			salt_len UNUSED,
690     char_u		*seed UNUSED,
691     int			seed_len UNUSED)
692 {
693 # ifdef FEAT_SODIUM
694     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
695     unsigned char	dkey[crypto_box_SEEDBYTES]; // 32
696     sodium_state_T	*sd_state;
697 
698     if (sodium_init() < 0)
699 	return FAIL;
700 
701     sd_state = (sodium_state_T *)sodium_malloc(sizeof(sodium_state_T));
702     sodium_memzero(sd_state, sizeof(sodium_state_T));
703 
704     // derive a key from the password
705     if (crypto_pwhash(dkey, sizeof(dkey), (const char *)key, STRLEN(key), salt,
706 	crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE,
707 	crypto_pwhash_ALG_DEFAULT) != 0)
708     {
709 	// out of memory
710 	sodium_free(sd_state);
711 	return FAIL;
712     }
713     memcpy(sd_state->key, dkey, crypto_box_SEEDBYTES);
714     sd_state->count = 0;
715     state->method_state = sd_state;
716 
717     return OK;
718 # else
719     emsg(e_libsodium_not_built_in);
720     return FAIL;
721 # endif
722 }
723 
724 /*
725  * Encrypt "from[len]" into "to[len]".
726  * "from" and "to" can be equal to encrypt in place.
727  * Call needs to ensure that there is enough space in to (for the header)
728  */
729     void
730 crypt_sodium_encode(
731     cryptstate_T *state UNUSED,
732     char_u	*from UNUSED,
733     size_t	len UNUSED,
734     char_u	*to UNUSED,
735     int		last UNUSED)
736 {
737 # ifdef FEAT_SODIUM
738     // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
739     sodium_state_T *sod_st = state->method_state;
740     unsigned char  tag = last
741 			? crypto_secretstream_xchacha20poly1305_TAG_FINAL  : 0;
742 
743     if (sod_st->count == 0)
744     {
745 	if (len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES)
746 	{
747 	    emsg(e_libsodium_cannot_encrypt_header);
748 	    return;
749 	}
750 	crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state,
751 							      to, sod_st->key);
752 	to += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
753     }
754 
755     if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES)
756     {
757 	emsg(e_libsodium_cannot_encrypt_buffer);
758 	return;
759     }
760 
761     crypto_secretstream_xchacha20poly1305_push(&sod_st->state, to, NULL,
762 						      from, len, NULL, 0, tag);
763 
764     sod_st->count++;
765 # endif
766 }
767 
768 /* TODO: Unused
769  * Decrypt "from[len]" into "to[len]".
770  * "from" and "to" can be equal to encrypt in place.
771  */
772     void
773 crypt_sodium_decode(
774     cryptstate_T *state UNUSED,
775     char_u	*from UNUSED,
776     size_t	len UNUSED,
777     char_u	*to UNUSED,
778     int		last UNUSED)
779 {
780 # ifdef FEAT_SODIUM
781     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
782     sodium_state_T *sod_st = state->method_state;
783     unsigned char  tag;
784     unsigned long long buf_len;
785     char_u *p1 = from;
786     char_u *p2 = to;
787     char_u *buf_out;
788 
789     if (sod_st->count == 0
790 		   && len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES)
791     {
792 	emsg(e_libsodium_cannot_decrypt_header);
793 	return;
794     }
795 
796     buf_out = (char_u *)alloc(len);
797 
798     if (buf_out == NULL)
799     {
800 	emsg(e_libsodium_cannot_allocate_buffer);
801 	return;
802     }
803     if (sod_st->count == 0)
804     {
805 	if (crypto_secretstream_xchacha20poly1305_init_pull(
806 				       &sod_st->state, from, sod_st->key) != 0)
807 	{
808 	    emsg(e_libsodium_decryption_failed_header_incomplete);
809 	    goto fail;
810 	}
811 
812 	from += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
813 	len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES;
814 
815 	if (p1 == p2)
816 	    to += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
817     }
818 
819     if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES)
820     {
821 	emsg(e_libsodium_cannot_decrypt_buffer);
822 	goto fail;
823     }
824     if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state,
825 			     buf_out, &buf_len, &tag, from, len, NULL, 0) != 0)
826     {
827 	emsg(e_libsodium_decryption_failed);
828 	goto fail;
829     }
830     sod_st->count++;
831 
832     if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last)
833     {
834 	emsg(e_libsodium_decryption_failed_premature);
835 	goto fail;
836     }
837     if (p1 == p2)
838 	mch_memmove(p2, buf_out, buf_len);
839 
840 fail:
841     vim_free(buf_out);
842 # endif
843 }
844 
845 /*
846  * Encrypt "from[len]" into "to[len]".
847  * "from" and "to" can be equal to encrypt in place.
848  */
849     long
850 crypt_sodium_buffer_encode(
851     cryptstate_T *state UNUSED,
852     char_u	*from UNUSED,
853     size_t	len UNUSED,
854     char_u	**buf_out UNUSED,
855     int		last UNUSED)
856 {
857 # ifdef FEAT_SODIUM
858     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
859     unsigned long long	out_len;
860     char_u		*ptr;
861     unsigned char	tag = last
862 			? crypto_secretstream_xchacha20poly1305_TAG_FINAL  : 0;
863     int			length;
864     sodium_state_T	*sod_st = state->method_state;
865     int			first = (sod_st->count == 0);
866 
867     length = len + crypto_secretstream_xchacha20poly1305_ABYTES
868 	     + (first ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0);
869     *buf_out = alloc_clear(length);
870     if (*buf_out == NULL)
871     {
872 	emsg(e_libsodium_cannot_allocate_buffer);
873 	return -1;
874     }
875     ptr = *buf_out;
876 
877     if (first)
878     {
879 	crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state,
880 		ptr, sod_st->key);
881 	ptr += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
882     }
883 
884     crypto_secretstream_xchacha20poly1305_push(&sod_st->state, ptr,
885 	    &out_len, from, len, NULL, 0, tag);
886 
887     sod_st->count++;
888     return out_len + (first
889 		      ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0);
890 # else
891     return -1;
892 # endif
893 }
894 
895 /*
896  * Decrypt "from[len]" into "to[len]".
897  * "from" and "to" can be equal to encrypt in place.
898  */
899     long
900 crypt_sodium_buffer_decode(
901     cryptstate_T *state UNUSED,
902     char_u	*from UNUSED,
903     size_t	len UNUSED,
904     char_u	**buf_out UNUSED,
905     int		last UNUSED)
906 {
907 # ifdef FEAT_SODIUM
908     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
909     sodium_state_T *sod_st = state->method_state;
910     unsigned char  tag;
911     unsigned long long out_len;
912     *buf_out = alloc_clear(len);
913     if (*buf_out == NULL)
914     {
915 	emsg(e_libsodium_cannot_allocate_buffer);
916 	return -1;
917     }
918 
919     if (sod_st->count == 0)
920     {
921 	if (crypto_secretstream_xchacha20poly1305_init_pull(&sod_st->state,
922 						       from, sod_st->key) != 0)
923 	{
924 	    emsg(e_libsodium_decryption_failed_header_incomplete);
925 	    return -1;
926 	}
927 	from += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
928 	len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES;
929 	sod_st->count++;
930     }
931     if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state,
932 			    *buf_out, &out_len, &tag, from, len, NULL, 0) != 0)
933     {
934 	emsg(e_libsodium_decryption_failed);
935 	return -1;
936     }
937 
938     if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last)
939 	emsg(e_libsodium_decryption_failed_premature);
940     return (long) out_len;
941 # else
942     return -1;
943 # endif
944 }
945 
946 #endif // FEAT_CRYPT
947