updated for version 7.4.399
Problem: Encryption implementation is messy. Blowfish encryption has a
weakness.
Solution: Refactor the encryption, store the state in an allocated struct
instead of using a save/restore mechanism. Introduce the
"blowfish2" method, which does not have the weakness and encrypts
the whole undo file. (largely by David Leadbeater)
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
*editing.txt* For Vim version 7.4. Last change: 2014 Jul 19
|
||||
*editing.txt* For Vim version 7.4. Last change: 2014 Aug 09
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -1370,8 +1370,13 @@ lose your work. The undo file can be disabled without much disadvantage. >
|
||||
|
||||
Note: The text in memory is not encrypted. A system administrator may be able
|
||||
to see your text while you are editing it. When filtering text with
|
||||
":!filter" or using ":w !command" the text is not encrypted, this may reveal
|
||||
it to others. The 'viminfo' file is not encrypted.
|
||||
":!filter" or using ":w !command" the text is also not encrypted, this may
|
||||
reveal it to others. The 'viminfo' file is not encrypted.
|
||||
|
||||
You could do this to edit very secret text: >
|
||||
:set noundofile viminfo=
|
||||
:noswapfile edit secrets.txt
|
||||
Keep in mind that without a swap file you risk loosing your work in a crash.
|
||||
|
||||
WARNING: If you make a typo when entering the key and then write the file and
|
||||
exit, the text will be lost!
|
||||
@ -1398,18 +1403,25 @@ To disable the encryption, reset the 'key' option to an empty value: >
|
||||
:set key=
|
||||
|
||||
You can use the 'cryptmethod' option to select the type of encryption, use one
|
||||
of these two: >
|
||||
:setlocal cm=zip " weak method, backwards compatible
|
||||
:setlocal cm=blowfish " strong method
|
||||
of these: >
|
||||
:setlocal cm=zip " weak method, backwards compatible
|
||||
:setlocal cm=blowfish " method with flaws
|
||||
:setlocal cm=blowfish2 " medium strong method
|
||||
|
||||
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
|
||||
change 'cryptmethod' before writing that file to change the method.
|
||||
|
||||
To set the default method, used for new files, use one of these in your
|
||||
|vimrc| file: >
|
||||
set cm=zip
|
||||
set cm=blowfish
|
||||
set cm=blowfish2
|
||||
Use the first one if you need to be compatible with Vim 7.2 and older. Using
|
||||
"blowfish2" is highly recommended if you can use a Vim version that supports
|
||||
it.
|
||||
|
||||
The message given for reading and writing a file will show "[crypted]" when
|
||||
using zip, "[blowfish]" when using blowfish.
|
||||
using zip, "[blowfish]" when using blowfish, etc.
|
||||
|
||||
When writing an undo file, the same key and method will be used for the text
|
||||
in the undo file. |persistent-undo|.
|
||||
@ -1444,7 +1456,7 @@ lines to "/etc/magic", "/usr/share/misc/magic" or wherever your system has the
|
||||
0 string VimCrypt~ Vim encrypted file
|
||||
>9 string 01 - "zip" cryptmethod
|
||||
>9 string 02 - "blowfish" cryptmethod
|
||||
|
||||
>9 string 03 - "blowfish2" cryptmethod
|
||||
|
||||
Notes:
|
||||
- Encryption is not possible when doing conversion with 'charconvert'.
|
||||
@ -1468,6 +1480,10 @@ Notes:
|
||||
- Pkzip uses the same encryption as 'cryptmethod' "zip", and US Govt has no
|
||||
objection to its export. Pkzip's public file APPNOTE.TXT describes this
|
||||
algorithm in detail.
|
||||
- The implmentation of 'cryptmethod' "blowfish" has a flaw. It is possible to
|
||||
crack the first 64 bytes of a file and in some circumstances more of the
|
||||
file. Use of it is not recommended, but it's still the strongest method
|
||||
supported by Vim 7.3 and 7.4. The "zip" method is even weaker.
|
||||
- Vim originates from the Netherlands. That is where the sources come from.
|
||||
Thus the encryption code is not exported from the USA.
|
||||
|
||||
|
||||
@ -2229,10 +2229,18 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
zip PkZip compatible method. A weak kind of encryption.
|
||||
Backwards compatible with Vim 7.2 and older.
|
||||
*blowfish*
|
||||
blowfish Blowfish method. Strong encryption. Requires Vim 7.3
|
||||
or later, files can NOT be read by Vim 7.2 and older.
|
||||
This adds a "seed" to the file, every time you write
|
||||
the file the encrypted bytes will be different.
|
||||
blowfish Blowfish method. Medium strong encryption but it has
|
||||
an implementation flaw. Requires Vim 7.3 or later,
|
||||
files can NOT be read by Vim 7.2 and older. This adds
|
||||
a "seed" to the file, every time you write the file
|
||||
the encrypted bytes will be different.
|
||||
*blowfish2*
|
||||
blowfish2 Blowfish method. Medium strong encryption. Requires
|
||||
Vim 7.4.399 or later, files can NOT be read by Vim 7.3
|
||||
and older. This adds a "seed" to the file, every time
|
||||
you write the file the encrypted bytes will be
|
||||
different. The whole undo file is encrypted, not just
|
||||
the pieces of text.
|
||||
|
||||
When reading an encrypted file 'cryptmethod' will be set automatically
|
||||
to the detected method of the file being read. Thus if you write it
|
||||
|
||||
31
src/Makefile
31
src/Makefile
@ -1431,6 +1431,8 @@ BASIC_SRC = \
|
||||
blowfish.c \
|
||||
buffer.c \
|
||||
charset.c \
|
||||
crypt.c \
|
||||
crypt_zip.c \
|
||||
diff.c \
|
||||
digraph.c \
|
||||
edit.c \
|
||||
@ -1520,6 +1522,8 @@ OBJ_COMMON = \
|
||||
objects/buffer.o \
|
||||
objects/blowfish.o \
|
||||
objects/charset.o \
|
||||
objects/crypt.o \
|
||||
objects/crypt_zip.o \
|
||||
objects/diff.o \
|
||||
objects/digraph.o \
|
||||
objects/edit.o \
|
||||
@ -1589,6 +1593,8 @@ PRO_AUTO = \
|
||||
blowfish.pro \
|
||||
buffer.pro \
|
||||
charset.pro \
|
||||
crypt.pro \
|
||||
crypt_zip.pro \
|
||||
diff.pro \
|
||||
digraph.pro \
|
||||
edit.pro \
|
||||
@ -1753,10 +1759,11 @@ xxd/xxd$(EXEEXT): xxd/xxd.c
|
||||
languages:
|
||||
@if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \
|
||||
cd $(PODIR); \
|
||||
CC="$(CC)" $(MAKE) prefix=$(DESTDIR)$(prefix); \
|
||||
CC="$(CC)" $(MAKE) prefix=$(DESTDIR)$(prefix); \
|
||||
fi
|
||||
-@if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \
|
||||
cd $(PODIR); CC="$(CC)" $(MAKE) prefix=$(DESTDIR)$(prefix) converted; \
|
||||
cd $(PODIR); \
|
||||
CC="$(CC)" $(MAKE) prefix=$(DESTDIR)$(prefix) converted; \
|
||||
fi
|
||||
|
||||
# Update the *.po files for changes in the sources. Only run manually.
|
||||
@ -1883,8 +1890,14 @@ unittest unittests: $(UNITTEST_TARGETS)
|
||||
# Run individual test, assuming that Vim was already compiled.
|
||||
test1 test2 test3 test4 test5 test6 test7 test8 test9 \
|
||||
test_autoformat_join \
|
||||
test_breakindent \
|
||||
test_changelist \
|
||||
test_eval \
|
||||
test_insertcount \
|
||||
test_listlbr \
|
||||
test_listlbr_utf8 \
|
||||
test_options \
|
||||
test_qf_title \
|
||||
test10 test11 test12 test13 test14 test15 test16 test17 test18 test19 \
|
||||
test20 test21 test22 test23 test24 test25 test26 test27 test28 test29 \
|
||||
test30 test31 test32 test33 test34 test35 test36 test37 test38 test39 \
|
||||
@ -2506,6 +2519,12 @@ objects/buffer.o: buffer.c
|
||||
objects/charset.o: charset.c
|
||||
$(CCC) -o $@ charset.c
|
||||
|
||||
objects/crypt.o: crypt.c
|
||||
$(CCC) -o $@ crypt.c
|
||||
|
||||
objects/crypt_zip.o: crypt_zip.c
|
||||
$(CCC) -o $@ crypt_zip.c
|
||||
|
||||
objects/diff.o: diff.c
|
||||
$(CCC) -o $@ diff.c
|
||||
|
||||
@ -2855,6 +2874,14 @@ objects/charset.o: charset.c vim.h auto/config.h feature.h os_unix.h auto/osdef.
|
||||
ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
|
||||
gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \
|
||||
arabic.h
|
||||
objects/crypt.o: crypt.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \
|
||||
ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
|
||||
gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \
|
||||
arabic.h
|
||||
objects/crypt_zip.o: crypt_zip.c vim.h auto/config.h feature.h os_unix.h \
|
||||
auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
|
||||
regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
|
||||
globals.h farsi.h arabic.h
|
||||
objects/diff.o: diff.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \
|
||||
ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
|
||||
gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \
|
||||
|
||||
305
src/blowfish.c
305
src/blowfish.c
@ -9,17 +9,25 @@
|
||||
* Blowfish encryption for Vim; in Blowfish cipher feedback mode.
|
||||
* Contributed by Mohsin Ahmed, http://www.cs.albany.edu/~mosh
|
||||
* Based on http://www.schneier.com/blowfish.html by Bruce Schneier.
|
||||
*
|
||||
* There are two variants:
|
||||
* - The old one "blowfish" has a flaw which makes it much easier to crack the
|
||||
* key. To see this, make a text file with one line of 1000 "x" characters
|
||||
* and write it encrypted. Use "xxd" to inspect the bytes in the file. You
|
||||
* will see that a block of 8 bytes repeats 8 times.
|
||||
* - The new one "blowfish2" is better. It uses an 8 byte CFB to avoid the
|
||||
* repeats.
|
||||
*/
|
||||
|
||||
#include "vim.h"
|
||||
|
||||
#if defined(FEAT_CRYPT)
|
||||
#if defined(FEAT_CRYPT) || defined(PROTO)
|
||||
|
||||
#define ARRAY_LENGTH(A) (sizeof(A)/sizeof(A[0]))
|
||||
|
||||
#define BF_BLOCK 8
|
||||
#define BF_BLOCK_MASK 7
|
||||
#define BF_CFB_LEN (8*(BF_BLOCK))
|
||||
#define BF_MAX_CFB_LEN (8 * BF_BLOCK)
|
||||
|
||||
typedef union {
|
||||
UINT32_T ul[2];
|
||||
@ -37,14 +45,26 @@ typedef union {
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static void bf_e_block __ARGS((UINT32_T *p_xl, UINT32_T *p_xr));
|
||||
static void bf_e_cblock __ARGS((char_u *block));
|
||||
static int bf_check_tables __ARGS((UINT32_T a_ipa[18], UINT32_T a_sbi[4][256], UINT32_T val));
|
||||
/* The state of encryption, referenced by cryptstate_T. */
|
||||
typedef struct {
|
||||
UINT32_T pax[18]; /* P-array */
|
||||
UINT32_T sbx[4][256]; /* S-boxes */
|
||||
int randbyte_offset;
|
||||
int update_offset;
|
||||
char_u cfb_buffer[BF_MAX_CFB_LEN]; /* up to 64 bytes used */
|
||||
int cfb_len; /* size of cfb_buffer actually used */
|
||||
} bf_state_T;
|
||||
|
||||
|
||||
static void bf_e_block __ARGS((bf_state_T *state, UINT32_T *p_xl, UINT32_T *p_xr));
|
||||
static void bf_e_cblock __ARGS((bf_state_T *state, char_u *block));
|
||||
static int bf_check_tables __ARGS((UINT32_T pax[18], UINT32_T sbx[4][256], UINT32_T val));
|
||||
static int bf_self_test __ARGS((void));
|
||||
static void bf_key_init __ARGS((bf_state_T *state, char_u *password, char_u *salt, int salt_len));
|
||||
static void bf_cfb_init __ARGS((bf_state_T *state, char_u *seed, int seed_len));
|
||||
|
||||
/* Blowfish code */
|
||||
static UINT32_T pax[18];
|
||||
static UINT32_T ipa[18] = {
|
||||
static UINT32_T pax_init[18] = {
|
||||
0x243f6a88u, 0x85a308d3u, 0x13198a2eu,
|
||||
0x03707344u, 0xa4093822u, 0x299f31d0u,
|
||||
0x082efa98u, 0xec4e6c89u, 0x452821e6u,
|
||||
@ -53,8 +73,7 @@ static UINT32_T ipa[18] = {
|
||||
0xb5470917u, 0x9216d5d9u, 0x8979fb1bu
|
||||
};
|
||||
|
||||
static UINT32_T sbx[4][256];
|
||||
static UINT32_T sbi[4][256] = {
|
||||
static UINT32_T sbx_init[4][256] = {
|
||||
{0xd1310ba6u, 0x98dfb5acu, 0x2ffd72dbu, 0xd01adfb7u,
|
||||
0xb8e1afedu, 0x6a267e96u, 0xba7c9045u, 0xf12c7f99u,
|
||||
0x24a19947u, 0xb3916cf7u, 0x0801f2e2u, 0x858efc16u,
|
||||
@ -314,33 +333,40 @@ static UINT32_T sbi[4][256] = {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#define F1(i) \
|
||||
xl ^= pax[i]; \
|
||||
xr ^= ((sbx[0][xl >> 24] + \
|
||||
sbx[1][(xl & 0xFF0000) >> 16]) ^ \
|
||||
sbx[2][(xl & 0xFF00) >> 8]) + \
|
||||
sbx[3][xl & 0xFF];
|
||||
xl ^= bfs->pax[i]; \
|
||||
xr ^= ((bfs->sbx[0][xl >> 24] + \
|
||||
bfs->sbx[1][(xl & 0xFF0000) >> 16]) ^ \
|
||||
bfs->sbx[2][(xl & 0xFF00) >> 8]) + \
|
||||
bfs->sbx[3][xl & 0xFF];
|
||||
|
||||
#define F2(i) \
|
||||
xr ^= pax[i]; \
|
||||
xl ^= ((sbx[0][xr >> 24] + \
|
||||
sbx[1][(xr & 0xFF0000) >> 16]) ^ \
|
||||
sbx[2][(xr & 0xFF00) >> 8]) + \
|
||||
sbx[3][xr & 0xFF];
|
||||
|
||||
xr ^= bfs->pax[i]; \
|
||||
xl ^= ((bfs->sbx[0][xr >> 24] + \
|
||||
bfs->sbx[1][(xr & 0xFF0000) >> 16]) ^ \
|
||||
bfs->sbx[2][(xr & 0xFF00) >> 8]) + \
|
||||
bfs->sbx[3][xr & 0xFF];
|
||||
|
||||
static void
|
||||
bf_e_block(p_xl, p_xr)
|
||||
bf_e_block(bfs, p_xl, p_xr)
|
||||
bf_state_T *bfs;
|
||||
UINT32_T *p_xl;
|
||||
UINT32_T *p_xr;
|
||||
{
|
||||
UINT32_T temp, xl = *p_xl, xr = *p_xr;
|
||||
UINT32_T temp;
|
||||
UINT32_T xl = *p_xl;
|
||||
UINT32_T xr = *p_xr;
|
||||
|
||||
F1(0) F2(1) F1(2) F2(3) F1(4) F2(5) F1(6) F2(7)
|
||||
F1(8) F2(9) F1(10) F2(11) F1(12) F2(13) F1(14) F2(15)
|
||||
xl ^= pax[16];
|
||||
xr ^= pax[17];
|
||||
F1(0) F2(1)
|
||||
F1(2) F2(3)
|
||||
F1(4) F2(5)
|
||||
F1(6) F2(7)
|
||||
F1(8) F2(9)
|
||||
F1(10) F2(11)
|
||||
F1(12) F2(13)
|
||||
F1(14) F2(15)
|
||||
xl ^= bfs->pax[16];
|
||||
xr ^= bfs->pax[17];
|
||||
temp = xl;
|
||||
xl = xr;
|
||||
xr = temp;
|
||||
@ -348,22 +374,6 @@ bf_e_block(p_xl, p_xr)
|
||||
*p_xr = xr;
|
||||
}
|
||||
|
||||
#if 0 /* not used */
|
||||
static void
|
||||
bf_d_block(p_xl, p_xr)
|
||||
UINT32_T *p_xl;
|
||||
UINT32_T *p_xr;
|
||||
{
|
||||
UINT32_T temp, xl = *p_xl, xr = *p_xr;
|
||||
F1(17) F2(16) F1(15) F2(14) F1(13) F2(12) F1(11) F2(10)
|
||||
F1(9) F2(8) F1(7) F2(6) F1(5) F2(4) F1(3) F2(2)
|
||||
xl ^= pax[1];
|
||||
xr ^= pax[0];
|
||||
temp = xl; xl = xr; xr = temp;
|
||||
*p_xl = xl; *p_xr = xr;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
# define htonl2(x) \
|
||||
@ -374,7 +384,8 @@ bf_d_block(p_xl, p_xr)
|
||||
#endif
|
||||
|
||||
static void
|
||||
bf_e_cblock(block)
|
||||
bf_e_cblock(bfs, block)
|
||||
bf_state_T *bfs;
|
||||
char_u *block;
|
||||
{
|
||||
block8 bk;
|
||||
@ -382,35 +393,22 @@ bf_e_cblock(block)
|
||||
memcpy(bk.uc, block, 8);
|
||||
htonl2(bk.ul[0]);
|
||||
htonl2(bk.ul[1]);
|
||||
bf_e_block(&bk.ul[0], &bk.ul[1]);
|
||||
bf_e_block(bfs, &bk.ul[0], &bk.ul[1]);
|
||||
htonl2(bk.ul[0]);
|
||||
htonl2(bk.ul[1]);
|
||||
memcpy(block, bk.uc, 8);
|
||||
}
|
||||
|
||||
#if 0 /* not used */
|
||||
void
|
||||
bf_d_cblock(block)
|
||||
char_u *block;
|
||||
{
|
||||
block8 bk;
|
||||
memcpy(bk.uc, block, 8);
|
||||
htonl2(bk.ul[0]); htonl2(bk.ul[1]);
|
||||
bf_d_block(&bk.ul[0], &bk.ul[1]);
|
||||
htonl2(bk.ul[0]); htonl2(bk.ul[1]);
|
||||
memcpy(block, bk.uc, 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize the crypt method using "password" as the encryption key and
|
||||
* "salt[salt_len]" as the salt.
|
||||
*/
|
||||
void
|
||||
bf_key_init(password, salt, salt_len)
|
||||
char_u *password;
|
||||
char_u *salt;
|
||||
int salt_len;
|
||||
static void
|
||||
bf_key_init(bfs, password, salt, salt_len)
|
||||
bf_state_T *bfs;
|
||||
char_u *password;
|
||||
char_u *salt;
|
||||
int salt_len;
|
||||
{
|
||||
int i, j, keypos = 0;
|
||||
unsigned u;
|
||||
@ -418,7 +416,7 @@ bf_key_init(password, salt, salt_len)
|
||||
char_u *key;
|
||||
int keylen;
|
||||
|
||||
/* Process the key 1000 times.
|
||||
/* Process the key 1001 times.
|
||||
* See http://en.wikipedia.org/wiki/Key_strengthening. */
|
||||
key = sha256_key(password, salt, salt_len);
|
||||
for (i = 0; i < 1000; i++)
|
||||
@ -437,52 +435,54 @@ bf_key_init(password, salt, salt_len)
|
||||
key[i] = u;
|
||||
}
|
||||
|
||||
mch_memmove(sbx, sbi, 4 * 4 * 256);
|
||||
/* Use "key" to initialize the P-array ("pax") and S-boxes ("sbx") of
|
||||
* Blowfish. */
|
||||
mch_memmove(bfs->sbx, sbx_init, 4 * 4 * 256);
|
||||
|
||||
for (i = 0; i < 18; ++i)
|
||||
{
|
||||
val = 0;
|
||||
for (j = 0; j < 4; ++j)
|
||||
val = (val << 8) | key[keypos++ % keylen];
|
||||
pax[i] = ipa[i] ^ val;
|
||||
bfs->pax[i] = pax_init[i] ^ val;
|
||||
}
|
||||
|
||||
data_l = data_r = 0;
|
||||
for (i = 0; i < 18; i += 2)
|
||||
{
|
||||
bf_e_block(&data_l, &data_r);
|
||||
pax[i + 0] = data_l;
|
||||
pax[i + 1] = data_r;
|
||||
bf_e_block(bfs, &data_l, &data_r);
|
||||
bfs->pax[i + 0] = data_l;
|
||||
bfs->pax[i + 1] = data_r;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
for (j = 0; j < 256; j += 2)
|
||||
{
|
||||
bf_e_block(&data_l, &data_r);
|
||||
sbx[i][j + 0] = data_l;
|
||||
sbx[i][j + 1] = data_r;
|
||||
bf_e_block(bfs, &data_l, &data_r);
|
||||
bfs->sbx[i][j + 0] = data_l;
|
||||
bfs->sbx[i][j + 1] = data_r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* BF Self test for corrupted tables or instructions
|
||||
* Blowfish self-test for corrupted tables or instructions.
|
||||
*/
|
||||
static int
|
||||
bf_check_tables(a_ipa, a_sbi, val)
|
||||
UINT32_T a_ipa[18];
|
||||
UINT32_T a_sbi[4][256];
|
||||
bf_check_tables(pax, sbx, val)
|
||||
UINT32_T pax[18];
|
||||
UINT32_T sbx[4][256];
|
||||
UINT32_T val;
|
||||
{
|
||||
int i, j;
|
||||
UINT32_T c = 0;
|
||||
|
||||
for (i = 0; i < 18; i++)
|
||||
c ^= a_ipa[i];
|
||||
c ^= pax[i];
|
||||
for (i = 0; i < 4; i++)
|
||||
for (j = 0; j < 256; j++)
|
||||
c ^= a_sbi[i][j];
|
||||
c ^= sbx[i][j];
|
||||
return c == val;
|
||||
}
|
||||
|
||||
@ -520,6 +520,10 @@ bf_self_test()
|
||||
int err = 0;
|
||||
block8 bk;
|
||||
UINT32_T ui = 0xffffffffUL;
|
||||
bf_state_T state;
|
||||
|
||||
vim_memset(&state, 0, sizeof(bf_state_T));
|
||||
state.cfb_len = BF_MAX_CFB_LEN;
|
||||
|
||||
/* We can't simply use sizeof(UINT32_T), it would generate a compiler
|
||||
* warning. */
|
||||
@ -528,21 +532,21 @@ bf_self_test()
|
||||
EMSG(_("E820: sizeof(uint32_t) != 4"));
|
||||
}
|
||||
|
||||
if (!bf_check_tables(ipa, sbi, 0x6ffa520a))
|
||||
if (!bf_check_tables(pax_init, sbx_init, 0x6ffa520a))
|
||||
err++;
|
||||
|
||||
bn = ARRAY_LENGTH(bf_test_data);
|
||||
for (i = 0; i < bn; i++)
|
||||
{
|
||||
bf_key_init((char_u *)(bf_test_data[i].password),
|
||||
bf_key_init(&state, (char_u *)(bf_test_data[i].password),
|
||||
bf_test_data[i].salt,
|
||||
(int)STRLEN(bf_test_data[i].salt));
|
||||
if (!bf_check_tables(pax, sbx, bf_test_data[i].keysum))
|
||||
if (!bf_check_tables(state.pax, state.sbx, bf_test_data[i].keysum))
|
||||
err++;
|
||||
|
||||
/* Don't modify bf_test_data[i].plaintxt, self test is idempotent. */
|
||||
memcpy(bk.uc, bf_test_data[i].plaintxt, 8);
|
||||
bf_e_cblock(bk.uc);
|
||||
bf_e_cblock(&state, bk.uc);
|
||||
if (memcmp(bk.uc, bf_test_data[i].cryptxt, 8) != 0)
|
||||
{
|
||||
if (err == 0 && memcmp(bk.uc, bf_test_data[i].badcryptxt, 8) == 0)
|
||||
@ -554,43 +558,43 @@ bf_self_test()
|
||||
return err > 0 ? FAIL : OK;
|
||||
}
|
||||
|
||||
/* Cipher feedback mode. */
|
||||
static int randbyte_offset = 0;
|
||||
static int update_offset = 0;
|
||||
static char_u cfb_buffer[BF_CFB_LEN]; /* 64 bytes */
|
||||
/*
|
||||
* CFB: Cipher Feedback Mode.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initialize with seed "iv[iv_len]".
|
||||
* Initialize with seed "seed[seed_len]".
|
||||
*/
|
||||
void
|
||||
bf_cfb_init(iv, iv_len)
|
||||
char_u *iv;
|
||||
int iv_len;
|
||||
static void
|
||||
bf_cfb_init(bfs, seed, seed_len)
|
||||
bf_state_T *bfs;
|
||||
char_u *seed;
|
||||
int seed_len;
|
||||
{
|
||||
int i, mi;
|
||||
|
||||
randbyte_offset = update_offset = 0;
|
||||
vim_memset(cfb_buffer, 0, BF_CFB_LEN);
|
||||
if (iv_len > 0)
|
||||
bfs->randbyte_offset = bfs->update_offset = 0;
|
||||
vim_memset(bfs->cfb_buffer, 0, bfs->cfb_len);
|
||||
if (seed_len > 0)
|
||||
{
|
||||
mi = iv_len > BF_CFB_LEN ? iv_len : BF_CFB_LEN;
|
||||
mi = seed_len > bfs->cfb_len ? seed_len : bfs->cfb_len;
|
||||
for (i = 0; i < mi; i++)
|
||||
cfb_buffer[i % BF_CFB_LEN] ^= iv[i % iv_len];
|
||||
bfs->cfb_buffer[i % bfs->cfb_len] ^= seed[i % seed_len];
|
||||
}
|
||||
}
|
||||
|
||||
#define BF_CFB_UPDATE(c) { \
|
||||
cfb_buffer[update_offset] ^= (char_u)c; \
|
||||
if (++update_offset == BF_CFB_LEN) \
|
||||
update_offset = 0; \
|
||||
#define BF_CFB_UPDATE(bfs, c) { \
|
||||
bfs->cfb_buffer[bfs->update_offset] ^= (char_u)c; \
|
||||
if (++bfs->update_offset == bfs->cfb_len) \
|
||||
bfs->update_offset = 0; \
|
||||
}
|
||||
|
||||
#define BF_RANBYTE(t) { \
|
||||
if ((randbyte_offset & BF_BLOCK_MASK) == 0) \
|
||||
bf_e_cblock(&cfb_buffer[randbyte_offset]); \
|
||||
t = cfb_buffer[randbyte_offset]; \
|
||||
if (++randbyte_offset == BF_CFB_LEN) \
|
||||
randbyte_offset = 0; \
|
||||
#define BF_RANBYTE(bfs, t) { \
|
||||
if ((bfs->randbyte_offset & BF_BLOCK_MASK) == 0) \
|
||||
bf_e_cblock(bfs, &(bfs->cfb_buffer[bfs->randbyte_offset])); \
|
||||
t = bfs->cfb_buffer[bfs->randbyte_offset]; \
|
||||
if (++bfs->randbyte_offset == bfs->cfb_len) \
|
||||
bfs->randbyte_offset = 0; \
|
||||
}
|
||||
|
||||
/*
|
||||
@ -598,90 +602,69 @@ bf_cfb_init(iv, iv_len)
|
||||
* "from" and "to" can be equal to encrypt in place.
|
||||
*/
|
||||
void
|
||||
bf_crypt_encode(from, len, to)
|
||||
crypt_blowfish_encode(state, from, len, to)
|
||||
cryptstate_T *state;
|
||||
char_u *from;
|
||||
size_t len;
|
||||
char_u *to;
|
||||
{
|
||||
bf_state_T *bfs = state->method_state;
|
||||
size_t i;
|
||||
int ztemp, t;
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
ztemp = from[i];
|
||||
BF_RANBYTE(t);
|
||||
BF_CFB_UPDATE(ztemp);
|
||||
BF_RANBYTE(bfs, t);
|
||||
BF_CFB_UPDATE(bfs, ztemp);
|
||||
to[i] = t ^ ztemp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrypt "ptr[len]" in place.
|
||||
* Decrypt "from[len]" into "to[len]".
|
||||
*/
|
||||
void
|
||||
bf_crypt_decode(ptr, len)
|
||||
char_u *ptr;
|
||||
long len;
|
||||
crypt_blowfish_decode(state, from, len, to)
|
||||
cryptstate_T *state;
|
||||
char_u *from;
|
||||
size_t len;
|
||||
char_u *to;
|
||||
{
|
||||
char_u *p;
|
||||
bf_state_T *bfs = state->method_state;
|
||||
size_t i;
|
||||
int t;
|
||||
|
||||
for (p = ptr; p < ptr + len; ++p)
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
BF_RANBYTE(t);
|
||||
*p ^= t;
|
||||
BF_CFB_UPDATE(*p);
|
||||
BF_RANBYTE(bfs, t);
|
||||
to[i] = from[i] ^ t;
|
||||
BF_CFB_UPDATE(bfs, to[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the encryption keys and the random header according to
|
||||
* the given password.
|
||||
*/
|
||||
void
|
||||
bf_crypt_init_keys(passwd)
|
||||
char_u *passwd; /* password string with which to modify keys */
|
||||
crypt_blowfish_init(state, key, salt, salt_len, seed, seed_len)
|
||||
cryptstate_T *state;
|
||||
char_u* key;
|
||||
char_u* salt;
|
||||
int salt_len;
|
||||
char_u* seed;
|
||||
int seed_len;
|
||||
{
|
||||
char_u *p;
|
||||
bf_state_T *bfs = (bf_state_T *)alloc_clear(sizeof(bf_state_T));
|
||||
|
||||
for (p = passwd; *p != NUL; ++p)
|
||||
{
|
||||
BF_CFB_UPDATE(*p);
|
||||
}
|
||||
}
|
||||
state->method_state = bfs;
|
||||
|
||||
static int save_randbyte_offset;
|
||||
static int save_update_offset;
|
||||
static char_u save_cfb_buffer[BF_CFB_LEN];
|
||||
static UINT32_T save_pax[18];
|
||||
static UINT32_T save_sbx[4][256];
|
||||
/* "blowfish" uses a 64 byte buffer, causing it to repeat 8 byte groups 8
|
||||
* times. "blowfish2" uses a 8 byte buffer to avoid repeating. */
|
||||
bfs->cfb_len = state->method_nr == CRYPT_M_BF ? BF_MAX_CFB_LEN : BF_BLOCK;
|
||||
|
||||
/*
|
||||
* Save the current crypt state. Can only be used once before
|
||||
* bf_crypt_restore().
|
||||
*/
|
||||
void
|
||||
bf_crypt_save()
|
||||
{
|
||||
save_randbyte_offset = randbyte_offset;
|
||||
save_update_offset = update_offset;
|
||||
mch_memmove(save_cfb_buffer, cfb_buffer, BF_CFB_LEN);
|
||||
mch_memmove(save_pax, pax, 4 * 18);
|
||||
mch_memmove(save_sbx, sbx, 4 * 4 * 256);
|
||||
}
|
||||
if (blowfish_self_test() == FAIL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Restore the current crypt state. Can only be used after
|
||||
* bf_crypt_save().
|
||||
*/
|
||||
void
|
||||
bf_crypt_restore()
|
||||
{
|
||||
randbyte_offset = save_randbyte_offset;
|
||||
update_offset = save_update_offset;
|
||||
mch_memmove(cfb_buffer, save_cfb_buffer, BF_CFB_LEN);
|
||||
mch_memmove(pax, save_pax, 4 * 18);
|
||||
mch_memmove(sbx, save_sbx, 4 * 4 * 256);
|
||||
bf_key_init(bfs, key, salt, salt_len);
|
||||
bf_cfb_init(bfs, seed, seed_len);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
585
src/crypt.c
Normal file
585
src/crypt.c
Normal file
@ -0,0 +1,585 @@
|
||||
/* vi:set ts=8 sts=4 sw=4:
|
||||
*
|
||||
* VIM - Vi IMproved by Bram Moolenaar
|
||||
*
|
||||
* Do ":help uganda" in Vim to read copying and usage conditions.
|
||||
* Do ":help credits" in Vim to see a list of people who contributed.
|
||||
* See README.txt for an overview of the Vim source code.
|
||||
*/
|
||||
|
||||
/*
|
||||
* crypt.c: Generic encryption support.
|
||||
*/
|
||||
#include "vim.h"
|
||||
|
||||
#if defined(FEAT_CRYPT) || defined(PROTO)
|
||||
/*
|
||||
* Optional encryption support.
|
||||
* Mohsin Ahmed, mosh@sasi.com, 1998-09-24
|
||||
* Based on zip/crypt sources.
|
||||
* Refactored by David Leadbeater, 2014.
|
||||
*
|
||||
* NOTE FOR USA: Since 2000 exporting this code from the USA is allowed to
|
||||
* most countries. There are a few exceptions, but that still should not be a
|
||||
* problem since this code was originally created in Europe and India.
|
||||
*
|
||||
* Blowfish addition originally made by Mohsin Ahmed,
|
||||
* http://www.cs.albany.edu/~mosh 2010-03-14
|
||||
* Based on blowfish by Bruce Schneier (http://www.schneier.com/blowfish.html)
|
||||
* and sha256 by Christophe Devine.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
char *name; /* encryption name as used in 'cryptmethod' */
|
||||
char *magic; /* magic bytes stored in file header */
|
||||
int salt_len; /* length of salt, or 0 when not using salt */
|
||||
int seed_len; /* length of seed, or 0 when not using salt */
|
||||
int works_inplace; /* encryption/decryption can be done in-place */
|
||||
int whole_undofile; /* whole undo file is encrypted */
|
||||
|
||||
/* Optional function pointer for a self-test. */
|
||||
int (* self_test_fn)();
|
||||
|
||||
/* Function pointer for initializing encryption/decription. */
|
||||
void (* init_fn)(cryptstate_T *state, char_u *key,
|
||||
char_u *salt, int salt_len, char_u *seed, int seed_len);
|
||||
|
||||
/* Function pointers for encoding/decoding from one buffer into another.
|
||||
* Optional, however, these or the _buffer ones should be configured. */
|
||||
void (*encode_fn)(cryptstate_T *state, char_u *from, size_t len,
|
||||
char_u *to);
|
||||
void (*decode_fn)(cryptstate_T *state, char_u *from, size_t len,
|
||||
char_u *to);
|
||||
|
||||
/* Function pointers for encoding and decoding, can buffer data if needed.
|
||||
* Optional (however, these or the above should be configured). */
|
||||
long (*encode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
|
||||
char_u **newptr);
|
||||
long (*decode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
|
||||
char_u **newptr);
|
||||
|
||||
/* Function pointers for in-place encoding and decoding, used for
|
||||
* crypt_*_inplace(). "from" and "to" arguments will be equal.
|
||||
* These may be the same as decode_fn and encode_fn above, however an
|
||||
* algorithm may implement them in a way that is not interchangeable with
|
||||
* the crypt_(en|de)code() interface (for example because it wishes to add
|
||||
* padding to files).
|
||||
* This method is used for swap and undo files which have a rigid format.
|
||||
*/
|
||||
void (*encode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
|
||||
char_u *p2);
|
||||
void (*decode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
|
||||
char_u *p2);
|
||||
} cryptmethod_T;
|
||||
|
||||
/* index is method_nr of cryptstate_T, CRYPT_M_* */
|
||||
static cryptmethod_T cryptmethods[CRYPT_M_COUNT] = {
|
||||
/* PK_Zip; very weak */
|
||||
{
|
||||
"zip",
|
||||
"VimCrypt~01!",
|
||||
0,
|
||||
0,
|
||||
TRUE,
|
||||
FALSE,
|
||||
NULL,
|
||||
crypt_zip_init,
|
||||
crypt_zip_encode, crypt_zip_decode,
|
||||
NULL, NULL,
|
||||
crypt_zip_encode, crypt_zip_decode,
|
||||
},
|
||||
|
||||
/* Blowfish/CFB + SHA-256 custom key derivation; implementation issues. */
|
||||
{
|
||||
"blowfish",
|
||||
"VimCrypt~02!",
|
||||
8,
|
||||
8,
|
||||
TRUE,
|
||||
FALSE,
|
||||
blowfish_self_test,
|
||||
crypt_blowfish_init,
|
||||
crypt_blowfish_encode, crypt_blowfish_decode,
|
||||
NULL, NULL,
|
||||
crypt_blowfish_encode, crypt_blowfish_decode,
|
||||
},
|
||||
|
||||
/* Blowfish/CFB + SHA-256 custom key derivation; fixed. */
|
||||
{
|
||||
"blowfish2",
|
||||
"VimCrypt~03!",
|
||||
8,
|
||||
8,
|
||||
TRUE,
|
||||
TRUE,
|
||||
blowfish_self_test,
|
||||
crypt_blowfish_init,
|
||||
crypt_blowfish_encode, crypt_blowfish_decode,
|
||||
NULL, NULL,
|
||||
crypt_blowfish_encode, crypt_blowfish_decode,
|
||||
},
|
||||
};
|
||||
|
||||
#define CRYPT_MAGIC_LEN 12 /* cannot change */
|
||||
static char crypt_magic_head[] = "VimCrypt~";
|
||||
|
||||
/*
|
||||
* Return int value for crypt method name.
|
||||
* 0 for "zip", the old method. Also for any non-valid value.
|
||||
* 1 for "blowfish".
|
||||
* 2 for "blowfish2".
|
||||
*/
|
||||
int
|
||||
crypt_method_nr_from_name(name)
|
||||
char_u *name;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CRYPT_M_COUNT; ++i)
|
||||
if (STRCMP(name, cryptmethods[i].name) == 0)
|
||||
return i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the crypt method used for a file from "ptr[len]", the magic text at the
|
||||
* start of the file.
|
||||
* Returns -1 when no encryption used.
|
||||
*/
|
||||
int
|
||||
crypt_method_nr_from_magic(ptr, len)
|
||||
char *ptr;
|
||||
int len;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (len < CRYPT_MAGIC_LEN)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < CRYPT_M_COUNT; i++)
|
||||
if (memcmp(ptr, cryptmethods[i].magic, CRYPT_MAGIC_LEN) == 0)
|
||||
return i;
|
||||
|
||||
i = (int)STRLEN(crypt_magic_head);
|
||||
if (len >= i && memcmp(ptr, crypt_magic_head, i) == 0)
|
||||
EMSG(_("E821: File is encrypted with unknown method"));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if the crypt method for "method_nr" can be done in-place.
|
||||
*/
|
||||
int
|
||||
crypt_works_inplace(state)
|
||||
cryptstate_T *state;
|
||||
{
|
||||
return cryptmethods[state->method_nr].works_inplace;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the crypt method for buffer "buf" as a number.
|
||||
*/
|
||||
int
|
||||
crypt_get_method_nr(buf)
|
||||
buf_T *buf;
|
||||
{
|
||||
return crypt_method_nr_from_name(*buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE when the buffer uses an encryption method that encrypts the
|
||||
* whole undo file, not only the text.
|
||||
*/
|
||||
int
|
||||
crypt_whole_undofile(method_nr)
|
||||
int method_nr;
|
||||
{
|
||||
return cryptmethods[method_nr].whole_undofile;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get crypt method specifc length of the file header in bytes.
|
||||
*/
|
||||
int
|
||||
crypt_get_header_len(method_nr)
|
||||
int method_nr;
|
||||
{
|
||||
return CRYPT_MAGIC_LEN
|
||||
+ cryptmethods[method_nr].salt_len
|
||||
+ cryptmethods[method_nr].seed_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the crypt method for buffer "buf" to "method_nr" using the int value as
|
||||
* returned by crypt_method_nr_from_name().
|
||||
*/
|
||||
void
|
||||
crypt_set_cm_option(buf, method_nr)
|
||||
buf_T *buf;
|
||||
int method_nr;
|
||||
{
|
||||
free_string_option(buf->b_p_cm);
|
||||
buf->b_p_cm = vim_strsave((char_u *)cryptmethods[method_nr].name);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the crypt method for the current buffer has a self-test, run it and
|
||||
* return OK/FAIL.
|
||||
*/
|
||||
int
|
||||
crypt_self_test()
|
||||
{
|
||||
int method_nr = crypt_get_method_nr(curbuf);
|
||||
|
||||
if (cryptmethods[method_nr].self_test_fn == NULL)
|
||||
return OK;
|
||||
return cryptmethods[method_nr].self_test_fn();
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a crypt state and initialize it.
|
||||
*/
|
||||
cryptstate_T *
|
||||
crypt_create(method_nr, key, salt, salt_len, seed, seed_len)
|
||||
int method_nr;
|
||||
char_u *key;
|
||||
char_u *salt;
|
||||
int salt_len;
|
||||
char_u *seed;
|
||||
int seed_len;
|
||||
{
|
||||
cryptstate_T *state = (cryptstate_T *)alloc((int)sizeof(cryptstate_T));
|
||||
|
||||
state->method_nr = method_nr;
|
||||
cryptmethods[method_nr].init_fn(state, key, salt, salt_len, seed, seed_len);
|
||||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a crypt state from a file header and initialize it.
|
||||
* Assumes that header contains at least the number of bytes that
|
||||
* crypt_get_header_len() returns for "method_nr".
|
||||
*/
|
||||
cryptstate_T *
|
||||
crypt_create_from_header(method_nr, key, header)
|
||||
int method_nr;
|
||||
char_u *key;
|
||||
char_u *header;
|
||||
{
|
||||
char_u *salt = NULL;
|
||||
char_u *seed = NULL;
|
||||
int salt_len = cryptmethods[method_nr].salt_len;
|
||||
int seed_len = cryptmethods[method_nr].seed_len;
|
||||
|
||||
if (salt_len > 0)
|
||||
salt = header + CRYPT_MAGIC_LEN;
|
||||
if (seed_len > 0)
|
||||
seed = header + CRYPT_MAGIC_LEN + salt_len;
|
||||
|
||||
return crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the crypt method specific header data from "fp".
|
||||
* Return an allocated cryptstate_T or NULL on error.
|
||||
*/
|
||||
cryptstate_T *
|
||||
crypt_create_from_file(fp, key)
|
||||
FILE *fp;
|
||||
char_u *key;
|
||||
{
|
||||
int method_nr;
|
||||
int header_len;
|
||||
char magic_buffer[CRYPT_MAGIC_LEN];
|
||||
char_u *buffer;
|
||||
cryptstate_T *state;
|
||||
|
||||
if (fread(magic_buffer, CRYPT_MAGIC_LEN, 1, fp) != 1)
|
||||
return NULL;
|
||||
method_nr = crypt_method_nr_from_magic(magic_buffer, CRYPT_MAGIC_LEN);
|
||||
if (method_nr < 0)
|
||||
return NULL;
|
||||
|
||||
header_len = crypt_get_header_len(method_nr);
|
||||
if ((buffer = alloc(header_len)) == NULL)
|
||||
return NULL;
|
||||
mch_memmove(buffer, magic_buffer, CRYPT_MAGIC_LEN);
|
||||
if (header_len > CRYPT_MAGIC_LEN
|
||||
&& fread(buffer + CRYPT_MAGIC_LEN,
|
||||
header_len - CRYPT_MAGIC_LEN, 1, fp) != 1)
|
||||
{
|
||||
vim_free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state = crypt_create_from_header(method_nr, key, buffer);
|
||||
vim_free(buffer);
|
||||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a cryptstate_T for writing and initialize it with "key".
|
||||
* Allocates and fills in the header and stores it in "header", setting
|
||||
* "header_len". The header may include salt and seed, depending on
|
||||
* cryptmethod. Caller must free header.
|
||||
* Returns the state or NULL on failure.
|
||||
*/
|
||||
cryptstate_T *
|
||||
crypt_create_for_writing(method_nr, key, header, header_len)
|
||||
int method_nr;
|
||||
char_u *key;
|
||||
char_u **header;
|
||||
int *header_len;
|
||||
{
|
||||
int len = crypt_get_header_len(method_nr);
|
||||
char_u *salt = NULL;
|
||||
char_u *seed = NULL;
|
||||
int salt_len = cryptmethods[method_nr].salt_len;
|
||||
int seed_len = cryptmethods[method_nr].seed_len;
|
||||
cryptstate_T *state;
|
||||
|
||||
*header_len = len;
|
||||
*header = alloc(len);
|
||||
if (*header == NULL)
|
||||
return NULL;
|
||||
|
||||
mch_memmove(*header, cryptmethods[method_nr].magic, CRYPT_MAGIC_LEN);
|
||||
if (salt_len > 0 || seed_len > 0)
|
||||
{
|
||||
if (salt_len > 0)
|
||||
salt = *header + CRYPT_MAGIC_LEN;
|
||||
if (seed_len > 0)
|
||||
seed = *header + CRYPT_MAGIC_LEN + salt_len;
|
||||
|
||||
/* TODO: Should this be crypt method specific? (Probably not worth
|
||||
* it). sha2_seed is pretty bad for large amounts of entropy, so make
|
||||
* that into something which is suitable for anything. */
|
||||
sha2_seed(salt, salt_len, seed, seed_len);
|
||||
}
|
||||
|
||||
state = crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
|
||||
if (state == NULL)
|
||||
{
|
||||
vim_free(*header);
|
||||
*header = NULL;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the crypt state.
|
||||
*/
|
||||
void
|
||||
crypt_free_state(state)
|
||||
cryptstate_T *state;
|
||||
{
|
||||
vim_free(state->method_state);
|
||||
vim_free(state);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode "from[len]" and store the result in a newly allocated buffer, which
|
||||
* is stored in "newptr".
|
||||
* Return number of bytes in "newptr", 0 for need more or -1 on error.
|
||||
*/
|
||||
long
|
||||
crypt_encode_alloc(state, from, len, newptr)
|
||||
cryptstate_T *state;
|
||||
char_u *from;
|
||||
size_t len;
|
||||
char_u **newptr;
|
||||
{
|
||||
cryptmethod_T *method = &cryptmethods[state->method_nr];
|
||||
|
||||
if (method->encode_buffer_fn != NULL)
|
||||
/* Has buffer function, pass through. */
|
||||
return method->encode_buffer_fn(state, from, len, newptr);
|
||||
if (len == 0)
|
||||
/* Not buffering, just return EOF. */
|
||||
return len;
|
||||
|
||||
*newptr = alloc(len);
|
||||
if (*newptr == NULL)
|
||||
return -1;
|
||||
method->encode_fn(state, from, len, *newptr);
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrypt "ptr[len]" and store the result in a newly allocated buffer, which
|
||||
* is stored in "newptr".
|
||||
* Return number of bytes in "newptr", 0 for need more or -1 on error.
|
||||
*/
|
||||
long
|
||||
crypt_decode_alloc(state, ptr, len, newptr)
|
||||
cryptstate_T *state;
|
||||
char_u *ptr;
|
||||
long len;
|
||||
char_u **newptr;
|
||||
{
|
||||
cryptmethod_T *method = &cryptmethods[state->method_nr];
|
||||
|
||||
if (method->decode_buffer_fn != NULL)
|
||||
/* Has buffer function, pass through. */
|
||||
return method->decode_buffer_fn(state, ptr, len, newptr);
|
||||
|
||||
if (len == 0)
|
||||
/* Not buffering, just return EOF. */
|
||||
return len;
|
||||
|
||||
*newptr = alloc(len);
|
||||
if (*newptr == NULL)
|
||||
return -1;
|
||||
method->decode_fn(state, ptr, len, *newptr);
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encrypting "from[len]" into "to[len]".
|
||||
*/
|
||||
void
|
||||
crypt_encode(state, from, len, to)
|
||||
cryptstate_T *state;
|
||||
char_u *from;
|
||||
size_t len;
|
||||
char_u *to;
|
||||
{
|
||||
cryptmethods[state->method_nr].encode_fn(state, from, len, to);
|
||||
}
|
||||
|
||||
/*
|
||||
* decrypting "from[len]" into "to[len]".
|
||||
*/
|
||||
void
|
||||
crypt_decode(state, from, len, to)
|
||||
cryptstate_T *state;
|
||||
char_u *from;
|
||||
size_t len;
|
||||
char_u *to;
|
||||
{
|
||||
cryptmethods[state->method_nr].decode_fn(state, from, len, to);
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple inplace encryption, modifies "buf[len]" in place.
|
||||
*/
|
||||
void
|
||||
crypt_encode_inplace(state, buf, len)
|
||||
cryptstate_T *state;
|
||||
char_u *buf;
|
||||
size_t len;
|
||||
{
|
||||
cryptmethods[state->method_nr].encode_inplace_fn(state, buf, len, buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple inplace decryption, modifies "buf[len]" in place.
|
||||
*/
|
||||
void
|
||||
crypt_decode_inplace(state, buf, len)
|
||||
cryptstate_T *state;
|
||||
char_u *buf;
|
||||
size_t len;
|
||||
{
|
||||
cryptmethods[state->method_nr].decode_inplace_fn(state, buf, len, buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free an allocated crypt key. Clear the text to make sure it doesn't stay
|
||||
* in memory anywhere.
|
||||
*/
|
||||
void
|
||||
crypt_free_key(key)
|
||||
char_u *key;
|
||||
{
|
||||
char_u *p;
|
||||
|
||||
if (key != NULL)
|
||||
{
|
||||
for (p = key; *p != NUL; ++p)
|
||||
*p = 0;
|
||||
vim_free(key);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ask the user for a crypt key.
|
||||
* When "store" is TRUE, the new key is stored in the 'key' option, and the
|
||||
* 'key' option value is returned: Don't free it.
|
||||
* When "store" is FALSE, the typed key is returned in allocated memory.
|
||||
* Returns NULL on failure.
|
||||
*/
|
||||
char_u *
|
||||
crypt_get_key(store, twice)
|
||||
int store;
|
||||
int twice; /* Ask for the key twice. */
|
||||
{
|
||||
char_u *p1, *p2 = NULL;
|
||||
int round;
|
||||
|
||||
for (round = 0; ; ++round)
|
||||
{
|
||||
cmdline_star = TRUE;
|
||||
cmdline_row = msg_row;
|
||||
p1 = getcmdline_prompt(NUL, round == 0
|
||||
? (char_u *)_("Enter encryption key: ")
|
||||
: (char_u *)_("Enter same key again: "), 0, EXPAND_NOTHING,
|
||||
NULL);
|
||||
cmdline_star = FALSE;
|
||||
|
||||
if (p1 == NULL)
|
||||
break;
|
||||
|
||||
if (round == twice)
|
||||
{
|
||||
if (p2 != NULL && STRCMP(p1, p2) != 0)
|
||||
{
|
||||
MSG(_("Keys don't match!"));
|
||||
crypt_free_key(p1);
|
||||
crypt_free_key(p2);
|
||||
p2 = NULL;
|
||||
round = -1; /* do it again */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (store)
|
||||
{
|
||||
set_option_value((char_u *)"key", 0L, p1, OPT_LOCAL);
|
||||
crypt_free_key(p1);
|
||||
p1 = curbuf->b_p_key;
|
||||
}
|
||||
break;
|
||||
}
|
||||
p2 = p1;
|
||||
}
|
||||
|
||||
/* since the user typed this, no need to wait for return */
|
||||
if (msg_didout)
|
||||
msg_putchar('\n');
|
||||
need_wait_return = FALSE;
|
||||
msg_didout = FALSE;
|
||||
|
||||
crypt_free_key(p2);
|
||||
return p1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Append a message to IObuff for the encryption/decryption method being used.
|
||||
*/
|
||||
void
|
||||
crypt_append_msg(buf)
|
||||
buf_T *buf;
|
||||
{
|
||||
if (crypt_get_method_nr(buf) == 0)
|
||||
STRCAT(IObuff, _("[crypted]"));
|
||||
else
|
||||
{
|
||||
STRCAT(IObuff, "[");
|
||||
STRCAT(IObuff, *buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
|
||||
STRCAT(IObuff, "]");
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* FEAT_CRYPT */
|
||||
158
src/crypt_zip.c
Normal file
158
src/crypt_zip.c
Normal file
@ -0,0 +1,158 @@
|
||||
/* vi:set ts=8 sts=4 sw=4:
|
||||
*
|
||||
* VIM - Vi IMproved by Bram Moolenaar
|
||||
*
|
||||
* Do ":help uganda" in Vim to read copying and usage conditions.
|
||||
* Do ":help credits" in Vim to see a list of people who contributed.
|
||||
* See README.txt for an overview of the Vim source code.
|
||||
*/
|
||||
|
||||
/*
|
||||
* crypt_zip.c: Zip encryption support.
|
||||
*/
|
||||
#include "vim.h"
|
||||
|
||||
#if defined(FEAT_CRYPT) || defined(PROTO)
|
||||
/*
|
||||
* Optional encryption support.
|
||||
* Mohsin Ahmed, mosh@sasi.com, 98-09-24
|
||||
* Based on zip/crypt sources.
|
||||
*
|
||||
* NOTE FOR USA: Since 2000 exporting this code from the USA is allowed to
|
||||
* most countries. There are a few exceptions, but that still should not be a
|
||||
* problem since this code was originally created in Europe and India.
|
||||
*/
|
||||
|
||||
/* Need a type that should be 32 bits. 64 also works but wastes space. */
|
||||
# if VIM_SIZEOF_INT >= 4
|
||||
typedef unsigned int u32_T; /* int is at least 32 bits */
|
||||
# else
|
||||
typedef unsigned long u32_T; /* long should be 32 bits or more */
|
||||
# endif
|
||||
|
||||
/* The state of encryption, referenced by cryptstate_T. */
|
||||
typedef struct {
|
||||
u32_T keys[3];
|
||||
} zip_state_T;
|
||||
|
||||
|
||||
static void make_crc_tab __ARGS((void));
|
||||
|
||||
static u32_T crc_32_table[256];
|
||||
|
||||
/*
|
||||
* Fill the CRC table, if not done already.
|
||||
*/
|
||||
static void
|
||||
make_crc_tab()
|
||||
{
|
||||
u32_T s, t, v;
|
||||
static int done = FALSE;
|
||||
|
||||
if (done)
|
||||
return;
|
||||
for (t = 0; t < 256; t++)
|
||||
{
|
||||
v = t;
|
||||
for (s = 0; s < 8; s++)
|
||||
v = (v >> 1) ^ ((v & 1) * (u32_T)0xedb88320L);
|
||||
crc_32_table[t] = v;
|
||||
}
|
||||
done = TRUE;
|
||||
}
|
||||
|
||||
#define CRC32(c, b) (crc_32_table[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
|
||||
|
||||
/*
|
||||
* Return the next byte in the pseudo-random sequence.
|
||||
*/
|
||||
#define DECRYPT_BYTE_ZIP(keys, t) { \
|
||||
short_u temp = (short_u)keys[2] | 2; \
|
||||
t = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff); \
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the encryption keys with the next byte of plain text.
|
||||
*/
|
||||
#define UPDATE_KEYS_ZIP(keys, c) { \
|
||||
keys[0] = CRC32(keys[0], (c)); \
|
||||
keys[1] += keys[0] & 0xff; \
|
||||
keys[1] = keys[1] * 134775813L + 1; \
|
||||
keys[2] = CRC32(keys[2], (int)(keys[1] >> 24)); \
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize for encryption/decryption.
|
||||
*/
|
||||
void
|
||||
crypt_zip_init(state, key, salt, salt_len, seed, seed_len)
|
||||
cryptstate_T *state;
|
||||
char_u *key;
|
||||
char_u *salt UNUSED;
|
||||
int salt_len UNUSED;
|
||||
char_u *seed UNUSED;
|
||||
int seed_len UNUSED;
|
||||
{
|
||||
char_u *p;
|
||||
zip_state_T *zs;
|
||||
|
||||
zs = (zip_state_T *)alloc(sizeof(zip_state_T));
|
||||
state->method_state = zs;
|
||||
|
||||
make_crc_tab();
|
||||
zs->keys[0] = 305419896L;
|
||||
zs->keys[1] = 591751049L;
|
||||
zs->keys[2] = 878082192L;
|
||||
for (p = key; *p != NUL; ++p)
|
||||
{
|
||||
UPDATE_KEYS_ZIP(zs->keys, (int)*p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Encrypt "from[len]" into "to[len]".
|
||||
* "from" and "to" can be equal to encrypt in place.
|
||||
*/
|
||||
void
|
||||
crypt_zip_encode(state, from, len, to)
|
||||
cryptstate_T *state;
|
||||
char_u *from;
|
||||
size_t len;
|
||||
char_u *to;
|
||||
{
|
||||
zip_state_T *zs = state->method_state;
|
||||
size_t i;
|
||||
int ztemp, t;
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
ztemp = from[i];
|
||||
DECRYPT_BYTE_ZIP(zs->keys, t);
|
||||
UPDATE_KEYS_ZIP(zs->keys, ztemp);
|
||||
to[i] = t ^ ztemp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrypt "from[len]" into "to[len]".
|
||||
*/
|
||||
void
|
||||
crypt_zip_decode(state, from, len, to)
|
||||
cryptstate_T *state;
|
||||
char_u *from;
|
||||
size_t len;
|
||||
char_u *to;
|
||||
{
|
||||
zip_state_T *zs = state->method_state;
|
||||
size_t i;
|
||||
short_u temp;
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
temp = (short_u)zs->keys[2] | 2;
|
||||
temp = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff);
|
||||
UPDATE_KEYS_ZIP(zs->keys, to[i] = from[i] ^ temp);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* FEAT_CRYPT */
|
||||
@ -11506,8 +11506,7 @@ ex_match(eap)
|
||||
ex_X(eap)
|
||||
exarg_T *eap UNUSED;
|
||||
{
|
||||
if (get_crypt_method(curbuf) == 0 || blowfish_self_test() == OK)
|
||||
(void)get_crypt_key(TRUE, TRUE);
|
||||
(void)crypt_get_key(TRUE, TRUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
346
src/fileio.c
346
src/fileio.c
@ -24,20 +24,6 @@
|
||||
#define BUFSIZE 8192 /* size of normal write buffer */
|
||||
#define SMBUFSIZE 256 /* size of emergency write buffer */
|
||||
|
||||
#ifdef FEAT_CRYPT
|
||||
/* crypt_magic[0] is pkzip crypt, crypt_magic[1] is sha2+blowfish */
|
||||
static char *crypt_magic[] = {"VimCrypt~01!", "VimCrypt~02!"};
|
||||
static char crypt_magic_head[] = "VimCrypt~";
|
||||
# define CRYPT_MAGIC_LEN 12 /* must be multiple of 4! */
|
||||
|
||||
/* For blowfish, after the magic header, we store 8 bytes of salt and then 8
|
||||
* bytes of seed (initialisation vector). */
|
||||
static int crypt_salt_len[] = {0, 8};
|
||||
static int crypt_seed_len[] = {0, 8};
|
||||
#define CRYPT_SALT_LEN_MAX 8
|
||||
#define CRYPT_SEED_LEN_MAX 8
|
||||
#endif
|
||||
|
||||
/* Is there any system that doesn't have access()? */
|
||||
#define USE_MCH_ACCESS
|
||||
|
||||
@ -55,7 +41,6 @@ static char_u *readfile_charconvert __ARGS((char_u *fname, char_u *fenc, int *fd
|
||||
static void check_marks_read __ARGS((void));
|
||||
#endif
|
||||
#ifdef FEAT_CRYPT
|
||||
static int crypt_method_from_magic __ARGS((char *ptr, int len));
|
||||
static char_u *check_for_cryptkey __ARGS((char_u *cryptkey, char_u *ptr, long *sizep, off_t *filesizep, int newfile, char_u *fname, int *did_ask));
|
||||
#endif
|
||||
#ifdef UNIX
|
||||
@ -116,6 +101,9 @@ struct bw_info
|
||||
#ifdef HAS_BW_FLAGS
|
||||
int bw_flags; /* FIO_ flags */
|
||||
#endif
|
||||
#ifdef FEAT_CRYPT
|
||||
buf_T *bw_buffer; /* buffer being written */
|
||||
#endif
|
||||
#ifdef FEAT_MBYTE
|
||||
char_u bw_rest[CONV_RESTLEN]; /* not converted bytes */
|
||||
int bw_restlen; /* nr of bytes in bw_rest[] */
|
||||
@ -250,7 +238,6 @@ readfile(fname, sfname, from, lines_to_skip, lines_to_read, eap, flags)
|
||||
#ifdef FEAT_CRYPT
|
||||
char_u *cryptkey = NULL;
|
||||
int did_ask_for_key = FALSE;
|
||||
int crypt_method_used;
|
||||
#endif
|
||||
#ifdef FEAT_PERSISTENT_UNDO
|
||||
context_sha256_T sha_ctx;
|
||||
@ -966,13 +953,6 @@ retry:
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef FEAT_CRYPT
|
||||
if (cryptkey != NULL)
|
||||
/* Need to reset the state, but keep the key, don't want to ask for it
|
||||
* again. */
|
||||
crypt_pop_state();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* When retrying with another "fenc" and the first time "fileformat"
|
||||
* will be reset.
|
||||
@ -1174,6 +1154,15 @@ retry:
|
||||
&& !read_buffer);
|
||||
if (read_undo_file)
|
||||
sha256_start(&sha_ctx);
|
||||
#endif
|
||||
#ifdef FEAT_CRYPT
|
||||
if (curbuf->b_cryptstate != NULL)
|
||||
{
|
||||
/* Need to free the state, but keep the key, don't want to ask for
|
||||
* it again. */
|
||||
crypt_free_state(curbuf->b_cryptstate);
|
||||
curbuf->b_cryptstate = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1339,6 +1328,76 @@ retry:
|
||||
size = read_eintr(fd, ptr, size);
|
||||
}
|
||||
|
||||
#ifdef FEAT_CRYPT
|
||||
/*
|
||||
* At start of file: Check for magic number of encryption.
|
||||
*/
|
||||
if (filesize == 0 && size > 0)
|
||||
cryptkey = check_for_cryptkey(cryptkey, ptr, &size,
|
||||
&filesize, newfile, sfname,
|
||||
&did_ask_for_key);
|
||||
/*
|
||||
* Decrypt the read bytes. This is done before checking for
|
||||
* EOF because the crypt layer may be buffering.
|
||||
*/
|
||||
if (cryptkey != NULL && size > 0)
|
||||
{
|
||||
if (crypt_works_inplace(curbuf->b_cryptstate))
|
||||
{
|
||||
crypt_decode_inplace(curbuf->b_cryptstate, ptr, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
char_u *newptr = NULL;
|
||||
int decrypted_size;
|
||||
|
||||
decrypted_size = crypt_decode_alloc(
|
||||
curbuf->b_cryptstate, ptr, size, &newptr);
|
||||
|
||||
/* If the crypt layer is buffering, not producing
|
||||
* anything yet, need to read more. */
|
||||
if (size > 0 && decrypted_size == 0)
|
||||
continue;
|
||||
|
||||
if (linerest == 0)
|
||||
{
|
||||
/* Simple case: reuse returned buffer (may be
|
||||
* NULL, checked later). */
|
||||
new_buffer = newptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
long_u new_size;
|
||||
|
||||
/* Need new buffer to add bytes carried over. */
|
||||
new_size = (long_u)(decrypted_size + linerest + 1);
|
||||
new_buffer = lalloc(new_size, FALSE);
|
||||
if (new_buffer == NULL)
|
||||
{
|
||||
do_outofmem_msg(new_size);
|
||||
error = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
mch_memmove(new_buffer, buffer, linerest);
|
||||
if (newptr != NULL)
|
||||
mch_memmove(new_buffer + linerest, newptr,
|
||||
decrypted_size);
|
||||
}
|
||||
|
||||
if (new_buffer != NULL)
|
||||
{
|
||||
vim_free(buffer);
|
||||
buffer = new_buffer;
|
||||
new_buffer = NULL;
|
||||
line_start = buffer;
|
||||
ptr = buffer + linerest;
|
||||
}
|
||||
size = decrypted_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (size <= 0)
|
||||
{
|
||||
if (size < 0) /* read error */
|
||||
@ -1403,21 +1462,6 @@ retry:
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef FEAT_CRYPT
|
||||
/*
|
||||
* At start of file: Check for magic number of encryption.
|
||||
*/
|
||||
if (filesize == 0)
|
||||
cryptkey = check_for_cryptkey(cryptkey, ptr, &size,
|
||||
&filesize, newfile, sfname,
|
||||
&did_ask_for_key);
|
||||
/*
|
||||
* Decrypt the read bytes.
|
||||
*/
|
||||
if (cryptkey != NULL && size > 0)
|
||||
crypt_decode(ptr, size);
|
||||
#endif
|
||||
}
|
||||
skip_read = FALSE;
|
||||
|
||||
@ -1430,10 +1474,9 @@ retry:
|
||||
*/
|
||||
if ((filesize == 0
|
||||
# ifdef FEAT_CRYPT
|
||||
|| (filesize == (CRYPT_MAGIC_LEN
|
||||
+ crypt_salt_len[use_crypt_method]
|
||||
+ crypt_seed_len[use_crypt_method])
|
||||
&& cryptkey != NULL)
|
||||
|| (cryptkey != NULL
|
||||
&& filesize == crypt_get_header_len(
|
||||
crypt_get_method_nr(curbuf)))
|
||||
# endif
|
||||
)
|
||||
&& (fio_flags == FIO_UCSBOM
|
||||
@ -2262,15 +2305,15 @@ failed:
|
||||
save_file_ff(curbuf); /* remember the current file format */
|
||||
|
||||
#ifdef FEAT_CRYPT
|
||||
crypt_method_used = use_crypt_method;
|
||||
if (cryptkey != NULL)
|
||||
if (curbuf->b_cryptstate != NULL)
|
||||
{
|
||||
crypt_pop_state();
|
||||
if (cryptkey != curbuf->b_p_key)
|
||||
free_crypt_key(cryptkey);
|
||||
/* don't set cryptkey to NULL, it's used below as a flag that
|
||||
* encryption was used */
|
||||
crypt_free_state(curbuf->b_cryptstate);
|
||||
curbuf->b_cryptstate = NULL;
|
||||
}
|
||||
if (cryptkey != NULL && cryptkey != curbuf->b_p_key)
|
||||
crypt_free_key(cryptkey);
|
||||
/* Don't set cryptkey to NULL, it's used below as a flag that
|
||||
* encryption was used. */
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_MBYTE
|
||||
@ -2457,10 +2500,7 @@ failed:
|
||||
#ifdef FEAT_CRYPT
|
||||
if (cryptkey != NULL)
|
||||
{
|
||||
if (crypt_method_used == 1)
|
||||
STRCAT(IObuff, _("[blowfish]"));
|
||||
else
|
||||
STRCAT(IObuff, _("[crypted]"));
|
||||
crypt_append_msg(curbuf);
|
||||
c = TRUE;
|
||||
}
|
||||
#endif
|
||||
@ -2489,9 +2529,7 @@ failed:
|
||||
#ifdef FEAT_CRYPT
|
||||
if (cryptkey != NULL)
|
||||
msg_add_lines(c, (long)linecnt, filesize
|
||||
- CRYPT_MAGIC_LEN
|
||||
- crypt_salt_len[use_crypt_method]
|
||||
- crypt_seed_len[use_crypt_method]);
|
||||
- crypt_get_header_len(crypt_get_method_nr(curbuf)));
|
||||
else
|
||||
#endif
|
||||
msg_add_lines(c, (long)linecnt, filesize);
|
||||
@ -2881,33 +2919,6 @@ check_marks_read()
|
||||
#endif
|
||||
|
||||
#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.
|
||||
* Returns -1 when no encryption used.
|
||||
*/
|
||||
static int
|
||||
crypt_method_from_magic(ptr, len)
|
||||
char *ptr;
|
||||
int len;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (int)(sizeof(crypt_magic) / sizeof(crypt_magic[0])); i++)
|
||||
{
|
||||
if (len < (CRYPT_MAGIC_LEN + crypt_salt_len[i] + crypt_seed_len[i]))
|
||||
continue;
|
||||
if (memcmp(ptr, crypt_magic[i], CRYPT_MAGIC_LEN) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
i = (int)STRLEN(crypt_magic_head);
|
||||
if (len >= i && memcmp(ptr, crypt_magic_head, i) == 0)
|
||||
EMSG(_("E821: File is encrypted with unknown method"));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for magic number used for encryption. Applies to the current buffer.
|
||||
* If found, the magic number is removed from ptr[*sizep] and *sizep and
|
||||
@ -2924,7 +2935,7 @@ check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile, fname, did_ask)
|
||||
char_u *fname; /* file name to display */
|
||||
int *did_ask; /* flag: whether already asked for key */
|
||||
{
|
||||
int method = crypt_method_from_magic((char *)ptr, *sizep);
|
||||
int method = crypt_method_nr_from_magic((char *)ptr, *sizep);
|
||||
int b_p_ro = curbuf->b_p_ro;
|
||||
|
||||
if (method >= 0)
|
||||
@ -2933,9 +2944,7 @@ check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile, fname, did_ask)
|
||||
* Avoids accidentally overwriting the file with garbage. */
|
||||
curbuf->b_p_ro = TRUE;
|
||||
|
||||
set_crypt_method(curbuf, method);
|
||||
if (method > 0)
|
||||
(void)blowfish_self_test();
|
||||
crypt_set_cm_option(curbuf, method);
|
||||
if (cryptkey == NULL && !*did_ask)
|
||||
{
|
||||
if (*curbuf->b_p_key)
|
||||
@ -2948,7 +2957,7 @@ check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile, fname, did_ask)
|
||||
* Happens when retrying to detect encoding. */
|
||||
smsg((char_u *)_(need_key_msg), fname);
|
||||
msg_scroll = TRUE;
|
||||
cryptkey = get_crypt_key(newfile, FALSE);
|
||||
cryptkey = crypt_get_key(newfile, FALSE);
|
||||
*did_ask = TRUE;
|
||||
|
||||
/* check if empty key entered */
|
||||
@ -2963,24 +2972,18 @@ check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile, fname, did_ask)
|
||||
|
||||
if (cryptkey != NULL)
|
||||
{
|
||||
int seed_len = crypt_seed_len[method];
|
||||
int salt_len = crypt_salt_len[method];
|
||||
int header_len;
|
||||
|
||||
crypt_push_state();
|
||||
use_crypt_method = method;
|
||||
if (method == 0)
|
||||
crypt_init_keys(cryptkey);
|
||||
else
|
||||
{
|
||||
bf_key_init(cryptkey, ptr + CRYPT_MAGIC_LEN, salt_len);
|
||||
bf_cfb_init(ptr + CRYPT_MAGIC_LEN + salt_len, seed_len);
|
||||
}
|
||||
curbuf->b_cryptstate = crypt_create_from_header(
|
||||
method, cryptkey, ptr);
|
||||
crypt_set_cm_option(curbuf, method);
|
||||
|
||||
/* Remove cryptmethod specific header from the text. */
|
||||
header_len = crypt_get_header_len(method);
|
||||
*filesizep += header_len;
|
||||
*sizep -= header_len;
|
||||
mch_memmove(ptr, ptr + header_len, (size_t)*sizep);
|
||||
|
||||
/* Remove magic number from the text */
|
||||
*filesizep += CRYPT_MAGIC_LEN + salt_len + seed_len;
|
||||
*sizep -= CRYPT_MAGIC_LEN + salt_len + seed_len;
|
||||
mch_memmove(ptr, ptr + CRYPT_MAGIC_LEN + salt_len + seed_len,
|
||||
(size_t)*sizep);
|
||||
/* Restore the read-only flag. */
|
||||
curbuf->b_p_ro = b_p_ro;
|
||||
}
|
||||
@ -2992,85 +2995,6 @@ check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile, fname, did_ask)
|
||||
|
||||
return cryptkey;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_SALT_LEN_MAX
|
||||
+ CRYPT_SEED_LEN_MAX + 2];
|
||||
|
||||
if (fread(buffer, CRYPT_MAGIC_LEN, 1, fp) != 1)
|
||||
return FAIL;
|
||||
method = crypt_method_from_magic((char *)buffer,
|
||||
CRYPT_MAGIC_LEN +
|
||||
CRYPT_SEED_LEN_MAX +
|
||||
CRYPT_SALT_LEN_MAX);
|
||||
if (method < 0 || method != get_crypt_method(curbuf))
|
||||
return FAIL;
|
||||
|
||||
crypt_push_state();
|
||||
if (method == 0)
|
||||
crypt_init_keys(curbuf->b_p_key);
|
||||
else
|
||||
{
|
||||
int salt_len = crypt_salt_len[method];
|
||||
int seed_len = crypt_seed_len[method];
|
||||
|
||||
if (fread(buffer, salt_len + seed_len, 1, fp) != 1)
|
||||
return FAIL;
|
||||
bf_key_init(curbuf->b_p_key, buffer, salt_len);
|
||||
bf_cfb_init(buffer + salt_len, seed_len);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare for writing encrypted bytes for buffer "buf".
|
||||
* Returns a pointer to an allocated header of length "*lenp".
|
||||
* When out of memory returns NULL.
|
||||
* Otherwise calls crypt_push_state(), call crypt_pop_state() later.
|
||||
*/
|
||||
char_u *
|
||||
prepare_crypt_write(buf, lenp)
|
||||
buf_T *buf;
|
||||
int *lenp;
|
||||
{
|
||||
char_u *header;
|
||||
int seed_len = crypt_seed_len[get_crypt_method(buf)];
|
||||
int salt_len = crypt_salt_len[get_crypt_method(buf)];
|
||||
char_u *salt;
|
||||
char_u *seed;
|
||||
|
||||
header = alloc_clear(CRYPT_MAGIC_LEN + CRYPT_SALT_LEN_MAX
|
||||
+ CRYPT_SEED_LEN_MAX + 2);
|
||||
if (header != NULL)
|
||||
{
|
||||
crypt_push_state();
|
||||
use_crypt_method = get_crypt_method(buf); /* select zip or blowfish */
|
||||
vim_strncpy(header, (char_u *)crypt_magic[use_crypt_method],
|
||||
CRYPT_MAGIC_LEN);
|
||||
if (use_crypt_method == 0)
|
||||
crypt_init_keys(buf->b_p_key);
|
||||
else
|
||||
{
|
||||
/* Using blowfish, add salt and seed. */
|
||||
salt = header + CRYPT_MAGIC_LEN;
|
||||
seed = salt + salt_len;
|
||||
sha2_seed(salt, salt_len, seed, seed_len);
|
||||
bf_key_init(buf->b_p_key, salt, salt_len);
|
||||
bf_cfb_init(seed, seed_len);
|
||||
}
|
||||
}
|
||||
*lenp = CRYPT_MAGIC_LEN + salt_len + seed_len;
|
||||
return header;
|
||||
}
|
||||
|
||||
#endif /* FEAT_CRYPT */
|
||||
|
||||
#ifdef UNIX
|
||||
@ -3224,9 +3148,6 @@ buf_write(buf, fname, sfname, start, end, eap, append, forceit,
|
||||
int write_undo_file = FALSE;
|
||||
context_sha256_T sha_ctx;
|
||||
#endif
|
||||
#ifdef FEAT_CRYPT
|
||||
int crypt_method_used;
|
||||
#endif
|
||||
|
||||
if (fname == NULL || *fname == NUL) /* safety check */
|
||||
return FAIL;
|
||||
@ -3261,6 +3182,9 @@ buf_write(buf, fname, sfname, start, end, eap, append, forceit,
|
||||
# ifdef USE_ICONV
|
||||
write_info.bw_iconv_fd = (iconv_t)-1;
|
||||
# endif
|
||||
#endif
|
||||
#ifdef FEAT_CRYPT
|
||||
write_info.bw_buffer = buf;
|
||||
#endif
|
||||
|
||||
/* After writing a file changedtick changes but we don't want to display
|
||||
@ -4505,17 +4429,17 @@ restore_backup:
|
||||
#ifdef FEAT_CRYPT
|
||||
if (*buf->b_p_key != NUL && !filtering)
|
||||
{
|
||||
char_u *header;
|
||||
int header_len;
|
||||
char_u *header;
|
||||
int header_len;
|
||||
|
||||
header = prepare_crypt_write(buf, &header_len);
|
||||
if (header == NULL)
|
||||
buf->b_cryptstate = crypt_create_for_writing(crypt_get_method_nr(buf),
|
||||
buf->b_p_key, &header, &header_len);
|
||||
if (buf->b_cryptstate == NULL || header == NULL)
|
||||
end = 0;
|
||||
else
|
||||
{
|
||||
/* 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 magic number, so that Vim knows how this file is
|
||||
* encrypted when reading it back. */
|
||||
write_info.bw_buf = header;
|
||||
write_info.bw_len = header_len;
|
||||
write_info.bw_flags = FIO_NOCONVERT;
|
||||
@ -4769,12 +4693,13 @@ restore_backup:
|
||||
mch_set_acl(wfname, acl);
|
||||
#endif
|
||||
#ifdef FEAT_CRYPT
|
||||
crypt_method_used = use_crypt_method;
|
||||
if (wb_flags & FIO_ENCRYPTED)
|
||||
crypt_pop_state();
|
||||
if (buf->b_cryptstate != NULL)
|
||||
{
|
||||
crypt_free_state(buf->b_cryptstate);
|
||||
buf->b_cryptstate = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(FEAT_MBYTE) && defined(FEAT_EVAL)
|
||||
if (wfname != fname)
|
||||
{
|
||||
@ -4924,10 +4849,7 @@ restore_backup:
|
||||
#ifdef FEAT_CRYPT
|
||||
if (wb_flags & FIO_ENCRYPTED)
|
||||
{
|
||||
if (crypt_method_used == 1)
|
||||
STRCAT(IObuff, _("[blowfish]"));
|
||||
else
|
||||
STRCAT(IObuff, _("[crypted]"));
|
||||
crypt_append_msg(buf);
|
||||
c = TRUE;
|
||||
}
|
||||
#endif
|
||||
@ -5740,8 +5662,26 @@ buf_write_bytes(ip)
|
||||
#endif /* FEAT_MBYTE */
|
||||
|
||||
#ifdef FEAT_CRYPT
|
||||
if (flags & FIO_ENCRYPTED) /* encrypt the data */
|
||||
crypt_encode(buf, len, buf);
|
||||
if (flags & FIO_ENCRYPTED)
|
||||
{
|
||||
/* Encrypt the data. Do it in-place if possible, otherwise use an
|
||||
* allocated buffer. */
|
||||
if (crypt_works_inplace(ip->bw_buffer->b_cryptstate))
|
||||
{
|
||||
crypt_encode_inplace(ip->bw_buffer->b_cryptstate, buf, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
char_u *outbuf;
|
||||
|
||||
len = crypt_encode_alloc(curbuf->b_cryptstate, buf, len, &outbuf);
|
||||
if (len == 0)
|
||||
return OK; /* Crypt layer is buffering, will flush later. */
|
||||
wlen = write_eintr(ip->bw_fd, outbuf, len);
|
||||
vim_free(outbuf);
|
||||
return (wlen < len) ? FAIL : OK;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
wlen = write_eintr(ip->bw_fd, buf, len);
|
||||
|
||||
@ -105,10 +105,6 @@ EXTERN int exec_from_reg INIT(= FALSE); /* executing register */
|
||||
|
||||
EXTERN int screen_cleared INIT(= FALSE); /* screen has been cleared */
|
||||
|
||||
#ifdef FEAT_CRYPT
|
||||
EXTERN int use_crypt_method INIT(= 0);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* When '$' is included in 'cpoptions' option set:
|
||||
* When a change command is given that deletes only part of a line, a dollar
|
||||
|
||||
@ -846,8 +846,7 @@ vim_main2(int argc UNUSED, char **argv UNUSED)
|
||||
#ifdef FEAT_CRYPT
|
||||
if (params.ask_for_key)
|
||||
{
|
||||
(void)blowfish_self_test();
|
||||
(void)get_crypt_key(TRUE, TRUE);
|
||||
(void)crypt_get_key(TRUE, TRUE);
|
||||
TIME_MSG("getting crypt key");
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -63,6 +63,15 @@ typedef struct pointer_entry PTR_EN; /* block/line-count pair */
|
||||
#define BLOCK0_ID1 '0' /* block 0 id 1 */
|
||||
#define BLOCK0_ID1_C0 'c' /* block 0 id 1 'cm' 0 */
|
||||
#define BLOCK0_ID1_C1 'C' /* block 0 id 1 'cm' 1 */
|
||||
#define BLOCK0_ID1_C2 'd' /* block 0 id 1 'cm' 2 */
|
||||
|
||||
#if defined(FEAT_CRYPT)
|
||||
static int id1_codes[] = {
|
||||
BLOCK0_ID1_C0, /* CRYPT_M_ZIP */
|
||||
BLOCK0_ID1_C1, /* CRYPT_M_BF */
|
||||
BLOCK0_ID1_C2, /* CRYPT_M_BF2 */
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* pointer to a block, used in a pointer block
|
||||
@ -151,7 +160,7 @@ struct data_block
|
||||
struct block0
|
||||
{
|
||||
char_u b0_id[2]; /* id for block 0: BLOCK0_ID0 and BLOCK0_ID1,
|
||||
* BLOCK0_ID1_C0, BLOCK0_ID1_C1 */
|
||||
* BLOCK0_ID1_C0, BLOCK0_ID1_C1, etc. */
|
||||
char_u b0_version[10]; /* Vim version string */
|
||||
char_u b0_page_size[4];/* number of bytes per page */
|
||||
char_u b0_mtime[4]; /* last modification time of file */
|
||||
@ -256,7 +265,7 @@ static long char_to_long __ARGS((char_u *));
|
||||
static char_u *make_percent_swname __ARGS((char_u *dir, char_u *name));
|
||||
#endif
|
||||
#ifdef FEAT_CRYPT
|
||||
static void ml_crypt_prepare __ARGS((memfile_T *mfp, off_t offset, int reading));
|
||||
static cryptstate_T *ml_crypt_prepare __ARGS((memfile_T *mfp, off_t offset, int reading));
|
||||
#endif
|
||||
#ifdef FEAT_BYTEOFF
|
||||
static void ml_updatechunk __ARGS((buf_T *buf, long line, long len, int updtype));
|
||||
@ -359,8 +368,7 @@ ml_open(buf)
|
||||
b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL;
|
||||
long_to_char(mch_get_pid(), b0p->b0_pid);
|
||||
#ifdef FEAT_CRYPT
|
||||
if (*buf->b_p_key != NUL)
|
||||
ml_set_b0_crypt(buf, b0p);
|
||||
ml_set_b0_crypt(buf, b0p);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -436,11 +444,11 @@ ml_set_b0_crypt(buf, b0p)
|
||||
b0p->b0_id[1] = BLOCK0_ID1;
|
||||
else
|
||||
{
|
||||
if (get_crypt_method(buf) == 0)
|
||||
b0p->b0_id[1] = BLOCK0_ID1_C0;
|
||||
else
|
||||
int method_nr = crypt_get_method_nr(buf);
|
||||
|
||||
b0p->b0_id[1] = id1_codes[method_nr];
|
||||
if (method_nr > CRYPT_M_ZIP)
|
||||
{
|
||||
b0p->b0_id[1] = BLOCK0_ID1_C1;
|
||||
/* Generate a seed and store it in block 0 and in the memfile. */
|
||||
sha2_seed(&b0p->b0_seed, MF_SEED_LEN, NULL, 0);
|
||||
mch_memmove(buf->b_ml.ml_mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
|
||||
@ -887,7 +895,8 @@ ml_check_b0_id(b0p)
|
||||
if (b0p->b0_id[0] != BLOCK0_ID0
|
||||
|| (b0p->b0_id[1] != BLOCK0_ID1
|
||||
&& b0p->b0_id[1] != BLOCK0_ID1_C0
|
||||
&& b0p->b0_id[1] != BLOCK0_ID1_C1)
|
||||
&& b0p->b0_id[1] != BLOCK0_ID1_C1
|
||||
&& b0p->b0_id[1] != BLOCK0_ID1_C2)
|
||||
)
|
||||
return FAIL;
|
||||
return OK;
|
||||
@ -1255,14 +1264,12 @@ ml_recover()
|
||||
}
|
||||
|
||||
#ifdef FEAT_CRYPT
|
||||
if (b0p->b0_id[1] == BLOCK0_ID1_C0)
|
||||
b0_cm = 0;
|
||||
else if (b0p->b0_id[1] == BLOCK0_ID1_C1)
|
||||
{
|
||||
b0_cm = 1;
|
||||
for (i = 0; i < (int)(sizeof(id1_codes) / sizeof(int)); ++i)
|
||||
if (id1_codes[i] == b0p->b0_id[1])
|
||||
b0_cm = i;
|
||||
if (b0_cm > 0)
|
||||
mch_memmove(mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
|
||||
}
|
||||
set_crypt_method(buf, b0_cm);
|
||||
crypt_set_cm_option(buf, b0_cm < 0 ? 0 : b0_cm);
|
||||
#else
|
||||
if (b0p->b0_id[1] != BLOCK0_ID1)
|
||||
{
|
||||
@ -1389,7 +1396,7 @@ ml_recover()
|
||||
}
|
||||
else
|
||||
smsg((char_u *)_(need_key_msg), fname_used);
|
||||
buf->b_p_key = get_crypt_key(FALSE, FALSE);
|
||||
buf->b_p_key = crypt_get_key(FALSE, FALSE);
|
||||
if (buf->b_p_key == NULL)
|
||||
buf->b_p_key = curbuf->b_p_key;
|
||||
else if (*buf->b_p_key == NUL)
|
||||
@ -4816,6 +4823,7 @@ ml_encrypt_data(mfp, data, offset, size)
|
||||
char_u *text_start;
|
||||
char_u *new_data;
|
||||
int text_len;
|
||||
cryptstate_T *state;
|
||||
|
||||
if (dp->db_id != DATA_ID)
|
||||
return data;
|
||||
@ -4831,10 +4839,9 @@ ml_encrypt_data(mfp, data, offset, size)
|
||||
mch_memmove(new_data, dp, head_end - (char_u *)dp);
|
||||
|
||||
/* Encrypt the text. */
|
||||
crypt_push_state();
|
||||
ml_crypt_prepare(mfp, offset, FALSE);
|
||||
crypt_encode(text_start, text_len, new_data + dp->db_txt_start);
|
||||
crypt_pop_state();
|
||||
state = ml_crypt_prepare(mfp, offset, FALSE);
|
||||
crypt_encode(state, text_start, text_len, new_data + dp->db_txt_start);
|
||||
crypt_free_state(state);
|
||||
|
||||
/* Clear the gap. */
|
||||
if (head_end < text_start)
|
||||
@ -4857,6 +4864,7 @@ ml_decrypt_data(mfp, data, offset, size)
|
||||
char_u *head_end;
|
||||
char_u *text_start;
|
||||
int text_len;
|
||||
cryptstate_T *state;
|
||||
|
||||
if (dp->db_id == DATA_ID)
|
||||
{
|
||||
@ -4869,17 +4877,17 @@ ml_decrypt_data(mfp, data, offset, size)
|
||||
return; /* data was messed up */
|
||||
|
||||
/* Decrypt the text in place. */
|
||||
crypt_push_state();
|
||||
ml_crypt_prepare(mfp, offset, TRUE);
|
||||
crypt_decode(text_start, text_len);
|
||||
crypt_pop_state();
|
||||
state = ml_crypt_prepare(mfp, offset, TRUE);
|
||||
crypt_decode_inplace(state, text_start, text_len);
|
||||
crypt_free_state(state);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare for encryption/decryption, using the key, seed and offset.
|
||||
* Return an allocated cryptstate_T *.
|
||||
*/
|
||||
static void
|
||||
static cryptstate_T *
|
||||
ml_crypt_prepare(mfp, offset, reading)
|
||||
memfile_T *mfp;
|
||||
off_t offset;
|
||||
@ -4887,38 +4895,37 @@ ml_crypt_prepare(mfp, offset, reading)
|
||||
{
|
||||
buf_T *buf = mfp->mf_buffer;
|
||||
char_u salt[50];
|
||||
int method;
|
||||
int method_nr;
|
||||
char_u *key;
|
||||
char_u *seed;
|
||||
|
||||
if (reading && mfp->mf_old_key != NULL)
|
||||
{
|
||||
/* Reading back blocks with the previous key/method/seed. */
|
||||
method = mfp->mf_old_cm;
|
||||
method_nr = mfp->mf_old_cm;
|
||||
key = mfp->mf_old_key;
|
||||
seed = mfp->mf_old_seed;
|
||||
}
|
||||
else
|
||||
{
|
||||
method = get_crypt_method(buf);
|
||||
method_nr = crypt_get_method_nr(buf);
|
||||
key = buf->b_p_key;
|
||||
seed = mfp->mf_seed;
|
||||
}
|
||||
|
||||
use_crypt_method = method; /* select pkzip or blowfish */
|
||||
if (method == 0)
|
||||
if (method_nr == CRYPT_M_ZIP)
|
||||
{
|
||||
/* For PKzip: Append the offset to the key, so that we use a different
|
||||
* key for every block. */
|
||||
vim_snprintf((char *)salt, sizeof(salt), "%s%ld", key, (long)offset);
|
||||
crypt_init_keys(salt);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Using blowfish, add salt and seed. We use the byte offset of the
|
||||
* block for the salt. */
|
||||
vim_snprintf((char *)salt, sizeof(salt), "%ld", (long)offset);
|
||||
bf_key_init(key, salt, (int)STRLEN(salt));
|
||||
bf_cfb_init(seed, MF_SEED_LEN);
|
||||
return crypt_create(method_nr, salt, NULL, 0, NULL, 0);
|
||||
}
|
||||
|
||||
/* Using blowfish or better: add salt and seed. We use the byte offset
|
||||
* of the block for the salt. */
|
||||
vim_snprintf((char *)salt, sizeof(salt), "%ld", (long)offset);
|
||||
return crypt_create(method_nr, key, salt, (int)STRLEN(salt),
|
||||
seed, MF_SEED_LEN);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
335
src/misc2.c
335
src/misc2.c
@ -3803,322 +3803,6 @@ update_mouseshape(shape_idx)
|
||||
#endif /* CURSOR_SHAPE */
|
||||
|
||||
|
||||
#ifdef FEAT_CRYPT
|
||||
/*
|
||||
* Optional encryption support.
|
||||
* Mohsin Ahmed, mosh@sasi.com, 98-09-24
|
||||
* Based on zip/crypt sources.
|
||||
*
|
||||
* NOTE FOR USA: Since 2000 exporting this code from the USA is allowed to
|
||||
* most countries. There are a few exceptions, but that still should not be a
|
||||
* problem since this code was originally created in Europe and India.
|
||||
*
|
||||
* Blowfish addition originally made by Mohsin Ahmed,
|
||||
* http://www.cs.albany.edu/~mosh 2010-03-14
|
||||
* Based on blowfish by Bruce Schneier (http://www.schneier.com/blowfish.html)
|
||||
* and sha256 by Christophe Devine.
|
||||
*/
|
||||
|
||||
/* from zip.h */
|
||||
|
||||
typedef unsigned short ush; /* unsigned 16-bit value */
|
||||
typedef unsigned long ulg; /* unsigned 32-bit value */
|
||||
|
||||
static void make_crc_tab __ARGS((void));
|
||||
|
||||
static ulg crc_32_tab[256];
|
||||
|
||||
/*
|
||||
* Fill the CRC table.
|
||||
*/
|
||||
static void
|
||||
make_crc_tab()
|
||||
{
|
||||
ulg s,t,v;
|
||||
static int done = FALSE;
|
||||
|
||||
if (done)
|
||||
return;
|
||||
for (t = 0; t < 256; t++)
|
||||
{
|
||||
v = t;
|
||||
for (s = 0; s < 8; s++)
|
||||
v = (v >> 1) ^ ((v & 1) * (ulg)0xedb88320L);
|
||||
crc_32_tab[t] = v;
|
||||
}
|
||||
done = TRUE;
|
||||
}
|
||||
|
||||
#define CRC32(c, b) (crc_32_tab[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
|
||||
|
||||
static ulg keys[3]; /* keys defining the pseudo-random sequence */
|
||||
|
||||
/*
|
||||
* Return the next byte in the pseudo-random sequence.
|
||||
*/
|
||||
#define DECRYPT_BYTE_ZIP(t) { \
|
||||
ush temp; \
|
||||
\
|
||||
temp = (ush)keys[2] | 2; \
|
||||
t = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff); \
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the encryption keys with the next byte of plain text.
|
||||
*/
|
||||
#define UPDATE_KEYS_ZIP(c) { \
|
||||
keys[0] = CRC32(keys[0], (c)); \
|
||||
keys[1] += keys[0] & 0xff; \
|
||||
keys[1] = keys[1] * 134775813L + 1; \
|
||||
keys[2] = CRC32(keys[2], (int)(keys[1] >> 24)); \
|
||||
}
|
||||
|
||||
static int crypt_busy = 0;
|
||||
static ulg saved_keys[3];
|
||||
static int saved_crypt_method;
|
||||
|
||||
/*
|
||||
* Return int value for crypt method string:
|
||||
* 0 for "zip", the old method. Also for any non-valid value.
|
||||
* 1 for "blowfish".
|
||||
*/
|
||||
int
|
||||
crypt_method_from_string(s)
|
||||
char_u *s;
|
||||
{
|
||||
return *s == 'b' ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the crypt method for buffer "buf" as a number.
|
||||
*/
|
||||
int
|
||||
get_crypt_method(buf)
|
||||
buf_T *buf;
|
||||
{
|
||||
return crypt_method_from_string(*buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the crypt method for buffer "buf" to "method" using the int value as
|
||||
* returned by crypt_method_from_string().
|
||||
*/
|
||||
void
|
||||
set_crypt_method(buf, method)
|
||||
buf_T *buf;
|
||||
int method;
|
||||
{
|
||||
free_string_option(buf->b_p_cm);
|
||||
buf->b_p_cm = vim_strsave((char_u *)(method == 0 ? "zip" : "blowfish"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare for initializing encryption. If already doing encryption then save
|
||||
* the state.
|
||||
* Must always be called symmetrically with crypt_pop_state().
|
||||
*/
|
||||
void
|
||||
crypt_push_state()
|
||||
{
|
||||
if (crypt_busy == 1)
|
||||
{
|
||||
/* save the state */
|
||||
if (use_crypt_method == 0)
|
||||
{
|
||||
saved_keys[0] = keys[0];
|
||||
saved_keys[1] = keys[1];
|
||||
saved_keys[2] = keys[2];
|
||||
}
|
||||
else
|
||||
bf_crypt_save();
|
||||
saved_crypt_method = use_crypt_method;
|
||||
}
|
||||
else if (crypt_busy > 1)
|
||||
EMSG2(_(e_intern2), "crypt_push_state()");
|
||||
++crypt_busy;
|
||||
}
|
||||
|
||||
/*
|
||||
* End encryption. If doing encryption before crypt_push_state() then restore
|
||||
* the saved state.
|
||||
* Must always be called symmetrically with crypt_push_state().
|
||||
*/
|
||||
void
|
||||
crypt_pop_state()
|
||||
{
|
||||
--crypt_busy;
|
||||
if (crypt_busy == 1)
|
||||
{
|
||||
use_crypt_method = saved_crypt_method;
|
||||
if (use_crypt_method == 0)
|
||||
{
|
||||
keys[0] = saved_keys[0];
|
||||
keys[1] = saved_keys[1];
|
||||
keys[2] = saved_keys[2];
|
||||
}
|
||||
else
|
||||
bf_crypt_restore();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Encrypt "from[len]" into "to[len]".
|
||||
* "from" and "to" can be equal to encrypt in place.
|
||||
*/
|
||||
void
|
||||
crypt_encode(from, len, to)
|
||||
char_u *from;
|
||||
size_t len;
|
||||
char_u *to;
|
||||
{
|
||||
size_t i;
|
||||
int ztemp, t;
|
||||
|
||||
if (use_crypt_method == 0)
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
ztemp = from[i];
|
||||
DECRYPT_BYTE_ZIP(t);
|
||||
UPDATE_KEYS_ZIP(ztemp);
|
||||
to[i] = t ^ ztemp;
|
||||
}
|
||||
else
|
||||
bf_crypt_encode(from, len, to);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrypt "ptr[len]" in place.
|
||||
*/
|
||||
void
|
||||
crypt_decode(ptr, len)
|
||||
char_u *ptr;
|
||||
long len;
|
||||
{
|
||||
char_u *p;
|
||||
|
||||
if (use_crypt_method == 0)
|
||||
for (p = ptr; p < ptr + len; ++p)
|
||||
{
|
||||
ush temp;
|
||||
|
||||
temp = (ush)keys[2] | 2;
|
||||
temp = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff);
|
||||
UPDATE_KEYS_ZIP(*p ^= temp);
|
||||
}
|
||||
else
|
||||
bf_crypt_decode(ptr, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the encryption keys and the random header according to
|
||||
* the given password.
|
||||
* If "passwd" is NULL or empty, don't do anything.
|
||||
*/
|
||||
void
|
||||
crypt_init_keys(passwd)
|
||||
char_u *passwd; /* password string with which to modify keys */
|
||||
{
|
||||
if (passwd != NULL && *passwd != NUL)
|
||||
{
|
||||
if (use_crypt_method == 0)
|
||||
{
|
||||
char_u *p;
|
||||
|
||||
make_crc_tab();
|
||||
keys[0] = 305419896L;
|
||||
keys[1] = 591751049L;
|
||||
keys[2] = 878082192L;
|
||||
for (p = passwd; *p!= NUL; ++p)
|
||||
{
|
||||
UPDATE_KEYS_ZIP((int)*p);
|
||||
}
|
||||
}
|
||||
else
|
||||
bf_crypt_init_keys(passwd);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Free an allocated crypt key. Clear the text to make sure it doesn't stay
|
||||
* in memory anywhere.
|
||||
*/
|
||||
void
|
||||
free_crypt_key(key)
|
||||
char_u *key;
|
||||
{
|
||||
char_u *p;
|
||||
|
||||
if (key != NULL)
|
||||
{
|
||||
for (p = key; *p != NUL; ++p)
|
||||
*p = 0;
|
||||
vim_free(key);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ask the user for a crypt key.
|
||||
* When "store" is TRUE, the new key is stored in the 'key' option, and the
|
||||
* 'key' option value is returned: Don't free it.
|
||||
* When "store" is FALSE, the typed key is returned in allocated memory.
|
||||
* Returns NULL on failure.
|
||||
*/
|
||||
char_u *
|
||||
get_crypt_key(store, twice)
|
||||
int store;
|
||||
int twice; /* Ask for the key twice. */
|
||||
{
|
||||
char_u *p1, *p2 = NULL;
|
||||
int round;
|
||||
|
||||
for (round = 0; ; ++round)
|
||||
{
|
||||
cmdline_star = TRUE;
|
||||
cmdline_row = msg_row;
|
||||
p1 = getcmdline_prompt(NUL, round == 0
|
||||
? (char_u *)_("Enter encryption key: ")
|
||||
: (char_u *)_("Enter same key again: "), 0, EXPAND_NOTHING,
|
||||
NULL);
|
||||
cmdline_star = FALSE;
|
||||
|
||||
if (p1 == NULL)
|
||||
break;
|
||||
|
||||
if (round == twice)
|
||||
{
|
||||
if (p2 != NULL && STRCMP(p1, p2) != 0)
|
||||
{
|
||||
MSG(_("Keys don't match!"));
|
||||
free_crypt_key(p1);
|
||||
free_crypt_key(p2);
|
||||
p2 = NULL;
|
||||
round = -1; /* do it again */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (store)
|
||||
{
|
||||
set_option_value((char_u *)"key", 0L, p1, OPT_LOCAL);
|
||||
free_crypt_key(p1);
|
||||
p1 = curbuf->b_p_key;
|
||||
}
|
||||
break;
|
||||
}
|
||||
p2 = p1;
|
||||
}
|
||||
|
||||
/* since the user typed this, no need to wait for return */
|
||||
if (msg_didout)
|
||||
msg_putchar('\n');
|
||||
need_wait_return = FALSE;
|
||||
msg_didout = FALSE;
|
||||
|
||||
free_crypt_key(p2);
|
||||
return p1;
|
||||
}
|
||||
|
||||
#endif /* FEAT_CRYPT */
|
||||
|
||||
/* TODO: make some #ifdef for this */
|
||||
/*--------[ file searching ]-------------------------------------------------*/
|
||||
/*
|
||||
@ -6587,9 +6271,24 @@ put_bytes(fd, nr, len)
|
||||
put_time(fd, the_time)
|
||||
FILE *fd;
|
||||
time_t the_time;
|
||||
{
|
||||
char_u buf[8];
|
||||
|
||||
time_to_bytes(the_time, buf);
|
||||
fwrite(buf, (size_t)8, (size_t)1, fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write time_t to "buf[8]".
|
||||
*/
|
||||
void
|
||||
time_to_bytes(the_time, buf)
|
||||
time_t the_time;
|
||||
char_u *buf;
|
||||
{
|
||||
int c;
|
||||
int i;
|
||||
int bi = 0;
|
||||
time_t wtime = the_time;
|
||||
|
||||
/* time_t can be up to 8 bytes in size, more than long_u, thus we
|
||||
@ -6603,7 +6302,7 @@ put_time(fd, the_time)
|
||||
{
|
||||
if (i + 1 > (int)sizeof(time_t))
|
||||
/* ">>" doesn't work well when shifting more bits than avail */
|
||||
putc(0, fd);
|
||||
buf[bi++] = 0;
|
||||
else
|
||||
{
|
||||
#if defined(SIZEOF_TIME_T) && SIZEOF_TIME_T > 4
|
||||
@ -6611,7 +6310,7 @@ put_time(fd, the_time)
|
||||
#else
|
||||
c = (int)((long_u)wtime >> (i * 8));
|
||||
#endif
|
||||
putc(c, fd);
|
||||
buf[bi++] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
10
src/option.c
10
src/option.c
@ -2989,7 +2989,7 @@ static char *(p_bg_values[]) = {"light", "dark", NULL};
|
||||
static char *(p_nf_values[]) = {"octal", "hex", "alpha", NULL};
|
||||
static char *(p_ff_values[]) = {FF_UNIX, FF_DOS, FF_MAC, NULL};
|
||||
#ifdef FEAT_CRYPT
|
||||
static char *(p_cm_values[]) = {"zip", "blowfish", NULL};
|
||||
static char *(p_cm_values[]) = {"zip", "blowfish", "blowfish2", NULL};
|
||||
#endif
|
||||
#ifdef FEAT_CMDL_COMPL
|
||||
static char *(p_wop_values[]) = {"tagfile", NULL};
|
||||
@ -6140,7 +6140,7 @@ did_set_string_option(opt_idx, varp, new_value_alloced, oldval, errbuf,
|
||||
# endif
|
||||
if (STRCMP(curbuf->b_p_key, oldval) != 0)
|
||||
/* Need to update the swapfile. */
|
||||
ml_set_crypt_key(curbuf, oldval, get_crypt_method(curbuf));
|
||||
ml_set_crypt_key(curbuf, oldval, crypt_get_method_nr(curbuf));
|
||||
}
|
||||
|
||||
else if (gvarp == &p_cm)
|
||||
@ -6151,7 +6151,7 @@ did_set_string_option(opt_idx, varp, new_value_alloced, oldval, errbuf,
|
||||
p = p_cm;
|
||||
if (check_opt_strings(p, p_cm_values, TRUE) != OK)
|
||||
errmsg = e_invarg;
|
||||
else if (get_crypt_method(curbuf) > 0 && blowfish_self_test() == FAIL)
|
||||
else if (crypt_self_test() == FAIL)
|
||||
errmsg = e_invarg;
|
||||
else
|
||||
{
|
||||
@ -6177,7 +6177,7 @@ did_set_string_option(opt_idx, varp, new_value_alloced, oldval, errbuf,
|
||||
p = curbuf->b_p_cm;
|
||||
if (STRCMP(s, p) != 0)
|
||||
ml_set_crypt_key(curbuf, curbuf->b_p_key,
|
||||
crypt_method_from_string(s));
|
||||
crypt_method_nr_from_name(s));
|
||||
|
||||
/* If the global value changes need to update the swapfile for all
|
||||
* buffers using that value. */
|
||||
@ -6188,7 +6188,7 @@ did_set_string_option(opt_idx, varp, new_value_alloced, oldval, errbuf,
|
||||
for (buf = firstbuf; buf != NULL; buf = buf->b_next)
|
||||
if (buf != curbuf && *buf->b_p_cm == NUL)
|
||||
ml_set_crypt_key(buf, buf->b_p_key,
|
||||
crypt_method_from_string(oldval));
|
||||
crypt_method_nr_from_name(oldval));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,6 +70,8 @@ extern int _stricoll __ARGS((char *a, char *b));
|
||||
|
||||
# ifdef FEAT_CRYPT
|
||||
# include "blowfish.pro"
|
||||
# include "crypt.pro"
|
||||
# include "crypt_zip.pro"
|
||||
# endif
|
||||
# include "buffer.pro"
|
||||
# include "charset.pro"
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
/* blowfish.c */
|
||||
void bf_key_init __ARGS((char_u *password, char_u *salt, int salt_len));
|
||||
void bf_cfb_init __ARGS((char_u *iv, int iv_len));
|
||||
void bf_crypt_encode __ARGS((char_u *from, size_t len, char_u *to));
|
||||
void bf_crypt_decode __ARGS((char_u *ptr, long len));
|
||||
void bf_crypt_init_keys __ARGS((char_u *passwd));
|
||||
void bf_crypt_save __ARGS((void));
|
||||
void bf_crypt_restore __ARGS((void));
|
||||
void crypt_blowfish_encode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to));
|
||||
void crypt_blowfish_decode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to));
|
||||
void crypt_blowfish_init __ARGS((cryptstate_T *state, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len));
|
||||
int blowfish_self_test __ARGS((void));
|
||||
/* vim: set ft=c : */
|
||||
|
||||
24
src/proto/crypt.pro
Normal file
24
src/proto/crypt.pro
Normal file
@ -0,0 +1,24 @@
|
||||
/* crypt.c */
|
||||
int crypt_method_nr_from_name __ARGS((char_u *name));
|
||||
int crypt_method_nr_from_magic __ARGS((char *ptr, int len));
|
||||
int crypt_works_inplace __ARGS((cryptstate_T *state));
|
||||
int crypt_get_method_nr __ARGS((buf_T *buf));
|
||||
int crypt_whole_undofile __ARGS((int method_nr));
|
||||
int crypt_get_header_len __ARGS((int method_nr));
|
||||
void crypt_set_cm_option __ARGS((buf_T *buf, int method_nr));
|
||||
int crypt_self_test __ARGS((void));
|
||||
cryptstate_T *crypt_create __ARGS((int method_nr, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len));
|
||||
cryptstate_T *crypt_create_from_header __ARGS((int method_nr, char_u *key, char_u *header));
|
||||
cryptstate_T *crypt_create_from_file __ARGS((FILE *fp, char_u *key));
|
||||
cryptstate_T *crypt_create_for_writing __ARGS((int method_nr, char_u *key, char_u **header, int *header_len));
|
||||
void crypt_free_state __ARGS((cryptstate_T *state));
|
||||
long crypt_encode_alloc __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u **newptr));
|
||||
long crypt_decode_alloc __ARGS((cryptstate_T *state, char_u *ptr, long len, char_u **newptr));
|
||||
void crypt_encode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to));
|
||||
void crypt_decode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to));
|
||||
void crypt_encode_inplace __ARGS((cryptstate_T *state, char_u *buf, size_t len));
|
||||
void crypt_decode_inplace __ARGS((cryptstate_T *state, char_u *buf, size_t len));
|
||||
void crypt_free_key __ARGS((char_u *key));
|
||||
char_u *crypt_get_key __ARGS((int store, int twice));
|
||||
void crypt_append_msg __ARGS((buf_T *buf));
|
||||
/* vim: set ft=c : */
|
||||
5
src/proto/crypt_zip.pro
Normal file
5
src/proto/crypt_zip.pro
Normal file
@ -0,0 +1,5 @@
|
||||
/* crypt_zip.c */
|
||||
void crypt_zip_init __ARGS((cryptstate_T *state, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len));
|
||||
void crypt_zip_encode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to));
|
||||
void crypt_zip_decode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to));
|
||||
/* vim: set ft=c : */
|
||||
@ -4,8 +4,6 @@ int readfile __ARGS((char_u *fname, char_u *sfname, linenr_T from, linenr_T line
|
||||
int prep_exarg __ARGS((exarg_T *eap, buf_T *buf));
|
||||
void set_file_options __ARGS((int set_options, exarg_T *eap));
|
||||
void set_forced_fenc __ARGS((exarg_T *eap));
|
||||
int prepare_crypt_read __ARGS((FILE *fp));
|
||||
char_u *prepare_crypt_write __ARGS((buf_T *buf, int *lenp));
|
||||
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));
|
||||
|
||||
@ -84,16 +84,6 @@ int illegal_slash __ARGS((char *name));
|
||||
char_u *parse_shape_opt __ARGS((int what));
|
||||
int get_shape_idx __ARGS((int mouse));
|
||||
void update_mouseshape __ARGS((int shape_idx));
|
||||
int crypt_method_from_string __ARGS((char_u *s));
|
||||
int get_crypt_method __ARGS((buf_T *buf));
|
||||
void set_crypt_method __ARGS((buf_T *buf, int method));
|
||||
void crypt_push_state __ARGS((void));
|
||||
void crypt_pop_state __ARGS((void));
|
||||
void crypt_encode __ARGS((char_u *from, size_t len, char_u *to));
|
||||
void crypt_decode __ARGS((char_u *ptr, long len));
|
||||
void crypt_init_keys __ARGS((char_u *passwd));
|
||||
void free_crypt_key __ARGS((char_u *key));
|
||||
char_u *get_crypt_key __ARGS((int store, int twice));
|
||||
void *vim_findfile_init __ARGS((char_u *path, char_u *filename, char_u *stopdirs, int level, int free_visited, int find_what, void *search_ctx_arg, int tagfile, char_u *rel_fname));
|
||||
char_u *vim_findfile_stopdir __ARGS((char_u *buf));
|
||||
void vim_findfile_cleanup __ARGS((void *ctx));
|
||||
@ -116,5 +106,6 @@ time_t get8ctime __ARGS((FILE *fd));
|
||||
char_u *read_string __ARGS((FILE *fd, int cnt));
|
||||
int put_bytes __ARGS((FILE *fd, long_u nr, int len));
|
||||
void put_time __ARGS((FILE *fd, time_t the_time));
|
||||
void time_to_bytes __ARGS((time_t the_time, char_u *buf));
|
||||
int has_non_ascii __ARGS((char_u *s));
|
||||
/* vim: set ft=c : */
|
||||
|
||||
@ -1251,6 +1251,24 @@ typedef struct {
|
||||
} syn_time_T;
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_CRYPT
|
||||
/*
|
||||
* Structure to hold the type of encryption and the state of encryption or
|
||||
* decryption.
|
||||
*/
|
||||
typedef struct {
|
||||
int method_nr;
|
||||
void *method_state; /* method-specific state information */
|
||||
} cryptstate_T;
|
||||
|
||||
/* values for method_nr */
|
||||
# define CRYPT_M_ZIP 0
|
||||
# define CRYPT_M_BF 1
|
||||
# define CRYPT_M_BF2 2
|
||||
# define CRYPT_M_COUNT 3 /* number of crypt methods */
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* These are items normally related to a buffer. But when using ":ownsyntax"
|
||||
* a window may have its own instance.
|
||||
@ -1778,7 +1796,12 @@ struct file_buffer
|
||||
int b_was_netbeans_file;/* TRUE if b_netbeans_file was once set */
|
||||
#endif
|
||||
|
||||
};
|
||||
#ifdef FEAT_CRYPT
|
||||
cryptstate_T *b_cryptstate; /* Encryption state while reading or writing
|
||||
* the file. NULL when not using encryption. */
|
||||
#endif
|
||||
|
||||
}; /* file_buffer */
|
||||
|
||||
|
||||
#ifdef FEAT_DIFF
|
||||
|
||||
@ -13,6 +13,8 @@ STARTTEST
|
||||
:let cm0_bytes = getline('.', '.')
|
||||
:/^start of cm=blowfish bytes/+1
|
||||
:let cm1_bytes = getline('.', '.')
|
||||
:/^start of cm=blowfish2 bytes/+1
|
||||
:let cm2_bytes = getline('.', '.')
|
||||
:bwipe!
|
||||
:call append(0, text_lines)
|
||||
:$d
|
||||
@ -36,6 +38,18 @@ barfoo
|
||||
:e Xtestfile
|
||||
barfoo
|
||||
:let cm1_read_back = getline('.', '$')
|
||||
:set key=
|
||||
:set cryptmethod=blowfish2
|
||||
:" If the blowfish test fails 'cryptmethod' will be 'zip' now.
|
||||
:%s/^/\=&cryptmethod == 'blowfish2' ? "OK " : "blowfish test failed "/
|
||||
:X
|
||||
bar2foo
|
||||
bar2foo
|
||||
:w! Xtestfile
|
||||
:bwipe!
|
||||
:e Xtestfile
|
||||
bar2foo
|
||||
:let cm2_read_back = getline('.', '$')
|
||||
:bwipe!
|
||||
:set bin noeol key=
|
||||
:call append(0, cm0_bytes)
|
||||
@ -57,7 +71,20 @@ foofoo
|
||||
:set nobin
|
||||
:e Xtestfile
|
||||
barbar
|
||||
:let cm1_read_bin = getline('.', '$')
|
||||
:bwipe!
|
||||
:set bin noeol key=
|
||||
:call append(0, cm2_bytes)
|
||||
:$d
|
||||
:set fenc=latin1
|
||||
:w! Xtestfile
|
||||
:bwipe!
|
||||
:set nobin
|
||||
:e Xtestfile
|
||||
barburp
|
||||
:call append(0, cm1_read_bin)
|
||||
:call append(0, cm0_read_bin)
|
||||
:call append(0, cm2_read_back)
|
||||
:call append(0, cm1_read_back)
|
||||
:call append(0, cm0_read_back)
|
||||
:set key= fenc=latin1
|
||||
|
||||
@ -4,7 +4,12 @@ line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
OK 01234567890123456789012345678901234567
|
||||
OK line 2 foo bar blah
|
||||
OK line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
OK OK 01234567890123456789012345678901234567
|
||||
OK OK line 2 foo bar blah
|
||||
OK OK line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
1234567890
|
||||
a<EFBFBD>bbccdde<EFBFBD>ff
|
||||
asdfasdfasdf
|
||||
0001112223333
|
||||
abcdefghijklmnopqrstuvwxyz
|
||||
!@#$%^&*()_+=-`~
|
||||
|
||||
@ -12,3 +12,7 @@ end of cm=zip bytes
|
||||
start of cm=blowfish bytes
|
||||
VimCrypt~02!k)<29><17>#<16>S<EFBFBD><53>=<3D><><EFBFBD>#<23>M<EFBFBD><4D>J<EFBFBD>AͥM<CDA5><4D>!<21><15><><0F><><19><16><>
|
||||
<EFBFBD>
|
||||
end of cm=blowfish bytes
|
||||
|
||||
start of cm=blowfish2 bytes
|
||||
VimCrypt~03!<1E>N<EFBFBD>;<3B><><EFBFBD>^C)<04>.<2E><>FS<19><>6<EFBFBD>[T˧<54>ؾ9<0B>2Q<><51>@<40>ߚ<>Iv<49>.<2E><><EFBFBD><EFBFBD>`<60>$<24>%<25>
|
||||
|
||||
@ -81,6 +81,7 @@ uu:w >>test.out
|
||||
:"
|
||||
:" With encryption, cryptmethod=blowfish
|
||||
:e! Xtestfile
|
||||
rubbish
|
||||
:set undofile cm=blowfish
|
||||
ggdGijan
|
||||
feb
|
||||
@ -104,6 +105,32 @@ u:.w >>test.out
|
||||
u:.w >>test.out
|
||||
u:.w >>test.out
|
||||
:"
|
||||
:" With encryption, cryptmethod=blowfish2
|
||||
:e! Xtestfile
|
||||
rubbish
|
||||
:set undofile cm=blowfish2
|
||||
ggdGijan
|
||||
feb
|
||||
mar
|
||||
apr
|
||||
jun:set ul=100
|
||||
kk0ifoo :set ul=100
|
||||
dd:set ul=100
|
||||
ibar :set ul=100
|
||||
:X
|
||||
foo2bar
|
||||
foo2bar
|
||||
:w!
|
||||
:bwipe!
|
||||
:e Xtestfile
|
||||
foo2bar
|
||||
: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.
|
||||
:if has("vms")
|
||||
: call rename("_un_Xtestfile", "Xtestundo")
|
||||
|
||||
@ -25,3 +25,7 @@ bar apr
|
||||
apr
|
||||
foo mar
|
||||
mar
|
||||
bar apr
|
||||
apr
|
||||
foo mar
|
||||
mar
|
||||
|
||||
698
src/undo.c
698
src/undo.c
File diff suppressed because it is too large
Load Diff
@ -741,6 +741,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
399,
|
||||
/**/
|
||||
398,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user