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