xref: /vim-8.2.3635/src/crypt.c (revision 131530a5)
1edf3f97aSBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
28f4ac015SBram Moolenaar  *
38f4ac015SBram Moolenaar  * VIM - Vi IMproved	by Bram Moolenaar
48f4ac015SBram Moolenaar  *
58f4ac015SBram Moolenaar  * Do ":help uganda"  in Vim to read copying and usage conditions.
68f4ac015SBram Moolenaar  * Do ":help credits" in Vim to see a list of people who contributed.
78f4ac015SBram Moolenaar  * See README.txt for an overview of the Vim source code.
88f4ac015SBram Moolenaar  */
98f4ac015SBram Moolenaar 
108f4ac015SBram Moolenaar /*
118f4ac015SBram Moolenaar  * crypt.c: Generic encryption support.
128f4ac015SBram Moolenaar  */
138f4ac015SBram Moolenaar #include "vim.h"
148f4ac015SBram Moolenaar 
158f4ac015SBram Moolenaar #if defined(FEAT_CRYPT) || defined(PROTO)
168f4ac015SBram Moolenaar /*
178f4ac015SBram Moolenaar  * Optional encryption support.
188f4ac015SBram Moolenaar  * Mohsin Ahmed, [email protected], 1998-09-24
198f4ac015SBram Moolenaar  * Based on zip/crypt sources.
208f4ac015SBram Moolenaar  * Refactored by David Leadbeater, 2014.
218f4ac015SBram Moolenaar  *
228f4ac015SBram Moolenaar  * NOTE FOR USA: Since 2000 exporting this code from the USA is allowed to
238f4ac015SBram Moolenaar  * most countries.  There are a few exceptions, but that still should not be a
248f4ac015SBram Moolenaar  * problem since this code was originally created in Europe and India.
258f4ac015SBram Moolenaar  *
268f4ac015SBram Moolenaar  * Blowfish addition originally made by Mohsin Ahmed,
278f4ac015SBram Moolenaar  * http://www.cs.albany.edu/~mosh 2010-03-14
288f4ac015SBram Moolenaar  * Based on blowfish by Bruce Schneier (http://www.schneier.com/blowfish.html)
298f4ac015SBram Moolenaar  * and sha256 by Christophe Devine.
308f4ac015SBram Moolenaar  */
318f4ac015SBram Moolenaar 
328f4ac015SBram Moolenaar typedef struct {
33c667da51SBram Moolenaar     char    *name;	// encryption name as used in 'cryptmethod'
34c667da51SBram Moolenaar     char    *magic;	// magic bytes stored in file header
35c667da51SBram Moolenaar     int	    salt_len;	// length of salt, or 0 when not using salt
36f573c6e1SChristian Brabandt     int	    seed_len;	// length of seed, or 0 when not using seed
37987411dbSBram Moolenaar #ifdef CRYPT_NOT_INPLACE
38c667da51SBram Moolenaar     int	    works_inplace; // encryption/decryption can be done in-place
39987411dbSBram Moolenaar #endif
40c667da51SBram Moolenaar     int	    whole_undofile; // whole undo file is encrypted
418f4ac015SBram Moolenaar 
42c667da51SBram Moolenaar     // Optional function pointer for a self-test.
438f4ac015SBram Moolenaar     int (* self_test_fn)();
448f4ac015SBram Moolenaar 
45ad3ec76bSBram Moolenaar     // Function pointer for initializing encryption/decryption.
466ee96587SBram Moolenaar     int (* init_fn)(cryptstate_T *state, char_u *key,
478f4ac015SBram Moolenaar 		      char_u *salt, int salt_len, char_u *seed, int seed_len);
488f4ac015SBram Moolenaar 
49c667da51SBram Moolenaar     // Function pointers for encoding/decoding from one buffer into another.
50c667da51SBram Moolenaar     // Optional, however, these or the _buffer ones should be configured.
518f4ac015SBram Moolenaar     void (*encode_fn)(cryptstate_T *state, char_u *from, size_t len,
52f573c6e1SChristian Brabandt 							char_u *to, int last);
538f4ac015SBram Moolenaar     void (*decode_fn)(cryptstate_T *state, char_u *from, size_t len,
54f573c6e1SChristian Brabandt 							char_u *to, int last);
558f4ac015SBram Moolenaar 
56c667da51SBram Moolenaar     // Function pointers for encoding and decoding, can buffer data if needed.
57c667da51SBram Moolenaar     // Optional (however, these or the above should be configured).
588f4ac015SBram Moolenaar     long (*encode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
59f573c6e1SChristian Brabandt 						    char_u **newptr, int last);
608f4ac015SBram Moolenaar     long (*decode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
61f573c6e1SChristian Brabandt 						    char_u **newptr, int last);
628f4ac015SBram Moolenaar 
63c667da51SBram Moolenaar     // Function pointers for in-place encoding and decoding, used for
64c667da51SBram Moolenaar     // crypt_*_inplace(). "from" and "to" arguments will be equal.
65c667da51SBram Moolenaar     // These may be the same as decode_fn and encode_fn above, however an
66c667da51SBram Moolenaar     // algorithm may implement them in a way that is not interchangeable with
67c667da51SBram Moolenaar     // the crypt_(en|de)code() interface (for example because it wishes to add
68c667da51SBram Moolenaar     // padding to files).
69c667da51SBram Moolenaar     // This method is used for swap and undo files which have a rigid format.
708f4ac015SBram Moolenaar     void (*encode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
71f573c6e1SChristian Brabandt 							char_u *p2, int last);
728f4ac015SBram Moolenaar     void (*decode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
73f573c6e1SChristian Brabandt 							char_u *p2, int last);
748f4ac015SBram Moolenaar } cryptmethod_T;
758f4ac015SBram Moolenaar 
76c667da51SBram Moolenaar // index is method_nr of cryptstate_T, CRYPT_M_*
778f4ac015SBram Moolenaar static cryptmethod_T cryptmethods[CRYPT_M_COUNT] = {
78c667da51SBram Moolenaar     // PK_Zip; very weak
798f4ac015SBram Moolenaar     {
808f4ac015SBram Moolenaar 	"zip",
818f4ac015SBram Moolenaar 	"VimCrypt~01!",
828f4ac015SBram Moolenaar 	0,
838f4ac015SBram Moolenaar 	0,
84987411dbSBram Moolenaar #ifdef CRYPT_NOT_INPLACE
858f4ac015SBram Moolenaar 	TRUE,
86987411dbSBram Moolenaar #endif
878f4ac015SBram Moolenaar 	FALSE,
888f4ac015SBram Moolenaar 	NULL,
898f4ac015SBram Moolenaar 	crypt_zip_init,
908f4ac015SBram Moolenaar 	crypt_zip_encode, crypt_zip_decode,
918f4ac015SBram Moolenaar 	NULL, NULL,
928f4ac015SBram Moolenaar 	crypt_zip_encode, crypt_zip_decode,
938f4ac015SBram Moolenaar     },
948f4ac015SBram Moolenaar 
95c667da51SBram Moolenaar     // Blowfish/CFB + SHA-256 custom key derivation; implementation issues.
968f4ac015SBram Moolenaar     {
978f4ac015SBram Moolenaar 	"blowfish",
988f4ac015SBram Moolenaar 	"VimCrypt~02!",
998f4ac015SBram Moolenaar 	8,
1008f4ac015SBram Moolenaar 	8,
101987411dbSBram Moolenaar #ifdef CRYPT_NOT_INPLACE
1028f4ac015SBram Moolenaar 	TRUE,
103987411dbSBram Moolenaar #endif
1048f4ac015SBram Moolenaar 	FALSE,
1058f4ac015SBram Moolenaar 	blowfish_self_test,
1068f4ac015SBram Moolenaar 	crypt_blowfish_init,
1078f4ac015SBram Moolenaar 	crypt_blowfish_encode, crypt_blowfish_decode,
1088f4ac015SBram Moolenaar 	NULL, NULL,
1098f4ac015SBram Moolenaar 	crypt_blowfish_encode, crypt_blowfish_decode,
1108f4ac015SBram Moolenaar     },
1118f4ac015SBram Moolenaar 
112c667da51SBram Moolenaar     // Blowfish/CFB + SHA-256 custom key derivation; fixed.
1138f4ac015SBram Moolenaar     {
1148f4ac015SBram Moolenaar 	"blowfish2",
1158f4ac015SBram Moolenaar 	"VimCrypt~03!",
1168f4ac015SBram Moolenaar 	8,
1178f4ac015SBram Moolenaar 	8,
118987411dbSBram Moolenaar #ifdef CRYPT_NOT_INPLACE
1198f4ac015SBram Moolenaar 	TRUE,
120987411dbSBram Moolenaar #endif
1218f4ac015SBram Moolenaar 	TRUE,
1228f4ac015SBram Moolenaar 	blowfish_self_test,
1238f4ac015SBram Moolenaar 	crypt_blowfish_init,
1248f4ac015SBram Moolenaar 	crypt_blowfish_encode, crypt_blowfish_decode,
1258f4ac015SBram Moolenaar 	NULL, NULL,
1268f4ac015SBram Moolenaar 	crypt_blowfish_encode, crypt_blowfish_decode,
1278f4ac015SBram Moolenaar     },
128d23a8236SBram Moolenaar 
129f573c6e1SChristian Brabandt     // XChaCha20 using libsodium
130f573c6e1SChristian Brabandt     {
131f573c6e1SChristian Brabandt 	"xchacha20",
132f573c6e1SChristian Brabandt 	"VimCrypt~04!",
133f573c6e1SChristian Brabandt #ifdef FEAT_SODIUM
134f573c6e1SChristian Brabandt 	crypto_pwhash_argon2id_SALTBYTES, // 16
135f573c6e1SChristian Brabandt #else
136f573c6e1SChristian Brabandt 	16,
137f573c6e1SChristian Brabandt #endif
138f573c6e1SChristian Brabandt 	8,
139f573c6e1SChristian Brabandt #ifdef CRYPT_NOT_INPLACE
140f573c6e1SChristian Brabandt 	FALSE,
141f573c6e1SChristian Brabandt #endif
142f573c6e1SChristian Brabandt 	FALSE,
143f573c6e1SChristian Brabandt 	NULL,
144f573c6e1SChristian Brabandt 	crypt_sodium_init,
145226b28b9SChristian Brabandt 	NULL, NULL,
146f573c6e1SChristian Brabandt 	crypt_sodium_buffer_encode, crypt_sodium_buffer_decode,
147226b28b9SChristian Brabandt 	NULL, NULL,
148f573c6e1SChristian Brabandt     },
149f573c6e1SChristian Brabandt 
150c667da51SBram Moolenaar     // NOTE: when adding a new method, use some random bytes for the magic key,
151c667da51SBram Moolenaar     // to avoid that a text file is recognized as encrypted.
1528f4ac015SBram Moolenaar };
1538f4ac015SBram Moolenaar 
154f573c6e1SChristian Brabandt #ifdef FEAT_SODIUM
155f573c6e1SChristian Brabandt typedef struct {
156f573c6e1SChristian Brabandt     size_t	    count;
157f573c6e1SChristian Brabandt     unsigned char   key[crypto_box_SEEDBYTES];
158f573c6e1SChristian Brabandt 		  // 32, same as crypto_secretstream_xchacha20poly1305_KEYBYTES
159f573c6e1SChristian Brabandt     crypto_secretstream_xchacha20poly1305_state
160f573c6e1SChristian Brabandt 		    state;
161f573c6e1SChristian Brabandt } sodium_state_T;
162f573c6e1SChristian Brabandt #endif
163f573c6e1SChristian Brabandt 
164c667da51SBram Moolenaar #define CRYPT_MAGIC_LEN	12	// cannot change
1658f4ac015SBram Moolenaar static char	crypt_magic_head[] = "VimCrypt~";
1668f4ac015SBram Moolenaar 
1678f4ac015SBram Moolenaar /*
1688f4ac015SBram Moolenaar  * Return int value for crypt method name.
1698f4ac015SBram Moolenaar  * 0 for "zip", the old method.  Also for any non-valid value.
1708f4ac015SBram Moolenaar  * 1 for "blowfish".
1718f4ac015SBram Moolenaar  * 2 for "blowfish2".
1728f4ac015SBram Moolenaar  */
1738f4ac015SBram Moolenaar     int
crypt_method_nr_from_name(char_u * name)1747454a06eSBram Moolenaar crypt_method_nr_from_name(char_u *name)
1758f4ac015SBram Moolenaar {
1768f4ac015SBram Moolenaar     int i;
1778f4ac015SBram Moolenaar 
1788f4ac015SBram Moolenaar     for (i = 0; i < CRYPT_M_COUNT; ++i)
1798f4ac015SBram Moolenaar 	if (STRCMP(name, cryptmethods[i].name) == 0)
1808f4ac015SBram Moolenaar 	    return i;
1818f4ac015SBram Moolenaar     return 0;
1828f4ac015SBram Moolenaar }
1838f4ac015SBram Moolenaar 
1848f4ac015SBram Moolenaar /*
1858f4ac015SBram Moolenaar  * Get the crypt method used for a file from "ptr[len]", the magic text at the
1868f4ac015SBram Moolenaar  * start of the file.
1878f4ac015SBram Moolenaar  * Returns -1 when no encryption used.
1888f4ac015SBram Moolenaar  */
1898f4ac015SBram Moolenaar     int
crypt_method_nr_from_magic(char * ptr,int len)1907454a06eSBram Moolenaar crypt_method_nr_from_magic(char *ptr, int len)
1918f4ac015SBram Moolenaar {
1928f4ac015SBram Moolenaar     int i;
1938f4ac015SBram Moolenaar 
1948f4ac015SBram Moolenaar     if (len < CRYPT_MAGIC_LEN)
1958f4ac015SBram Moolenaar 	return -1;
1968f4ac015SBram Moolenaar 
1978f4ac015SBram Moolenaar     for (i = 0; i < CRYPT_M_COUNT; i++)
1988f4ac015SBram Moolenaar 	if (memcmp(ptr, cryptmethods[i].magic, CRYPT_MAGIC_LEN) == 0)
1998f4ac015SBram Moolenaar 	    return i;
2008f4ac015SBram Moolenaar 
2018f4ac015SBram Moolenaar     i = (int)STRLEN(crypt_magic_head);
2028f4ac015SBram Moolenaar     if (len >= i && memcmp(ptr, crypt_magic_head, i) == 0)
203f9e3e09fSBram Moolenaar 	emsg(_("E821: File is encrypted with unknown method"));
2048f4ac015SBram Moolenaar 
2058f4ac015SBram Moolenaar     return -1;
2068f4ac015SBram Moolenaar }
2078f4ac015SBram Moolenaar 
208987411dbSBram Moolenaar #ifdef CRYPT_NOT_INPLACE
2098f4ac015SBram Moolenaar /*
2108f4ac015SBram Moolenaar  * Return TRUE if the crypt method for "method_nr" can be done in-place.
2118f4ac015SBram Moolenaar  */
2128f4ac015SBram Moolenaar     int
crypt_works_inplace(cryptstate_T * state)2137454a06eSBram Moolenaar crypt_works_inplace(cryptstate_T *state)
2148f4ac015SBram Moolenaar {
2158f4ac015SBram Moolenaar     return cryptmethods[state->method_nr].works_inplace;
2168f4ac015SBram Moolenaar }
217987411dbSBram Moolenaar #endif
2188f4ac015SBram Moolenaar 
2198f4ac015SBram Moolenaar /*
2208f4ac015SBram Moolenaar  * Get the crypt method for buffer "buf" as a number.
2218f4ac015SBram Moolenaar  */
2228f4ac015SBram Moolenaar     int
crypt_get_method_nr(buf_T * buf)2237454a06eSBram Moolenaar crypt_get_method_nr(buf_T *buf)
2248f4ac015SBram Moolenaar {
2258f4ac015SBram Moolenaar     return crypt_method_nr_from_name(*buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
2268f4ac015SBram Moolenaar }
2278f4ac015SBram Moolenaar 
2288f4ac015SBram Moolenaar /*
2298f4ac015SBram Moolenaar  * Return TRUE when the buffer uses an encryption method that encrypts the
2308f4ac015SBram Moolenaar  * whole undo file, not only the text.
2318f4ac015SBram Moolenaar  */
2328f4ac015SBram Moolenaar     int
crypt_whole_undofile(int method_nr)2337454a06eSBram Moolenaar crypt_whole_undofile(int method_nr)
2348f4ac015SBram Moolenaar {
2358f4ac015SBram Moolenaar     return cryptmethods[method_nr].whole_undofile;
2368f4ac015SBram Moolenaar }
2378f4ac015SBram Moolenaar 
2388f4ac015SBram Moolenaar /*
23932aa1020SBram Moolenaar  * Get crypt method specific length of the file header in bytes.
2408f4ac015SBram Moolenaar  */
2418f4ac015SBram Moolenaar     int
crypt_get_header_len(int method_nr)2427454a06eSBram Moolenaar crypt_get_header_len(int method_nr)
2438f4ac015SBram Moolenaar {
2448f4ac015SBram Moolenaar     return CRYPT_MAGIC_LEN
2458f4ac015SBram Moolenaar 	+ cryptmethods[method_nr].salt_len
2468f4ac015SBram Moolenaar 	+ cryptmethods[method_nr].seed_len;
2478f4ac015SBram Moolenaar }
2488f4ac015SBram Moolenaar 
249226b28b9SChristian Brabandt 
250226b28b9SChristian Brabandt /*
251226b28b9SChristian Brabandt  * Get maximum crypt method specific length of the file header in bytes.
252226b28b9SChristian Brabandt  */
253226b28b9SChristian Brabandt     int
crypt_get_max_header_len()254226b28b9SChristian Brabandt crypt_get_max_header_len()
255226b28b9SChristian Brabandt {
256226b28b9SChristian Brabandt     int i;
257226b28b9SChristian Brabandt     int max = 0;
258226b28b9SChristian Brabandt     int temp = 0;
259226b28b9SChristian Brabandt 
260226b28b9SChristian Brabandt     for (i = 0; i < CRYPT_M_COUNT; ++i)
261226b28b9SChristian Brabandt     {
262226b28b9SChristian Brabandt 	temp = crypt_get_header_len(i);
263226b28b9SChristian Brabandt 	if (temp > max)
264226b28b9SChristian Brabandt 	    max = temp;
265226b28b9SChristian Brabandt     }
266226b28b9SChristian Brabandt     return max;
267226b28b9SChristian Brabandt }
268226b28b9SChristian Brabandt 
2698f4ac015SBram Moolenaar /*
2708f4ac015SBram Moolenaar  * Set the crypt method for buffer "buf" to "method_nr" using the int value as
2718f4ac015SBram Moolenaar  * returned by crypt_method_nr_from_name().
2728f4ac015SBram Moolenaar  */
2738f4ac015SBram Moolenaar     void
crypt_set_cm_option(buf_T * buf,int method_nr)2747454a06eSBram Moolenaar crypt_set_cm_option(buf_T *buf, int method_nr)
2758f4ac015SBram Moolenaar {
2768f4ac015SBram Moolenaar     free_string_option(buf->b_p_cm);
2778f4ac015SBram Moolenaar     buf->b_p_cm = vim_strsave((char_u *)cryptmethods[method_nr].name);
2788f4ac015SBram Moolenaar }
2798f4ac015SBram Moolenaar 
2808f4ac015SBram Moolenaar /*
2818f4ac015SBram Moolenaar  * If the crypt method for the current buffer has a self-test, run it and
2828f4ac015SBram Moolenaar  * return OK/FAIL.
2838f4ac015SBram Moolenaar  */
2848f4ac015SBram Moolenaar     int
crypt_self_test(void)2857454a06eSBram Moolenaar crypt_self_test(void)
2868f4ac015SBram Moolenaar {
2878f4ac015SBram Moolenaar     int method_nr = crypt_get_method_nr(curbuf);
2888f4ac015SBram Moolenaar 
2898f4ac015SBram Moolenaar     if (cryptmethods[method_nr].self_test_fn == NULL)
2908f4ac015SBram Moolenaar 	return OK;
2918f4ac015SBram Moolenaar     return cryptmethods[method_nr].self_test_fn();
2928f4ac015SBram Moolenaar }
2938f4ac015SBram Moolenaar 
2948f4ac015SBram Moolenaar /*
2958f4ac015SBram Moolenaar  * Allocate a crypt state and initialize it.
2966ee96587SBram Moolenaar  * Return NULL for failure.
2978f4ac015SBram Moolenaar  */
2988f4ac015SBram Moolenaar     cryptstate_T *
crypt_create(int method_nr,char_u * key,char_u * salt,int salt_len,char_u * seed,int seed_len)2997454a06eSBram Moolenaar crypt_create(
3007454a06eSBram Moolenaar     int		method_nr,
3017454a06eSBram Moolenaar     char_u	*key,
3027454a06eSBram Moolenaar     char_u	*salt,
3037454a06eSBram Moolenaar     int		salt_len,
3047454a06eSBram Moolenaar     char_u	*seed,
3057454a06eSBram Moolenaar     int		seed_len)
3068f4ac015SBram Moolenaar {
307c799fe20SBram Moolenaar     cryptstate_T *state = ALLOC_ONE(cryptstate_T);
3088f4ac015SBram Moolenaar 
3096ee96587SBram Moolenaar     if (state == NULL)
3106ee96587SBram Moolenaar 	return state;
3116ee96587SBram Moolenaar 
3128f4ac015SBram Moolenaar     state->method_nr = method_nr;
3136ee96587SBram Moolenaar     if (cryptmethods[method_nr].init_fn(
3146ee96587SBram Moolenaar 	state, key, salt, salt_len, seed, seed_len) == FAIL)
3156ee96587SBram Moolenaar     {
3166ee96587SBram Moolenaar         vim_free(state);
3176ee96587SBram Moolenaar         return NULL;
3186ee96587SBram Moolenaar     }
3198f4ac015SBram Moolenaar     return state;
3208f4ac015SBram Moolenaar }
3218f4ac015SBram Moolenaar 
3228f4ac015SBram Moolenaar /*
3238f4ac015SBram Moolenaar  * Allocate a crypt state from a file header and initialize it.
3248f4ac015SBram Moolenaar  * Assumes that header contains at least the number of bytes that
3258f4ac015SBram Moolenaar  * crypt_get_header_len() returns for "method_nr".
3268f4ac015SBram Moolenaar  */
3278f4ac015SBram Moolenaar     cryptstate_T *
crypt_create_from_header(int method_nr,char_u * key,char_u * header)3287454a06eSBram Moolenaar crypt_create_from_header(
3297454a06eSBram Moolenaar     int		method_nr,
3307454a06eSBram Moolenaar     char_u	*key,
3317454a06eSBram Moolenaar     char_u	*header)
3328f4ac015SBram Moolenaar {
3338f4ac015SBram Moolenaar     char_u	*salt = NULL;
3348f4ac015SBram Moolenaar     char_u	*seed = NULL;
3358f4ac015SBram Moolenaar     int		salt_len = cryptmethods[method_nr].salt_len;
3368f4ac015SBram Moolenaar     int		seed_len = cryptmethods[method_nr].seed_len;
3378f4ac015SBram Moolenaar 
3388f4ac015SBram Moolenaar     if (salt_len > 0)
3398f4ac015SBram Moolenaar 	salt = header + CRYPT_MAGIC_LEN;
3408f4ac015SBram Moolenaar     if (seed_len > 0)
3418f4ac015SBram Moolenaar 	seed = header + CRYPT_MAGIC_LEN + salt_len;
3428f4ac015SBram Moolenaar 
3438f4ac015SBram Moolenaar     return crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
3448f4ac015SBram Moolenaar }
3458f4ac015SBram Moolenaar 
3468f4ac015SBram Moolenaar /*
3478f4ac015SBram Moolenaar  * Read the crypt method specific header data from "fp".
3488f4ac015SBram Moolenaar  * Return an allocated cryptstate_T or NULL on error.
3498f4ac015SBram Moolenaar  */
3508f4ac015SBram Moolenaar     cryptstate_T *
crypt_create_from_file(FILE * fp,char_u * key)3517454a06eSBram Moolenaar crypt_create_from_file(FILE *fp, char_u *key)
3528f4ac015SBram Moolenaar {
3538f4ac015SBram Moolenaar     int		method_nr;
3548f4ac015SBram Moolenaar     int		header_len;
3558f4ac015SBram Moolenaar     char	magic_buffer[CRYPT_MAGIC_LEN];
3568f4ac015SBram Moolenaar     char_u	*buffer;
3578f4ac015SBram Moolenaar     cryptstate_T *state;
3588f4ac015SBram Moolenaar 
3598f4ac015SBram Moolenaar     if (fread(magic_buffer, CRYPT_MAGIC_LEN, 1, fp) != 1)
3608f4ac015SBram Moolenaar 	return NULL;
3618f4ac015SBram Moolenaar     method_nr = crypt_method_nr_from_magic(magic_buffer, CRYPT_MAGIC_LEN);
3628f4ac015SBram Moolenaar     if (method_nr < 0)
3638f4ac015SBram Moolenaar 	return NULL;
3648f4ac015SBram Moolenaar 
3658f4ac015SBram Moolenaar     header_len = crypt_get_header_len(method_nr);
3668f4ac015SBram Moolenaar     if ((buffer = alloc(header_len)) == NULL)
3678f4ac015SBram Moolenaar 	return NULL;
3688f4ac015SBram Moolenaar     mch_memmove(buffer, magic_buffer, CRYPT_MAGIC_LEN);
3698f4ac015SBram Moolenaar     if (header_len > CRYPT_MAGIC_LEN
3708f4ac015SBram Moolenaar 	    && fread(buffer + CRYPT_MAGIC_LEN,
3718f4ac015SBram Moolenaar 				    header_len - CRYPT_MAGIC_LEN, 1, fp) != 1)
3728f4ac015SBram Moolenaar     {
3738f4ac015SBram Moolenaar 	vim_free(buffer);
3748f4ac015SBram Moolenaar 	return NULL;
3758f4ac015SBram Moolenaar     }
3768f4ac015SBram Moolenaar 
3778f4ac015SBram Moolenaar     state = crypt_create_from_header(method_nr, key, buffer);
3788f4ac015SBram Moolenaar     vim_free(buffer);
3798f4ac015SBram Moolenaar     return state;
3808f4ac015SBram Moolenaar }
3818f4ac015SBram Moolenaar 
3828f4ac015SBram Moolenaar /*
3838f4ac015SBram Moolenaar  * Allocate a cryptstate_T for writing and initialize it with "key".
3848f4ac015SBram Moolenaar  * Allocates and fills in the header and stores it in "header", setting
3858f4ac015SBram Moolenaar  * "header_len".  The header may include salt and seed, depending on
3868f4ac015SBram Moolenaar  * cryptmethod.  Caller must free header.
3878f4ac015SBram Moolenaar  * Returns the state or NULL on failure.
3888f4ac015SBram Moolenaar  */
3898f4ac015SBram Moolenaar     cryptstate_T *
crypt_create_for_writing(int method_nr,char_u * key,char_u ** header,int * header_len)3907454a06eSBram Moolenaar crypt_create_for_writing(
3917454a06eSBram Moolenaar     int	    method_nr,
3927454a06eSBram Moolenaar     char_u  *key,
3937454a06eSBram Moolenaar     char_u  **header,
3947454a06eSBram Moolenaar     int	    *header_len)
3958f4ac015SBram Moolenaar {
3968f4ac015SBram Moolenaar     int	    len = crypt_get_header_len(method_nr);
3978f4ac015SBram Moolenaar     char_u  *salt = NULL;
3988f4ac015SBram Moolenaar     char_u  *seed = NULL;
3998f4ac015SBram Moolenaar     int	    salt_len = cryptmethods[method_nr].salt_len;
4008f4ac015SBram Moolenaar     int	    seed_len = cryptmethods[method_nr].seed_len;
4018f4ac015SBram Moolenaar     cryptstate_T *state;
4028f4ac015SBram Moolenaar 
4038f4ac015SBram Moolenaar     *header_len = len;
4048f4ac015SBram Moolenaar     *header = alloc(len);
4058f4ac015SBram Moolenaar     if (*header == NULL)
4068f4ac015SBram Moolenaar 	return NULL;
4078f4ac015SBram Moolenaar 
4088f4ac015SBram Moolenaar     mch_memmove(*header, cryptmethods[method_nr].magic, CRYPT_MAGIC_LEN);
4098f4ac015SBram Moolenaar     if (salt_len > 0 || seed_len > 0)
4108f4ac015SBram Moolenaar     {
4118f4ac015SBram Moolenaar 	if (salt_len > 0)
4128f4ac015SBram Moolenaar 	    salt = *header + CRYPT_MAGIC_LEN;
4138f4ac015SBram Moolenaar 	if (seed_len > 0)
4148f4ac015SBram Moolenaar 	    seed = *header + CRYPT_MAGIC_LEN + salt_len;
4158f4ac015SBram Moolenaar 
416c667da51SBram Moolenaar 	// TODO: Should this be crypt method specific? (Probably not worth
417c667da51SBram Moolenaar 	// it).  sha2_seed is pretty bad for large amounts of entropy, so make
418c667da51SBram Moolenaar 	// that into something which is suitable for anything.
419f573c6e1SChristian Brabandt #ifdef FEAT_SODIUM
420f573c6e1SChristian Brabandt 	if (sodium_init() >= 0)
421f573c6e1SChristian Brabandt 	{
422226b28b9SChristian Brabandt 	    if (salt_len > 0)
423f573c6e1SChristian Brabandt 		randombytes_buf(salt, salt_len);
424226b28b9SChristian Brabandt 	    if (seed_len > 0)
425f573c6e1SChristian Brabandt 		randombytes_buf(seed, seed_len);
426f573c6e1SChristian Brabandt 	}
427f573c6e1SChristian Brabandt 	else
428f573c6e1SChristian Brabandt #endif
4298f4ac015SBram Moolenaar 	    sha2_seed(salt, salt_len, seed, seed_len);
4308f4ac015SBram Moolenaar     }
4318f4ac015SBram Moolenaar     state = crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
4328f4ac015SBram Moolenaar     if (state == NULL)
433d23a8236SBram Moolenaar 	VIM_CLEAR(*header);
4348f4ac015SBram Moolenaar     return state;
4358f4ac015SBram Moolenaar }
4368f4ac015SBram Moolenaar 
4378f4ac015SBram Moolenaar /*
4388f4ac015SBram Moolenaar  * Free the crypt state.
4398f4ac015SBram Moolenaar  */
4408f4ac015SBram Moolenaar     void
crypt_free_state(cryptstate_T * state)4417454a06eSBram Moolenaar crypt_free_state(cryptstate_T *state)
4428f4ac015SBram Moolenaar {
443f573c6e1SChristian Brabandt #ifdef FEAT_SODIUM
444f573c6e1SChristian Brabandt     if (state->method_nr == CRYPT_M_SOD)
445f573c6e1SChristian Brabandt     {
446*131530a5SBram Moolenaar 	sodium_munlock(((sodium_state_T *)state->method_state)->key,
447*131530a5SBram Moolenaar 							 crypto_box_SEEDBYTES);
448f573c6e1SChristian Brabandt 	sodium_memzero(state->method_state, sizeof(sodium_state_T));
449f573c6e1SChristian Brabandt 	sodium_free(state->method_state);
450f573c6e1SChristian Brabandt     }
451f573c6e1SChristian Brabandt     else
452f573c6e1SChristian Brabandt #endif
4538f4ac015SBram Moolenaar 	vim_free(state->method_state);
4548f4ac015SBram Moolenaar     vim_free(state);
4558f4ac015SBram Moolenaar }
4568f4ac015SBram Moolenaar 
457987411dbSBram Moolenaar #ifdef CRYPT_NOT_INPLACE
4588f4ac015SBram Moolenaar /*
4598f4ac015SBram Moolenaar  * Encode "from[len]" and store the result in a newly allocated buffer, which
4608f4ac015SBram Moolenaar  * is stored in "newptr".
4618f4ac015SBram Moolenaar  * Return number of bytes in "newptr", 0 for need more or -1 on error.
4628f4ac015SBram Moolenaar  */
4638f4ac015SBram Moolenaar     long
crypt_encode_alloc(cryptstate_T * state,char_u * from,size_t len,char_u ** newptr,int last)4647454a06eSBram Moolenaar crypt_encode_alloc(
4657454a06eSBram Moolenaar     cryptstate_T *state,
4667454a06eSBram Moolenaar     char_u	*from,
4677454a06eSBram Moolenaar     size_t	len,
468f573c6e1SChristian Brabandt     char_u	**newptr,
469f573c6e1SChristian Brabandt     int		last)
4708f4ac015SBram Moolenaar {
4718f4ac015SBram Moolenaar     cryptmethod_T *method = &cryptmethods[state->method_nr];
4728f4ac015SBram Moolenaar 
4738f4ac015SBram Moolenaar     if (method->encode_buffer_fn != NULL)
474c667da51SBram Moolenaar 	// Has buffer function, pass through.
475f573c6e1SChristian Brabandt 	return method->encode_buffer_fn(state, from, len, newptr, last);
4768f4ac015SBram Moolenaar     if (len == 0)
477c667da51SBram Moolenaar 	// Not buffering, just return EOF.
4789b8f021dSBram Moolenaar 	return (long)len;
4798f4ac015SBram Moolenaar 
480f573c6e1SChristian Brabandt     *newptr = alloc(len + 50);
4818f4ac015SBram Moolenaar     if (*newptr == NULL)
4828f4ac015SBram Moolenaar 	return -1;
483f573c6e1SChristian Brabandt     method->encode_fn(state, from, len, *newptr, last);
4849b8f021dSBram Moolenaar     return (long)len;
4858f4ac015SBram Moolenaar }
4868f4ac015SBram Moolenaar 
4878f4ac015SBram Moolenaar /*
4888f4ac015SBram Moolenaar  * Decrypt "ptr[len]" and store the result in a newly allocated buffer, which
4898f4ac015SBram Moolenaar  * is stored in "newptr".
4908f4ac015SBram Moolenaar  * Return number of bytes in "newptr", 0 for need more or -1 on error.
4918f4ac015SBram Moolenaar  */
4928f4ac015SBram Moolenaar     long
crypt_decode_alloc(cryptstate_T * state,char_u * ptr,long len,char_u ** newptr,int last)4937454a06eSBram Moolenaar crypt_decode_alloc(
4947454a06eSBram Moolenaar     cryptstate_T *state,
4957454a06eSBram Moolenaar     char_u	*ptr,
4967454a06eSBram Moolenaar     long	len,
497f573c6e1SChristian Brabandt     char_u      **newptr,
498f573c6e1SChristian Brabandt     int		last)
4998f4ac015SBram Moolenaar {
5008f4ac015SBram Moolenaar     cryptmethod_T *method = &cryptmethods[state->method_nr];
5018f4ac015SBram Moolenaar 
5028f4ac015SBram Moolenaar     if (method->decode_buffer_fn != NULL)
503c667da51SBram Moolenaar 	// Has buffer function, pass through.
504f573c6e1SChristian Brabandt 	return method->decode_buffer_fn(state, ptr, len, newptr, last);
5058f4ac015SBram Moolenaar 
5068f4ac015SBram Moolenaar     if (len == 0)
507c667da51SBram Moolenaar 	// Not buffering, just return EOF.
5088f4ac015SBram Moolenaar 	return len;
5098f4ac015SBram Moolenaar 
5108f4ac015SBram Moolenaar     *newptr = alloc(len);
5118f4ac015SBram Moolenaar     if (*newptr == NULL)
5128f4ac015SBram Moolenaar 	return -1;
513f573c6e1SChristian Brabandt     method->decode_fn(state, ptr, len, *newptr, last);
5148f4ac015SBram Moolenaar     return len;
5158f4ac015SBram Moolenaar }
516987411dbSBram Moolenaar #endif
5178f4ac015SBram Moolenaar 
5188f4ac015SBram Moolenaar /*
5198f4ac015SBram Moolenaar  * Encrypting "from[len]" into "to[len]".
5208f4ac015SBram Moolenaar  */
5218f4ac015SBram Moolenaar     void
crypt_encode(cryptstate_T * state,char_u * from,size_t len,char_u * to,int last)5227454a06eSBram Moolenaar crypt_encode(
5237454a06eSBram Moolenaar     cryptstate_T *state,
5247454a06eSBram Moolenaar     char_u	*from,
5257454a06eSBram Moolenaar     size_t	len,
526f573c6e1SChristian Brabandt     char_u	*to,
527f573c6e1SChristian Brabandt     int		last)
5288f4ac015SBram Moolenaar {
529f573c6e1SChristian Brabandt     cryptmethods[state->method_nr].encode_fn(state, from, len, to, last);
5308f4ac015SBram Moolenaar }
5318f4ac015SBram Moolenaar 
532987411dbSBram Moolenaar #if 0  // unused
5338f4ac015SBram Moolenaar /*
5348f4ac015SBram Moolenaar  * decrypting "from[len]" into "to[len]".
5358f4ac015SBram Moolenaar  */
5368f4ac015SBram Moolenaar     void
5377454a06eSBram Moolenaar crypt_decode(
5387454a06eSBram Moolenaar     cryptstate_T *state,
5397454a06eSBram Moolenaar     char_u	*from,
5407454a06eSBram Moolenaar     size_t	len,
541f573c6e1SChristian Brabandt     char_u	*to,
542f573c6e1SChristian Brabandt     int		last)
5438f4ac015SBram Moolenaar {
544f573c6e1SChristian Brabandt     cryptmethods[state->method_nr].decode_fn(state, from, len, to, last);
5458f4ac015SBram Moolenaar }
546987411dbSBram Moolenaar #endif
5478f4ac015SBram Moolenaar 
5488f4ac015SBram Moolenaar /*
5498f4ac015SBram Moolenaar  * Simple inplace encryption, modifies "buf[len]" in place.
5508f4ac015SBram Moolenaar  */
5518f4ac015SBram Moolenaar     void
crypt_encode_inplace(cryptstate_T * state,char_u * buf,size_t len,int last)5527454a06eSBram Moolenaar crypt_encode_inplace(
5537454a06eSBram Moolenaar     cryptstate_T *state,
5547454a06eSBram Moolenaar     char_u	*buf,
555f573c6e1SChristian Brabandt     size_t	len,
556f573c6e1SChristian Brabandt     int         last)
5578f4ac015SBram Moolenaar {
558f573c6e1SChristian Brabandt     cryptmethods[state->method_nr].encode_inplace_fn(state, buf, len,
559f573c6e1SChristian Brabandt 								    buf, last);
5608f4ac015SBram Moolenaar }
5618f4ac015SBram Moolenaar 
5628f4ac015SBram Moolenaar /*
5638f4ac015SBram Moolenaar  * Simple inplace decryption, modifies "buf[len]" in place.
5648f4ac015SBram Moolenaar  */
5658f4ac015SBram Moolenaar     void
crypt_decode_inplace(cryptstate_T * state,char_u * buf,size_t len,int last)5667454a06eSBram Moolenaar crypt_decode_inplace(
5677454a06eSBram Moolenaar     cryptstate_T *state,
5687454a06eSBram Moolenaar     char_u	*buf,
569f573c6e1SChristian Brabandt     size_t	len,
570f573c6e1SChristian Brabandt     int		last)
5718f4ac015SBram Moolenaar {
572f573c6e1SChristian Brabandt     cryptmethods[state->method_nr].decode_inplace_fn(state, buf, len,
573f573c6e1SChristian Brabandt 								    buf, last);
5748f4ac015SBram Moolenaar }
5758f4ac015SBram Moolenaar 
5768f4ac015SBram Moolenaar /*
5778f4ac015SBram Moolenaar  * Free an allocated crypt key.  Clear the text to make sure it doesn't stay
5788f4ac015SBram Moolenaar  * in memory anywhere.
5798f4ac015SBram Moolenaar  */
5808f4ac015SBram Moolenaar     void
crypt_free_key(char_u * key)5817454a06eSBram Moolenaar crypt_free_key(char_u *key)
5828f4ac015SBram Moolenaar {
5838f4ac015SBram Moolenaar     char_u *p;
5848f4ac015SBram Moolenaar 
5858f4ac015SBram Moolenaar     if (key != NULL)
5868f4ac015SBram Moolenaar     {
5878f4ac015SBram Moolenaar 	for (p = key; *p != NUL; ++p)
5888f4ac015SBram Moolenaar 	    *p = 0;
5898f4ac015SBram Moolenaar 	vim_free(key);
5908f4ac015SBram Moolenaar     }
5918f4ac015SBram Moolenaar }
5928f4ac015SBram Moolenaar 
5938f4ac015SBram Moolenaar /*
5943a0c9089SBram Moolenaar  * Check the crypt method and give a warning if it's outdated.
5953a0c9089SBram Moolenaar  */
5963a0c9089SBram Moolenaar     void
crypt_check_method(int method)5977454a06eSBram Moolenaar crypt_check_method(int method)
5983a0c9089SBram Moolenaar {
5993a0c9089SBram Moolenaar     if (method < CRYPT_M_BF2)
6003a0c9089SBram Moolenaar     {
6013a0c9089SBram Moolenaar 	msg_scroll = TRUE;
60232526b3cSBram Moolenaar 	msg(_("Warning: Using a weak encryption method; see :help 'cm'"));
6033a0c9089SBram Moolenaar     }
604226b28b9SChristian Brabandt }
605226b28b9SChristian Brabandt 
606226b28b9SChristian Brabandt #ifdef FEAT_SODIUM
607226b28b9SChristian Brabandt     static void
crypt_check_swapfile_curbuf(void)608226b28b9SChristian Brabandt crypt_check_swapfile_curbuf(void)
609226b28b9SChristian Brabandt {
610226b28b9SChristian Brabandt     int method = crypt_get_method_nr(curbuf);
611f573c6e1SChristian Brabandt     if (method == CRYPT_M_SOD)
612f573c6e1SChristian Brabandt     {
613f573c6e1SChristian Brabandt 	// encryption uses padding and MAC, that does not work very well with
614f573c6e1SChristian Brabandt 	// swap and undo files, so disable them
615f573c6e1SChristian Brabandt 	mf_close_file(curbuf, TRUE);	// remove the swap file
616f573c6e1SChristian Brabandt 	set_option_value((char_u *)"swf", 0, NULL, OPT_LOCAL);
617f573c6e1SChristian Brabandt 	msg_scroll = TRUE;
6188a4c812eSChristian Brabandt 	msg(_("Note: Encryption of swapfile not supported, disabling swap file"));
619f573c6e1SChristian Brabandt     }
6203a0c9089SBram Moolenaar }
621226b28b9SChristian Brabandt #endif
6223a0c9089SBram Moolenaar 
6233a0c9089SBram Moolenaar     void
crypt_check_current_method(void)6247454a06eSBram Moolenaar crypt_check_current_method(void)
6253a0c9089SBram Moolenaar {
6263a0c9089SBram Moolenaar     crypt_check_method(crypt_get_method_nr(curbuf));
6273a0c9089SBram Moolenaar }
6283a0c9089SBram Moolenaar 
6293a0c9089SBram Moolenaar /*
6308f4ac015SBram Moolenaar  * Ask the user for a crypt key.
6318f4ac015SBram Moolenaar  * When "store" is TRUE, the new key is stored in the 'key' option, and the
6328f4ac015SBram Moolenaar  * 'key' option value is returned: Don't free it.
6338f4ac015SBram Moolenaar  * When "store" is FALSE, the typed key is returned in allocated memory.
6348f4ac015SBram Moolenaar  * Returns NULL on failure.
6358f4ac015SBram Moolenaar  */
6368f4ac015SBram Moolenaar     char_u *
crypt_get_key(int store,int twice)6377454a06eSBram Moolenaar crypt_get_key(
6387454a06eSBram Moolenaar     int		store,
639c667da51SBram Moolenaar     int		twice)	    // Ask for the key twice.
6408f4ac015SBram Moolenaar {
6418f4ac015SBram Moolenaar     char_u	*p1, *p2 = NULL;
6428f4ac015SBram Moolenaar     int		round;
6438f4ac015SBram Moolenaar 
6448f4ac015SBram Moolenaar     for (round = 0; ; ++round)
6458f4ac015SBram Moolenaar     {
6468f4ac015SBram Moolenaar 	cmdline_star = TRUE;
6478f4ac015SBram Moolenaar 	cmdline_row = msg_row;
6488f4ac015SBram Moolenaar 	p1 = getcmdline_prompt(NUL, round == 0
6498f4ac015SBram Moolenaar 		? (char_u *)_("Enter encryption key: ")
6508f4ac015SBram Moolenaar 		: (char_u *)_("Enter same key again: "), 0, EXPAND_NOTHING,
6518f4ac015SBram Moolenaar 		NULL);
6528f4ac015SBram Moolenaar 	cmdline_star = FALSE;
6538f4ac015SBram Moolenaar 
6548f4ac015SBram Moolenaar 	if (p1 == NULL)
6558f4ac015SBram Moolenaar 	    break;
6568f4ac015SBram Moolenaar 
6578f4ac015SBram Moolenaar 	if (round == twice)
6588f4ac015SBram Moolenaar 	{
6598f4ac015SBram Moolenaar 	    if (p2 != NULL && STRCMP(p1, p2) != 0)
6608f4ac015SBram Moolenaar 	    {
66132526b3cSBram Moolenaar 		msg(_("Keys don't match!"));
6628f4ac015SBram Moolenaar 		crypt_free_key(p1);
6638f4ac015SBram Moolenaar 		crypt_free_key(p2);
6648f4ac015SBram Moolenaar 		p2 = NULL;
665c667da51SBram Moolenaar 		round = -1;		// do it again
6668f4ac015SBram Moolenaar 		continue;
6678f4ac015SBram Moolenaar 	    }
6688f4ac015SBram Moolenaar 
6698f4ac015SBram Moolenaar 	    if (store)
6708f4ac015SBram Moolenaar 	    {
6718f4ac015SBram Moolenaar 		set_option_value((char_u *)"key", 0L, p1, OPT_LOCAL);
6728f4ac015SBram Moolenaar 		crypt_free_key(p1);
6738f4ac015SBram Moolenaar 		p1 = curbuf->b_p_key;
674226b28b9SChristian Brabandt #ifdef FEAT_SODIUM
675226b28b9SChristian Brabandt 		crypt_check_swapfile_curbuf();
676226b28b9SChristian Brabandt #endif
6778f4ac015SBram Moolenaar 	    }
6788f4ac015SBram Moolenaar 	    break;
6798f4ac015SBram Moolenaar 	}
6808f4ac015SBram Moolenaar 	p2 = p1;
6818f4ac015SBram Moolenaar     }
6828f4ac015SBram Moolenaar 
683c667da51SBram Moolenaar     // since the user typed this, no need to wait for return
684226b28b9SChristian Brabandt     if (crypt_get_method_nr(curbuf) != CRYPT_M_SOD)
685226b28b9SChristian Brabandt     {
6868f4ac015SBram Moolenaar 	if (msg_didout)
6878f4ac015SBram Moolenaar 	    msg_putchar('\n');
6888f4ac015SBram Moolenaar 	need_wait_return = FALSE;
6898f4ac015SBram Moolenaar 	msg_didout = FALSE;
690226b28b9SChristian Brabandt     }
6918f4ac015SBram Moolenaar 
6928f4ac015SBram Moolenaar     crypt_free_key(p2);
6938f4ac015SBram Moolenaar     return p1;
6948f4ac015SBram Moolenaar }
6958f4ac015SBram Moolenaar 
6968f4ac015SBram Moolenaar 
6978f4ac015SBram Moolenaar /*
6988f4ac015SBram Moolenaar  * Append a message to IObuff for the encryption/decryption method being used.
6998f4ac015SBram Moolenaar  */
7008f4ac015SBram Moolenaar     void
crypt_append_msg(buf_T * buf)7017454a06eSBram Moolenaar crypt_append_msg(
7027454a06eSBram Moolenaar     buf_T *buf)
7038f4ac015SBram Moolenaar {
7048f4ac015SBram Moolenaar     if (crypt_get_method_nr(buf) == 0)
7058f4ac015SBram Moolenaar 	STRCAT(IObuff, _("[crypted]"));
7068f4ac015SBram Moolenaar     else
7078f4ac015SBram Moolenaar     {
7088f4ac015SBram Moolenaar 	STRCAT(IObuff, "[");
7098f4ac015SBram Moolenaar 	STRCAT(IObuff, *buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
7108f4ac015SBram Moolenaar 	STRCAT(IObuff, "]");
7118f4ac015SBram Moolenaar     }
7128f4ac015SBram Moolenaar }
7138f4ac015SBram Moolenaar 
714f573c6e1SChristian Brabandt     int
crypt_sodium_init(cryptstate_T * state UNUSED,char_u * key UNUSED,char_u * salt UNUSED,int salt_len UNUSED,char_u * seed UNUSED,int seed_len UNUSED)715f573c6e1SChristian Brabandt crypt_sodium_init(
716f573c6e1SChristian Brabandt     cryptstate_T	*state UNUSED,
717f573c6e1SChristian Brabandt     char_u		*key UNUSED,
718f573c6e1SChristian Brabandt     char_u		*salt UNUSED,
719f573c6e1SChristian Brabandt     int			salt_len UNUSED,
720f573c6e1SChristian Brabandt     char_u		*seed UNUSED,
721f573c6e1SChristian Brabandt     int			seed_len UNUSED)
722f573c6e1SChristian Brabandt {
723f573c6e1SChristian Brabandt # ifdef FEAT_SODIUM
724f573c6e1SChristian Brabandt     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
725f573c6e1SChristian Brabandt     unsigned char	dkey[crypto_box_SEEDBYTES]; // 32
726f573c6e1SChristian Brabandt     sodium_state_T	*sd_state;
727*131530a5SBram Moolenaar     int			retval = 0;
728f573c6e1SChristian Brabandt 
729f573c6e1SChristian Brabandt     if (sodium_init() < 0)
730f573c6e1SChristian Brabandt 	return FAIL;
731f573c6e1SChristian Brabandt 
732f573c6e1SChristian Brabandt     sd_state = (sodium_state_T *)sodium_malloc(sizeof(sodium_state_T));
733f573c6e1SChristian Brabandt     sodium_memzero(sd_state, sizeof(sodium_state_T));
734f573c6e1SChristian Brabandt 
735f573c6e1SChristian Brabandt     // derive a key from the password
736f573c6e1SChristian Brabandt     if (crypto_pwhash(dkey, sizeof(dkey), (const char *)key, STRLEN(key), salt,
737f573c6e1SChristian Brabandt 	crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE,
738f573c6e1SChristian Brabandt 	crypto_pwhash_ALG_DEFAULT) != 0)
739f573c6e1SChristian Brabandt     {
740f573c6e1SChristian Brabandt 	// out of memory
741f573c6e1SChristian Brabandt 	sodium_free(sd_state);
742f573c6e1SChristian Brabandt 	return FAIL;
743f573c6e1SChristian Brabandt     }
744f573c6e1SChristian Brabandt     memcpy(sd_state->key, dkey, crypto_box_SEEDBYTES);
745*131530a5SBram Moolenaar 
746*131530a5SBram Moolenaar     retval += sodium_mlock(sd_state->key, crypto_box_SEEDBYTES);
747*131530a5SBram Moolenaar     retval += sodium_mlock(key, STRLEN(key));
748*131530a5SBram Moolenaar 
749*131530a5SBram Moolenaar     if (retval < 0)
750*131530a5SBram Moolenaar     {
751*131530a5SBram Moolenaar 	emsg(_(e_encryption_sodium_mlock_failed));
752*131530a5SBram Moolenaar 	sodium_free(sd_state);
753*131530a5SBram Moolenaar 	return FAIL;
754*131530a5SBram Moolenaar     }
755f573c6e1SChristian Brabandt     sd_state->count = 0;
756f573c6e1SChristian Brabandt     state->method_state = sd_state;
757f573c6e1SChristian Brabandt 
758f573c6e1SChristian Brabandt     return OK;
759f573c6e1SChristian Brabandt # else
760f573c6e1SChristian Brabandt     emsg(e_libsodium_not_built_in);
761f573c6e1SChristian Brabandt     return FAIL;
762f573c6e1SChristian Brabandt # endif
763f573c6e1SChristian Brabandt }
764f573c6e1SChristian Brabandt 
765f573c6e1SChristian Brabandt /*
766f573c6e1SChristian Brabandt  * Encrypt "from[len]" into "to[len]".
767f573c6e1SChristian Brabandt  * "from" and "to" can be equal to encrypt in place.
768f573c6e1SChristian Brabandt  * Call needs to ensure that there is enough space in to (for the header)
769f573c6e1SChristian Brabandt  */
770226b28b9SChristian Brabandt #if 0  // Currently unused
771f573c6e1SChristian Brabandt     void
772f573c6e1SChristian Brabandt crypt_sodium_encode(
773f573c6e1SChristian Brabandt     cryptstate_T *state UNUSED,
774f573c6e1SChristian Brabandt     char_u	*from UNUSED,
775f573c6e1SChristian Brabandt     size_t	len UNUSED,
776f573c6e1SChristian Brabandt     char_u	*to UNUSED,
777f573c6e1SChristian Brabandt     int		last UNUSED)
778f573c6e1SChristian Brabandt {
779f573c6e1SChristian Brabandt # ifdef FEAT_SODIUM
780f573c6e1SChristian Brabandt     // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
781f573c6e1SChristian Brabandt     sodium_state_T *sod_st = state->method_state;
782f573c6e1SChristian Brabandt     unsigned char  tag = last
783f573c6e1SChristian Brabandt 			? crypto_secretstream_xchacha20poly1305_TAG_FINAL  : 0;
784f573c6e1SChristian Brabandt 
785f573c6e1SChristian Brabandt     if (sod_st->count == 0)
786f573c6e1SChristian Brabandt     {
787f573c6e1SChristian Brabandt 	if (len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES)
788f573c6e1SChristian Brabandt 	{
789f573c6e1SChristian Brabandt 	    emsg(e_libsodium_cannot_encrypt_header);
790f573c6e1SChristian Brabandt 	    return;
791f573c6e1SChristian Brabandt 	}
792f573c6e1SChristian Brabandt 	crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state,
793f573c6e1SChristian Brabandt 							      to, sod_st->key);
794f573c6e1SChristian Brabandt 	to += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
795f573c6e1SChristian Brabandt     }
796f573c6e1SChristian Brabandt 
797f573c6e1SChristian Brabandt     if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES)
798f573c6e1SChristian Brabandt     {
799f573c6e1SChristian Brabandt 	emsg(e_libsodium_cannot_encrypt_buffer);
800f573c6e1SChristian Brabandt 	return;
801f573c6e1SChristian Brabandt     }
802f573c6e1SChristian Brabandt 
803f573c6e1SChristian Brabandt     crypto_secretstream_xchacha20poly1305_push(&sod_st->state, to, NULL,
804f573c6e1SChristian Brabandt 						      from, len, NULL, 0, tag);
805f573c6e1SChristian Brabandt 
806f573c6e1SChristian Brabandt     sod_st->count++;
807f573c6e1SChristian Brabandt # endif
808f573c6e1SChristian Brabandt }
809226b28b9SChristian Brabandt #endif
810f573c6e1SChristian Brabandt 
811226b28b9SChristian Brabandt /*
812f573c6e1SChristian Brabandt  * Decrypt "from[len]" into "to[len]".
813f573c6e1SChristian Brabandt  * "from" and "to" can be equal to encrypt in place.
814f573c6e1SChristian Brabandt  */
815226b28b9SChristian Brabandt #if 0  // Currently unused
816f573c6e1SChristian Brabandt     void
817f573c6e1SChristian Brabandt crypt_sodium_decode(
818f573c6e1SChristian Brabandt     cryptstate_T *state UNUSED,
819f573c6e1SChristian Brabandt     char_u	*from UNUSED,
820f573c6e1SChristian Brabandt     size_t	len UNUSED,
821f573c6e1SChristian Brabandt     char_u	*to UNUSED,
822f573c6e1SChristian Brabandt     int		last UNUSED)
823f573c6e1SChristian Brabandt {
824f573c6e1SChristian Brabandt # ifdef FEAT_SODIUM
825f573c6e1SChristian Brabandt     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
826f573c6e1SChristian Brabandt     sodium_state_T *sod_st = state->method_state;
827f573c6e1SChristian Brabandt     unsigned char  tag;
828f573c6e1SChristian Brabandt     unsigned long long buf_len;
829f573c6e1SChristian Brabandt     char_u *p1 = from;
830f573c6e1SChristian Brabandt     char_u *p2 = to;
831f573c6e1SChristian Brabandt     char_u *buf_out;
832f573c6e1SChristian Brabandt 
833f573c6e1SChristian Brabandt     if (sod_st->count == 0
834f573c6e1SChristian Brabandt 		   && len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES)
835f573c6e1SChristian Brabandt     {
836f573c6e1SChristian Brabandt 	emsg(e_libsodium_cannot_decrypt_header);
837f573c6e1SChristian Brabandt 	return;
838f573c6e1SChristian Brabandt     }
839f573c6e1SChristian Brabandt 
840f573c6e1SChristian Brabandt     buf_out = (char_u *)alloc(len);
841f573c6e1SChristian Brabandt 
842f573c6e1SChristian Brabandt     if (buf_out == NULL)
843f573c6e1SChristian Brabandt     {
844f573c6e1SChristian Brabandt 	emsg(e_libsodium_cannot_allocate_buffer);
845f573c6e1SChristian Brabandt 	return;
846f573c6e1SChristian Brabandt     }
847f573c6e1SChristian Brabandt     if (sod_st->count == 0)
848f573c6e1SChristian Brabandt     {
849f573c6e1SChristian Brabandt 	if (crypto_secretstream_xchacha20poly1305_init_pull(
850f573c6e1SChristian Brabandt 				       &sod_st->state, from, sod_st->key) != 0)
851f573c6e1SChristian Brabandt 	{
852f573c6e1SChristian Brabandt 	    emsg(e_libsodium_decryption_failed_header_incomplete);
853f573c6e1SChristian Brabandt 	    goto fail;
854f573c6e1SChristian Brabandt 	}
855f573c6e1SChristian Brabandt 
856f573c6e1SChristian Brabandt 	from += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
857f573c6e1SChristian Brabandt 	len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES;
858f573c6e1SChristian Brabandt 
859f573c6e1SChristian Brabandt 	if (p1 == p2)
860f573c6e1SChristian Brabandt 	    to += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
861f573c6e1SChristian Brabandt     }
862f573c6e1SChristian Brabandt 
863f573c6e1SChristian Brabandt     if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES)
864f573c6e1SChristian Brabandt     {
865f573c6e1SChristian Brabandt 	emsg(e_libsodium_cannot_decrypt_buffer);
866cb54bc65SDominique Pelle 	goto fail;
867f573c6e1SChristian Brabandt     }
868f573c6e1SChristian Brabandt     if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state,
869f573c6e1SChristian Brabandt 			     buf_out, &buf_len, &tag, from, len, NULL, 0) != 0)
870f573c6e1SChristian Brabandt     {
871cb54bc65SDominique Pelle 	emsg(e_libsodium_decryption_failed);
872f573c6e1SChristian Brabandt 	goto fail;
873f573c6e1SChristian Brabandt     }
874f573c6e1SChristian Brabandt     sod_st->count++;
875f573c6e1SChristian Brabandt 
876f573c6e1SChristian Brabandt     if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last)
877f573c6e1SChristian Brabandt     {
878cb54bc65SDominique Pelle 	emsg(e_libsodium_decryption_failed_premature);
879f573c6e1SChristian Brabandt 	goto fail;
880f573c6e1SChristian Brabandt     }
881f573c6e1SChristian Brabandt     if (p1 == p2)
882f573c6e1SChristian Brabandt 	mch_memmove(p2, buf_out, buf_len);
883f573c6e1SChristian Brabandt 
884f573c6e1SChristian Brabandt fail:
885f573c6e1SChristian Brabandt     vim_free(buf_out);
886f573c6e1SChristian Brabandt # endif
887f573c6e1SChristian Brabandt }
888226b28b9SChristian Brabandt #endif
889f573c6e1SChristian Brabandt 
890f573c6e1SChristian Brabandt /*
891f573c6e1SChristian Brabandt  * Encrypt "from[len]" into "to[len]".
892f573c6e1SChristian Brabandt  * "from" and "to" can be equal to encrypt in place.
893f573c6e1SChristian Brabandt  */
894f573c6e1SChristian Brabandt     long
crypt_sodium_buffer_encode(cryptstate_T * state UNUSED,char_u * from UNUSED,size_t len UNUSED,char_u ** buf_out UNUSED,int last UNUSED)895f573c6e1SChristian Brabandt crypt_sodium_buffer_encode(
896f573c6e1SChristian Brabandt     cryptstate_T *state UNUSED,
897f573c6e1SChristian Brabandt     char_u	*from UNUSED,
898f573c6e1SChristian Brabandt     size_t	len UNUSED,
899f573c6e1SChristian Brabandt     char_u	**buf_out UNUSED,
900f573c6e1SChristian Brabandt     int		last UNUSED)
901f573c6e1SChristian Brabandt {
902f573c6e1SChristian Brabandt # ifdef FEAT_SODIUM
903f573c6e1SChristian Brabandt     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
904f573c6e1SChristian Brabandt     unsigned long long	out_len;
905f573c6e1SChristian Brabandt     char_u		*ptr;
906f573c6e1SChristian Brabandt     unsigned char	tag = last
907f573c6e1SChristian Brabandt 			? crypto_secretstream_xchacha20poly1305_TAG_FINAL  : 0;
908f573c6e1SChristian Brabandt     int			length;
909f573c6e1SChristian Brabandt     sodium_state_T	*sod_st = state->method_state;
910f573c6e1SChristian Brabandt     int			first = (sod_st->count == 0);
911f573c6e1SChristian Brabandt 
912226b28b9SChristian Brabandt     length = (int)len + crypto_secretstream_xchacha20poly1305_ABYTES
913f573c6e1SChristian Brabandt 	     + (first ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0);
914f573c6e1SChristian Brabandt     *buf_out = alloc_clear(length);
915f573c6e1SChristian Brabandt     if (*buf_out == NULL)
916f573c6e1SChristian Brabandt     {
917f573c6e1SChristian Brabandt 	emsg(e_libsodium_cannot_allocate_buffer);
918f573c6e1SChristian Brabandt 	return -1;
919f573c6e1SChristian Brabandt     }
920f573c6e1SChristian Brabandt     ptr = *buf_out;
921f573c6e1SChristian Brabandt 
922f573c6e1SChristian Brabandt     if (first)
923f573c6e1SChristian Brabandt     {
924f573c6e1SChristian Brabandt 	crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state,
925f573c6e1SChristian Brabandt 		ptr, sod_st->key);
926f573c6e1SChristian Brabandt 	ptr += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
927f573c6e1SChristian Brabandt     }
928f573c6e1SChristian Brabandt 
929f573c6e1SChristian Brabandt     crypto_secretstream_xchacha20poly1305_push(&sod_st->state, ptr,
930f573c6e1SChristian Brabandt 	    &out_len, from, len, NULL, 0, tag);
931f573c6e1SChristian Brabandt 
932f573c6e1SChristian Brabandt     sod_st->count++;
933f573c6e1SChristian Brabandt     return out_len + (first
934f573c6e1SChristian Brabandt 		      ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0);
935f573c6e1SChristian Brabandt # else
936f573c6e1SChristian Brabandt     return -1;
937f573c6e1SChristian Brabandt # endif
938f573c6e1SChristian Brabandt }
939f573c6e1SChristian Brabandt 
940f573c6e1SChristian Brabandt /*
941f573c6e1SChristian Brabandt  * Decrypt "from[len]" into "to[len]".
942f573c6e1SChristian Brabandt  * "from" and "to" can be equal to encrypt in place.
943f573c6e1SChristian Brabandt  */
944f573c6e1SChristian Brabandt     long
crypt_sodium_buffer_decode(cryptstate_T * state UNUSED,char_u * from UNUSED,size_t len UNUSED,char_u ** buf_out UNUSED,int last UNUSED)945f573c6e1SChristian Brabandt crypt_sodium_buffer_decode(
946f573c6e1SChristian Brabandt     cryptstate_T *state UNUSED,
947f573c6e1SChristian Brabandt     char_u	*from UNUSED,
948f573c6e1SChristian Brabandt     size_t	len UNUSED,
949f573c6e1SChristian Brabandt     char_u	**buf_out UNUSED,
950f573c6e1SChristian Brabandt     int		last UNUSED)
951f573c6e1SChristian Brabandt {
952f573c6e1SChristian Brabandt # ifdef FEAT_SODIUM
953f573c6e1SChristian Brabandt     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
954f573c6e1SChristian Brabandt     sodium_state_T *sod_st = state->method_state;
955f573c6e1SChristian Brabandt     unsigned char  tag;
956f573c6e1SChristian Brabandt     unsigned long long out_len;
957f573c6e1SChristian Brabandt     *buf_out = alloc_clear(len);
958f573c6e1SChristian Brabandt     if (*buf_out == NULL)
959f573c6e1SChristian Brabandt     {
960f573c6e1SChristian Brabandt 	emsg(e_libsodium_cannot_allocate_buffer);
961f573c6e1SChristian Brabandt 	return -1;
962f573c6e1SChristian Brabandt     }
963f573c6e1SChristian Brabandt 
964f573c6e1SChristian Brabandt     if (sod_st->count == 0)
965f573c6e1SChristian Brabandt     {
966f573c6e1SChristian Brabandt 	if (crypto_secretstream_xchacha20poly1305_init_pull(&sod_st->state,
967f573c6e1SChristian Brabandt 						       from, sod_st->key) != 0)
968f573c6e1SChristian Brabandt 	{
969f573c6e1SChristian Brabandt 	    emsg(e_libsodium_decryption_failed_header_incomplete);
970f573c6e1SChristian Brabandt 	    return -1;
971f573c6e1SChristian Brabandt 	}
972f573c6e1SChristian Brabandt 	from += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
973f573c6e1SChristian Brabandt 	len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES;
974f573c6e1SChristian Brabandt 	sod_st->count++;
975f573c6e1SChristian Brabandt     }
976f573c6e1SChristian Brabandt     if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state,
977f573c6e1SChristian Brabandt 			    *buf_out, &out_len, &tag, from, len, NULL, 0) != 0)
978f573c6e1SChristian Brabandt     {
979cb54bc65SDominique Pelle 	emsg(e_libsodium_decryption_failed);
980f573c6e1SChristian Brabandt 	return -1;
981f573c6e1SChristian Brabandt     }
982f573c6e1SChristian Brabandt 
983f573c6e1SChristian Brabandt     if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last)
984cb54bc65SDominique Pelle 	emsg(e_libsodium_decryption_failed_premature);
985f573c6e1SChristian Brabandt     return (long) out_len;
986f573c6e1SChristian Brabandt # else
987f573c6e1SChristian Brabandt     return -1;
988f573c6e1SChristian Brabandt # endif
989f573c6e1SChristian Brabandt }
990f573c6e1SChristian Brabandt 
991c667da51SBram Moolenaar #endif // FEAT_CRYPT
992