forked from aniani/vim
patch 9.0.1481: decrypting with libsodium may fail if the library changes
Problem: Decrypting with libsodium may fail if the library changes. Solution: Add parameters used to the encrypted file header. (Christian Brabandt, closes #12279)
This commit is contained in:
parent
dcd40cfca0
commit
aae583441b
@ -1533,9 +1533,10 @@ To disable the encryption, reset the 'key' option to an empty value: >
|
|||||||
|
|
||||||
You can use the 'cryptmethod' option to select the type of encryption, use one
|
You can use the 'cryptmethod' option to select the type of encryption, use one
|
||||||
of these: >
|
of these: >
|
||||||
:setlocal cm=zip " weak method, backwards compatible
|
:setlocal cm=zip " weak method, backwards compatible
|
||||||
:setlocal cm=blowfish " method with flaws
|
:setlocal cm=blowfish " method with flaws, do not use
|
||||||
:setlocal cm=blowfish2 " medium strong method
|
:setlocal cm=blowfish2 " medium strong method
|
||||||
|
:setlocal cm=xchacha20v2 " medium strong method using libsodium
|
||||||
|
|
||||||
Do this before writing the file. When reading an encrypted file it will be
|
Do this before writing the file. When reading an encrypted file it will be
|
||||||
set automatically to the method used when that file was written. You can
|
set automatically to the method used when that file was written. You can
|
||||||
|
@ -2511,12 +2511,14 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
*pkzip*
|
*pkzip*
|
||||||
zip PkZip compatible method. A weak kind of encryption.
|
zip PkZip compatible method. A weak kind of encryption.
|
||||||
Backwards compatible with Vim 7.2 and older.
|
Backwards compatible with Vim 7.2 and older.
|
||||||
|
Only use if you need to be backwards compatible.
|
||||||
*blowfish*
|
*blowfish*
|
||||||
blowfish Blowfish method. Medium strong encryption but it has
|
blowfish Blowfish method. Medium strong encryption but it has
|
||||||
an implementation flaw. Requires Vim 7.3 or later,
|
an implementation flaw. Requires Vim 7.3 or later,
|
||||||
files can NOT be read by Vim 7.2 and older. This adds
|
files can NOT be read by Vim 7.2 and older. This adds
|
||||||
a "seed" to the file, every time you write the file
|
a "seed" to the file, every time you write the file
|
||||||
the encrypted bytes will be different.
|
the encrypted bytes will be different.
|
||||||
|
Obsolete, please do no longer use.
|
||||||
*blowfish2*
|
*blowfish2*
|
||||||
blowfish2 Blowfish method. Medium strong encryption. Requires
|
blowfish2 Blowfish method. Medium strong encryption. Requires
|
||||||
Vim 7.4.401 or later, files can NOT be read by Vim 7.3
|
Vim 7.4.401 or later, files can NOT be read by Vim 7.3
|
||||||
@ -2538,11 +2540,21 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
enabled.
|
enabled.
|
||||||
Encryption of undo files is not yet supported,
|
Encryption of undo files is not yet supported,
|
||||||
therefore no undo file will currently be written.
|
therefore no undo file will currently be written.
|
||||||
CURRENTLY EXPERIMENTAL: Files written with this method
|
CAREFUL: Files written with this method might have to
|
||||||
|
be read back with the same version of Vim if the
|
||||||
|
binary format changes later.
|
||||||
|
Obsolete, please do no longer use.
|
||||||
|
xchacha20v2 Same algorithm as with "xchacha20" that correctly
|
||||||
|
stores the key derivation parameters together with the
|
||||||
|
encrypted file. Should work better in case the
|
||||||
|
parameters in the libsodium library ever change.
|
||||||
|
STILL EXPERIMENTAL: Files written with this method
|
||||||
might have to be read back with the same version of
|
might have to be read back with the same version of
|
||||||
Vim if the binary format changes later.
|
Vim if the binary format changes later.
|
||||||
|
|
||||||
You should use "blowfish2", also to re-encrypt older files.
|
You should use "blowfish2", also to re-encrypt older files. The
|
||||||
|
"xchacha20" method provides better encryption, but it does not work
|
||||||
|
with all versions of Vim.
|
||||||
|
|
||||||
When reading an encrypted file 'cryptmethod' will be set automatically
|
When reading an encrypted file 'cryptmethod' will be set automatically
|
||||||
to the detected method of the file being read. Thus if you write it
|
to the detected method of the file being read. Thus if you write it
|
||||||
|
@ -641,11 +641,8 @@ crypt_blowfish_decode(
|
|||||||
int
|
int
|
||||||
crypt_blowfish_init(
|
crypt_blowfish_init(
|
||||||
cryptstate_T *state,
|
cryptstate_T *state,
|
||||||
char_u* key,
|
char_u *key,
|
||||||
char_u* salt,
|
crypt_arg_T *arg)
|
||||||
int salt_len,
|
|
||||||
char_u* seed,
|
|
||||||
int seed_len)
|
|
||||||
{
|
{
|
||||||
bf_state_T *bfs = ALLOC_CLEAR_ONE(bf_state_T);
|
bf_state_T *bfs = ALLOC_CLEAR_ONE(bf_state_T);
|
||||||
|
|
||||||
@ -660,8 +657,8 @@ crypt_blowfish_init(
|
|||||||
if (blowfish_self_test() == FAIL)
|
if (blowfish_self_test() == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
bf_key_init(bfs, key, salt, salt_len);
|
bf_key_init(bfs, key, arg->cat_salt, arg->cat_salt_len);
|
||||||
bf_cfb_init(bfs, seed, seed_len);
|
bf_cfb_init(bfs, arg->cat_seed, arg->cat_seed_len);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
@ -2362,8 +2362,8 @@ free_buf_options(
|
|||||||
#endif
|
#endif
|
||||||
#ifdef FEAT_CRYPT
|
#ifdef FEAT_CRYPT
|
||||||
# ifdef FEAT_SODIUM
|
# ifdef FEAT_SODIUM
|
||||||
if ((buf->b_p_key != NULL) && (*buf->b_p_key != NUL) &&
|
if (buf->b_p_key != NULL && *buf->b_p_key != NUL
|
||||||
(crypt_get_method_nr(buf) == CRYPT_M_SOD))
|
&& crypt_method_is_sodium(crypt_get_method_nr(buf)))
|
||||||
crypt_sodium_munlock(buf->b_p_key, STRLEN(buf->b_p_key));
|
crypt_sodium_munlock(buf->b_p_key, STRLEN(buf->b_p_key));
|
||||||
# endif
|
# endif
|
||||||
clear_string_option(&buf->b_p_key);
|
clear_string_option(&buf->b_p_key);
|
||||||
|
274
src/crypt.c
274
src/crypt.c
@ -34,6 +34,8 @@ typedef struct {
|
|||||||
char *magic; // magic bytes stored in file header
|
char *magic; // magic bytes stored in file header
|
||||||
int salt_len; // length of salt, or 0 when not using salt
|
int salt_len; // length of salt, or 0 when not using salt
|
||||||
int seed_len; // length of seed, or 0 when not using seed
|
int seed_len; // length of seed, or 0 when not using seed
|
||||||
|
int add_len; // additional length in the header needed for storing
|
||||||
|
// custom data
|
||||||
#ifdef CRYPT_NOT_INPLACE
|
#ifdef CRYPT_NOT_INPLACE
|
||||||
int works_inplace; // encryption/decryption can be done in-place
|
int works_inplace; // encryption/decryption can be done in-place
|
||||||
#endif
|
#endif
|
||||||
@ -44,7 +46,7 @@ typedef struct {
|
|||||||
|
|
||||||
// Function pointer for initializing encryption/decryption.
|
// Function pointer for initializing encryption/decryption.
|
||||||
int (* init_fn)(cryptstate_T *state, char_u *key,
|
int (* init_fn)(cryptstate_T *state, char_u *key,
|
||||||
char_u *salt, int salt_len, char_u *seed, int seed_len);
|
crypt_arg_T *arg);
|
||||||
|
|
||||||
// Function pointers for encoding/decoding from one buffer into another.
|
// Function pointers for encoding/decoding from one buffer into another.
|
||||||
// Optional, however, these or the _buffer ones should be configured.
|
// Optional, however, these or the _buffer ones should be configured.
|
||||||
@ -73,9 +75,12 @@ typedef struct {
|
|||||||
char_u *p2, int last);
|
char_u *p2, int last);
|
||||||
} cryptmethod_T;
|
} cryptmethod_T;
|
||||||
|
|
||||||
static int crypt_sodium_init_(cryptstate_T *state, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len);
|
static int crypt_sodium_init_(cryptstate_T *state, char_u *key, crypt_arg_T *arg);
|
||||||
static long crypt_sodium_buffer_decode(cryptstate_T *state, char_u *from, size_t len, char_u **buf_out, int last);
|
static long crypt_sodium_buffer_decode(cryptstate_T *state, char_u *from, size_t len, char_u **buf_out, int last);
|
||||||
static long crypt_sodium_buffer_encode(cryptstate_T *state, char_u *from, size_t len, char_u **buf_out, int last);
|
static long crypt_sodium_buffer_encode(cryptstate_T *state, char_u *from, size_t len, char_u **buf_out, int last);
|
||||||
|
#if defined(FEAT_EVAL) && defined(FEAT_SODIUM)
|
||||||
|
static void crypt_sodium_report_hash_params( unsigned long long opslimit, unsigned long long ops_def, size_t memlimit, size_t mem_def, int alg, int alg_def);
|
||||||
|
#endif
|
||||||
|
|
||||||
// index is method_nr of cryptstate_T, CRYPT_M_*
|
// index is method_nr of cryptstate_T, CRYPT_M_*
|
||||||
static cryptmethod_T cryptmethods[CRYPT_M_COUNT] = {
|
static cryptmethod_T cryptmethods[CRYPT_M_COUNT] = {
|
||||||
@ -85,6 +90,7 @@ static cryptmethod_T cryptmethods[CRYPT_M_COUNT] = {
|
|||||||
"VimCrypt~01!",
|
"VimCrypt~01!",
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
#ifdef CRYPT_NOT_INPLACE
|
#ifdef CRYPT_NOT_INPLACE
|
||||||
TRUE,
|
TRUE,
|
||||||
#endif
|
#endif
|
||||||
@ -102,6 +108,7 @@ static cryptmethod_T cryptmethods[CRYPT_M_COUNT] = {
|
|||||||
"VimCrypt~02!",
|
"VimCrypt~02!",
|
||||||
8,
|
8,
|
||||||
8,
|
8,
|
||||||
|
0,
|
||||||
#ifdef CRYPT_NOT_INPLACE
|
#ifdef CRYPT_NOT_INPLACE
|
||||||
TRUE,
|
TRUE,
|
||||||
#endif
|
#endif
|
||||||
@ -119,6 +126,7 @@ static cryptmethod_T cryptmethods[CRYPT_M_COUNT] = {
|
|||||||
"VimCrypt~03!",
|
"VimCrypt~03!",
|
||||||
8,
|
8,
|
||||||
8,
|
8,
|
||||||
|
0,
|
||||||
#ifdef CRYPT_NOT_INPLACE
|
#ifdef CRYPT_NOT_INPLACE
|
||||||
TRUE,
|
TRUE,
|
||||||
#endif
|
#endif
|
||||||
@ -130,7 +138,7 @@ static cryptmethod_T cryptmethods[CRYPT_M_COUNT] = {
|
|||||||
crypt_blowfish_encode, crypt_blowfish_decode,
|
crypt_blowfish_encode, crypt_blowfish_decode,
|
||||||
},
|
},
|
||||||
|
|
||||||
// XChaCha20 using libsodium
|
// XChaCha20 using libsodium; implementation issues
|
||||||
{
|
{
|
||||||
"xchacha20",
|
"xchacha20",
|
||||||
"VimCrypt~04!",
|
"VimCrypt~04!",
|
||||||
@ -140,6 +148,29 @@ static cryptmethod_T cryptmethods[CRYPT_M_COUNT] = {
|
|||||||
16,
|
16,
|
||||||
#endif
|
#endif
|
||||||
8,
|
8,
|
||||||
|
0,
|
||||||
|
#ifdef CRYPT_NOT_INPLACE
|
||||||
|
FALSE,
|
||||||
|
#endif
|
||||||
|
FALSE,
|
||||||
|
NULL,
|
||||||
|
crypt_sodium_init_,
|
||||||
|
NULL, NULL,
|
||||||
|
crypt_sodium_buffer_encode, crypt_sodium_buffer_decode,
|
||||||
|
NULL, NULL,
|
||||||
|
},
|
||||||
|
// XChaCha20 using libsodium; stores parameters in header
|
||||||
|
{
|
||||||
|
"xchacha20v2",
|
||||||
|
"VimCrypt~05!",
|
||||||
|
#ifdef FEAT_SODIUM
|
||||||
|
crypto_pwhash_argon2id_SALTBYTES, // 16
|
||||||
|
#else
|
||||||
|
16,
|
||||||
|
#endif
|
||||||
|
8,
|
||||||
|
// sizeof(crypto_pwhash_OPSLIMIT_INTERACTIVE + crypto_pwhash_MEMLIMIT_INTERACTIVE + crypto_pwhash_ALG_DEFAULT)
|
||||||
|
20,
|
||||||
#ifdef CRYPT_NOT_INPLACE
|
#ifdef CRYPT_NOT_INPLACE
|
||||||
FALSE,
|
FALSE,
|
||||||
#endif
|
#endif
|
||||||
@ -369,6 +400,15 @@ crypt_get_method_nr(buf_T *buf)
|
|||||||
return crypt_method_nr_from_name(*buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
|
return crypt_method_nr_from_name(*buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns True for Sodium Encryption.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
crypt_method_is_sodium(int method)
|
||||||
|
{
|
||||||
|
return method == CRYPT_M_SOD || method == CRYPT_M_SOD2;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return TRUE when the buffer uses an encryption method that encrypts the
|
* Return TRUE when the buffer uses an encryption method that encrypts the
|
||||||
* whole undo file, not only the text.
|
* whole undo file, not only the text.
|
||||||
@ -387,7 +427,8 @@ crypt_get_header_len(int method_nr)
|
|||||||
{
|
{
|
||||||
return CRYPT_MAGIC_LEN
|
return CRYPT_MAGIC_LEN
|
||||||
+ cryptmethods[method_nr].salt_len
|
+ cryptmethods[method_nr].salt_len
|
||||||
+ cryptmethods[method_nr].seed_len;
|
+ cryptmethods[method_nr].seed_len
|
||||||
|
+ cryptmethods[method_nr].add_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -445,10 +486,7 @@ crypt_self_test(void)
|
|||||||
crypt_create(
|
crypt_create(
|
||||||
int method_nr,
|
int method_nr,
|
||||||
char_u *key,
|
char_u *key,
|
||||||
char_u *salt,
|
crypt_arg_T *crypt_arg)
|
||||||
int salt_len,
|
|
||||||
char_u *seed,
|
|
||||||
int seed_len)
|
|
||||||
{
|
{
|
||||||
cryptstate_T *state = ALLOC_ONE(cryptstate_T);
|
cryptstate_T *state = ALLOC_ONE(cryptstate_T);
|
||||||
|
|
||||||
@ -456,8 +494,7 @@ crypt_create(
|
|||||||
return state;
|
return state;
|
||||||
|
|
||||||
state->method_nr = method_nr;
|
state->method_nr = method_nr;
|
||||||
if (cryptmethods[method_nr].init_fn(
|
if (cryptmethods[method_nr].init_fn(state, key, crypt_arg) == FAIL)
|
||||||
state, key, salt, salt_len, seed, seed_len) == FAIL)
|
|
||||||
{
|
{
|
||||||
vim_free(state);
|
vim_free(state);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -476,17 +513,22 @@ crypt_create_from_header(
|
|||||||
char_u *key,
|
char_u *key,
|
||||||
char_u *header)
|
char_u *header)
|
||||||
{
|
{
|
||||||
char_u *salt = NULL;
|
crypt_arg_T arg;
|
||||||
char_u *seed = NULL;
|
|
||||||
int salt_len = cryptmethods[method_nr].salt_len;
|
|
||||||
int seed_len = cryptmethods[method_nr].seed_len;
|
|
||||||
|
|
||||||
if (salt_len > 0)
|
CLEAR_FIELD(arg);
|
||||||
salt = header + CRYPT_MAGIC_LEN;
|
arg.cat_init_from_file = TRUE;
|
||||||
if (seed_len > 0)
|
|
||||||
seed = header + CRYPT_MAGIC_LEN + salt_len;
|
|
||||||
|
|
||||||
return crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
|
arg.cat_salt_len = cryptmethods[method_nr].salt_len;
|
||||||
|
arg.cat_seed_len = cryptmethods[method_nr].seed_len;
|
||||||
|
arg.cat_add_len = cryptmethods[method_nr].add_len;
|
||||||
|
if (arg.cat_salt_len > 0)
|
||||||
|
arg.cat_salt = header + CRYPT_MAGIC_LEN;
|
||||||
|
if (arg.cat_seed_len > 0)
|
||||||
|
arg.cat_seed = header + CRYPT_MAGIC_LEN + arg.cat_salt_len;
|
||||||
|
if (arg.cat_add_len > 0)
|
||||||
|
arg.cat_add = header + CRYPT_MAGIC_LEN + arg.cat_salt_len + arg.cat_seed_len;
|
||||||
|
|
||||||
|
return crypt_create(method_nr, key, &arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -540,24 +582,29 @@ crypt_create_for_writing(
|
|||||||
int *header_len)
|
int *header_len)
|
||||||
{
|
{
|
||||||
int len = crypt_get_header_len(method_nr);
|
int len = crypt_get_header_len(method_nr);
|
||||||
char_u *salt = NULL;
|
crypt_arg_T arg;
|
||||||
char_u *seed = NULL;
|
|
||||||
int salt_len = cryptmethods[method_nr].salt_len;
|
|
||||||
int seed_len = cryptmethods[method_nr].seed_len;
|
|
||||||
cryptstate_T *state;
|
cryptstate_T *state;
|
||||||
|
|
||||||
|
CLEAR_FIELD(arg);
|
||||||
|
arg.cat_salt_len = cryptmethods[method_nr].salt_len;
|
||||||
|
arg.cat_seed_len = cryptmethods[method_nr].seed_len;
|
||||||
|
arg.cat_add_len = cryptmethods[method_nr].add_len;
|
||||||
|
arg.cat_init_from_file = FALSE;
|
||||||
|
|
||||||
*header_len = len;
|
*header_len = len;
|
||||||
*header = alloc(len);
|
*header = alloc(len);
|
||||||
if (*header == NULL)
|
if (*header == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
mch_memmove(*header, cryptmethods[method_nr].magic, CRYPT_MAGIC_LEN);
|
mch_memmove(*header, cryptmethods[method_nr].magic, CRYPT_MAGIC_LEN);
|
||||||
if (salt_len > 0 || seed_len > 0)
|
if (arg.cat_salt_len > 0 || arg.cat_seed_len > 0 || arg.cat_add_len > 0)
|
||||||
{
|
{
|
||||||
if (salt_len > 0)
|
if (arg.cat_salt_len > 0)
|
||||||
salt = *header + CRYPT_MAGIC_LEN;
|
arg.cat_salt = *header + CRYPT_MAGIC_LEN;
|
||||||
if (seed_len > 0)
|
if (arg.cat_seed_len > 0)
|
||||||
seed = *header + CRYPT_MAGIC_LEN + salt_len;
|
arg.cat_seed = *header + CRYPT_MAGIC_LEN + arg.cat_salt_len;
|
||||||
|
if (arg.cat_add_len > 0)
|
||||||
|
arg.cat_add = *header + CRYPT_MAGIC_LEN + arg.cat_salt_len + arg.cat_seed_len;
|
||||||
|
|
||||||
// TODO: Should this be crypt method specific? (Probably not worth
|
// TODO: Should this be crypt method specific? (Probably not worth
|
||||||
// it). sha2_seed is pretty bad for large amounts of entropy, so make
|
// it). sha2_seed is pretty bad for large amounts of entropy, so make
|
||||||
@ -565,16 +612,16 @@ crypt_create_for_writing(
|
|||||||
#ifdef FEAT_SODIUM
|
#ifdef FEAT_SODIUM
|
||||||
if (sodium_init() >= 0)
|
if (sodium_init() >= 0)
|
||||||
{
|
{
|
||||||
if (salt_len > 0)
|
if (arg.cat_salt_len > 0)
|
||||||
randombytes_buf(salt, salt_len);
|
randombytes_buf(arg.cat_salt, arg.cat_salt_len);
|
||||||
if (seed_len > 0)
|
if (arg.cat_seed_len > 0)
|
||||||
randombytes_buf(seed, seed_len);
|
randombytes_buf(arg.cat_seed, arg.cat_seed_len);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
sha2_seed(salt, salt_len, seed, seed_len);
|
sha2_seed(arg.cat_salt, arg.cat_salt_len, arg.cat_seed, arg.cat_seed_len);
|
||||||
}
|
}
|
||||||
state = crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
|
state = crypt_create(method_nr, key, &arg);
|
||||||
if (state == NULL)
|
if (state == NULL)
|
||||||
VIM_CLEAR(*header);
|
VIM_CLEAR(*header);
|
||||||
return state;
|
return state;
|
||||||
@ -587,7 +634,7 @@ crypt_create_for_writing(
|
|||||||
crypt_free_state(cryptstate_T *state)
|
crypt_free_state(cryptstate_T *state)
|
||||||
{
|
{
|
||||||
#ifdef FEAT_SODIUM
|
#ifdef FEAT_SODIUM
|
||||||
if (state->method_nr == CRYPT_M_SOD)
|
if (crypt_method_is_sodium(state->method_nr))
|
||||||
{
|
{
|
||||||
sodium_munlock(((sodium_state_T *)state->method_state)->key,
|
sodium_munlock(((sodium_state_T *)state->method_state)->key,
|
||||||
crypto_box_SEEDBYTES);
|
crypto_box_SEEDBYTES);
|
||||||
@ -742,7 +789,7 @@ crypt_free_key(char_u *key)
|
|||||||
void
|
void
|
||||||
crypt_check_method(int method)
|
crypt_check_method(int method)
|
||||||
{
|
{
|
||||||
if (method < CRYPT_M_BF2)
|
if (method < CRYPT_M_BF2 || method == CRYPT_M_SOD)
|
||||||
{
|
{
|
||||||
msg_scroll = TRUE;
|
msg_scroll = TRUE;
|
||||||
msg(_("Warning: Using a weak encryption method; see :help 'cm'"));
|
msg(_("Warning: Using a weak encryption method; see :help 'cm'"));
|
||||||
@ -754,7 +801,7 @@ crypt_check_method(int method)
|
|||||||
crypt_check_swapfile_curbuf(void)
|
crypt_check_swapfile_curbuf(void)
|
||||||
{
|
{
|
||||||
int method = crypt_get_method_nr(curbuf);
|
int method = crypt_get_method_nr(curbuf);
|
||||||
if (method == CRYPT_M_SOD)
|
if (crypt_method_is_sodium(method))
|
||||||
{
|
{
|
||||||
// encryption uses padding and MAC, that does not work very well with
|
// encryption uses padding and MAC, that does not work very well with
|
||||||
// swap and undo files, so disable them
|
// swap and undo files, so disable them
|
||||||
@ -827,7 +874,7 @@ crypt_get_key(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// since the user typed this, no need to wait for return
|
// since the user typed this, no need to wait for return
|
||||||
if (crypt_get_method_nr(curbuf) != CRYPT_M_SOD)
|
if (!crypt_method_is_sodium(crypt_get_method_nr(curbuf)))
|
||||||
{
|
{
|
||||||
if (msg_didout)
|
if (msg_didout)
|
||||||
msg_putchar('\n');
|
msg_putchar('\n');
|
||||||
@ -861,16 +908,16 @@ crypt_append_msg(
|
|||||||
crypt_sodium_init_(
|
crypt_sodium_init_(
|
||||||
cryptstate_T *state UNUSED,
|
cryptstate_T *state UNUSED,
|
||||||
char_u *key UNUSED,
|
char_u *key UNUSED,
|
||||||
char_u *salt UNUSED,
|
crypt_arg_T *arg UNUSED)
|
||||||
int salt_len UNUSED,
|
|
||||||
char_u *seed UNUSED,
|
|
||||||
int seed_len UNUSED)
|
|
||||||
{
|
{
|
||||||
# ifdef FEAT_SODIUM
|
# ifdef FEAT_SODIUM
|
||||||
// crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
|
// crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
|
||||||
unsigned char dkey[crypto_box_SEEDBYTES]; // 32
|
unsigned char dkey[crypto_box_SEEDBYTES]; // 32
|
||||||
sodium_state_T *sd_state;
|
sodium_state_T *sd_state;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
unsigned long long opslimit;
|
||||||
|
size_t memlimit;
|
||||||
|
int alg;
|
||||||
|
|
||||||
if (sodium_init() < 0)
|
if (sodium_init() < 0)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@ -878,25 +925,98 @@ crypt_sodium_init_(
|
|||||||
sd_state = (sodium_state_T *)sodium_malloc(sizeof(sodium_state_T));
|
sd_state = (sodium_state_T *)sodium_malloc(sizeof(sodium_state_T));
|
||||||
sodium_memzero(sd_state, sizeof(sodium_state_T));
|
sodium_memzero(sd_state, sizeof(sodium_state_T));
|
||||||
|
|
||||||
// derive a key from the password
|
if ((state->method_nr == CRYPT_M_SOD2 && !arg->cat_init_from_file)
|
||||||
if (crypto_pwhash(dkey, sizeof(dkey), (const char *)key, STRLEN(key), salt,
|
|| state->method_nr == CRYPT_M_SOD)
|
||||||
crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE,
|
|
||||||
crypto_pwhash_ALG_DEFAULT) != 0)
|
|
||||||
{
|
{
|
||||||
// out of memory
|
opslimit = crypto_pwhash_OPSLIMIT_INTERACTIVE;
|
||||||
sodium_free(sd_state);
|
memlimit = crypto_pwhash_MEMLIMIT_INTERACTIVE;
|
||||||
return FAIL;
|
alg = crypto_pwhash_ALG_DEFAULT;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// For testing
|
||||||
|
if (state->method_nr == CRYPT_M_SOD2)
|
||||||
|
{
|
||||||
|
opslimit = crypto_pwhash_OPSLIMIT_MODERATE;
|
||||||
|
memlimit = crypto_pwhash_MEMLIMIT_MODERATE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// derive a key from the password
|
||||||
|
if (crypto_pwhash(dkey, sizeof(dkey), (const char *)key, STRLEN(key),
|
||||||
|
arg->cat_salt, opslimit, memlimit, alg) != 0)
|
||||||
|
{
|
||||||
|
// out of memory
|
||||||
|
sodium_free(sd_state);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
memcpy(sd_state->key, dkey, crypto_box_SEEDBYTES);
|
||||||
|
|
||||||
|
retval += sodium_mlock(sd_state->key, crypto_box_SEEDBYTES);
|
||||||
|
retval += sodium_mlock(key, STRLEN(key));
|
||||||
|
|
||||||
|
if (retval < 0)
|
||||||
|
{
|
||||||
|
emsg(_(e_encryption_sodium_mlock_failed));
|
||||||
|
sodium_free(sd_state);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
if (state->method_nr == CRYPT_M_SOD2)
|
||||||
|
{
|
||||||
|
memcpy(arg->cat_add, &opslimit, sizeof(opslimit));
|
||||||
|
arg->cat_add += sizeof(opslimit);
|
||||||
|
|
||||||
|
memcpy(arg->cat_add, &memlimit, sizeof(memlimit));
|
||||||
|
arg->cat_add += sizeof(memlimit);
|
||||||
|
|
||||||
|
memcpy(arg->cat_add, &alg, sizeof(alg));
|
||||||
|
arg->cat_add += sizeof(alg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
memcpy(sd_state->key, dkey, crypto_box_SEEDBYTES);
|
else
|
||||||
|
|
||||||
retval += sodium_mlock(sd_state->key, crypto_box_SEEDBYTES);
|
|
||||||
retval += sodium_mlock(key, STRLEN(key));
|
|
||||||
|
|
||||||
if (retval < 0)
|
|
||||||
{
|
{
|
||||||
emsg(_(e_encryption_sodium_mlock_failed));
|
// Reading parameters from file
|
||||||
sodium_free(sd_state);
|
if (arg->cat_add_len
|
||||||
return FAIL;
|
< (int)(sizeof(opslimit) + sizeof(memlimit) + sizeof(alg)))
|
||||||
|
{
|
||||||
|
sodium_free(sd_state);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// derive the key from the file header
|
||||||
|
memcpy(&opslimit, arg->cat_add, sizeof(opslimit));
|
||||||
|
arg->cat_add += sizeof(opslimit);
|
||||||
|
|
||||||
|
memcpy(&memlimit, arg->cat_add, sizeof(memlimit));
|
||||||
|
arg->cat_add += sizeof(memlimit);
|
||||||
|
|
||||||
|
memcpy(&alg, arg->cat_add, sizeof(alg));
|
||||||
|
arg->cat_add += sizeof(alg);
|
||||||
|
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
crypt_sodium_report_hash_params(opslimit,
|
||||||
|
crypto_pwhash_OPSLIMIT_INTERACTIVE,
|
||||||
|
memlimit, crypto_pwhash_MEMLIMIT_INTERACTIVE,
|
||||||
|
alg, crypto_pwhash_ALG_DEFAULT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (crypto_pwhash(dkey, sizeof(dkey), (const char *)key, STRLEN(key),
|
||||||
|
arg->cat_salt, opslimit, memlimit, alg) != 0)
|
||||||
|
{
|
||||||
|
// out of memory
|
||||||
|
sodium_free(sd_state);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
memcpy(sd_state->key, dkey, crypto_box_SEEDBYTES);
|
||||||
|
|
||||||
|
retval += sodium_mlock(sd_state->key, crypto_box_SEEDBYTES);
|
||||||
|
retval += sodium_mlock(key, STRLEN(key));
|
||||||
|
|
||||||
|
if (retval < 0)
|
||||||
|
{
|
||||||
|
emsg(_(e_encryption_sodium_mlock_failed));
|
||||||
|
sodium_free(sd_state);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sd_state->count = 0;
|
sd_state->count = 0;
|
||||||
state->method_state = sd_state;
|
state->method_state = sd_state;
|
||||||
@ -1100,6 +1220,14 @@ crypt_sodium_buffer_decode(
|
|||||||
sodium_state_T *sod_st = state->method_state;
|
sodium_state_T *sod_st = state->method_state;
|
||||||
unsigned char tag;
|
unsigned char tag;
|
||||||
unsigned long long out_len;
|
unsigned long long out_len;
|
||||||
|
|
||||||
|
if (sod_st->count == 0
|
||||||
|
&& state->method_nr == CRYPT_M_SOD
|
||||||
|
&& len > WRITEBUFSIZE
|
||||||
|
+ crypto_secretstream_xchacha20poly1305_HEADERBYTES
|
||||||
|
+ crypto_secretstream_xchacha20poly1305_ABYTES)
|
||||||
|
len -= cryptmethods[CRYPT_M_SOD2].add_len;
|
||||||
|
|
||||||
*buf_out = alloc_clear(len);
|
*buf_out = alloc_clear(len);
|
||||||
if (*buf_out == NULL)
|
if (*buf_out == NULL)
|
||||||
{
|
{
|
||||||
@ -1158,6 +1286,36 @@ crypt_sodium_randombytes_random(void)
|
|||||||
{
|
{
|
||||||
return randombytes_random();
|
return randombytes_random();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(FEAT_EVAL) || defined(PROTO)
|
||||||
|
static void
|
||||||
|
crypt_sodium_report_hash_params(
|
||||||
|
unsigned long long opslimit,
|
||||||
|
unsigned long long ops_def,
|
||||||
|
size_t memlimit,
|
||||||
|
size_t mem_def,
|
||||||
|
int alg,
|
||||||
|
int alg_def)
|
||||||
|
{
|
||||||
|
if (p_verbose > 0)
|
||||||
|
{
|
||||||
|
verbose_enter();
|
||||||
|
if (opslimit != ops_def)
|
||||||
|
smsg(_("xchacha20v2: using custom opslimit \"%llu\" for Key derivation."), opslimit);
|
||||||
|
else
|
||||||
|
smsg(_("xchacha20v2: using default opslimit \"%llu\" for Key derivation."), opslimit);
|
||||||
|
if (memlimit != mem_def)
|
||||||
|
smsg(_("xchacha20v2: using custom memlimit \"%lu\" for Key derivation."), (unsigned long)memlimit);
|
||||||
|
else
|
||||||
|
smsg(_("xchacha20v2: using default memlimit \"%lu\" for Key derivation."), (unsigned long)memlimit);
|
||||||
|
if (alg != alg_def)
|
||||||
|
smsg(_("xchacha20v2: using custom algorithm \"%d\" for Key derivation."), alg);
|
||||||
|
else
|
||||||
|
smsg(_("xchacha20v2: using default algorithm \"%d\" for Key derivation."), alg);
|
||||||
|
verbose_leave();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#endif // FEAT_CRYPT
|
#endif // FEAT_CRYPT
|
||||||
|
@ -83,10 +83,7 @@ make_crc_tab(void)
|
|||||||
crypt_zip_init(
|
crypt_zip_init(
|
||||||
cryptstate_T *state,
|
cryptstate_T *state,
|
||||||
char_u *key,
|
char_u *key,
|
||||||
char_u *salt UNUSED,
|
crypt_arg_T *arg UNUSED)
|
||||||
int salt_len UNUSED,
|
|
||||||
char_u *seed UNUSED,
|
|
||||||
int seed_len UNUSED)
|
|
||||||
{
|
{
|
||||||
char_u *p;
|
char_u *p;
|
||||||
zip_state_T *zs;
|
zip_state_T *zs;
|
||||||
|
35
src/fileio.c
35
src/fileio.c
@ -218,6 +218,9 @@ readfile(
|
|||||||
int using_b_fname;
|
int using_b_fname;
|
||||||
static char *msg_is_a_directory = N_("is a directory");
|
static char *msg_is_a_directory = N_("is a directory");
|
||||||
int eof;
|
int eof;
|
||||||
|
#ifdef FEAT_SODIUM
|
||||||
|
int may_need_lseek = FALSE;
|
||||||
|
#endif
|
||||||
|
|
||||||
au_did_filetype = FALSE; // reset before triggering any autocommands
|
au_did_filetype = FALSE; // reset before triggering any autocommands
|
||||||
|
|
||||||
@ -1282,15 +1285,43 @@ retry:
|
|||||||
*/
|
*/
|
||||||
# ifdef FEAT_SODIUM
|
# ifdef FEAT_SODIUM
|
||||||
// Let the crypt layer work with a buffer size of 8192
|
// Let the crypt layer work with a buffer size of 8192
|
||||||
|
//
|
||||||
|
// Sodium encryption requires a fixed block size to
|
||||||
|
// successfully decrypt. However, unfortunately the file
|
||||||
|
// header size changes between xchacha20 and xchacha20v2 by
|
||||||
|
// 'add_len' bytes.
|
||||||
|
// So we will now read the maximum header size + encryption
|
||||||
|
// metadata, but after determining to read an xchacha20
|
||||||
|
// encrypted file, we have to rewind the file descriptor by
|
||||||
|
// 'add_len' bytes in the second round.
|
||||||
|
//
|
||||||
|
// Be careful with changing it, it needs to stay the same
|
||||||
|
// for reading back previously encrypted files!
|
||||||
if (filesize == 0)
|
if (filesize == 0)
|
||||||
|
{
|
||||||
// set size to 8K + Sodium Crypt Metadata
|
// set size to 8K + Sodium Crypt Metadata
|
||||||
size = WRITEBUFSIZE + crypt_get_max_header_len()
|
size = WRITEBUFSIZE + crypt_get_max_header_len()
|
||||||
+ crypto_secretstream_xchacha20poly1305_HEADERBYTES
|
+ crypto_secretstream_xchacha20poly1305_HEADERBYTES
|
||||||
+ crypto_secretstream_xchacha20poly1305_ABYTES;
|
+ crypto_secretstream_xchacha20poly1305_ABYTES;
|
||||||
|
may_need_lseek = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
else if (filesize > 0 && (curbuf->b_cryptstate != NULL &&
|
else if (filesize > 0 && (curbuf->b_cryptstate != NULL
|
||||||
curbuf->b_cryptstate->method_nr == CRYPT_M_SOD))
|
&& crypt_method_is_sodium(
|
||||||
|
curbuf->b_cryptstate->method_nr)))
|
||||||
|
{
|
||||||
size = WRITEBUFSIZE + crypto_secretstream_xchacha20poly1305_ABYTES;
|
size = WRITEBUFSIZE + crypto_secretstream_xchacha20poly1305_ABYTES;
|
||||||
|
// need to rewind by - add_len from CRYPT_M_SOD2 (see
|
||||||
|
// description above)
|
||||||
|
if (curbuf->b_cryptstate->method_nr == CRYPT_M_SOD
|
||||||
|
&& !eof && may_need_lseek)
|
||||||
|
{
|
||||||
|
lseek(fd, crypt_get_header_len(
|
||||||
|
curbuf->b_cryptstate->method_nr)
|
||||||
|
- crypt_get_max_header_len(), SEEK_CUR);
|
||||||
|
may_need_lseek = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
# endif
|
# endif
|
||||||
eof = size;
|
eof = size;
|
||||||
size = read_eintr(fd, ptr, size);
|
size = read_eintr(fd, ptr, size);
|
||||||
|
@ -436,7 +436,7 @@ ml_set_mfp_crypt(buf_T *buf)
|
|||||||
sha2_seed(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN, NULL, 0);
|
sha2_seed(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN, NULL, 0);
|
||||||
}
|
}
|
||||||
#ifdef FEAT_SODIUM
|
#ifdef FEAT_SODIUM
|
||||||
else if (method_nr == CRYPT_M_SOD)
|
else if (crypt_method_is_sodium(method_nr))
|
||||||
crypt_sodium_randombytes_buf(buf->b_ml.ml_mfp->mf_seed,
|
crypt_sodium_randombytes_buf(buf->b_ml.ml_mfp->mf_seed,
|
||||||
MF_SEED_LEN);
|
MF_SEED_LEN);
|
||||||
#endif
|
#endif
|
||||||
@ -495,7 +495,7 @@ ml_set_crypt_key(
|
|||||||
old_method = crypt_method_nr_from_name(old_cm);
|
old_method = crypt_method_nr_from_name(old_cm);
|
||||||
|
|
||||||
// Swapfile encryption not supported by XChaCha20
|
// Swapfile encryption not supported by XChaCha20
|
||||||
if (crypt_get_method_nr(buf) == CRYPT_M_SOD && *buf->b_p_key != NUL)
|
if (crypt_method_is_sodium(crypt_get_method_nr(buf)) && *buf->b_p_key != NUL)
|
||||||
{
|
{
|
||||||
// close the swapfile
|
// close the swapfile
|
||||||
mf_close_file(buf, TRUE);
|
mf_close_file(buf, TRUE);
|
||||||
@ -5512,6 +5512,7 @@ ml_decrypt_data(
|
|||||||
/*
|
/*
|
||||||
* Prepare for encryption/decryption, using the key, seed and offset.
|
* Prepare for encryption/decryption, using the key, seed and offset.
|
||||||
* Return an allocated cryptstate_T *.
|
* Return an allocated cryptstate_T *.
|
||||||
|
* Note: Encryption not supported for SODIUM
|
||||||
*/
|
*/
|
||||||
static cryptstate_T *
|
static cryptstate_T *
|
||||||
ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading)
|
ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading)
|
||||||
@ -5520,21 +5521,23 @@ ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading)
|
|||||||
char_u salt[50];
|
char_u salt[50];
|
||||||
int method_nr;
|
int method_nr;
|
||||||
char_u *key;
|
char_u *key;
|
||||||
char_u *seed;
|
crypt_arg_T arg;
|
||||||
|
|
||||||
|
CLEAR_FIELD(arg);
|
||||||
if (reading && mfp->mf_old_key != NULL)
|
if (reading && mfp->mf_old_key != NULL)
|
||||||
{
|
{
|
||||||
// Reading back blocks with the previous key/method/seed.
|
// Reading back blocks with the previous key/method/seed.
|
||||||
method_nr = mfp->mf_old_cm;
|
method_nr = mfp->mf_old_cm;
|
||||||
key = mfp->mf_old_key;
|
key = mfp->mf_old_key;
|
||||||
seed = mfp->mf_old_seed;
|
arg.cat_seed = mfp->mf_old_seed;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
method_nr = crypt_get_method_nr(buf);
|
method_nr = crypt_get_method_nr(buf);
|
||||||
key = buf->b_p_key;
|
key = buf->b_p_key;
|
||||||
seed = mfp->mf_seed;
|
arg.cat_seed = mfp->mf_seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*key == NUL)
|
if (*key == NUL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -5543,14 +5546,24 @@ ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading)
|
|||||||
// For PKzip: Append the offset to the key, so that we use a different
|
// For PKzip: Append the offset to the key, so that we use a different
|
||||||
// key for every block.
|
// key for every block.
|
||||||
vim_snprintf((char *)salt, sizeof(salt), "%s%ld", key, (long)offset);
|
vim_snprintf((char *)salt, sizeof(salt), "%s%ld", key, (long)offset);
|
||||||
return crypt_create(method_nr, salt, NULL, 0, NULL, 0);
|
arg.cat_seed = NULL;
|
||||||
|
arg.cat_init_from_file = FALSE;
|
||||||
|
|
||||||
|
return crypt_create(method_nr, salt, &arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using blowfish or better: add salt and seed. We use the byte offset
|
// Using blowfish or better: add salt and seed. We use the byte offset
|
||||||
// of the block for the salt.
|
// of the block for the salt.
|
||||||
vim_snprintf((char *)salt, sizeof(salt), "%ld", (long)offset);
|
vim_snprintf((char *)salt, sizeof(salt), "%ld", (long)offset);
|
||||||
return crypt_create(method_nr, key, salt, (int)STRLEN(salt),
|
|
||||||
seed, MF_SEED_LEN);
|
arg.cat_salt = salt;
|
||||||
|
arg.cat_salt_len = (int)STRLEN(salt);
|
||||||
|
arg.cat_seed_len = MF_SEED_LEN;
|
||||||
|
arg.cat_add_len = 0;
|
||||||
|
arg.cat_add = NULL;
|
||||||
|
arg.cat_init_from_file = FALSE;
|
||||||
|
|
||||||
|
return crypt_create(method_nr, key, &arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4274,7 +4274,7 @@ did_set_undofile(optset_T *args)
|
|||||||
&& !curbufIsChanged() && curbuf->b_ml.ml_mfp != NULL)
|
&& !curbufIsChanged() && curbuf->b_ml.ml_mfp != NULL)
|
||||||
{
|
{
|
||||||
#ifdef FEAT_CRYPT
|
#ifdef FEAT_CRYPT
|
||||||
if (crypt_get_method_nr(curbuf) == CRYPT_M_SOD)
|
if (crypt_method_is_sodium(crypt_get_method_nr(curbuf)))
|
||||||
continue;
|
continue;
|
||||||
#endif
|
#endif
|
||||||
u_compute_hash(hash);
|
u_compute_hash(hash);
|
||||||
|
@ -29,7 +29,7 @@ static char *(p_ff_values[]) = {FF_UNIX, FF_DOS, FF_MAC, NULL};
|
|||||||
#ifdef FEAT_CRYPT
|
#ifdef FEAT_CRYPT
|
||||||
static char *(p_cm_values[]) = {"zip", "blowfish", "blowfish2",
|
static char *(p_cm_values[]) = {"zip", "blowfish", "blowfish2",
|
||||||
# ifdef FEAT_SODIUM
|
# ifdef FEAT_SODIUM
|
||||||
"xchacha20",
|
"xchacha20", "xchacha20v2",
|
||||||
# endif
|
# endif
|
||||||
NULL};
|
NULL};
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* blowfish.c */
|
/* blowfish.c */
|
||||||
void crypt_blowfish_encode(cryptstate_T *state, char_u *from, size_t len, char_u *to, int last);
|
void crypt_blowfish_encode(cryptstate_T *state, char_u *from, size_t len, char_u *to, int last);
|
||||||
void crypt_blowfish_decode(cryptstate_T *state, char_u *from, size_t len, char_u *to, int last);
|
void crypt_blowfish_decode(cryptstate_T *state, char_u *from, size_t len, char_u *to, int last);
|
||||||
int crypt_blowfish_init(cryptstate_T *state, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len);
|
int crypt_blowfish_init(cryptstate_T *state, char_u *key, crypt_arg_T *arg);
|
||||||
int blowfish_self_test(void);
|
int blowfish_self_test(void);
|
||||||
/* vim: set ft=c : */
|
/* vim: set ft=c : */
|
||||||
|
@ -4,12 +4,13 @@ int crypt_method_nr_from_name(char_u *name);
|
|||||||
int crypt_method_nr_from_magic(char *ptr, int len);
|
int crypt_method_nr_from_magic(char *ptr, int len);
|
||||||
int crypt_works_inplace(cryptstate_T *state);
|
int crypt_works_inplace(cryptstate_T *state);
|
||||||
int crypt_get_method_nr(buf_T *buf);
|
int crypt_get_method_nr(buf_T *buf);
|
||||||
|
int crypt_method_is_sodium(int method);
|
||||||
int crypt_whole_undofile(int method_nr);
|
int crypt_whole_undofile(int method_nr);
|
||||||
int crypt_get_header_len(int method_nr);
|
int crypt_get_header_len(int method_nr);
|
||||||
int crypt_get_max_header_len(void);
|
int crypt_get_max_header_len(void);
|
||||||
void crypt_set_cm_option(buf_T *buf, int method_nr);
|
void crypt_set_cm_option(buf_T *buf, int method_nr);
|
||||||
int crypt_self_test(void);
|
int crypt_self_test(void);
|
||||||
cryptstate_T *crypt_create(int method_nr, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len);
|
cryptstate_T *crypt_create(int method_nr, char_u *key, crypt_arg_T *crypt_arg);
|
||||||
cryptstate_T *crypt_create_from_header(int method_nr, char_u *key, char_u *header);
|
cryptstate_T *crypt_create_from_header(int method_nr, char_u *key, char_u *header);
|
||||||
cryptstate_T *crypt_create_from_file(FILE *fp, char_u *key);
|
cryptstate_T *crypt_create_from_file(FILE *fp, char_u *key);
|
||||||
cryptstate_T *crypt_create_for_writing(int method_nr, char_u *key, char_u **header, int *header_len);
|
cryptstate_T *crypt_create_for_writing(int method_nr, char_u *key, char_u **header, int *header_len);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* crypt_zip.c */
|
/* crypt_zip.c */
|
||||||
int crypt_zip_init(cryptstate_T *state, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len);
|
int crypt_zip_init(cryptstate_T *state, char_u *key, crypt_arg_T *arg);
|
||||||
void crypt_zip_encode(cryptstate_T *state, char_u *from, size_t len, char_u *to, int last);
|
void crypt_zip_encode(cryptstate_T *state, char_u *from, size_t len, char_u *to, int last);
|
||||||
void crypt_zip_decode(cryptstate_T *state, char_u *from, size_t len, char_u *to, int last);
|
void crypt_zip_decode(cryptstate_T *state, char_u *from, size_t len, char_u *to, int last);
|
||||||
/* vim: set ft=c : */
|
/* vim: set ft=c : */
|
||||||
|
@ -2771,11 +2771,24 @@ typedef struct {
|
|||||||
# define CRYPT_M_BF 1
|
# define CRYPT_M_BF 1
|
||||||
# define CRYPT_M_BF2 2
|
# define CRYPT_M_BF2 2
|
||||||
# define CRYPT_M_SOD 3
|
# define CRYPT_M_SOD 3
|
||||||
# define CRYPT_M_COUNT 4 // number of crypt methods
|
# define CRYPT_M_SOD2 4
|
||||||
|
# define CRYPT_M_COUNT 5 // number of crypt methods
|
||||||
|
|
||||||
// Currently all crypt methods work inplace. If one is added that isn't then
|
// Currently all crypt methods work inplace. If one is added that isn't then
|
||||||
// define this.
|
// define this.
|
||||||
# define CRYPT_NOT_INPLACE 1
|
# define CRYPT_NOT_INPLACE 1
|
||||||
|
|
||||||
|
// Struct for passing arguments down to the crypt_init functions
|
||||||
|
typedef struct {
|
||||||
|
char_u *cat_salt;
|
||||||
|
int cat_salt_len;
|
||||||
|
char_u *cat_seed;
|
||||||
|
int cat_seed_len;
|
||||||
|
char_u *cat_add;
|
||||||
|
int cat_add_len;
|
||||||
|
int cat_init_from_file;
|
||||||
|
} crypt_arg_T;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef FEAT_PROP_POPUP
|
#ifdef FEAT_PROP_POPUP
|
||||||
|
@ -81,6 +81,11 @@ func Test_crypt_sodium()
|
|||||||
call Crypt_uncrypt('xchacha20')
|
call Crypt_uncrypt('xchacha20')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_crypt_sodium_v2()
|
||||||
|
CheckFeature sodium
|
||||||
|
call Crypt_uncrypt('xchacha20v2')
|
||||||
|
endfunc
|
||||||
|
|
||||||
func Uncrypt_stable(method, crypted_text, key, uncrypted_text)
|
func Uncrypt_stable(method, crypted_text, key, uncrypted_text)
|
||||||
split Xtest.txt
|
split Xtest.txt
|
||||||
set bin noeol key= fenc=latin1
|
set bin noeol key= fenc=latin1
|
||||||
@ -96,13 +101,15 @@ func Uncrypt_stable(method, crypted_text, key, uncrypted_text)
|
|||||||
set key=
|
set key=
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Uncrypt_stable_xxd(method, hex, key, uncrypted_text)
|
func Uncrypt_stable_xxd(method, hex, key, uncrypted_text, verbose)
|
||||||
if empty(s:xxd_cmd)
|
if empty(s:xxd_cmd)
|
||||||
throw 'Skipped: xxd program missing'
|
throw 'Skipped: xxd program missing'
|
||||||
endif
|
endif
|
||||||
" use xxd to write the binary content
|
" use xxd to write the binary content
|
||||||
call system(s:xxd_cmd .. ' -r >Xtest.txt', a:hex)
|
call system(s:xxd_cmd .. ' -r >Xtest.txt', a:hex)
|
||||||
call feedkeys(":split Xtest.txt\<CR>" . a:key . "\<CR>", 'xt')
|
let cmd = (a:verbose ? ':verbose' : '') ..
|
||||||
|
\ ":split Xtest.txt\<CR>" . a:key . "\<CR>"
|
||||||
|
call feedkeys(cmd, 'xt')
|
||||||
call assert_equal(a:uncrypted_text, getline(1, len(a:uncrypted_text)))
|
call assert_equal(a:uncrypted_text, getline(1, len(a:uncrypted_text)))
|
||||||
bwipe!
|
bwipe!
|
||||||
call delete('Xtest.txt')
|
call delete('Xtest.txt')
|
||||||
@ -138,7 +145,40 @@ func Test_uncrypt_xchacha20()
|
|||||||
\ '00000080: 72be 0136 84a1 d3 r..6...']
|
\ '00000080: 72be 0136 84a1 d3 r..6...']
|
||||||
" the file should be in latin1 encoding, this makes sure that readfile()
|
" the file should be in latin1 encoding, this makes sure that readfile()
|
||||||
" retries several times converting the multi-byte characters
|
" retries several times converting the multi-byte characters
|
||||||
call Uncrypt_stable_xxd('xchacha20', hex, "sodium_crypt", ["abcdefghijklmnopqrstuvwxyzäöü", "ZZZ_äüöÄÜÖ_!@#$%^&*()_+=-`~"])
|
call Uncrypt_stable_xxd('xchacha20', hex, "sodium_crypt", ["abcdefghijklmnopqrstuvwxyzäöü", "ZZZ_äüöÄÜÖ_!@#$%^&*()_+=-`~"], 0)
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_uncrypt_xchacha20v2_custom()
|
||||||
|
CheckFeature sodium
|
||||||
|
" Test, reading xchacha20v2 with custom encryption parameters
|
||||||
|
let hex = ['00000000: 5669 6d43 7279 7074 7e30 3521 934b f288 VimCrypt~05!.K..',
|
||||||
|
\ '00000010: 10ba 8bc9 25a0 8876 f85c f135 6fb8 518b ....%..v.\.5o.Q.',
|
||||||
|
\ '00000020: b133 9af1 0300 0000 0000 0000 0000 0010 .3..............',
|
||||||
|
\ '00000030: 0000 0000 0200 0000 b973 5f33 80e9 54fc .........s_3..T.',
|
||||||
|
\ '00000040: 138f ba3e 046b 3135 90b7 7783 5eac 7fe3 ...>.k15..w.^...',
|
||||||
|
\ '00000050: 0cd2 14df ed75 4b65 8763 8205 035c ec81 .....uKe.c...\..',
|
||||||
|
\ "00000060: a4cf 33d2 7507 ec38 ba62 a327 9068 d8ad ..3.u..8.b.'.h..",
|
||||||
|
\ '00000070: 2607 3fa6 f95d 7ea8 9799 f997 4820 0c &.?..]~.....H .']
|
||||||
|
call Uncrypt_stable_xxd('xchacha20v2', hex, "foobar", ["", "foo", "bar", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"], 1)
|
||||||
|
call assert_match('xchacha20v2: using custom \w\+ "\d\+" for Key derivation.', execute(':messages'))
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_uncrypt_xchacha20v2()
|
||||||
|
CheckFeature sodium
|
||||||
|
" Test, reading xchacha20v2
|
||||||
|
let hex = [
|
||||||
|
\ '00000000: 5669 6d43 7279 7074 7e30 3521 9f20 4e14 VimCrypt~05!. N.',
|
||||||
|
\ '00000010: c7da c1bd 7dea 8fbc db6c 38e6 7a77 6fef ....}....l8.zwo.',
|
||||||
|
\ '00000020: 82dd 964b 0300 0000 0000 0000 0000 0010 ...K............',
|
||||||
|
\ '00000030: 0000 0000 0200 0000 a97c 2f00 0b9d 19eb .........|/.....',
|
||||||
|
\ '00000040: 1d92 1ea5 3f22 c179 4b3e 870a eb19 6380 ....?".yK>....c.',
|
||||||
|
\ '00000050: 63f8 222d b5d1 3c73 7be5 d580 47ea 44cc c."-..<s{...G.D.',
|
||||||
|
\ '00000060: 6c25 8078 3fd5 d836 c700 0122 bb30 7a59 l%.x?..6...".0zY',
|
||||||
|
\ '00000070: b184 2ae8 e7db 113a f732 938f 7a34 1333 ..*....:.2..z4.3',
|
||||||
|
\ '00000080: dc89 1491 51a0 67b9 0f3a b56c 1f9d 53b0 ....Q.g..:.l..S.',
|
||||||
|
\ '00000090: 2416 205a 8c4c 5fde 4dac 2611 8a48 24f0 $. Z.L_.M.&..H$.',
|
||||||
|
\ '000000a0: ba00 92c1 60 ....`']
|
||||||
|
call Uncrypt_stable_xxd('xchacha20v2', hex, "foo1234", ["abcdefghijklmnopqrstuvwxyzäöü", 'ZZZ_äüöÄÜÖ_!@#$%^&*()_+=-`~"'], 0)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_uncrypt_xchacha20_invalid()
|
func Test_uncrypt_xchacha20_invalid()
|
||||||
@ -165,7 +205,7 @@ func Test_uncrypt_xchacha20_2()
|
|||||||
|
|
||||||
sp Xcrypt_sodium.txt
|
sp Xcrypt_sodium.txt
|
||||||
" Create a larger file, so that Vim will write in several blocks
|
" Create a larger file, so that Vim will write in several blocks
|
||||||
call setline(1, range(1,4000))
|
call setline(1, range(1, 4000))
|
||||||
call assert_equal(1, &swapfile)
|
call assert_equal(1, &swapfile)
|
||||||
set cryptmethod=xchacha20
|
set cryptmethod=xchacha20
|
||||||
call feedkeys(":X\<CR>sodium\<CR>sodium\<CR>", 'xt')
|
call feedkeys(":X\<CR>sodium\<CR>sodium\<CR>", 'xt')
|
||||||
@ -186,38 +226,73 @@ func Test_uncrypt_xchacha20_2()
|
|||||||
bw!
|
bw!
|
||||||
call delete('Xcrypt_sodium.txt')
|
call delete('Xcrypt_sodium.txt')
|
||||||
set cryptmethod&vim
|
set cryptmethod&vim
|
||||||
|
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_uncrypt_xchacha20v2_2()
|
||||||
|
CheckFeature sodium
|
||||||
|
|
||||||
|
sp Xcrypt_sodium_v2.txt
|
||||||
|
" Create a larger file, so that Vim will write in several blocks
|
||||||
|
call setline(1, range(1, 4000))
|
||||||
|
call assert_equal(1, &swapfile)
|
||||||
|
set cryptmethod=xchacha20v2
|
||||||
|
call feedkeys(":X\<CR>sodium\<CR>sodium\<CR>", 'xt')
|
||||||
|
" swapfile disabled
|
||||||
|
call assert_equal(0, &swapfile)
|
||||||
|
call assert_match("Note: Encryption of swapfile not supported, disabling swap file", execute(':messages'))
|
||||||
|
w!
|
||||||
|
" encrypted using xchacha20
|
||||||
|
call assert_match("\[xchachav2\]", execute(':messages'))
|
||||||
|
bw!
|
||||||
|
call feedkeys(":verbose :sp Xcrypt_sodium_v2.txt\<CR>sodium\<CR>", 'xt')
|
||||||
|
" successfully decrypted
|
||||||
|
call assert_equal(range(1, 4000)->map( {_, v -> string(v)}), getline(1,'$'))
|
||||||
|
call assert_match('xchacha20v2: using default \w\+ "\d\+" for Key derivation.', execute(':messages'))
|
||||||
|
set key=
|
||||||
|
w! ++ff=unix
|
||||||
|
" encryption removed (on MS-Windows the .* matches [unix])
|
||||||
|
call assert_match('"Xcrypt_sodium_v2.txt".*4000L, 18893B written', execute(':message'))
|
||||||
|
bw!
|
||||||
|
call delete('Xcrypt_sodium_v2.txt')
|
||||||
|
set cryptmethod&vim
|
||||||
|
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_uncrypt_xchacha20_3_persistent_undo()
|
func Test_uncrypt_xchacha20_3_persistent_undo()
|
||||||
CheckFeature sodium
|
CheckFeature sodium
|
||||||
CheckFeature persistent_undo
|
CheckFeature persistent_undo
|
||||||
|
|
||||||
sp Xcrypt_sodium_undo.txt
|
for meth in ['xchacha20', 'xchacha20v2']
|
||||||
set cryptmethod=xchacha20 undofile
|
|
||||||
call feedkeys(":X\<CR>sodium\<CR>sodium\<CR>", 'xt')
|
|
||||||
call assert_equal(1, &undofile)
|
|
||||||
let ufile=undofile(@%)
|
|
||||||
call append(0, ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'])
|
|
||||||
call cursor(1, 1)
|
|
||||||
|
|
||||||
set undolevels=100
|
sp Xcrypt_sodium_undo.txt
|
||||||
normal dd
|
exe "set cryptmethod=" .. meth .. " undofile"
|
||||||
set undolevels=100
|
call feedkeys(":X\<CR>sodium\<CR>sodium\<CR>", 'xt')
|
||||||
normal dd
|
call assert_equal(1, &undofile)
|
||||||
set undolevels=100
|
let ufile=undofile(@%)
|
||||||
normal dd
|
call append(0, ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'])
|
||||||
set undolevels=100
|
call cursor(1, 1)
|
||||||
w!
|
|
||||||
call assert_equal(0, &undofile)
|
set undolevels=100
|
||||||
bw!
|
normal dd
|
||||||
call feedkeys(":sp Xcrypt_sodium_undo.txt\<CR>sodium\<CR>", 'xt')
|
set undolevels=100
|
||||||
" should fail
|
normal dd
|
||||||
norm! u
|
set undolevels=100
|
||||||
call assert_match('Already at oldest change', execute(':1mess'))
|
normal dd
|
||||||
call assert_fails('verbose rundo ' .. fnameescape(ufile), 'E822')
|
set undolevels=100
|
||||||
bw!
|
w!
|
||||||
set undolevels& cryptmethod& undofile&
|
call assert_equal(0, &undofile)
|
||||||
call delete('Xcrypt_sodium_undo.txt')
|
bw!
|
||||||
|
call feedkeys(":sp Xcrypt_sodium_undo.txt\<CR>sodium\<CR>", 'xt')
|
||||||
|
" should fail
|
||||||
|
norm! u
|
||||||
|
call assert_match('Already at oldest change', execute(':1mess'))
|
||||||
|
call assert_fails('verbose rundo ' .. fnameescape(ufile), 'E822')
|
||||||
|
bw!
|
||||||
|
set undolevels& cryptmethod& undofile&
|
||||||
|
call delete('Xcrypt_sodium_undo.txt')
|
||||||
|
|
||||||
|
endfor
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_encrypt_xchacha20_missing()
|
func Test_encrypt_xchacha20_missing()
|
||||||
@ -226,6 +301,7 @@ func Test_encrypt_xchacha20_missing()
|
|||||||
endif
|
endif
|
||||||
sp Xcrypt_sodium_undo.txt
|
sp Xcrypt_sodium_undo.txt
|
||||||
call assert_fails(':set cryptmethod=xchacha20', 'E474')
|
call assert_fails(':set cryptmethod=xchacha20', 'E474')
|
||||||
|
call assert_fails(':set cryptmethod=xchacha20v2', 'E474')
|
||||||
bw!
|
bw!
|
||||||
set cm&
|
set cm&
|
||||||
endfunc
|
endfunc
|
||||||
|
@ -695,6 +695,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1481,
|
||||||
/**/
|
/**/
|
||||||
1480,
|
1480,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user