xref: /vim-8.2.3635/src/crypt.c (revision 8a4c812e)
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 	NULL, NULL,
150 	crypt_sodium_buffer_encode, crypt_sodium_buffer_decode,
151 	NULL, NULL,
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 /*
255  * Get maximum crypt method specific length of the file header in bytes.
256  */
257     int
258 crypt_get_max_header_len()
259 {
260     int i;
261     int max = 0;
262     int temp = 0;
263 
264     for (i = 0; i < CRYPT_M_COUNT; ++i)
265     {
266 	temp = crypt_get_header_len(i);
267 	if (temp > max)
268 	    max = temp;
269     }
270     return max;
271 }
272 
273 /*
274  * Set the crypt method for buffer "buf" to "method_nr" using the int value as
275  * returned by crypt_method_nr_from_name().
276  */
277     void
278 crypt_set_cm_option(buf_T *buf, int method_nr)
279 {
280     free_string_option(buf->b_p_cm);
281     buf->b_p_cm = vim_strsave((char_u *)cryptmethods[method_nr].name);
282 }
283 
284 /*
285  * If the crypt method for the current buffer has a self-test, run it and
286  * return OK/FAIL.
287  */
288     int
289 crypt_self_test(void)
290 {
291     int method_nr = crypt_get_method_nr(curbuf);
292 
293     if (cryptmethods[method_nr].self_test_fn == NULL)
294 	return OK;
295     return cryptmethods[method_nr].self_test_fn();
296 }
297 
298 /*
299  * Allocate a crypt state and initialize it.
300  * Return NULL for failure.
301  */
302     cryptstate_T *
303 crypt_create(
304     int		method_nr,
305     char_u	*key,
306     char_u	*salt,
307     int		salt_len,
308     char_u	*seed,
309     int		seed_len)
310 {
311     cryptstate_T *state = ALLOC_ONE(cryptstate_T);
312 
313     if (state == NULL)
314 	return state;
315 
316     state->method_nr = method_nr;
317     if (cryptmethods[method_nr].init_fn(
318 	state, key, salt, salt_len, seed, seed_len) == FAIL)
319     {
320         vim_free(state);
321         return NULL;
322     }
323     return state;
324 }
325 
326 /*
327  * Allocate a crypt state from a file header and initialize it.
328  * Assumes that header contains at least the number of bytes that
329  * crypt_get_header_len() returns for "method_nr".
330  */
331     cryptstate_T *
332 crypt_create_from_header(
333     int		method_nr,
334     char_u	*key,
335     char_u	*header)
336 {
337     char_u	*salt = NULL;
338     char_u	*seed = NULL;
339     int		salt_len = cryptmethods[method_nr].salt_len;
340     int		seed_len = cryptmethods[method_nr].seed_len;
341 
342     if (salt_len > 0)
343 	salt = header + CRYPT_MAGIC_LEN;
344     if (seed_len > 0)
345 	seed = header + CRYPT_MAGIC_LEN + salt_len;
346 
347     return crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
348 }
349 
350 /*
351  * Read the crypt method specific header data from "fp".
352  * Return an allocated cryptstate_T or NULL on error.
353  */
354     cryptstate_T *
355 crypt_create_from_file(FILE *fp, char_u *key)
356 {
357     int		method_nr;
358     int		header_len;
359     char	magic_buffer[CRYPT_MAGIC_LEN];
360     char_u	*buffer;
361     cryptstate_T *state;
362 
363     if (fread(magic_buffer, CRYPT_MAGIC_LEN, 1, fp) != 1)
364 	return NULL;
365     method_nr = crypt_method_nr_from_magic(magic_buffer, CRYPT_MAGIC_LEN);
366     if (method_nr < 0)
367 	return NULL;
368 
369     header_len = crypt_get_header_len(method_nr);
370     if ((buffer = alloc(header_len)) == NULL)
371 	return NULL;
372     mch_memmove(buffer, magic_buffer, CRYPT_MAGIC_LEN);
373     if (header_len > CRYPT_MAGIC_LEN
374 	    && fread(buffer + CRYPT_MAGIC_LEN,
375 				    header_len - CRYPT_MAGIC_LEN, 1, fp) != 1)
376     {
377 	vim_free(buffer);
378 	return NULL;
379     }
380 
381     state = crypt_create_from_header(method_nr, key, buffer);
382     vim_free(buffer);
383     return state;
384 }
385 
386 /*
387  * Allocate a cryptstate_T for writing and initialize it with "key".
388  * Allocates and fills in the header and stores it in "header", setting
389  * "header_len".  The header may include salt and seed, depending on
390  * cryptmethod.  Caller must free header.
391  * Returns the state or NULL on failure.
392  */
393     cryptstate_T *
394 crypt_create_for_writing(
395     int	    method_nr,
396     char_u  *key,
397     char_u  **header,
398     int	    *header_len)
399 {
400     int	    len = crypt_get_header_len(method_nr);
401     char_u  *salt = NULL;
402     char_u  *seed = NULL;
403     int	    salt_len = cryptmethods[method_nr].salt_len;
404     int	    seed_len = cryptmethods[method_nr].seed_len;
405     cryptstate_T *state;
406 
407     *header_len = len;
408     *header = alloc(len);
409     if (*header == NULL)
410 	return NULL;
411 
412     mch_memmove(*header, cryptmethods[method_nr].magic, CRYPT_MAGIC_LEN);
413     if (salt_len > 0 || seed_len > 0)
414     {
415 	if (salt_len > 0)
416 	    salt = *header + CRYPT_MAGIC_LEN;
417 	if (seed_len > 0)
418 	    seed = *header + CRYPT_MAGIC_LEN + salt_len;
419 
420 	// TODO: Should this be crypt method specific? (Probably not worth
421 	// it).  sha2_seed is pretty bad for large amounts of entropy, so make
422 	// that into something which is suitable for anything.
423 #ifdef FEAT_SODIUM
424 	if (sodium_init() >= 0)
425 	{
426 	    if (salt_len > 0)
427 		randombytes_buf(salt, salt_len);
428 	    if (seed_len > 0)
429 		randombytes_buf(seed, seed_len);
430 	}
431 	else
432 #endif
433 	    sha2_seed(salt, salt_len, seed, seed_len);
434     }
435     state = crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
436     if (state == NULL)
437 	VIM_CLEAR(*header);
438     return state;
439 }
440 
441 /*
442  * Free the crypt state.
443  */
444     void
445 crypt_free_state(cryptstate_T *state)
446 {
447 #ifdef FEAT_SODIUM
448     if (state->method_nr == CRYPT_M_SOD)
449     {
450 	sodium_memzero(state->method_state, sizeof(sodium_state_T));
451 	sodium_free(state->method_state);
452     }
453     else
454 #endif
455 	vim_free(state->method_state);
456     vim_free(state);
457 }
458 
459 #ifdef CRYPT_NOT_INPLACE
460 /*
461  * Encode "from[len]" and store the result in a newly allocated buffer, which
462  * is stored in "newptr".
463  * Return number of bytes in "newptr", 0 for need more or -1 on error.
464  */
465     long
466 crypt_encode_alloc(
467     cryptstate_T *state,
468     char_u	*from,
469     size_t	len,
470     char_u	**newptr,
471     int		last)
472 {
473     cryptmethod_T *method = &cryptmethods[state->method_nr];
474 
475     if (method->encode_buffer_fn != NULL)
476 	// Has buffer function, pass through.
477 	return method->encode_buffer_fn(state, from, len, newptr, last);
478     if (len == 0)
479 	// Not buffering, just return EOF.
480 	return (long)len;
481 
482     *newptr = alloc(len + 50);
483     if (*newptr == NULL)
484 	return -1;
485     method->encode_fn(state, from, len, *newptr, last);
486     return (long)len;
487 }
488 
489 /*
490  * Decrypt "ptr[len]" and store the result in a newly allocated buffer, which
491  * is stored in "newptr".
492  * Return number of bytes in "newptr", 0 for need more or -1 on error.
493  */
494     long
495 crypt_decode_alloc(
496     cryptstate_T *state,
497     char_u	*ptr,
498     long	len,
499     char_u      **newptr,
500     int		last)
501 {
502     cryptmethod_T *method = &cryptmethods[state->method_nr];
503 
504     if (method->decode_buffer_fn != NULL)
505 	// Has buffer function, pass through.
506 	return method->decode_buffer_fn(state, ptr, len, newptr, last);
507 
508     if (len == 0)
509 	// Not buffering, just return EOF.
510 	return len;
511 
512     *newptr = alloc(len);
513     if (*newptr == NULL)
514 	return -1;
515     method->decode_fn(state, ptr, len, *newptr, last);
516     return len;
517 }
518 #endif
519 
520 /*
521  * Encrypting "from[len]" into "to[len]".
522  */
523     void
524 crypt_encode(
525     cryptstate_T *state,
526     char_u	*from,
527     size_t	len,
528     char_u	*to,
529     int		last)
530 {
531     cryptmethods[state->method_nr].encode_fn(state, from, len, to, last);
532 }
533 
534 #if 0  // unused
535 /*
536  * decrypting "from[len]" into "to[len]".
537  */
538     void
539 crypt_decode(
540     cryptstate_T *state,
541     char_u	*from,
542     size_t	len,
543     char_u	*to,
544     int		last)
545 {
546     cryptmethods[state->method_nr].decode_fn(state, from, len, to, last);
547 }
548 #endif
549 
550 /*
551  * Simple inplace encryption, modifies "buf[len]" in place.
552  */
553     void
554 crypt_encode_inplace(
555     cryptstate_T *state,
556     char_u	*buf,
557     size_t	len,
558     int         last)
559 {
560     cryptmethods[state->method_nr].encode_inplace_fn(state, buf, len,
561 								    buf, last);
562 }
563 
564 /*
565  * Simple inplace decryption, modifies "buf[len]" in place.
566  */
567     void
568 crypt_decode_inplace(
569     cryptstate_T *state,
570     char_u	*buf,
571     size_t	len,
572     int		last)
573 {
574     cryptmethods[state->method_nr].decode_inplace_fn(state, buf, len,
575 								    buf, last);
576 }
577 
578 /*
579  * Free an allocated crypt key.  Clear the text to make sure it doesn't stay
580  * in memory anywhere.
581  */
582     void
583 crypt_free_key(char_u *key)
584 {
585     char_u *p;
586 
587     if (key != NULL)
588     {
589 	for (p = key; *p != NUL; ++p)
590 	    *p = 0;
591 	vim_free(key);
592     }
593 }
594 
595 /*
596  * Check the crypt method and give a warning if it's outdated.
597  */
598     void
599 crypt_check_method(int method)
600 {
601     if (method < CRYPT_M_BF2)
602     {
603 	msg_scroll = TRUE;
604 	msg(_("Warning: Using a weak encryption method; see :help 'cm'"));
605     }
606 }
607 
608 #ifdef FEAT_SODIUM
609     static void
610 crypt_check_swapfile_curbuf(void)
611 {
612     int method = crypt_get_method_nr(curbuf);
613     if (method == CRYPT_M_SOD)
614     {
615 	// encryption uses padding and MAC, that does not work very well with
616 	// swap and undo files, so disable them
617 	mf_close_file(curbuf, TRUE);	// remove the swap file
618 	set_option_value((char_u *)"swf", 0, NULL, OPT_LOCAL);
619 	msg_scroll = TRUE;
620 	msg(_("Note: Encryption of swapfile not supported, disabling swap file"));
621     }
622 }
623 #endif
624 
625     void
626 crypt_check_current_method(void)
627 {
628     crypt_check_method(crypt_get_method_nr(curbuf));
629 }
630 
631 /*
632  * Ask the user for a crypt key.
633  * When "store" is TRUE, the new key is stored in the 'key' option, and the
634  * 'key' option value is returned: Don't free it.
635  * When "store" is FALSE, the typed key is returned in allocated memory.
636  * Returns NULL on failure.
637  */
638     char_u *
639 crypt_get_key(
640     int		store,
641     int		twice)	    // Ask for the key twice.
642 {
643     char_u	*p1, *p2 = NULL;
644     int		round;
645 
646     for (round = 0; ; ++round)
647     {
648 	cmdline_star = TRUE;
649 	cmdline_row = msg_row;
650 	p1 = getcmdline_prompt(NUL, round == 0
651 		? (char_u *)_("Enter encryption key: ")
652 		: (char_u *)_("Enter same key again: "), 0, EXPAND_NOTHING,
653 		NULL);
654 	cmdline_star = FALSE;
655 
656 	if (p1 == NULL)
657 	    break;
658 
659 	if (round == twice)
660 	{
661 	    if (p2 != NULL && STRCMP(p1, p2) != 0)
662 	    {
663 		msg(_("Keys don't match!"));
664 		crypt_free_key(p1);
665 		crypt_free_key(p2);
666 		p2 = NULL;
667 		round = -1;		// do it again
668 		continue;
669 	    }
670 
671 	    if (store)
672 	    {
673 		set_option_value((char_u *)"key", 0L, p1, OPT_LOCAL);
674 		crypt_free_key(p1);
675 		p1 = curbuf->b_p_key;
676 #ifdef FEAT_SODIUM
677 		crypt_check_swapfile_curbuf();
678 #endif
679 	    }
680 	    break;
681 	}
682 	p2 = p1;
683     }
684 
685     // since the user typed this, no need to wait for return
686     if (crypt_get_method_nr(curbuf) != CRYPT_M_SOD)
687     {
688 	if (msg_didout)
689 	    msg_putchar('\n');
690 	need_wait_return = FALSE;
691 	msg_didout = FALSE;
692     }
693 
694     crypt_free_key(p2);
695     return p1;
696 }
697 
698 
699 /*
700  * Append a message to IObuff for the encryption/decryption method being used.
701  */
702     void
703 crypt_append_msg(
704     buf_T *buf)
705 {
706     if (crypt_get_method_nr(buf) == 0)
707 	STRCAT(IObuff, _("[crypted]"));
708     else
709     {
710 	STRCAT(IObuff, "[");
711 	STRCAT(IObuff, *buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
712 	STRCAT(IObuff, "]");
713     }
714 }
715 
716     int
717 crypt_sodium_init(
718     cryptstate_T	*state UNUSED,
719     char_u		*key UNUSED,
720     char_u		*salt UNUSED,
721     int			salt_len UNUSED,
722     char_u		*seed UNUSED,
723     int			seed_len UNUSED)
724 {
725 # ifdef FEAT_SODIUM
726     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
727     unsigned char	dkey[crypto_box_SEEDBYTES]; // 32
728     sodium_state_T	*sd_state;
729 
730     if (sodium_init() < 0)
731 	return FAIL;
732 
733     sd_state = (sodium_state_T *)sodium_malloc(sizeof(sodium_state_T));
734     sodium_memzero(sd_state, sizeof(sodium_state_T));
735 
736     // derive a key from the password
737     if (crypto_pwhash(dkey, sizeof(dkey), (const char *)key, STRLEN(key), salt,
738 	crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE,
739 	crypto_pwhash_ALG_DEFAULT) != 0)
740     {
741 	// out of memory
742 	sodium_free(sd_state);
743 	return FAIL;
744     }
745     memcpy(sd_state->key, dkey, crypto_box_SEEDBYTES);
746     sd_state->count = 0;
747     state->method_state = sd_state;
748 
749     return OK;
750 # else
751     emsg(e_libsodium_not_built_in);
752     return FAIL;
753 # endif
754 }
755 
756 /*
757  * Encrypt "from[len]" into "to[len]".
758  * "from" and "to" can be equal to encrypt in place.
759  * Call needs to ensure that there is enough space in to (for the header)
760  */
761 #if 0  // Currently unused
762     void
763 crypt_sodium_encode(
764     cryptstate_T *state UNUSED,
765     char_u	*from UNUSED,
766     size_t	len UNUSED,
767     char_u	*to UNUSED,
768     int		last UNUSED)
769 {
770 # ifdef FEAT_SODIUM
771     // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
772     sodium_state_T *sod_st = state->method_state;
773     unsigned char  tag = last
774 			? crypto_secretstream_xchacha20poly1305_TAG_FINAL  : 0;
775 
776     if (sod_st->count == 0)
777     {
778 	if (len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES)
779 	{
780 	    emsg(e_libsodium_cannot_encrypt_header);
781 	    return;
782 	}
783 	crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state,
784 							      to, sod_st->key);
785 	to += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
786     }
787 
788     if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES)
789     {
790 	emsg(e_libsodium_cannot_encrypt_buffer);
791 	return;
792     }
793 
794     crypto_secretstream_xchacha20poly1305_push(&sod_st->state, to, NULL,
795 						      from, len, NULL, 0, tag);
796 
797     sod_st->count++;
798 # endif
799 }
800 #endif
801 
802 /*
803  * Decrypt "from[len]" into "to[len]".
804  * "from" and "to" can be equal to encrypt in place.
805  */
806 #if 0  // Currently unused
807     void
808 crypt_sodium_decode(
809     cryptstate_T *state UNUSED,
810     char_u	*from UNUSED,
811     size_t	len UNUSED,
812     char_u	*to UNUSED,
813     int		last UNUSED)
814 {
815 # ifdef FEAT_SODIUM
816     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
817     sodium_state_T *sod_st = state->method_state;
818     unsigned char  tag;
819     unsigned long long buf_len;
820     char_u *p1 = from;
821     char_u *p2 = to;
822     char_u *buf_out;
823 
824     if (sod_st->count == 0
825 		   && len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES)
826     {
827 	emsg(e_libsodium_cannot_decrypt_header);
828 	return;
829     }
830 
831     buf_out = (char_u *)alloc(len);
832 
833     if (buf_out == NULL)
834     {
835 	emsg(e_libsodium_cannot_allocate_buffer);
836 	return;
837     }
838     if (sod_st->count == 0)
839     {
840 	if (crypto_secretstream_xchacha20poly1305_init_pull(
841 				       &sod_st->state, from, sod_st->key) != 0)
842 	{
843 	    emsg(e_libsodium_decryption_failed_header_incomplete);
844 	    goto fail;
845 	}
846 
847 	from += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
848 	len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES;
849 
850 	if (p1 == p2)
851 	    to += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
852     }
853 
854     if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES)
855     {
856 	emsg(e_libsodium_cannot_decrypt_buffer);
857 	goto fail;
858     }
859     if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state,
860 			     buf_out, &buf_len, &tag, from, len, NULL, 0) != 0)
861     {
862 	emsg(e_libsodium_decryption_failed);
863 	goto fail;
864     }
865     sod_st->count++;
866 
867     if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last)
868     {
869 	emsg(e_libsodium_decryption_failed_premature);
870 	goto fail;
871     }
872     if (p1 == p2)
873 	mch_memmove(p2, buf_out, buf_len);
874 
875 fail:
876     vim_free(buf_out);
877 # endif
878 }
879 #endif
880 
881 /*
882  * Encrypt "from[len]" into "to[len]".
883  * "from" and "to" can be equal to encrypt in place.
884  */
885     long
886 crypt_sodium_buffer_encode(
887     cryptstate_T *state UNUSED,
888     char_u	*from UNUSED,
889     size_t	len UNUSED,
890     char_u	**buf_out UNUSED,
891     int		last UNUSED)
892 {
893 # ifdef FEAT_SODIUM
894     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
895     unsigned long long	out_len;
896     char_u		*ptr;
897     unsigned char	tag = last
898 			? crypto_secretstream_xchacha20poly1305_TAG_FINAL  : 0;
899     int			length;
900     sodium_state_T	*sod_st = state->method_state;
901     int			first = (sod_st->count == 0);
902 
903     length = (int)len + crypto_secretstream_xchacha20poly1305_ABYTES
904 	     + (first ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0);
905     *buf_out = alloc_clear(length);
906     if (*buf_out == NULL)
907     {
908 	emsg(e_libsodium_cannot_allocate_buffer);
909 	return -1;
910     }
911     ptr = *buf_out;
912 
913     if (first)
914     {
915 	crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state,
916 		ptr, sod_st->key);
917 	ptr += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
918     }
919 
920     crypto_secretstream_xchacha20poly1305_push(&sod_st->state, ptr,
921 	    &out_len, from, len, NULL, 0, tag);
922 
923     sod_st->count++;
924     return out_len + (first
925 		      ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0);
926 # else
927     return -1;
928 # endif
929 }
930 
931 /*
932  * Decrypt "from[len]" into "to[len]".
933  * "from" and "to" can be equal to encrypt in place.
934  */
935     long
936 crypt_sodium_buffer_decode(
937     cryptstate_T *state UNUSED,
938     char_u	*from UNUSED,
939     size_t	len UNUSED,
940     char_u	**buf_out UNUSED,
941     int		last UNUSED)
942 {
943 # ifdef FEAT_SODIUM
944     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
945     sodium_state_T *sod_st = state->method_state;
946     unsigned char  tag;
947     unsigned long long out_len;
948     *buf_out = alloc_clear(len);
949     if (*buf_out == NULL)
950     {
951 	emsg(e_libsodium_cannot_allocate_buffer);
952 	return -1;
953     }
954 
955     if (sod_st->count == 0)
956     {
957 	if (crypto_secretstream_xchacha20poly1305_init_pull(&sod_st->state,
958 						       from, sod_st->key) != 0)
959 	{
960 	    emsg(e_libsodium_decryption_failed_header_incomplete);
961 	    return -1;
962 	}
963 	from += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
964 	len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES;
965 	sod_st->count++;
966     }
967     if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state,
968 			    *buf_out, &out_len, &tag, from, len, NULL, 0) != 0)
969     {
970 	emsg(e_libsodium_decryption_failed);
971 	return -1;
972     }
973 
974     if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last)
975 	emsg(e_libsodium_decryption_failed_premature);
976     return (long) out_len;
977 # else
978     return -1;
979 # endif
980 }
981 
982 #endif // FEAT_CRYPT
983