mirror of
https://github.com/vim/vim.git
synced 2025-09-23 03:43:49 -04:00
Crypt the text in the undo file if the file itself is crypted.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
" Vim Compiler File
|
||||
" Compiler: Perl syntax checks (perl -Wc)
|
||||
" Maintainer: Christian J. Robinson <infynity@onewest.net>
|
||||
" Maintainer: Christian J. Robinson <heptite@gmail.com>
|
||||
" Last Change: 2006 Aug 13
|
||||
|
||||
if exists("current_compiler")
|
||||
|
@@ -1366,6 +1366,9 @@ 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 change
|
||||
'cryptmethod' before writing that file to change the method.
|
||||
|
||||
When writing an undo file, the same key and method will be used for the text
|
||||
in the undo file. |persistent-undo|.
|
||||
|
||||
*E817* *E818* *E819* *E820*
|
||||
When encryption does not work properly, you would be able to write your text
|
||||
to a file and never be able to read it back. Therefore a test is performed to
|
||||
|
@@ -1085,9 +1085,6 @@ Vim 7.3:
|
||||
- using NSIS 2.46: install on Windows 7 works, but no "Edit with Vim" menu.
|
||||
Use register_shell_extension()? (George Reilly, 2010 May 26)
|
||||
Ron's version: http://dev.ronware.org/p/vim/finfo?name=gvim.nsi
|
||||
- Persistent undo bugs / fixes:
|
||||
- Need to check all values for evil manipulation.
|
||||
- Also crypt the undo file.
|
||||
- Also crypt the swap file, each block separately. Change mf_write() and
|
||||
mf_read(). How to get b_p_key to these functions?
|
||||
- Do profiling on sha256 code to find obvious bottlenecks.
|
||||
|
@@ -225,6 +225,9 @@ after the undo file was written, to prevent corruption.
|
||||
Undo files are normally saved in the same directory as the file. This can be
|
||||
changed with the 'undodir' option.
|
||||
|
||||
When the file is encrypted, the text in the undo file is also crypted. The
|
||||
same key and method is used. |encryption|
|
||||
|
||||
You can also save and restore undo histories by using ":wundo" and ":rundo"
|
||||
respectively:
|
||||
*:wundo* *:rundo*
|
||||
|
@@ -1,7 +1,7 @@
|
||||
" Vim indent file
|
||||
" Language: tf (TinyFugue)
|
||||
" Maintainer: Christian J. Robinson <infynity@onewest.net>
|
||||
" URL: http://www.infynity.spodzone.com/vim/indent/tf.vim
|
||||
" Maintainer: Christian J. Robinson <heptite@gmail.com>
|
||||
" URL: http://christianrobinson.name/vim/indent/tf.vim
|
||||
" Last Change: 2002 May 29
|
||||
|
||||
" Only load this indent file when no other was loaded.
|
||||
|
153
src/fileio.c
153
src/fileio.c
@@ -2827,7 +2827,7 @@ check_marks_read()
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_CRYPT
|
||||
#if defined(FEAT_CRYPT) || defined(PROTO)
|
||||
/*
|
||||
* Get the crypt method used for a file from "ptr[len]", the magic text at the
|
||||
* start of the file.
|
||||
@@ -2926,7 +2926,129 @@ check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile, did_ask)
|
||||
|
||||
return cryptkey;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check for magic number used for encryption. Applies to the current buffer.
|
||||
* If found and decryption is possible returns OK;
|
||||
*/
|
||||
int
|
||||
prepare_crypt_read(fp)
|
||||
FILE *fp;
|
||||
{
|
||||
int method;
|
||||
char_u buffer[CRYPT_MAGIC_LEN + CRYPT_SEED_LEN_MAX + 2];
|
||||
|
||||
if (fread(buffer, CRYPT_MAGIC_LEN, 1, fp) != 1)
|
||||
return FAIL;
|
||||
method = get_crypt_method((char *)buffer,
|
||||
CRYPT_MAGIC_LEN + CRYPT_SEED_LEN_MAX);
|
||||
if (method < 0 || method != curbuf->b_p_cm)
|
||||
return FAIL;
|
||||
|
||||
if (method == 0)
|
||||
crypt_init_keys(curbuf->b_p_key);
|
||||
else
|
||||
{
|
||||
int seed_len = crypt_seed_len[method];
|
||||
|
||||
if (fread(buffer, seed_len, 1, fp) != 1)
|
||||
return FAIL;
|
||||
bf_key_init(curbuf->b_p_key);
|
||||
bf_ofb_init(buffer, seed_len);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare for writing encrypted bytes for buffer "buf".
|
||||
* Returns a pointer to an allocated header of length "*lenp".
|
||||
*/
|
||||
char_u *
|
||||
prepare_crypt_write(buf, lenp)
|
||||
buf_T *buf;
|
||||
int *lenp;
|
||||
{
|
||||
char_u *header;
|
||||
int seed_len = crypt_seed_len[buf->b_p_cm];
|
||||
|
||||
header = alloc_clear(CRYPT_MAGIC_LEN + CRYPT_SEED_LEN_MAX + 2);
|
||||
if (header != NULL)
|
||||
{
|
||||
use_crypt_method = buf->b_p_cm; /* select pkzip or blowfish */
|
||||
vim_strncpy(header, (char_u *)crypt_magic[use_crypt_method],
|
||||
CRYPT_MAGIC_LEN);
|
||||
if (buf->b_p_cm == 0)
|
||||
crypt_init_keys(buf->b_p_key);
|
||||
else
|
||||
{
|
||||
/* Using blowfish, add seed. */
|
||||
sha2_seed(header + CRYPT_MAGIC_LEN, seed_len); /* create iv */
|
||||
bf_ofb_init(header + CRYPT_MAGIC_LEN, seed_len);
|
||||
bf_key_init(buf->b_p_key);
|
||||
}
|
||||
}
|
||||
*lenp = CRYPT_MAGIC_LEN + seed_len;
|
||||
return header;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like fwrite() but crypt the bytes when 'key' is set.
|
||||
* Returns 1 if successful.
|
||||
*/
|
||||
size_t
|
||||
fwrite_crypt(buf, ptr, len, fp)
|
||||
buf_T *buf;
|
||||
char_u *ptr;
|
||||
size_t len;
|
||||
FILE *fp;
|
||||
{
|
||||
char_u *copy;
|
||||
char_u small_buf[100];
|
||||
int ztemp, t;
|
||||
size_t i;
|
||||
|
||||
if (*buf->b_p_key == NUL)
|
||||
return fwrite(ptr, len, (size_t)1, fp);
|
||||
if (len < 100)
|
||||
copy = small_buf; /* no malloc()/free() for short strings */
|
||||
else
|
||||
{
|
||||
copy = lalloc(len, FALSE);
|
||||
if (copy == NULL)
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
ztemp = ptr[i];
|
||||
copy[i] = ZENCODE(ztemp, t);
|
||||
}
|
||||
i = fwrite(copy, len, (size_t)1, fp);
|
||||
if (copy != small_buf)
|
||||
vim_free(copy);
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a string of length "len" from "fd".
|
||||
* When 'key' is set decrypt the bytes.
|
||||
*/
|
||||
char_u *
|
||||
read_string_decrypt(buf, fd, len)
|
||||
buf_T *buf;
|
||||
FILE *fd;
|
||||
int len;
|
||||
{
|
||||
char_u *ptr;
|
||||
char_u *p;
|
||||
|
||||
ptr = read_string(fd, len);
|
||||
if (ptr != NULL || *buf->b_p_key != NUL)
|
||||
for (p = ptr; p < ptr + len; ++p)
|
||||
ZDECODE(*p);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#endif /* FEAT_CRYPT */
|
||||
|
||||
#ifdef UNIX
|
||||
static void
|
||||
@@ -4323,34 +4445,25 @@ restore_backup:
|
||||
#ifdef FEAT_CRYPT
|
||||
if (*buf->b_p_key && !filtering)
|
||||
{
|
||||
char_u header[CRYPT_MAGIC_LEN + CRYPT_SEED_LEN_MAX + 2];
|
||||
int seed_len = crypt_seed_len[buf->b_p_cm];
|
||||
char_u *header;
|
||||
int header_len;
|
||||
|
||||
use_crypt_method = buf->b_p_cm; /* select pkzip or blowfish */
|
||||
|
||||
vim_memset(header, 0, sizeof(header));
|
||||
vim_strncpy(header, (char_u *)crypt_magic[use_crypt_method],
|
||||
CRYPT_MAGIC_LEN);
|
||||
|
||||
if (buf->b_p_cm == 0)
|
||||
crypt_init_keys(buf->b_p_key);
|
||||
header = prepare_crypt_write(buf, &header_len);
|
||||
if (header == NULL)
|
||||
end = 0;
|
||||
else
|
||||
{
|
||||
/* Using blowfish, add seed. */
|
||||
sha2_seed(header + CRYPT_MAGIC_LEN, seed_len); /* create iv */
|
||||
bf_ofb_init(header + CRYPT_MAGIC_LEN, seed_len);
|
||||
bf_key_init(buf->b_p_key);
|
||||
}
|
||||
|
||||
/* Write magic number, so that Vim knows that this file is
|
||||
* encrypted when reading it again. This also undergoes utf-8 to
|
||||
* ucs-2/4 conversion when needed. */
|
||||
write_info.bw_buf = (char_u *)header;
|
||||
write_info.bw_len = CRYPT_MAGIC_LEN + seed_len;
|
||||
write_info.bw_buf = header;
|
||||
write_info.bw_len = header_len;
|
||||
write_info.bw_flags = FIO_NOCONVERT;
|
||||
if (buf_write_bytes(&write_info) == FAIL)
|
||||
end = 0;
|
||||
wb_flags |= FIO_ENCRYPTED;
|
||||
vim_free(header);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@@ -2,6 +2,10 @@
|
||||
void filemess __ARGS((buf_T *buf, char_u *name, char_u *s, int attr));
|
||||
int readfile __ARGS((char_u *fname, char_u *sfname, linenr_T from, linenr_T lines_to_skip, linenr_T lines_to_read, exarg_T *eap, int flags));
|
||||
int prep_exarg __ARGS((exarg_T *eap, buf_T *buf));
|
||||
int prepare_crypt_read __ARGS((FILE *fp));
|
||||
char_u *prepare_crypt_write __ARGS((buf_T *buf, int *lenp));
|
||||
size_t fwrite_crypt __ARGS((buf_T *buf, char_u *ptr, size_t len, FILE *fp));
|
||||
char_u *read_string_decrypt __ARGS((buf_T *buf, FILE *fd, int len));
|
||||
int check_file_readonly __ARGS((char_u *fname, int perm));
|
||||
int buf_write __ARGS((buf_T *buf, char_u *fname, char_u *sfname, linenr_T start, linenr_T end, exarg_T *eap, int append, int forceit, int reset_changed, int filtering));
|
||||
void msg_add_fname __ARGS((buf_T *buf, char_u *fname));
|
||||
|
@@ -49,6 +49,55 @@ dd:set ul=100
|
||||
:e Xtestfile
|
||||
uuu:w >>test.out
|
||||
:"
|
||||
:" And now with encryption, cryptmethod=0
|
||||
:e! Xtestfile
|
||||
:set undofile cm=0
|
||||
ggdG
|
||||
imonday
|
||||
tuesday
|
||||
wednesday
|
||||
thursday
|
||||
friday:set ul=100
|
||||
kkkdd:set ul=100
|
||||
dd:set ul=100
|
||||
dd:set ul=100
|
||||
:X
|
||||
foobar
|
||||
foobar
|
||||
:w!
|
||||
:bwipe!
|
||||
:e Xtestfile
|
||||
foobar
|
||||
:set key=
|
||||
uu:w >>test.out
|
||||
:"
|
||||
:"
|
||||
:" With encryption, cryptmethod=1
|
||||
:e! Xtestfile
|
||||
:set undofile cm=1
|
||||
ggdG
|
||||
ijan
|
||||
feb
|
||||
mar
|
||||
apr
|
||||
jun:set ul=100
|
||||
kk0ifoo :set ul=100
|
||||
dd:set ul=100
|
||||
ibar :set ul=100
|
||||
:X
|
||||
foobar
|
||||
foobar
|
||||
:w!
|
||||
:bwipe!
|
||||
:e Xtestfile
|
||||
foobar
|
||||
:set key=
|
||||
/bar
|
||||
:.w >>test.out
|
||||
u:.w >>test.out
|
||||
u:.w >>test.out
|
||||
u:.w >>test.out
|
||||
:"
|
||||
:" Rename the undo file so that it gets cleaned up.
|
||||
:call rename(".Xtestfile.un~", "Xtestundo")
|
||||
:qa!
|
||||
|
@@ -7,3 +7,11 @@ seven
|
||||
eight
|
||||
nine
|
||||
ten
|
||||
monday
|
||||
wednesday
|
||||
thursday
|
||||
friday
|
||||
bar apr
|
||||
apr
|
||||
foo mar
|
||||
mar
|
||||
|
65
src/undo.c
65
src/undo.c
@@ -103,9 +103,9 @@ static void u_freeentry __ARGS((u_entry_T *, long));
|
||||
static void corruption_error __ARGS((char *msg, char_u *file_name));
|
||||
static void u_free_uhp __ARGS((u_header_T *uhp));
|
||||
static int serialize_header __ARGS((FILE *fp, buf_T *buf, char_u *hash));
|
||||
static int serialize_uhp __ARGS((FILE *fp, u_header_T *uhp));
|
||||
static int serialize_uhp __ARGS((FILE *fp, buf_T *buf, u_header_T *uhp));
|
||||
static u_header_T *unserialize_uhp __ARGS((FILE *fp, char_u *file_name));
|
||||
static int serialize_uep __ARGS((u_entry_T *uep, FILE *fp));
|
||||
static int serialize_uep __ARGS((FILE *fp, buf_T *buf, u_entry_T *uep));
|
||||
static u_entry_T *unserialize_uep __ARGS((FILE *fp, int *error, char_u *file_name));
|
||||
static void serialize_pos __ARGS((pos_T pos, FILE *fp));
|
||||
static void unserialize_pos __ARGS((pos_T *pos, FILE *fp));
|
||||
@@ -670,6 +670,7 @@ nomem:
|
||||
# define UF_ENTRY_MAGIC 0xf518 /* magic at start of entry */
|
||||
# define UF_ENTRY_END_MAGIC 0x3581 /* magic after last entry */
|
||||
# define UF_VERSION 1 /* 2-byte undofile version number */
|
||||
# define UF_VERSION_CRYPT 0x8001 /* idem, encrypted */
|
||||
|
||||
static char_u e_not_open[] = N_("E828: Cannot open undo file for writing: %s");
|
||||
|
||||
@@ -811,8 +812,29 @@ serialize_header(fp, buf, hash)
|
||||
/* Start writing, first the magic marker and undo info version. */
|
||||
if (fwrite(UF_START_MAGIC, (size_t)UF_START_MAGIC_LEN, (size_t)1, fp) != 1)
|
||||
return FAIL;
|
||||
|
||||
/* If the buffer is encrypted then all text bytes following will be
|
||||
* encrypted. Numbers and other info is not crypted. */
|
||||
#ifdef FEAT_CRYPT
|
||||
if (*buf->b_p_key)
|
||||
{
|
||||
char_u *header;
|
||||
int header_len;
|
||||
|
||||
put_bytes(fp, (long_u)UF_VERSION_CRYPT, 2);
|
||||
header = prepare_crypt_write(buf, &header_len);
|
||||
if (header == NULL)
|
||||
return FAIL;
|
||||
len = fwrite(header, (size_t)header_len, (size_t)1, fp);
|
||||
vim_free(header);
|
||||
if (len != 1)
|
||||
return FAIL;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
put_bytes(fp, (long_u)UF_VERSION, 2);
|
||||
|
||||
|
||||
/* Write a hash of the buffer text, so that we can verify it is still the
|
||||
* same when reading the buffer text. */
|
||||
if (fwrite(hash, (size_t)UNDO_HASH_SIZE, (size_t)1, fp) != 1)
|
||||
@@ -822,7 +844,7 @@ serialize_header(fp, buf, hash)
|
||||
put_bytes(fp, (long_u)buf->b_ml.ml_line_count, 4);
|
||||
len = buf->b_u_line_ptr != NULL ? (int)STRLEN(buf->b_u_line_ptr) : 0;
|
||||
put_bytes(fp, (long_u)len, 4);
|
||||
if (len > 0 && fwrite(buf->b_u_line_ptr, (size_t)len, (size_t)1, fp) != 1)
|
||||
if (len > 0 && fwrite_crypt(buf, buf->b_u_line_ptr, (size_t)len, fp) != 1)
|
||||
return FAIL;
|
||||
put_bytes(fp, (long_u)buf->b_u_line_lnum, 4);
|
||||
put_bytes(fp, (long_u)buf->b_u_line_colnr, 4);
|
||||
@@ -841,8 +863,9 @@ serialize_header(fp, buf, hash)
|
||||
}
|
||||
|
||||
static int
|
||||
serialize_uhp(fp, uhp)
|
||||
serialize_uhp(fp, buf, uhp)
|
||||
FILE *fp;
|
||||
buf_T *buf;
|
||||
u_header_T *uhp;
|
||||
{
|
||||
int i;
|
||||
@@ -882,7 +905,7 @@ serialize_uhp(fp, uhp)
|
||||
for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next)
|
||||
{
|
||||
put_bytes(fp, (long_u)UF_ENTRY_MAGIC, 2);
|
||||
if (serialize_uep(uep, fp) == FAIL)
|
||||
if (serialize_uep(fp, buf, uep) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
put_bytes(fp, (long_u)UF_ENTRY_END_MAGIC, 2);
|
||||
@@ -971,9 +994,10 @@ unserialize_uhp(fp, file_name)
|
||||
* Serialize "uep" to "fp".
|
||||
*/
|
||||
static int
|
||||
serialize_uep(uep, fp)
|
||||
u_entry_T *uep;
|
||||
serialize_uep(fp, buf, uep)
|
||||
FILE *fp;
|
||||
buf_T *buf;
|
||||
u_entry_T *uep;
|
||||
{
|
||||
int i;
|
||||
size_t len;
|
||||
@@ -987,7 +1011,7 @@ serialize_uep(uep, fp)
|
||||
len = STRLEN(uep->ue_array[i]);
|
||||
if (put_bytes(fp, (long_u)len, 4) == FAIL)
|
||||
return FAIL;
|
||||
if (len > 0 && fwrite(uep->ue_array[i], len, (size_t)1, fp) != 1)
|
||||
if (len > 0 && fwrite_crypt(buf, uep->ue_array[i], len, fp) != 1)
|
||||
return FAIL;
|
||||
}
|
||||
return OK;
|
||||
@@ -1034,7 +1058,7 @@ unserialize_uep(fp, error, file_name)
|
||||
{
|
||||
line_len = get4c(fp);
|
||||
if (line_len >= 0)
|
||||
line = read_string(fp, line_len);
|
||||
line = read_string_decrypt(curbuf, fp, line_len);
|
||||
else
|
||||
{
|
||||
line = NULL;
|
||||
@@ -1333,7 +1357,7 @@ u_write_undo(name, forceit, buf, hash)
|
||||
#ifdef U_DEBUG
|
||||
++headers_written;
|
||||
#endif
|
||||
if (serialize_uhp(fp, uhp) == FAIL)
|
||||
if (serialize_uhp(fp, buf, uhp) == FAIL)
|
||||
goto write_error;
|
||||
}
|
||||
|
||||
@@ -1478,7 +1502,20 @@ u_read_undo(name, hash, orig_name)
|
||||
goto error;
|
||||
}
|
||||
version = get2c(fp);
|
||||
if (version != UF_VERSION)
|
||||
if (version == UF_VERSION_CRYPT)
|
||||
{
|
||||
#ifdef FEAT_CRYPT
|
||||
if (prepare_crypt_read(fp) == FAIL)
|
||||
{
|
||||
EMSG2(_("E826: Undo file decryption failed: %s"), file_name);
|
||||
goto error;
|
||||
}
|
||||
#else
|
||||
EMSG2(_("E826: Undo file is encrypted: %s"), file_name);
|
||||
goto error;
|
||||
#endif
|
||||
}
|
||||
else if (version != UF_VERSION)
|
||||
{
|
||||
EMSG2(_("E824: Incompatible undo file: %s"), file_name);
|
||||
goto error;
|
||||
@@ -1510,7 +1547,7 @@ u_read_undo(name, hash, orig_name)
|
||||
if (str_len < 0)
|
||||
goto error;
|
||||
if (str_len > 0)
|
||||
line_ptr = read_string(fp, str_len);
|
||||
line_ptr = read_string_decrypt(curbuf, fp, str_len);
|
||||
line_lnum = (linenr_T)get4c(fp);
|
||||
line_colnr = (colnr_T)get4c(fp);
|
||||
if (line_lnum < 0 || line_colnr < 0)
|
||||
@@ -1634,10 +1671,6 @@ u_read_undo(name, hash, orig_name)
|
||||
curbuf->b_u_oldhead = old_idx < 0 ? NULL : uhp_table[old_idx];
|
||||
curbuf->b_u_newhead = new_idx < 0 ? NULL : uhp_table[new_idx];
|
||||
curbuf->b_u_curhead = cur_idx < 0 ? NULL : uhp_table[cur_idx];
|
||||
#ifdef U_DEBUG
|
||||
if (curbuf->b_u_curhead != NULL)
|
||||
corruption_error("curhead not NULL", file_name);
|
||||
#endif
|
||||
curbuf->b_u_line_ptr = line_ptr;
|
||||
curbuf->b_u_line_lnum = line_lnum;
|
||||
curbuf->b_u_line_colnr = line_colnr;
|
||||
|
Reference in New Issue
Block a user