xref: /vim-8.2.3635/src/crypt.c (revision f3caeb63)
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 #ifdef FEAT_PERSISTENT_UNDO
620 	set_option_value((char_u *)"udf", 0, NULL, OPT_LOCAL);
621 #endif
622 	msg_scroll = TRUE;
623 	msg(_("Note: Encryption of swapfile not supported, disabling swap- and undofile"));
624     }
625 }
626 #endif
627 
628     void
629 crypt_check_current_method(void)
630 {
631     crypt_check_method(crypt_get_method_nr(curbuf));
632 }
633 
634 /*
635  * Ask the user for a crypt key.
636  * When "store" is TRUE, the new key is stored in the 'key' option, and the
637  * 'key' option value is returned: Don't free it.
638  * When "store" is FALSE, the typed key is returned in allocated memory.
639  * Returns NULL on failure.
640  */
641     char_u *
642 crypt_get_key(
643     int		store,
644     int		twice)	    // Ask for the key twice.
645 {
646     char_u	*p1, *p2 = NULL;
647     int		round;
648 
649     for (round = 0; ; ++round)
650     {
651 	cmdline_star = TRUE;
652 	cmdline_row = msg_row;
653 	p1 = getcmdline_prompt(NUL, round == 0
654 		? (char_u *)_("Enter encryption key: ")
655 		: (char_u *)_("Enter same key again: "), 0, EXPAND_NOTHING,
656 		NULL);
657 	cmdline_star = FALSE;
658 
659 	if (p1 == NULL)
660 	    break;
661 
662 	if (round == twice)
663 	{
664 	    if (p2 != NULL && STRCMP(p1, p2) != 0)
665 	    {
666 		msg(_("Keys don't match!"));
667 		crypt_free_key(p1);
668 		crypt_free_key(p2);
669 		p2 = NULL;
670 		round = -1;		// do it again
671 		continue;
672 	    }
673 
674 	    if (store)
675 	    {
676 		set_option_value((char_u *)"key", 0L, p1, OPT_LOCAL);
677 		crypt_free_key(p1);
678 		p1 = curbuf->b_p_key;
679 #ifdef FEAT_SODIUM
680 		crypt_check_swapfile_curbuf();
681 #endif
682 	    }
683 	    break;
684 	}
685 	p2 = p1;
686     }
687 
688     // since the user typed this, no need to wait for return
689     if (crypt_get_method_nr(curbuf) != CRYPT_M_SOD)
690     {
691 	if (msg_didout)
692 	    msg_putchar('\n');
693 	need_wait_return = FALSE;
694 	msg_didout = FALSE;
695     }
696 
697     crypt_free_key(p2);
698     return p1;
699 }
700 
701 
702 /*
703  * Append a message to IObuff for the encryption/decryption method being used.
704  */
705     void
706 crypt_append_msg(
707     buf_T *buf)
708 {
709     if (crypt_get_method_nr(buf) == 0)
710 	STRCAT(IObuff, _("[crypted]"));
711     else
712     {
713 	STRCAT(IObuff, "[");
714 	STRCAT(IObuff, *buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
715 	STRCAT(IObuff, "]");
716     }
717 }
718 
719     int
720 crypt_sodium_init(
721     cryptstate_T	*state UNUSED,
722     char_u		*key UNUSED,
723     char_u		*salt UNUSED,
724     int			salt_len UNUSED,
725     char_u		*seed UNUSED,
726     int			seed_len UNUSED)
727 {
728 # ifdef FEAT_SODIUM
729     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
730     unsigned char	dkey[crypto_box_SEEDBYTES]; // 32
731     sodium_state_T	*sd_state;
732 
733     if (sodium_init() < 0)
734 	return FAIL;
735 
736     sd_state = (sodium_state_T *)sodium_malloc(sizeof(sodium_state_T));
737     sodium_memzero(sd_state, sizeof(sodium_state_T));
738 
739     // derive a key from the password
740     if (crypto_pwhash(dkey, sizeof(dkey), (const char *)key, STRLEN(key), salt,
741 	crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE,
742 	crypto_pwhash_ALG_DEFAULT) != 0)
743     {
744 	// out of memory
745 	sodium_free(sd_state);
746 	return FAIL;
747     }
748     memcpy(sd_state->key, dkey, crypto_box_SEEDBYTES);
749     sd_state->count = 0;
750     state->method_state = sd_state;
751 
752     return OK;
753 # else
754     emsg(e_libsodium_not_built_in);
755     return FAIL;
756 # endif
757 }
758 
759 /*
760  * Encrypt "from[len]" into "to[len]".
761  * "from" and "to" can be equal to encrypt in place.
762  * Call needs to ensure that there is enough space in to (for the header)
763  */
764 #if 0  // Currently unused
765     void
766 crypt_sodium_encode(
767     cryptstate_T *state UNUSED,
768     char_u	*from UNUSED,
769     size_t	len UNUSED,
770     char_u	*to UNUSED,
771     int		last UNUSED)
772 {
773 # ifdef FEAT_SODIUM
774     // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
775     sodium_state_T *sod_st = state->method_state;
776     unsigned char  tag = last
777 			? crypto_secretstream_xchacha20poly1305_TAG_FINAL  : 0;
778 
779     if (sod_st->count == 0)
780     {
781 	if (len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES)
782 	{
783 	    emsg(e_libsodium_cannot_encrypt_header);
784 	    return;
785 	}
786 	crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state,
787 							      to, sod_st->key);
788 	to += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
789     }
790 
791     if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES)
792     {
793 	emsg(e_libsodium_cannot_encrypt_buffer);
794 	return;
795     }
796 
797     crypto_secretstream_xchacha20poly1305_push(&sod_st->state, to, NULL,
798 						      from, len, NULL, 0, tag);
799 
800     sod_st->count++;
801 # endif
802 }
803 #endif
804 
805 /*
806  * Decrypt "from[len]" into "to[len]".
807  * "from" and "to" can be equal to encrypt in place.
808  */
809 #if 0  // Currently unused
810     void
811 crypt_sodium_decode(
812     cryptstate_T *state UNUSED,
813     char_u	*from UNUSED,
814     size_t	len UNUSED,
815     char_u	*to UNUSED,
816     int		last UNUSED)
817 {
818 # ifdef FEAT_SODIUM
819     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
820     sodium_state_T *sod_st = state->method_state;
821     unsigned char  tag;
822     unsigned long long buf_len;
823     char_u *p1 = from;
824     char_u *p2 = to;
825     char_u *buf_out;
826 
827     if (sod_st->count == 0
828 		   && len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES)
829     {
830 	emsg(e_libsodium_cannot_decrypt_header);
831 	return;
832     }
833 
834     buf_out = (char_u *)alloc(len);
835 
836     if (buf_out == NULL)
837     {
838 	emsg(e_libsodium_cannot_allocate_buffer);
839 	return;
840     }
841     if (sod_st->count == 0)
842     {
843 	if (crypto_secretstream_xchacha20poly1305_init_pull(
844 				       &sod_st->state, from, sod_st->key) != 0)
845 	{
846 	    emsg(e_libsodium_decryption_failed_header_incomplete);
847 	    goto fail;
848 	}
849 
850 	from += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
851 	len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES;
852 
853 	if (p1 == p2)
854 	    to += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
855     }
856 
857     if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES)
858     {
859 	emsg(e_libsodium_cannot_decrypt_buffer);
860 	goto fail;
861     }
862     if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state,
863 			     buf_out, &buf_len, &tag, from, len, NULL, 0) != 0)
864     {
865 	emsg(e_libsodium_decryption_failed);
866 	goto fail;
867     }
868     sod_st->count++;
869 
870     if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last)
871     {
872 	emsg(e_libsodium_decryption_failed_premature);
873 	goto fail;
874     }
875     if (p1 == p2)
876 	mch_memmove(p2, buf_out, buf_len);
877 
878 fail:
879     vim_free(buf_out);
880 # endif
881 }
882 #endif
883 
884 /*
885  * Encrypt "from[len]" into "to[len]".
886  * "from" and "to" can be equal to encrypt in place.
887  */
888     long
889 crypt_sodium_buffer_encode(
890     cryptstate_T *state UNUSED,
891     char_u	*from UNUSED,
892     size_t	len UNUSED,
893     char_u	**buf_out UNUSED,
894     int		last UNUSED)
895 {
896 # ifdef FEAT_SODIUM
897     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
898     unsigned long long	out_len;
899     char_u		*ptr;
900     unsigned char	tag = last
901 			? crypto_secretstream_xchacha20poly1305_TAG_FINAL  : 0;
902     int			length;
903     sodium_state_T	*sod_st = state->method_state;
904     int			first = (sod_st->count == 0);
905 
906     length = (int)len + crypto_secretstream_xchacha20poly1305_ABYTES
907 	     + (first ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0);
908     *buf_out = alloc_clear(length);
909     if (*buf_out == NULL)
910     {
911 	emsg(e_libsodium_cannot_allocate_buffer);
912 	return -1;
913     }
914     ptr = *buf_out;
915 
916     if (first)
917     {
918 	crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state,
919 		ptr, sod_st->key);
920 	ptr += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
921     }
922 
923     crypto_secretstream_xchacha20poly1305_push(&sod_st->state, ptr,
924 	    &out_len, from, len, NULL, 0, tag);
925 
926     sod_st->count++;
927     return out_len + (first
928 		      ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0);
929 # else
930     return -1;
931 # endif
932 }
933 
934 /*
935  * Decrypt "from[len]" into "to[len]".
936  * "from" and "to" can be equal to encrypt in place.
937  */
938     long
939 crypt_sodium_buffer_decode(
940     cryptstate_T *state UNUSED,
941     char_u	*from UNUSED,
942     size_t	len UNUSED,
943     char_u	**buf_out UNUSED,
944     int		last UNUSED)
945 {
946 # ifdef FEAT_SODIUM
947     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
948     sodium_state_T *sod_st = state->method_state;
949     unsigned char  tag;
950     unsigned long long out_len;
951     *buf_out = alloc_clear(len);
952     if (*buf_out == NULL)
953     {
954 	emsg(e_libsodium_cannot_allocate_buffer);
955 	return -1;
956     }
957 
958     if (sod_st->count == 0)
959     {
960 	if (crypto_secretstream_xchacha20poly1305_init_pull(&sod_st->state,
961 						       from, sod_st->key) != 0)
962 	{
963 	    emsg(e_libsodium_decryption_failed_header_incomplete);
964 	    return -1;
965 	}
966 	from += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
967 	len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES;
968 	sod_st->count++;
969     }
970     if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state,
971 			    *buf_out, &out_len, &tag, from, len, NULL, 0) != 0)
972     {
973 	emsg(e_libsodium_decryption_failed);
974 	return -1;
975     }
976 
977     if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last)
978 	emsg(e_libsodium_decryption_failed_premature);
979     return (long) out_len;
980 # else
981     return -1;
982 # endif
983 }
984 
985 #endif // FEAT_CRYPT
986