From 5f67cf4e10afd9f02d0adfe9a212479efceb567e Mon Sep 17 00:00:00 2001 From: Karsten Hopp Date: Aug 12 2014 08:46:25 +0000 Subject: - patchlevel 399 --- diff --git a/7.4.399 b/7.4.399 new file mode 100644 index 0000000..08aa8c7 --- /dev/null +++ b/7.4.399 @@ -0,0 +1,5059 @@ +To: vim_dev@googlegroups.com +Subject: Patch 7.4.399 +Fcc: outbox +From: Bram Moolenaar +Mime-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +------------ + +Patch 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) +Files: runtime/doc/editing.txt, runtime/doc/options.txt, src/Makefile, + src/blowfish.c, src/crypt.c, src/crypt_zip.c, src/ex_docmd.c, + src/fileio.c, src/globals.h, src/main.c, src/memline.c, + src/misc2.c, src/option.c, src/proto.h, src/proto/blowfish.pro, + src/proto/crypt.pro, src/proto/crypt_zip.pro, + src/proto/fileio.pro, src/proto/misc2.pro, src/structs.h, + src/undo.c, src/testdir/test71.in, src/testdir/test71.ok, + src/testdir/test71a.in, src/testdir/test72.in, + src/testdir/test72.ok + + +*** ../vim-7.4.398/runtime/doc/editing.txt 2013-08-10 13:24:53.000000000 +0200 +--- runtime/doc/editing.txt 2014-08-09 15:35:40.101354406 +0200 +*************** +*** 1361,1371 **** + {only available when compiled with the |+cryptv| feature} *E833* + + The text in the swap file and the undo file is also encrypted. *E843* + + 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. + + WARNING: If you make a typo when entering the key and then write the file and + exit, the text will be lost! +--- 1362,1382 ---- + {only available when compiled with the |+cryptv| feature} *E833* + + The text in the swap file and the undo file is also encrypted. *E843* ++ However, this is done block-by-block and may reduce the time needed to crack a ++ password. You can disable the swap file, but then a crash will cause you to ++ lose your work. The undo file can be disabled without much disadvantage. > ++ :set noundofile ++ :noswapfile edit secrets + + 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 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! +*************** +*** 1392,1409 **** + :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 + 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 + The message given for reading and writing a file will show "[crypted]" when +! using zip, "[blowfish]" when using blowfish. + + When writing an undo file, the same key and method will be used for the text + in the undo file. |persistent-undo|. +--- 1403,1427 ---- + :set key= + + You can use the 'cryptmethod' option to select the type of encryption, use one +! 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=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, etc. + + When writing an undo file, the same key and method will be used for the text + in the undo file. |persistent-undo|. +*************** +*** 1438,1444 **** + 0 string VimCrypt~ Vim encrypted file + >9 string 01 - "zip" cryptmethod + >9 string 02 - "blowfish" cryptmethod +! + + Notes: + - Encryption is not possible when doing conversion with 'charconvert'. +--- 1456,1462 ---- + 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'. +*************** +*** 1462,1481 **** + - 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. + - Vim originates from the Netherlands. That is where the sources come from. + Thus the encryption code is not exported from the USA. + + ============================================================================== + 10. Timestamps *timestamp* *timestamps* + +! Vim remembers the modification timestamp of a file when you begin editing it. +! This is used to avoid that you have two different versions of the same file +! (without you knowing this). +! +! After a shell command is run (|:!cmd| |suspend| |:read!| |K|) timestamps are +! compared for all buffers in a window. Vim will run any associated +! |FileChangedShell| autocommands or display a warning for any files that have +! changed. In the GUI this happens when Vim regains input focus. + + *E321* *E462* + If you want to automatically reload a file when it has been changed outside of +--- 1480,1504 ---- + - 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. + + ============================================================================== + 10. Timestamps *timestamp* *timestamps* + +! Vim remembers the modification timestamp, mode and size of a file when you +! begin editing it. This is used to avoid that you have two different versions +! of the same file (without you knowing this). +! +! After a shell command is run (|:!cmd| |suspend| |:read!| |K|) timestamps, +! file modes and file sizes are compared for all buffers in a window. Vim will +! run any associated |FileChangedShell| autocommands or display a warning for +! any files that have changed. In the GUI this happens when Vim regains input +! focus. + + *E321* *E462* + If you want to automatically reload a file when it has been changed outside of +*** ../vim-7.4.398/runtime/doc/options.txt 2014-08-06 14:52:05.039236174 +0200 +--- runtime/doc/options.txt 2014-08-09 15:36:48.165353916 +0200 +*************** +*** 2229,2238 **** + 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. + + When reading an encrypted file 'cryptmethod' will be set automatically + to the detected method of the file being read. Thus if you write it +--- 2229,2246 ---- + zip PkZip compatible method. A weak kind of encryption. + Backwards compatible with Vim 7.2 and older. + *blowfish* +! 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 +*** ../vim-7.4.398/src/Makefile 2014-05-22 14:54:22.850468654 +0200 +--- src/Makefile 2014-08-09 15:37:19.689353690 +0200 +*************** +*** 1431,1436 **** +--- 1431,1438 ---- + blowfish.c \ + buffer.c \ + charset.c \ ++ crypt.c \ ++ crypt_zip.c \ + diff.c \ + digraph.c \ + edit.c \ +*************** +*** 1520,1525 **** +--- 1522,1529 ---- + 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,1594 **** +--- 1593,1600 ---- + blowfish.pro \ + buffer.pro \ + charset.pro \ ++ crypt.pro \ ++ crypt_zip.pro \ + diff.pro \ + digraph.pro \ + edit.pro \ +*************** +*** 1753,1762 **** + languages: + @if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \ + cd $(PODIR); \ +! 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; \ + fi + + # Update the *.po files for changes in the sources. Only run manually. +--- 1759,1769 ---- + languages: + @if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \ + cd $(PODIR); \ +! 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; \ + fi + + # Update the *.po files for changes in the sources. Only run manually. +*************** +*** 1883,1890 **** +--- 1890,1903 ---- + # 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,2511 **** +--- 2519,2530 ---- + 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,2860 **** +--- 2874,2887 ---- + 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 \ +*** ../vim-7.4.398/src/blowfish.c 2014-02-11 15:23:27.930123631 +0100 +--- src/blowfish.c 2014-08-09 15:31:32.493356185 +0200 +*************** +*** 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. + */ + + #include "vim.h" + +! #if defined(FEAT_CRYPT) + + #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)) + + typedef union { + UINT32_T ul[2]; +--- 9,33 ---- + * 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) || defined(PROTO) + + #define ARRAY_LENGTH(A) (sizeof(A)/sizeof(A[0])) + + #define BF_BLOCK 8 + #define BF_BLOCK_MASK 7 +! #define BF_MAX_CFB_LEN (8 * BF_BLOCK) + + typedef union { + UINT32_T ul[2]; +*************** +*** 37,50 **** + # 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)); + static int bf_self_test __ARGS((void)); + + /* Blowfish code */ +! static UINT32_T pax[18]; +! static UINT32_T ipa[18] = { + 0x243f6a88u, 0x85a308d3u, 0x13198a2eu, + 0x03707344u, 0xa4093822u, 0x299f31d0u, + 0x082efa98u, 0xec4e6c89u, 0x452821e6u, +--- 45,70 ---- + # endif + #endif + +! /* 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_init[18] = { + 0x243f6a88u, 0x85a308d3u, 0x13198a2eu, + 0x03707344u, 0xa4093822u, 0x299f31d0u, + 0x082efa98u, 0xec4e6c89u, 0x452821e6u, +*************** +*** 53,60 **** + 0xb5470917u, 0x9216d5d9u, 0x8979fb1bu + }; + +! static UINT32_T sbx[4][256]; +! static UINT32_T sbi[4][256] = { + {0xd1310ba6u, 0x98dfb5acu, 0x2ffd72dbu, 0xd01adfb7u, + 0xb8e1afedu, 0x6a267e96u, 0xba7c9045u, 0xf12c7f99u, + 0x24a19947u, 0xb3916cf7u, 0x0801f2e2u, 0x858efc16u, +--- 73,79 ---- + 0xb5470917u, 0x9216d5d9u, 0x8979fb1bu + }; + +! static UINT32_T sbx_init[4][256] = { + {0xd1310ba6u, 0x98dfb5acu, 0x2ffd72dbu, 0xd01adfb7u, + 0xb8e1afedu, 0x6a267e96u, 0xba7c9045u, 0xf12c7f99u, + 0x24a19947u, 0xb3916cf7u, 0x0801f2e2u, 0x858efc16u, +*************** +*** 314,346 **** + } + }; + +- + #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]; + + #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]; +! + + static void +! bf_e_block(p_xl, p_xr) + UINT32_T *p_xl; + UINT32_T *p_xr; + { +! UINT32_T temp, xl = *p_xl, 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]; + temp = xl; + xl = xr; + xr = temp; +--- 333,372 ---- + } + }; + + #define F1(i) \ +! 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 ^= 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(bfs, p_xl, p_xr) +! bf_state_T *bfs; + UINT32_T *p_xl; + UINT32_T *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 ^= bfs->pax[16]; +! xr ^= bfs->pax[17]; + temp = xl; + xl = xr; + xr = temp; +*************** +*** 348,369 **** + *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,379 ---- +*************** +*** 374,380 **** + #endif + + static void +! bf_e_cblock(block) + char_u *block; + { + block8 bk; +--- 384,391 ---- + #endif + + static void +! bf_e_cblock(bfs, block) +! bf_state_T *bfs; + char_u *block; + { + block8 bk; +*************** +*** 382,416 **** + memcpy(bk.uc, block, 8); + htonl2(bk.ul[0]); + htonl2(bk.ul[1]); +! bf_e_block(&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; + { + int i, j, keypos = 0; + unsigned u; +--- 393,414 ---- + memcpy(bk.uc, block, 8); + htonl2(bk.ul[0]); + htonl2(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); + } + + /* + * Initialize the crypt method using "password" as the encryption key and + * "salt[salt_len]" as the salt. + */ +! 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,424 **** + char_u *key; + int keylen; + +! /* Process the key 1000 times. + * See http://en.wikipedia.org/wiki/Key_strengthening. */ + key = sha256_key(password, salt, salt_len); + for (i = 0; i < 1000; i++) +--- 416,422 ---- + char_u *key; + int keylen; + +! /* 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,488 **** + key[i] = u; + } + +! mch_memmove(sbx, sbi, 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; + } + + 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; + } + + 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 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]; + UINT32_T val; + { + int i, j; + UINT32_T c = 0; + + for (i = 0; i < 18; i++) +! c ^= a_ipa[i]; + for (i = 0; i < 4; i++) + for (j = 0; j < 256; j++) +! c ^= a_sbi[i][j]; + return c == val; + } + +--- 435,488 ---- + key[i] = u; + } + +! /* 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]; +! bfs->pax[i] = pax_init[i] ^ val; + } + + data_l = data_r = 0; + for (i = 0; i < 18; i += 2) + { +! 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(bfs, &data_l, &data_r); +! bfs->sbx[i][j + 0] = data_l; +! bfs->sbx[i][j + 1] = data_r; + } + } + } + + /* +! * Blowfish self-test for corrupted tables or instructions. + */ + static int +! 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 ^= pax[i]; + for (i = 0; i < 4; i++) + for (j = 0; j < 256; j++) +! c ^= sbx[i][j]; + return c == val; + } + +*************** +*** 520,525 **** +--- 520,529 ---- + 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,548 **** + EMSG(_("E820: sizeof(uint32_t) != 4")); + } + +! if (!bf_check_tables(ipa, sbi, 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_test_data[i].salt, + (int)STRLEN(bf_test_data[i].salt)); +! if (!bf_check_tables(pax, 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); + if (memcmp(bk.uc, bf_test_data[i].cryptxt, 8) != 0) + { + if (err == 0 && memcmp(bk.uc, bf_test_data[i].badcryptxt, 8) == 0) +--- 532,552 ---- + EMSG(_("E820: sizeof(uint32_t) != 4")); + } + +! 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(&state, (char_u *)(bf_test_data[i].password), + bf_test_data[i].salt, + (int)STRLEN(bf_test_data[i].salt)); +! 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(&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,596 **** + 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 */ + + /* +! * Initialize with seed "iv[iv_len]". + */ +! void +! bf_cfb_init(iv, iv_len) +! char_u *iv; +! int iv_len; + { + int i, mi; + +! randbyte_offset = update_offset = 0; +! vim_memset(cfb_buffer, 0, BF_CFB_LEN); +! if (iv_len > 0) + { +! mi = iv_len > BF_CFB_LEN ? iv_len : BF_CFB_LEN; + for (i = 0; i < mi; i++) +! cfb_buffer[i % BF_CFB_LEN] ^= iv[i % iv_len]; + } + } + +! #define BF_CFB_UPDATE(c) { \ +! cfb_buffer[update_offset] ^= (char_u)c; \ +! if (++update_offset == BF_CFB_LEN) \ +! 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; \ + } + + /* +--- 558,600 ---- + return err > 0 ? FAIL : OK; + } + +! /* +! * CFB: Cipher Feedback Mode. +! */ + + /* +! * Initialize with seed "seed[seed_len]". + */ +! static void +! bf_cfb_init(bfs, seed, seed_len) +! bf_state_T *bfs; +! char_u *seed; +! int seed_len; + { + int i, mi; + +! bfs->randbyte_offset = bfs->update_offset = 0; +! vim_memset(bfs->cfb_buffer, 0, bfs->cfb_len); +! if (seed_len > 0) + { +! mi = seed_len > bfs->cfb_len ? seed_len : bfs->cfb_len; + for (i = 0; i < mi; i++) +! bfs->cfb_buffer[i % bfs->cfb_len] ^= seed[i % seed_len]; + } + } + +! #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(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,687 **** + * "from" and "to" can be equal to encrypt in place. + */ + void +! bf_crypt_encode(from, len, to) + char_u *from; + size_t len; + char_u *to; + { + size_t i; + int ztemp, t; + + for (i = 0; i < len; ++i) + { + ztemp = from[i]; +! BF_RANBYTE(t); +! BF_CFB_UPDATE(ztemp); + to[i] = t ^ ztemp; + } + } + + /* +! * Decrypt "ptr[len]" in place. + */ + void +! bf_crypt_decode(ptr, len) +! char_u *ptr; +! long len; + { +! char_u *p; + int t; + +! for (p = ptr; p < ptr + len; ++p) + { +! BF_RANBYTE(t); +! *p ^= t; +! BF_CFB_UPDATE(*p); + } + } + +- /* +- * 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 */ +! { +! char_u *p; +! +! for (p = passwd; *p != NUL; ++p) +! { +! BF_CFB_UPDATE(*p); +! } +! } + +! 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]; +! +! /* +! * 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); +! } + +! /* +! * 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); + } + + /* +--- 602,670 ---- + * "from" and "to" can be equal to encrypt in place. + */ + void +! 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(bfs, t); +! BF_CFB_UPDATE(bfs, ztemp); + to[i] = t ^ ztemp; + } + } + + /* +! * Decrypt "from[len]" into "to[len]". + */ + void +! crypt_blowfish_decode(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 t; + +! for (i = 0; i < len; ++i) + { +! BF_RANBYTE(bfs, t); +! to[i] = from[i] ^ t; +! BF_CFB_UPDATE(bfs, to[i]); + } + } + + void +! 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; +! { +! bf_state_T *bfs = (bf_state_T *)alloc_clear(sizeof(bf_state_T)); +! +! state->method_state = bfs; +! +! /* "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; + +! if (blowfish_self_test() == FAIL) +! return; + +! bf_key_init(bfs, key, salt, salt_len); +! bf_cfb_init(bfs, seed, seed_len); + } + + /* +*** ../vim-7.4.398/src/crypt.c 2014-08-10 13:30:43.816787293 +0200 +--- src/crypt.c 2014-08-09 15:37:46.189353499 +0200 +*************** +*** 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 */ +*** ../vim-7.4.398/src/crypt_zip.c 2014-08-10 13:30:43.824787293 +0200 +--- src/crypt_zip.c 2014-08-09 15:31:32.493356185 +0200 +*************** +*** 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 */ +*** ../vim-7.4.398/src/ex_docmd.c 2014-08-06 18:17:03.475147780 +0200 +--- src/ex_docmd.c 2014-08-09 15:31:32.493356185 +0200 +*************** +*** 11506,11513 **** + ex_X(eap) + exarg_T *eap UNUSED; + { +! if (get_crypt_method(curbuf) == 0 || blowfish_self_test() == OK) +! (void)get_crypt_key(TRUE, TRUE); + } + #endif + +--- 11506,11512 ---- + ex_X(eap) + exarg_T *eap UNUSED; + { +! (void)crypt_get_key(TRUE, TRUE); + } + #endif + +*** ../vim-7.4.398/src/fileio.c 2014-06-12 14:01:27.575769788 +0200 +--- src/fileio.c 2014-08-09 15:31:32.497356185 +0200 +*************** +*** 24,43 **** + #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 + +--- 24,29 ---- +*************** +*** 55,61 **** + 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 +--- 41,46 ---- +*************** +*** 116,121 **** +--- 101,109 ---- + #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,256 **** + #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; +--- 238,243 ---- +*************** +*** 966,978 **** + #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. +--- 953,958 ---- +*************** +*** 1175,1180 **** +--- 1155,1169 ---- + 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 + } + + while (!error && !got_int) +*************** +*** 1339,1344 **** +--- 1328,1403 ---- + 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,1423 **** + } + #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; + +--- 1462,1467 ---- +*************** +*** 1430,1439 **** + */ + if ((filesize == 0 + # ifdef FEAT_CRYPT +! || (filesize == (CRYPT_MAGIC_LEN +! + crypt_salt_len[use_crypt_method] +! + crypt_seed_len[use_crypt_method]) +! && cryptkey != NULL) + # endif + ) + && (fio_flags == FIO_UCSBOM +--- 1474,1482 ---- + */ + if ((filesize == 0 + # ifdef FEAT_CRYPT +! || (cryptkey != NULL +! && filesize == crypt_get_header_len( +! crypt_get_method_nr(curbuf))) + # endif + ) + && (fio_flags == FIO_UCSBOM +*************** +*** 2262,2276 **** + save_file_ff(curbuf); /* remember the current file format */ + + #ifdef FEAT_CRYPT +! crypt_method_used = use_crypt_method; +! if (cryptkey != 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 */ + } + #endif + + #ifdef FEAT_MBYTE +--- 2305,2319 ---- + save_file_ff(curbuf); /* remember the current file format */ + + #ifdef FEAT_CRYPT +! if (curbuf->b_cryptstate != NULL) + { +! 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,2466 **** + #ifdef FEAT_CRYPT + if (cryptkey != NULL) + { +! if (crypt_method_used == 1) +! STRCAT(IObuff, _("[blowfish]")); +! else +! STRCAT(IObuff, _("[crypted]")); + c = TRUE; + } + #endif +--- 2500,2506 ---- + #ifdef FEAT_CRYPT + if (cryptkey != NULL) + { +! crypt_append_msg(curbuf); + c = TRUE; + } + #endif +*************** +*** 2489,2497 **** + #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]); + else + #endif + msg_add_lines(c, (long)linecnt, filesize); +--- 2529,2535 ---- + #ifdef FEAT_CRYPT + if (cryptkey != NULL) + msg_add_lines(c, (long)linecnt, filesize +! - crypt_get_header_len(crypt_get_method_nr(curbuf))); + else + #endif + msg_add_lines(c, (long)linecnt, filesize); +*************** +*** 2882,2914 **** + + #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 + * *filesizep are updated. +--- 2920,2925 ---- +*************** +*** 2924,2930 **** + 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 b_p_ro = curbuf->b_p_ro; + + if (method >= 0) +--- 2935,2941 ---- + char_u *fname; /* file name to display */ + int *did_ask; /* flag: whether already asked for key */ + { +! int method = crypt_method_nr_from_magic((char *)ptr, *sizep); + int b_p_ro = curbuf->b_p_ro; + + if (method >= 0) +*************** +*** 2933,2941 **** + * Avoids accidentally overwriting the file with garbage. */ + curbuf->b_p_ro = TRUE; + +! set_crypt_method(curbuf, method); +! if (method > 0) +! (void)blowfish_self_test(); + if (cryptkey == NULL && !*did_ask) + { + if (*curbuf->b_p_key) +--- 2944,2950 ---- + * Avoids accidentally overwriting the file with garbage. */ + curbuf->b_p_ro = TRUE; + +! crypt_set_cm_option(curbuf, method); + if (cryptkey == NULL && !*did_ask) + { + if (*curbuf->b_p_key) +*************** +*** 2948,2954 **** + * Happens when retrying to detect encoding. */ + smsg((char_u *)_(need_key_msg), fname); + msg_scroll = TRUE; +! cryptkey = get_crypt_key(newfile, FALSE); + *did_ask = TRUE; + + /* check if empty key entered */ +--- 2957,2963 ---- + * Happens when retrying to detect encoding. */ + smsg((char_u *)_(need_key_msg), fname); + msg_scroll = TRUE; +! cryptkey = crypt_get_key(newfile, FALSE); + *did_ask = TRUE; + + /* check if empty key entered */ +*************** +*** 2963,2986 **** + + if (cryptkey != NULL) + { +! int seed_len = crypt_seed_len[method]; +! int salt_len = crypt_salt_len[method]; + +! 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); +! } + +- /* 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; + } +--- 2972,2989 ---- + + if (cryptkey != NULL) + { +! int header_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); + + /* Restore the read-only flag. */ + curbuf->b_p_ro = b_p_ro; + } +*************** +*** 2992,3076 **** + + 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 +--- 2995,3000 ---- +*************** +*** 3224,3232 **** + 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; +--- 3148,3153 ---- +*************** +*** 3262,3267 **** +--- 3183,3191 ---- + 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 + * the line. */ +*************** +*** 4505,4521 **** + #ifdef FEAT_CRYPT + if (*buf->b_p_key != NUL && !filtering) + { +! char_u *header; +! int header_len; + +! header = prepare_crypt_write(buf, &header_len); +! if (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_info.bw_buf = header; + write_info.bw_len = header_len; + write_info.bw_flags = FIO_NOCONVERT; +--- 4429,4445 ---- + #ifdef FEAT_CRYPT + if (*buf->b_p_key != NUL && !filtering) + { +! char_u *header; +! int header_len; + +! 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 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,4780 **** + mch_set_acl(wfname, acl); + #endif + #ifdef FEAT_CRYPT +! crypt_method_used = use_crypt_method; +! if (wb_flags & FIO_ENCRYPTED) +! crypt_pop_state(); + #endif + +- + #if defined(FEAT_MBYTE) && defined(FEAT_EVAL) + if (wfname != fname) + { +--- 4693,4705 ---- + mch_set_acl(wfname, acl); + #endif + #ifdef FEAT_CRYPT +! 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,4933 **** + #ifdef FEAT_CRYPT + if (wb_flags & FIO_ENCRYPTED) + { +! if (crypt_method_used == 1) +! STRCAT(IObuff, _("[blowfish]")); +! else +! STRCAT(IObuff, _("[crypted]")); + c = TRUE; + } + #endif +--- 4849,4855 ---- + #ifdef FEAT_CRYPT + if (wb_flags & FIO_ENCRYPTED) + { +! crypt_append_msg(buf); + c = TRUE; + } + #endif +*************** +*** 5740,5747 **** + #endif /* FEAT_MBYTE */ + + #ifdef FEAT_CRYPT +! if (flags & FIO_ENCRYPTED) /* encrypt the data */ +! crypt_encode(buf, len, buf); + #endif + + wlen = write_eintr(ip->bw_fd, buf, len); +--- 5662,5687 ---- + #endif /* FEAT_MBYTE */ + + #ifdef FEAT_CRYPT +! 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); +*** ../vim-7.4.398/src/globals.h 2014-08-06 18:17:03.475147780 +0200 +--- src/globals.h 2014-08-09 15:31:32.497356185 +0200 +*************** +*** 105,114 **** + + 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 +--- 105,110 ---- +*** ../vim-7.4.398/src/main.c 2014-05-28 18:22:37.876225054 +0200 +--- src/main.c 2014-08-09 15:31:32.497356185 +0200 +*************** +*** 846,853 **** + #ifdef FEAT_CRYPT + if (params.ask_for_key) + { +! (void)blowfish_self_test(); +! (void)get_crypt_key(TRUE, TRUE); + TIME_MSG("getting crypt key"); + } + #endif +--- 846,852 ---- + #ifdef FEAT_CRYPT + if (params.ask_for_key) + { +! (void)crypt_get_key(TRUE, TRUE); + TIME_MSG("getting crypt key"); + } + #endif +*** ../vim-7.4.398/src/memline.c 2014-03-23 16:03:56.171311627 +0100 +--- src/memline.c 2014-08-09 15:39:22.629352806 +0200 +*************** +*** 63,68 **** +--- 63,77 ---- + #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,157 **** + struct block0 + { + char_u b0_id[2]; /* id for block 0: BLOCK0_ID0 and BLOCK0_ID1, +! * BLOCK0_ID1_C0, BLOCK0_ID1_C1 */ + 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 */ +--- 160,166 ---- + struct block0 + { + char_u b0_id[2]; /* id for block 0: BLOCK0_ID0 and BLOCK0_ID1, +! * 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,262 **** + 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)); + #endif + #ifdef FEAT_BYTEOFF + static void ml_updatechunk __ARGS((buf_T *buf, long line, long len, int updtype)); +--- 265,271 ---- + static char_u *make_percent_swname __ARGS((char_u *dir, char_u *name)); + #endif + #ifdef FEAT_CRYPT +! 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,366 **** + 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); + #endif + } + +--- 368,374 ---- + b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL; + long_to_char(mch_get_pid(), b0p->b0_pid); + #ifdef FEAT_CRYPT +! ml_set_b0_crypt(buf, b0p); + #endif + } + +*************** +*** 436,446 **** + b0p->b0_id[1] = BLOCK0_ID1; + else + { +! if (get_crypt_method(buf) == 0) +! b0p->b0_id[1] = BLOCK0_ID1_C0; +! else + { +- 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); +--- 444,454 ---- + b0p->b0_id[1] = BLOCK0_ID1; + else + { +! int method_nr = crypt_get_method_nr(buf); +! +! b0p->b0_id[1] = id1_codes[method_nr]; +! if (method_nr > CRYPT_M_ZIP) + { + /* 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,893 **** + 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) + ) + return FAIL; + return OK; +--- 895,902 ---- + 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_C2) + ) + return FAIL; + return OK; +*************** +*** 1255,1268 **** + } + + #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; + mch_memmove(mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN); +! } +! set_crypt_method(buf, b0_cm); + #else + if (b0p->b0_id[1] != BLOCK0_ID1) + { +--- 1264,1275 ---- + } + + #ifdef FEAT_CRYPT +! 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); +! crypt_set_cm_option(buf, b0_cm < 0 ? 0 : b0_cm); + #else + if (b0p->b0_id[1] != BLOCK0_ID1) + { +*************** +*** 1389,1395 **** + } + else + smsg((char_u *)_(need_key_msg), fname_used); +! buf->b_p_key = get_crypt_key(FALSE, FALSE); + if (buf->b_p_key == NULL) + buf->b_p_key = curbuf->b_p_key; + else if (*buf->b_p_key == NUL) +--- 1396,1402 ---- + } + else + smsg((char_u *)_(need_key_msg), fname_used); +! 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,4821 **** +--- 4823,4829 ---- + char_u *text_start; + char_u *new_data; + int text_len; ++ cryptstate_T *state; + + if (dp->db_id != DATA_ID) + return data; +*************** +*** 4831,4840 **** + 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(); + + /* Clear the gap. */ + if (head_end < text_start) +--- 4839,4847 ---- + mch_memmove(new_data, dp, head_end - (char_u *)dp); + + /* Encrypt the text. */ +! 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,4862 **** +--- 4864,4870 ---- + char_u *head_end; + char_u *text_start; + int text_len; ++ cryptstate_T *state; + + if (dp->db_id == DATA_ID) + { +*************** +*** 4869,4885 **** + 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(); + } + } + + /* + * Prepare for encryption/decryption, using the key, seed and offset. + */ +! static void + ml_crypt_prepare(mfp, offset, reading) + memfile_T *mfp; + off_t offset; +--- 4877,4893 ---- + return; /* data was messed up */ + + /* Decrypt the text in place. */ +! 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 cryptstate_T * + ml_crypt_prepare(mfp, offset, reading) + memfile_T *mfp; + off_t offset; +*************** +*** 4887,4924 **** + { + buf_T *buf = mfp->mf_buffer; + char_u salt[50]; +! int method; + 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; + key = mfp->mf_old_key; + seed = mfp->mf_old_seed; + } + else + { +! method = get_crypt_method(buf); + key = buf->b_p_key; + seed = mfp->mf_seed; + } + +! use_crypt_method = method; /* select pkzip or blowfish */ +! if (method == 0) + { + 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); + } + } + + #endif +--- 4895,4931 ---- + { + buf_T *buf = mfp->mf_buffer; + char_u salt[50]; +! 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_nr = mfp->mf_old_cm; + key = mfp->mf_old_key; + seed = mfp->mf_old_seed; + } + else + { +! method_nr = crypt_get_method_nr(buf); + key = buf->b_p_key; + seed = mfp->mf_seed; + } + +! 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); +! 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 +*** ../vim-7.4.398/src/misc2.c 2014-06-25 14:39:35.106348584 +0200 +--- src/misc2.c 2014-08-09 15:31:32.501356185 +0200 +*************** +*** 3803,4124 **** + #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 ]-------------------------------------------------*/ + /* +--- 3803,3808 ---- +*************** +*** 6588,6595 **** +--- 6272,6294 ---- + 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,6609 **** + { + if (i + 1 > (int)sizeof(time_t)) + /* ">>" doesn't work well when shifting more bits than avail */ +! putc(0, fd); + else + { + #if defined(SIZEOF_TIME_T) && SIZEOF_TIME_T > 4 +--- 6302,6308 ---- + { + if (i + 1 > (int)sizeof(time_t)) + /* ">>" doesn't work well when shifting more bits than avail */ +! buf[bi++] = 0; + else + { + #if defined(SIZEOF_TIME_T) && SIZEOF_TIME_T > 4 +*************** +*** 6611,6617 **** + #else + c = (int)((long_u)wtime >> (i * 8)); + #endif +! putc(c, fd); + } + } + } +--- 6310,6316 ---- + #else + c = (int)((long_u)wtime >> (i * 8)); + #endif +! buf[bi++] = c; + } + } + } +*** ../vim-7.4.398/src/option.c 2014-08-06 14:52:05.047236174 +0200 +--- src/option.c 2014-08-09 15:39:29.741352755 +0200 +*************** +*** 2989,2995 **** + 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}; + #endif + #ifdef FEAT_CMDL_COMPL + static char *(p_wop_values[]) = {"tagfile", NULL}; +--- 2989,2995 ---- + 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", "blowfish2", NULL}; + #endif + #ifdef FEAT_CMDL_COMPL + static char *(p_wop_values[]) = {"tagfile", NULL}; +*************** +*** 6140,6146 **** + # endif + if (STRCMP(curbuf->b_p_key, oldval) != 0) + /* Need to update the swapfile. */ +! ml_set_crypt_key(curbuf, oldval, get_crypt_method(curbuf)); + } + + else if (gvarp == &p_cm) +--- 6140,6146 ---- + # endif + if (STRCMP(curbuf->b_p_key, oldval) != 0) + /* Need to update the swapfile. */ +! ml_set_crypt_key(curbuf, oldval, crypt_get_method_nr(curbuf)); + } + + else if (gvarp == &p_cm) +*************** +*** 6151,6157 **** + 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) + errmsg = e_invarg; + else + { +--- 6151,6157 ---- + p = p_cm; + if (check_opt_strings(p, p_cm_values, TRUE) != OK) + errmsg = e_invarg; +! else if (crypt_self_test() == FAIL) + errmsg = e_invarg; + else + { +*************** +*** 6177,6183 **** + p = curbuf->b_p_cm; + if (STRCMP(s, p) != 0) + ml_set_crypt_key(curbuf, curbuf->b_p_key, +! crypt_method_from_string(s)); + + /* If the global value changes need to update the swapfile for all + * buffers using that value. */ +--- 6177,6183 ---- + p = curbuf->b_p_cm; + if (STRCMP(s, p) != 0) + ml_set_crypt_key(curbuf, curbuf->b_p_key, +! crypt_method_nr_from_name(s)); + + /* If the global value changes need to update the swapfile for all + * buffers using that value. */ +*************** +*** 6188,6194 **** + 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)); + } + } + } +--- 6188,6194 ---- + 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_nr_from_name(oldval)); + } + } + } +*** ../vim-7.4.398/src/proto.h 2013-02-26 14:18:19.000000000 +0100 +--- src/proto.h 2014-08-09 15:39:39.333352686 +0200 +*************** +*** 70,75 **** +--- 70,77 ---- + + # ifdef FEAT_CRYPT + # include "blowfish.pro" ++ # include "crypt.pro" ++ # include "crypt_zip.pro" + # endif + # include "buffer.pro" + # include "charset.pro" +*** ../vim-7.4.398/src/proto/blowfish.pro 2014-02-11 15:23:27.938123631 +0100 +--- src/proto/blowfish.pro 2014-08-09 15:31:32.501356185 +0200 +*************** +*** 1,10 **** + /* 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)); + int blowfish_self_test __ARGS((void)); + /* vim: set ft=c : */ +--- 1,6 ---- + /* blowfish.c */ +! 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 : */ +*** ../vim-7.4.398/src/proto/crypt.pro 2014-08-10 13:30:43.880787293 +0200 +--- src/proto/crypt.pro 2014-08-09 15:31:32.501356185 +0200 +*************** +*** 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 : */ +*** ../vim-7.4.398/src/proto/crypt_zip.pro 2014-08-10 13:30:43.884787293 +0200 +--- src/proto/crypt_zip.pro 2014-08-09 15:31:32.501356185 +0200 +*************** +*** 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 : */ +*** ../vim-7.4.398/src/proto/fileio.pro 2013-08-10 13:37:11.000000000 +0200 +--- src/proto/fileio.pro 2014-08-09 15:31:32.501356185 +0200 +*************** +*** 4,11 **** + 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)); +--- 4,9 ---- +*** ../vim-7.4.398/src/proto/misc2.pro 2014-05-07 18:35:25.669216052 +0200 +--- src/proto/misc2.pro 2014-08-09 15:31:32.501356185 +0200 +*************** +*** 84,99 **** + 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)); +--- 84,89 ---- +*************** +*** 116,120 **** +--- 106,111 ---- + 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 : */ +*** ../vim-7.4.398/src/structs.h 2014-06-25 14:39:35.110348584 +0200 +--- src/structs.h 2014-08-09 15:40:08.501352476 +0200 +*************** +*** 1251,1256 **** +--- 1251,1274 ---- + } 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,1784 **** + int b_was_netbeans_file;/* TRUE if b_netbeans_file was once set */ + #endif + +! }; + + + #ifdef FEAT_DIFF +--- 1796,1807 ---- + 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 +*** ../vim-7.4.398/src/undo.c 2014-04-02 14:05:33.999887839 +0200 +--- src/undo.c 2014-08-09 16:55:40.541319903 +0200 +*************** +*** 81,88 **** +--- 81,105 ---- + #define UH_MAGIC 0x18dade /* value for uh_magic when in use */ + #define UE_MAGIC 0xabc123 /* value for ue_magic when in use */ + ++ /* Size of buffer used for encryption. */ ++ #define CRYPT_BUF_SIZE 8192 ++ + #include "vim.h" + ++ /* Structure passed around between functions. ++ * Avoids passing cryptstate_T when encryption not available. */ ++ typedef struct { ++ buf_T *bi_buf; ++ FILE *bi_fp; ++ #ifdef FEAT_CRYPT ++ cryptstate_T *bi_state; ++ char_u *bi_buffer; /* CRYPT_BUF_SIZE, NULL when not buffering */ ++ size_t bi_used; /* bytes written to/read from bi_buffer */ ++ size_t bi_avail; /* bytes available in bi_buffer */ ++ #endif ++ } bufinfo_T; ++ ++ + static long get_undolevel __ARGS((void)); + static void u_unch_branch __ARGS((u_header_T *uhp)); + static u_entry_T *u_get_headentry __ARGS((void)); +*************** +*** 98,115 **** + #ifdef FEAT_PERSISTENT_UNDO + static void corruption_error __ARGS((char *mesg, char_u *file_name)); + static void u_free_uhp __ARGS((u_header_T *uhp)); +! static size_t fwrite_crypt __ARGS((buf_T *buf UNUSED, char_u *ptr, size_t len, FILE *fp)); +! static char_u *read_string_decrypt __ARGS((buf_T *buf UNUSED, FILE *fd, int len)); +! static int serialize_header __ARGS((FILE *fp, buf_T *buf, char_u *hash)); +! static int serialize_uhp __ARGS((FILE *fp, buf_T *buf, u_header_T *uhp)); +! static u_header_T *unserialize_uhp __ARGS((FILE *fp, char_u *file_name)); +! static int serialize_uep __ARGS((FILE *fp, buf_T *buf, u_entry_T *uep)); +! static u_entry_T *unserialize_uep __ARGS((FILE *fp, int *error, char_u *file_name)); +! static void serialize_pos __ARGS((pos_T pos, FILE *fp)); +! static void unserialize_pos __ARGS((pos_T *pos, FILE *fp)); +! static void serialize_visualinfo __ARGS((visualinfo_T *info, FILE *fp)); +! static void unserialize_visualinfo __ARGS((visualinfo_T *info, FILE *fp)); +! static void put_header_ptr __ARGS((FILE *fp, u_header_T *uhp)); + #endif + + #define U_ALLOC_LINE(size) lalloc((long_u)(size), FALSE) +--- 115,140 ---- + #ifdef FEAT_PERSISTENT_UNDO + static void corruption_error __ARGS((char *mesg, char_u *file_name)); + static void u_free_uhp __ARGS((u_header_T *uhp)); +! static int undo_write __ARGS((bufinfo_T *bi, char_u *ptr, size_t len)); +! static int undo_flush __ARGS((bufinfo_T *bi)); +! static int fwrite_crypt __ARGS((bufinfo_T *bi, char_u *ptr, size_t len)); +! static int undo_write_bytes __ARGS((bufinfo_T *bi, long_u nr, int len)); +! static void put_header_ptr __ARGS((bufinfo_T *bi, u_header_T *uhp)); +! static int undo_read_4c __ARGS((bufinfo_T *bi)); +! static int undo_read_2c __ARGS((bufinfo_T *bi)); +! static int undo_read_byte __ARGS((bufinfo_T *bi)); +! static time_t undo_read_time __ARGS((bufinfo_T *bi)); +! static int undo_read __ARGS((bufinfo_T *bi, char_u *buffer, size_t size)); +! static char_u *read_string_decrypt __ARGS((bufinfo_T *bi, int len)); +! static int serialize_header __ARGS((bufinfo_T *bi, char_u *hash)); +! static int serialize_uhp __ARGS((bufinfo_T *bi, u_header_T *uhp)); +! static u_header_T *unserialize_uhp __ARGS((bufinfo_T *bi, char_u *file_name)); +! static int serialize_uep __ARGS((bufinfo_T *bi, u_entry_T *uep)); +! static u_entry_T *unserialize_uep __ARGS((bufinfo_T *bi, int *error, char_u *file_name)); +! static void serialize_pos __ARGS((bufinfo_T *bi, pos_T pos)); +! static void unserialize_pos __ARGS((bufinfo_T *bi, pos_T *pos)); +! static void serialize_visualinfo __ARGS((bufinfo_T *bi, visualinfo_T *info)); +! static void unserialize_visualinfo __ARGS((bufinfo_T *bi, visualinfo_T *info)); + #endif + + #define U_ALLOC_LINE(size) lalloc((long_u)(size), FALSE) +*************** +*** 859,926 **** + } + + /* +! * Like fwrite() but crypt the bytes when 'key' is set. +! * Returns 1 if successful. + */ +! static size_t +! fwrite_crypt(buf, ptr, len, fp) +! buf_T *buf UNUSED; + char_u *ptr; + size_t len; +- FILE *fp; + { + #ifdef FEAT_CRYPT + char_u *copy; + char_u small_buf[100]; + size_t i; + +! if (*buf->b_p_key == NUL) +! return fwrite(ptr, len, (size_t)1, fp); +! if (len < 100) +! copy = small_buf; /* no malloc()/free() for short strings */ +! else + { +! copy = lalloc(len, FALSE); +! if (copy == NULL) +! return 0; +! } +! crypt_encode(ptr, len, copy); +! i = fwrite(copy, len, (size_t)1, fp); +! if (copy != small_buf) +! vim_free(copy); +! return i; +! #else +! return fwrite(ptr, len, (size_t)1, fp); + #endif + } + + /* +! * Read a string of length "len" from "fd". +! * When 'key' is set decrypt the bytes. + */ +! static char_u * +! read_string_decrypt(buf, fd, len) +! buf_T *buf UNUSED; +! FILE *fd; + int len; + { +! char_u *ptr; + +! ptr = read_string(fd, len); + #ifdef FEAT_CRYPT +! if (ptr != NULL && *buf->b_p_key != NUL) +! crypt_decode(ptr, len); + #endif + return ptr; + } + + static int +! serialize_header(fp, buf, hash) +! FILE *fp; +! buf_T *buf; + char_u *hash; + { +! int len; + + /* Start writing, first the magic marker and undo info version. */ + if (fwrite(UF_START_MAGIC, (size_t)UF_START_MAGIC_LEN, (size_t)1, fp) != 1) +--- 884,1177 ---- + } + + /* +! * Write a sequence of bytes to the undo file. +! * Buffers and encrypts as needed. +! * Returns OK or FAIL. + */ +! static int +! undo_write(bi, ptr, len) +! bufinfo_T *bi; +! char_u *ptr; +! size_t len; +! { +! #ifdef FEAT_CRYPT +! if (bi->bi_buffer != NULL) +! { +! size_t len_todo = len; +! char_u *p = ptr; +! +! while (bi->bi_used + len_todo >= CRYPT_BUF_SIZE) +! { +! size_t n = CRYPT_BUF_SIZE - bi->bi_used; +! +! mch_memmove(bi->bi_buffer + bi->bi_used, p, n); +! len_todo -= n; +! p += n; +! bi->bi_used = CRYPT_BUF_SIZE; +! if (undo_flush(bi) == FAIL) +! return FAIL; +! } +! if (len_todo > 0) +! { +! mch_memmove(bi->bi_buffer + bi->bi_used, p, len_todo); +! bi->bi_used += len_todo; +! } +! return OK; +! } +! #endif +! if (fwrite(ptr, len, (size_t)1, bi->bi_fp) != 1) +! return FAIL; +! return OK; +! } +! +! #ifdef FEAT_CRYPT +! static int +! undo_flush(bi) +! bufinfo_T *bi; +! { +! if (bi->bi_used > 0) +! { +! crypt_encode_inplace(bi->bi_state, bi->bi_buffer, bi->bi_used); +! if (fwrite(bi->bi_buffer, bi->bi_used, (size_t)1, bi->bi_fp) != 1) +! return FAIL; +! bi->bi_used = 0; +! } +! return OK; +! } +! #endif +! +! /* +! * Write "ptr[len]" and crypt the bytes when needed. +! * Returns OK or FAIL. +! */ +! static int +! fwrite_crypt(bi, ptr, len) +! bufinfo_T *bi; + char_u *ptr; + size_t len; + { + #ifdef FEAT_CRYPT + char_u *copy; + char_u small_buf[100]; + size_t i; + +! if (bi->bi_state != NULL && bi->bi_buffer == NULL) + { +! /* crypting every piece of text separately */ +! if (len < 100) +! copy = small_buf; /* no malloc()/free() for short strings */ +! else +! { +! copy = lalloc(len, FALSE); +! if (copy == NULL) +! return 0; +! } +! crypt_encode(bi->bi_state, ptr, len, copy); +! i = fwrite(copy, len, (size_t)1, bi->bi_fp); +! if (copy != small_buf) +! vim_free(copy); +! return i == 1 ? OK : FAIL; +! } + #endif ++ return undo_write(bi, ptr, len); + } + + /* +! * Write a number, MSB first, in "len" bytes. +! * Must match with undo_read_?c() functions. +! * Returns OK or FAIL. + */ +! static int +! undo_write_bytes(bi, nr, len) +! bufinfo_T *bi; +! long_u nr; + int len; + { +! char_u buf[8]; +! int i; +! int bufi = 0; +! +! for (i = len - 1; i >= 0; --i) +! buf[bufi++] = nr >> (i * 8); +! return undo_write(bi, buf, (size_t)len); +! } +! +! /* +! * Write the pointer to an undo header. Instead of writing the pointer itself +! * we use the sequence number of the header. This is converted back to +! * pointers when reading. */ +! static void +! put_header_ptr(bi, uhp) +! bufinfo_T *bi; +! u_header_T *uhp; +! { +! undo_write_bytes(bi, (long_u)(uhp != NULL ? uhp->uh_seq : 0), 4); +! } +! +! static int +! undo_read_4c(bi) +! bufinfo_T *bi; +! { +! #ifdef FEAT_CRYPT +! if (bi->bi_buffer != NULL) +! { +! char_u buf[4]; +! int n; +! +! undo_read(bi, buf, (size_t)4); +! n = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]; +! return n; +! } +! #endif +! return get4c(bi->bi_fp); +! } +! +! static int +! undo_read_2c(bi) +! bufinfo_T *bi; +! { +! #ifdef FEAT_CRYPT +! if (bi->bi_buffer != NULL) +! { +! char_u buf[2]; +! int n; +! +! undo_read(bi, buf, (size_t)2); +! n = (buf[0] << 8) + buf[1]; +! return n; +! } +! #endif +! return get2c(bi->bi_fp); +! } +! +! static int +! undo_read_byte(bi) +! bufinfo_T *bi; +! { +! #ifdef FEAT_CRYPT +! if (bi->bi_buffer != NULL) +! { +! char_u buf[1]; +! +! undo_read(bi, buf, (size_t)1); +! return buf[0]; +! } +! #endif +! return getc(bi->bi_fp); +! } +! +! static time_t +! undo_read_time(bi) +! bufinfo_T *bi; +! { +! #ifdef FEAT_CRYPT +! if (bi->bi_buffer != NULL) +! { +! char_u buf[8]; +! time_t n = 0; +! int i; +! +! undo_read(bi, buf, (size_t)8); +! for (i = 0; i < 8; ++i) +! n = (n << 8) + buf[i]; +! return n; +! } +! #endif +! return get8ctime(bi->bi_fp); +! } +! +! /* +! * Read "buffer[size]" from the undo file. +! * Return OK or FAIL. +! */ +! static int +! undo_read(bi, buffer, size) +! bufinfo_T *bi; +! char_u *buffer; +! size_t size; +! { +! #ifdef FEAT_CRYPT +! if (bi->bi_buffer != NULL) +! { +! int size_todo = size; +! char_u *p = buffer; +! +! while (size_todo > 0) +! { +! size_t n; +! +! if (bi->bi_used >= bi->bi_avail) +! { +! n = fread(bi->bi_buffer, 1, (size_t)CRYPT_BUF_SIZE, bi->bi_fp); +! if (n <= 0) +! { +! /* Error may be checked for only later. Fill with zeros, +! * so that the reader won't use garbage. */ +! vim_memset(p, 0, size_todo); +! return FAIL; +! } +! bi->bi_avail = n; +! bi->bi_used = 0; +! crypt_decode_inplace(bi->bi_state, bi->bi_buffer, bi->bi_avail); +! } +! n = size_todo; +! if (n > bi->bi_avail - bi->bi_used) +! n = bi->bi_avail - bi->bi_used; +! mch_memmove(p, bi->bi_buffer + bi->bi_used, n); +! bi->bi_used += n; +! size_todo -= n; +! p += n; +! } +! return OK; +! } +! #endif +! if (fread(buffer, (size_t)size, 1, bi->bi_fp) != 1) +! return FAIL; +! return OK; +! } +! +! /* +! * Read a string of length "len" from "bi->bi_fd". +! * "len" can be zero to allocate an empty line. +! * Decrypt the bytes if needed. +! * Append a NUL. +! * Returns a pointer to allocated memory or NULL for failure. +! */ +! static char_u * +! read_string_decrypt(bi, len) +! bufinfo_T *bi; +! int len; +! { +! char_u *ptr = alloc((unsigned)len + 1); + +! if (ptr != NULL) +! { +! if (len > 0 && undo_read(bi, ptr, len) == FAIL) +! { +! vim_free(ptr); +! return NULL; +! } +! ptr[len] = NUL; + #ifdef FEAT_CRYPT +! if (bi->bi_state != NULL && bi->bi_buffer == NULL) +! crypt_decode_inplace(bi->bi_state, ptr, len); + #endif ++ } + return ptr; + } + ++ /* ++ * Writes the (not encrypted) header and initializes encryption if needed. ++ */ + static int +! serialize_header(bi, hash) +! bufinfo_T *bi; + char_u *hash; + { +! int len; +! buf_T *buf = bi->bi_buf; +! FILE *fp = bi->bi_fp; +! char_u time_buf[8]; + + /* Start writing, first the magic marker and undo info version. */ + if (fwrite(UF_START_MAGIC, (size_t)UF_START_MAGIC_LEN, (size_t)1, fp) != 1) +*************** +*** 934,1041 **** + char_u *header; + int header_len; + +! put_bytes(fp, (long_u)UF_VERSION_CRYPT, 2); +! header = prepare_crypt_write(buf, &header_len); +! if (header == NULL) + return FAIL; + len = (int)fwrite(header, (size_t)header_len, (size_t)1, fp); + vim_free(header); + if (len != 1) + { +! crypt_pop_state(); + return FAIL; + } + } + else + #endif +! put_bytes(fp, (long_u)UF_VERSION, 2); + + + /* Write a hash of the buffer text, so that we can verify it is still the + * same when reading the buffer text. */ +! if (fwrite(hash, (size_t)UNDO_HASH_SIZE, (size_t)1, fp) != 1) + return FAIL; + + /* buffer-specific data */ +! put_bytes(fp, (long_u)buf->b_ml.ml_line_count, 4); + len = buf->b_u_line_ptr != NULL ? (int)STRLEN(buf->b_u_line_ptr) : 0; +! put_bytes(fp, (long_u)len, 4); +! if (len > 0 && fwrite_crypt(buf, buf->b_u_line_ptr, (size_t)len, fp) != 1) + return FAIL; +! put_bytes(fp, (long_u)buf->b_u_line_lnum, 4); +! put_bytes(fp, (long_u)buf->b_u_line_colnr, 4); + + /* Undo structures header data */ +! put_header_ptr(fp, buf->b_u_oldhead); +! put_header_ptr(fp, buf->b_u_newhead); +! put_header_ptr(fp, buf->b_u_curhead); +! +! put_bytes(fp, (long_u)buf->b_u_numhead, 4); +! put_bytes(fp, (long_u)buf->b_u_seq_last, 4); +! put_bytes(fp, (long_u)buf->b_u_seq_cur, 4); +! put_time(fp, buf->b_u_time_cur); + + /* Optional fields. */ +! putc(4, fp); +! putc(UF_LAST_SAVE_NR, fp); +! put_bytes(fp, (long_u)buf->b_u_save_nr_last, 4); + +! putc(0, fp); /* end marker */ + + return OK; + } + + static int +! serialize_uhp(fp, buf, uhp) +! FILE *fp; +! buf_T *buf; + u_header_T *uhp; + { + int i; + u_entry_T *uep; + +! if (put_bytes(fp, (long_u)UF_HEADER_MAGIC, 2) == FAIL) + return FAIL; + +! put_header_ptr(fp, uhp->uh_next.ptr); +! put_header_ptr(fp, uhp->uh_prev.ptr); +! put_header_ptr(fp, uhp->uh_alt_next.ptr); +! put_header_ptr(fp, uhp->uh_alt_prev.ptr); +! put_bytes(fp, uhp->uh_seq, 4); +! serialize_pos(uhp->uh_cursor, fp); + #ifdef FEAT_VIRTUALEDIT +! put_bytes(fp, (long_u)uhp->uh_cursor_vcol, 4); + #else +! put_bytes(fp, (long_u)0, 4); + #endif +! put_bytes(fp, (long_u)uhp->uh_flags, 2); + /* Assume NMARKS will stay the same. */ + for (i = 0; i < NMARKS; ++i) +! serialize_pos(uhp->uh_namedm[i], fp); +! serialize_visualinfo(&uhp->uh_visual, fp); +! put_time(fp, uhp->uh_time); + + /* Optional fields. */ +! putc(4, fp); +! putc(UHP_SAVE_NR, fp); +! put_bytes(fp, (long_u)uhp->uh_save_nr, 4); + +! putc(0, fp); /* end marker */ + + /* Write all the entries. */ + for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next) + { +! put_bytes(fp, (long_u)UF_ENTRY_MAGIC, 2); +! if (serialize_uep(fp, buf, uep) == FAIL) + return FAIL; + } +! put_bytes(fp, (long_u)UF_ENTRY_END_MAGIC, 2); + return OK; + } + + static u_header_T * +! unserialize_uhp(fp, file_name) +! FILE *fp; + char_u *file_name; + { + u_header_T *uhp; +--- 1185,1308 ---- + char_u *header; + int header_len; + +! undo_write_bytes(bi, (long_u)UF_VERSION_CRYPT, 2); +! bi->bi_state = crypt_create_for_writing(crypt_get_method_nr(buf), +! buf->b_p_key, &header, &header_len); +! if (bi->bi_state == NULL) + return FAIL; + len = (int)fwrite(header, (size_t)header_len, (size_t)1, fp); + vim_free(header); + if (len != 1) + { +! crypt_free_state(bi->bi_state); +! bi->bi_state = NULL; + return FAIL; + } ++ ++ if (crypt_whole_undofile(crypt_get_method_nr(buf))) ++ { ++ bi->bi_buffer = alloc(CRYPT_BUF_SIZE); ++ if (bi->bi_buffer == NULL) ++ { ++ crypt_free_state(bi->bi_state); ++ bi->bi_state = NULL; ++ return FAIL; ++ } ++ bi->bi_used = 0; ++ } + } + else + #endif +! undo_write_bytes(bi, (long_u)UF_VERSION, 2); + + + /* Write a hash of the buffer text, so that we can verify it is still the + * same when reading the buffer text. */ +! if (undo_write(bi, hash, (size_t)UNDO_HASH_SIZE) == FAIL) + return FAIL; + + /* buffer-specific data */ +! undo_write_bytes(bi, (long_u)buf->b_ml.ml_line_count, 4); + len = buf->b_u_line_ptr != NULL ? (int)STRLEN(buf->b_u_line_ptr) : 0; +! undo_write_bytes(bi, (long_u)len, 4); +! if (len > 0 && fwrite_crypt(bi, buf->b_u_line_ptr, (size_t)len) == FAIL) + return FAIL; +! undo_write_bytes(bi, (long_u)buf->b_u_line_lnum, 4); +! undo_write_bytes(bi, (long_u)buf->b_u_line_colnr, 4); + + /* Undo structures header data */ +! put_header_ptr(bi, buf->b_u_oldhead); +! put_header_ptr(bi, buf->b_u_newhead); +! put_header_ptr(bi, buf->b_u_curhead); +! +! undo_write_bytes(bi, (long_u)buf->b_u_numhead, 4); +! undo_write_bytes(bi, (long_u)buf->b_u_seq_last, 4); +! undo_write_bytes(bi, (long_u)buf->b_u_seq_cur, 4); +! time_to_bytes(buf->b_u_time_cur, time_buf); +! undo_write(bi, time_buf, 8); + + /* Optional fields. */ +! undo_write_bytes(bi, 4, 1); +! undo_write_bytes(bi, UF_LAST_SAVE_NR, 1); +! undo_write_bytes(bi, (long_u)buf->b_u_save_nr_last, 4); + +! undo_write_bytes(bi, 0, 1); /* end marker */ + + return OK; + } + + static int +! serialize_uhp(bi, uhp) +! bufinfo_T *bi; + u_header_T *uhp; + { + int i; + u_entry_T *uep; ++ char_u time_buf[8]; + +! if (undo_write_bytes(bi, (long_u)UF_HEADER_MAGIC, 2) == FAIL) + return FAIL; + +! put_header_ptr(bi, uhp->uh_next.ptr); +! put_header_ptr(bi, uhp->uh_prev.ptr); +! put_header_ptr(bi, uhp->uh_alt_next.ptr); +! put_header_ptr(bi, uhp->uh_alt_prev.ptr); +! undo_write_bytes(bi, uhp->uh_seq, 4); +! serialize_pos(bi, uhp->uh_cursor); + #ifdef FEAT_VIRTUALEDIT +! undo_write_bytes(bi, (long_u)uhp->uh_cursor_vcol, 4); + #else +! undo_write_bytes(bi, (long_u)0, 4); + #endif +! undo_write_bytes(bi, (long_u)uhp->uh_flags, 2); + /* Assume NMARKS will stay the same. */ + for (i = 0; i < NMARKS; ++i) +! serialize_pos(bi, uhp->uh_namedm[i]); +! serialize_visualinfo(bi, &uhp->uh_visual); +! time_to_bytes(uhp->uh_time, time_buf); +! undo_write(bi, time_buf, 8); + + /* Optional fields. */ +! undo_write_bytes(bi, 4, 1); +! undo_write_bytes(bi, UHP_SAVE_NR, 1); +! undo_write_bytes(bi, (long_u)uhp->uh_save_nr, 4); + +! undo_write_bytes(bi, 0, 1); /* end marker */ + + /* Write all the entries. */ + for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next) + { +! undo_write_bytes(bi, (long_u)UF_ENTRY_MAGIC, 2); +! if (serialize_uep(bi, uep) == FAIL) + return FAIL; + } +! undo_write_bytes(bi, (long_u)UF_ENTRY_END_MAGIC, 2); + return OK; + } + + static u_header_T * +! unserialize_uhp(bi, file_name) +! bufinfo_T *bi; + char_u *file_name; + { + u_header_T *uhp; +*************** +*** 1051,1106 **** + #ifdef U_DEBUG + uhp->uh_magic = UH_MAGIC; + #endif +! uhp->uh_next.seq = get4c(fp); +! uhp->uh_prev.seq = get4c(fp); +! uhp->uh_alt_next.seq = get4c(fp); +! uhp->uh_alt_prev.seq = get4c(fp); +! uhp->uh_seq = get4c(fp); + if (uhp->uh_seq <= 0) + { + corruption_error("uh_seq", file_name); + vim_free(uhp); + return NULL; + } +! unserialize_pos(&uhp->uh_cursor, fp); + #ifdef FEAT_VIRTUALEDIT +! uhp->uh_cursor_vcol = get4c(fp); + #else +! (void)get4c(fp); + #endif +! uhp->uh_flags = get2c(fp); + for (i = 0; i < NMARKS; ++i) +! unserialize_pos(&uhp->uh_namedm[i], fp); +! unserialize_visualinfo(&uhp->uh_visual, fp); +! uhp->uh_time = get8ctime(fp); + + /* Optional fields. */ + for (;;) + { +! int len = getc(fp); + int what; + + if (len == 0) + break; +! what = getc(fp); + switch (what) + { + case UHP_SAVE_NR: +! uhp->uh_save_nr = get4c(fp); + break; + default: + /* field not supported, skip */ + while (--len >= 0) +! (void)getc(fp); + } + } + + /* Unserialize the uep list. */ + last_uep = NULL; +! while ((c = get2c(fp)) == UF_ENTRY_MAGIC) + { + error = FALSE; +! uep = unserialize_uep(fp, &error, file_name); + if (last_uep == NULL) + uhp->uh_entry = uep; + else +--- 1318,1373 ---- + #ifdef U_DEBUG + uhp->uh_magic = UH_MAGIC; + #endif +! uhp->uh_next.seq = undo_read_4c(bi); +! uhp->uh_prev.seq = undo_read_4c(bi); +! uhp->uh_alt_next.seq = undo_read_4c(bi); +! uhp->uh_alt_prev.seq = undo_read_4c(bi); +! uhp->uh_seq = undo_read_4c(bi); + if (uhp->uh_seq <= 0) + { + corruption_error("uh_seq", file_name); + vim_free(uhp); + return NULL; + } +! unserialize_pos(bi, &uhp->uh_cursor); + #ifdef FEAT_VIRTUALEDIT +! uhp->uh_cursor_vcol = undo_read_4c(bi); + #else +! (void)undo_read_4c(bi); + #endif +! uhp->uh_flags = undo_read_2c(bi); + for (i = 0; i < NMARKS; ++i) +! unserialize_pos(bi, &uhp->uh_namedm[i]); +! unserialize_visualinfo(bi, &uhp->uh_visual); +! uhp->uh_time = undo_read_time(bi); + + /* Optional fields. */ + for (;;) + { +! int len = undo_read_byte(bi); + int what; + + if (len == 0) + break; +! what = undo_read_byte(bi); + switch (what) + { + case UHP_SAVE_NR: +! uhp->uh_save_nr = undo_read_4c(bi); + break; + default: + /* field not supported, skip */ + while (--len >= 0) +! (void)undo_read_byte(bi); + } + } + + /* Unserialize the uep list. */ + last_uep = NULL; +! while ((c = undo_read_2c(bi)) == UF_ENTRY_MAGIC) + { + error = FALSE; +! uep = unserialize_uep(bi, &error, file_name); + if (last_uep == NULL) + uhp->uh_entry = uep; + else +*************** +*** 1123,1157 **** + } + + /* +! * Serialize "uep" to "fp". + */ + static int +! serialize_uep(fp, buf, uep) +! FILE *fp; +! buf_T *buf; + u_entry_T *uep; + { + int i; + size_t len; + +! put_bytes(fp, (long_u)uep->ue_top, 4); +! put_bytes(fp, (long_u)uep->ue_bot, 4); +! put_bytes(fp, (long_u)uep->ue_lcount, 4); +! put_bytes(fp, (long_u)uep->ue_size, 4); + for (i = 0; i < uep->ue_size; ++i) + { + len = STRLEN(uep->ue_array[i]); +! if (put_bytes(fp, (long_u)len, 4) == FAIL) + return FAIL; +! if (len > 0 && fwrite_crypt(buf, uep->ue_array[i], len, fp) != 1) + return FAIL; + } + return OK; + } + + static u_entry_T * +! unserialize_uep(fp, error, file_name) +! FILE *fp; + int *error; + char_u *file_name; + { +--- 1390,1423 ---- + } + + /* +! * Serialize "uep". + */ + static int +! serialize_uep(bi, uep) +! bufinfo_T *bi; + u_entry_T *uep; + { + int i; + size_t len; + +! undo_write_bytes(bi, (long_u)uep->ue_top, 4); +! undo_write_bytes(bi, (long_u)uep->ue_bot, 4); +! undo_write_bytes(bi, (long_u)uep->ue_lcount, 4); +! undo_write_bytes(bi, (long_u)uep->ue_size, 4); + for (i = 0; i < uep->ue_size; ++i) + { + len = STRLEN(uep->ue_array[i]); +! if (undo_write_bytes(bi, (long_u)len, 4) == FAIL) + return FAIL; +! if (len > 0 && fwrite_crypt(bi, uep->ue_array[i], len) == FAIL) + return FAIL; + } + return OK; + } + + static u_entry_T * +! unserialize_uep(bi, error, file_name) +! bufinfo_T *bi; + int *error; + char_u *file_name; + { +*************** +*** 1168,1177 **** + #ifdef U_DEBUG + uep->ue_magic = UE_MAGIC; + #endif +! uep->ue_top = get4c(fp); +! uep->ue_bot = get4c(fp); +! uep->ue_lcount = get4c(fp); +! uep->ue_size = get4c(fp); + if (uep->ue_size > 0) + { + array = (char_u **)U_ALLOC_LINE(sizeof(char_u *) * uep->ue_size); +--- 1434,1443 ---- + #ifdef U_DEBUG + uep->ue_magic = UE_MAGIC; + #endif +! uep->ue_top = undo_read_4c(bi); +! uep->ue_bot = undo_read_4c(bi); +! uep->ue_lcount = undo_read_4c(bi); +! uep->ue_size = undo_read_4c(bi); + if (uep->ue_size > 0) + { + array = (char_u **)U_ALLOC_LINE(sizeof(char_u *) * uep->ue_size); +*************** +*** 1188,1196 **** + + for (i = 0; i < uep->ue_size; ++i) + { +! line_len = get4c(fp); + if (line_len >= 0) +! line = read_string_decrypt(curbuf, fp, line_len); + else + { + line = NULL; +--- 1454,1462 ---- + + for (i = 0; i < uep->ue_size; ++i) + { +! line_len = undo_read_4c(bi); + if (line_len >= 0) +! line = read_string_decrypt(bi, line_len); + else + { + line = NULL; +*************** +*** 1207,1289 **** + } + + /* +! * Serialize "pos" to "fp". + */ + static void +! serialize_pos(pos, fp) + pos_T pos; +- FILE *fp; + { +! put_bytes(fp, (long_u)pos.lnum, 4); +! put_bytes(fp, (long_u)pos.col, 4); + #ifdef FEAT_VIRTUALEDIT +! put_bytes(fp, (long_u)pos.coladd, 4); + #else +! put_bytes(fp, (long_u)0, 4); + #endif + } + + /* +! * Unserialize the pos_T at the current position in fp. + */ + static void +! unserialize_pos(pos, fp) + pos_T *pos; +- FILE *fp; + { +! pos->lnum = get4c(fp); + if (pos->lnum < 0) + pos->lnum = 0; +! pos->col = get4c(fp); + if (pos->col < 0) + pos->col = 0; + #ifdef FEAT_VIRTUALEDIT +! pos->coladd = get4c(fp); + if (pos->coladd < 0) + pos->coladd = 0; + #else +! (void)get4c(fp); + #endif + } + + /* +! * Serialize "info" to "fp". + */ + static void +! serialize_visualinfo(info, fp) + visualinfo_T *info; +- FILE *fp; + { +! serialize_pos(info->vi_start, fp); +! serialize_pos(info->vi_end, fp); +! put_bytes(fp, (long_u)info->vi_mode, 4); +! put_bytes(fp, (long_u)info->vi_curswant, 4); + } + + /* +! * Unserialize the visualinfo_T at the current position in fp. + */ + static void +! unserialize_visualinfo(info, fp) + visualinfo_T *info; +- FILE *fp; +- { +- unserialize_pos(&info->vi_start, fp); +- unserialize_pos(&info->vi_end, fp); +- info->vi_mode = get4c(fp); +- info->vi_curswant = get4c(fp); +- } +- +- /* +- * Write the pointer to an undo header. Instead of writing the pointer itself +- * we use the sequence number of the header. This is converted back to +- * pointers when reading. */ +- static void +- put_header_ptr(fp, uhp) +- FILE *fp; +- u_header_T *uhp; + { +! put_bytes(fp, (long_u)(uhp != NULL ? uhp->uh_seq : 0), 4); + } + + /* +--- 1473,1543 ---- + } + + /* +! * Serialize "pos". + */ + static void +! serialize_pos(bi, pos) +! bufinfo_T *bi; + pos_T pos; + { +! undo_write_bytes(bi, (long_u)pos.lnum, 4); +! undo_write_bytes(bi, (long_u)pos.col, 4); + #ifdef FEAT_VIRTUALEDIT +! undo_write_bytes(bi, (long_u)pos.coladd, 4); + #else +! undo_write_bytes(bi, (long_u)0, 4); + #endif + } + + /* +! * Unserialize the pos_T at the current position. + */ + static void +! unserialize_pos(bi, pos) +! bufinfo_T *bi; + pos_T *pos; + { +! pos->lnum = undo_read_4c(bi); + if (pos->lnum < 0) + pos->lnum = 0; +! pos->col = undo_read_4c(bi); + if (pos->col < 0) + pos->col = 0; + #ifdef FEAT_VIRTUALEDIT +! pos->coladd = undo_read_4c(bi); + if (pos->coladd < 0) + pos->coladd = 0; + #else +! (void)undo_read_4c(bi); + #endif + } + + /* +! * Serialize "info". + */ + static void +! serialize_visualinfo(bi, info) +! bufinfo_T *bi; + visualinfo_T *info; + { +! serialize_pos(bi, info->vi_start); +! serialize_pos(bi, info->vi_end); +! undo_write_bytes(bi, (long_u)info->vi_mode, 4); +! undo_write_bytes(bi, (long_u)info->vi_curswant, 4); + } + + /* +! * Unserialize the visualinfo_T at the current position. + */ + static void +! unserialize_visualinfo(bi, info) +! bufinfo_T *bi; + visualinfo_T *info; + { +! unserialize_pos(bi, &info->vi_start); +! unserialize_pos(bi, &info->vi_end); +! info->vi_mode = undo_read_4c(bi); +! info->vi_curswant = undo_read_4c(bi); + } + + /* +*************** +*** 1317,1324 **** + struct stat st_old; + struct stat st_new; + #endif + #ifdef FEAT_CRYPT +! int do_crypt = FALSE; + #endif + + if (name == NULL) +--- 1571,1581 ---- + struct stat st_old; + struct stat st_new; + #endif ++ bufinfo_T bi; ++ + #ifdef FEAT_CRYPT +! bi.bi_state = NULL; +! bi.bi_buffer = NULL; + #endif + + if (name == NULL) +*************** +*** 1474,1487 **** + u_sync(TRUE); + + /* +! * Write the header. + */ +! if (serialize_header(fp, buf, hash) == FAIL) + goto write_error; +- #ifdef FEAT_CRYPT +- if (*buf->b_p_key != NUL) +- do_crypt = TRUE; +- #endif + + /* + * Iteratively serialize UHPs and their UEPs from the top down. +--- 1731,1742 ---- + u_sync(TRUE); + + /* +! * Write the header. Initializes encryption, if enabled. + */ +! bi.bi_buf = buf; +! bi.bi_fp = fp; +! if (serialize_header(&bi, hash) == FAIL) + goto write_error; + + /* + * Iteratively serialize UHPs and their UEPs from the top down. +*************** +*** 1497,1503 **** + #ifdef U_DEBUG + ++headers_written; + #endif +! if (serialize_uhp(fp, buf, uhp) == FAIL) + goto write_error; + } + +--- 1752,1758 ---- + #ifdef U_DEBUG + ++headers_written; + #endif +! if (serialize_uhp(&bi, uhp) == FAIL) + goto write_error; + } + +*************** +*** 1516,1522 **** + uhp = uhp->uh_next.ptr; + } + +! if (put_bytes(fp, (long_u)UF_HEADER_END_MAGIC, 2) == OK) + write_ok = TRUE; + #ifdef U_DEBUG + if (headers_written != buf->b_u_numhead) +--- 1771,1777 ---- + uhp = uhp->uh_next.ptr; + } + +! if (undo_write_bytes(&bi, (long_u)UF_HEADER_END_MAGIC, 2) == OK) + write_ok = TRUE; + #ifdef U_DEBUG + if (headers_written != buf->b_u_numhead) +*************** +*** 1526,1531 **** +--- 1781,1791 ---- + } + #endif + ++ #ifdef FEAT_CRYPT ++ if (bi.bi_state != NULL && undo_flush(&bi) == FAIL) ++ write_ok = FALSE; ++ #endif ++ + write_error: + fclose(fp); + if (!write_ok) +*************** +*** 1551,1558 **** + + theend: + #ifdef FEAT_CRYPT +! if (do_crypt) +! crypt_pop_state(); + #endif + if (file_name != name) + vim_free(file_name); +--- 1811,1819 ---- + + theend: + #ifdef FEAT_CRYPT +! if (bi.bi_state != NULL) +! crypt_free_state(bi.bi_state); +! vim_free(bi.bi_buffer); + #endif + if (file_name != name) + vim_free(file_name); +*************** +*** 1598,1606 **** + struct stat st_orig; + struct stat st_undo; + #endif +! #ifdef FEAT_CRYPT +! int do_decrypt = FALSE; +! #endif + + if (name == NULL) + { +--- 1859,1865 ---- + struct stat st_orig; + struct stat st_undo; + #endif +! bufinfo_T bi; + + if (name == NULL) + { +*************** +*** 1644,1649 **** +--- 1903,1914 ---- + EMSG2(_("E822: Cannot open undo file for reading: %s"), file_name); + goto error; + } ++ bi.bi_buf = curbuf; ++ bi.bi_fp = fp; ++ #ifdef FEAT_CRYPT ++ bi.bi_state = NULL; ++ bi.bi_buffer = NULL; ++ #endif + + /* + * Read the undo file header. +*************** +*** 1664,1675 **** + file_name); + goto error; + } +! if (prepare_crypt_read(fp) == FAIL) + { + EMSG2(_("E826: Undo file decryption failed: %s"), file_name); + goto error; + } +! do_decrypt = TRUE; + #else + EMSG2(_("E827: Undo file is encrypted: %s"), file_name); + goto error; +--- 1929,1952 ---- + file_name); + goto error; + } +! bi.bi_state = crypt_create_from_file(fp, curbuf->b_p_key); +! if (bi.bi_state == NULL) + { + EMSG2(_("E826: Undo file decryption failed: %s"), file_name); + goto error; + } +! if (crypt_whole_undofile(bi.bi_state->method_nr)) +! { +! bi.bi_buffer = alloc(CRYPT_BUF_SIZE); +! if (bi.bi_buffer == NULL) +! { +! crypt_free_state(bi.bi_state); +! bi.bi_state = NULL; +! goto error; +! } +! bi.bi_avail = 0; +! bi.bi_used = 0; +! } + #else + EMSG2(_("E827: Undo file is encrypted: %s"), file_name); + goto error; +*************** +*** 1681,1692 **** + goto error; + } + +! if (fread(read_hash, UNDO_HASH_SIZE, 1, fp) != 1) + { + corruption_error("hash", file_name); + goto error; + } +! line_count = (linenr_T)get4c(fp); + if (memcmp(hash, read_hash, UNDO_HASH_SIZE) != 0 + || line_count != curbuf->b_ml.ml_line_count) + { +--- 1958,1969 ---- + goto error; + } + +! if (undo_read(&bi, read_hash, (size_t)UNDO_HASH_SIZE) == FAIL) + { + corruption_error("hash", file_name); + goto error; + } +! line_count = (linenr_T)undo_read_4c(&bi); + if (memcmp(hash, read_hash, UNDO_HASH_SIZE) != 0 + || line_count != curbuf->b_ml.ml_line_count) + { +*************** +*** 1703,1715 **** + } + + /* Read undo data for "U" command. */ +! str_len = get4c(fp); + if (str_len < 0) + goto error; + if (str_len > 0) +! line_ptr = read_string_decrypt(curbuf, fp, str_len); +! line_lnum = (linenr_T)get4c(fp); +! line_colnr = (colnr_T)get4c(fp); + if (line_lnum < 0 || line_colnr < 0) + { + corruption_error("line lnum/col", file_name); +--- 1980,1992 ---- + } + + /* Read undo data for "U" command. */ +! str_len = undo_read_4c(&bi); + if (str_len < 0) + goto error; + if (str_len > 0) +! line_ptr = read_string_decrypt(&bi, str_len); +! line_lnum = (linenr_T)undo_read_4c(&bi); +! line_colnr = (colnr_T)undo_read_4c(&bi); + if (line_lnum < 0 || line_colnr < 0) + { + corruption_error("line lnum/col", file_name); +*************** +*** 1717,1748 **** + } + + /* Begin general undo data */ +! old_header_seq = get4c(fp); +! new_header_seq = get4c(fp); +! cur_header_seq = get4c(fp); +! num_head = get4c(fp); +! seq_last = get4c(fp); +! seq_cur = get4c(fp); +! seq_time = get8ctime(fp); + + /* Optional header fields. */ + for (;;) + { +! int len = getc(fp); + int what; + + if (len == 0 || len == EOF) + break; +! what = getc(fp); + switch (what) + { + case UF_LAST_SAVE_NR: +! last_save_nr = get4c(fp); + break; + default: + /* field not supported, skip */ + while (--len >= 0) +! (void)getc(fp); + } + } + +--- 1994,2025 ---- + } + + /* Begin general undo data */ +! old_header_seq = undo_read_4c(&bi); +! new_header_seq = undo_read_4c(&bi); +! cur_header_seq = undo_read_4c(&bi); +! num_head = undo_read_4c(&bi); +! seq_last = undo_read_4c(&bi); +! seq_cur = undo_read_4c(&bi); +! seq_time = undo_read_time(&bi); + + /* Optional header fields. */ + for (;;) + { +! int len = undo_read_byte(&bi); + int what; + + if (len == 0 || len == EOF) + break; +! what = undo_read_byte(&bi); + switch (what) + { + case UF_LAST_SAVE_NR: +! last_save_nr = undo_read_4c(&bi); + break; + default: + /* field not supported, skip */ + while (--len >= 0) +! (void)undo_read_byte(&bi); + } + } + +*************** +*** 1758,1764 **** + goto error; + } + +! while ((c = get2c(fp)) == UF_HEADER_MAGIC) + { + if (num_read_uhps >= num_head) + { +--- 2035,2041 ---- + goto error; + } + +! while ((c = undo_read_2c(&bi)) == UF_HEADER_MAGIC) + { + if (num_read_uhps >= num_head) + { +*************** +*** 1766,1772 **** + goto error; + } + +! uhp = unserialize_uhp(fp, file_name); + if (uhp == NULL) + goto error; + uhp_table[num_read_uhps++] = uhp; +--- 2043,2049 ---- + goto error; + } + +! uhp = unserialize_uhp(&bi, file_name); + if (uhp == NULL) + goto error; + uhp_table[num_read_uhps++] = uhp; +*************** +*** 1898,1905 **** + + theend: + #ifdef FEAT_CRYPT +! if (do_decrypt) +! crypt_pop_state(); + #endif + if (fp != NULL) + fclose(fp); +--- 2175,2183 ---- + + theend: + #ifdef FEAT_CRYPT +! if (bi.bi_state != NULL) +! crypt_free_state(bi.bi_state); +! vim_free(bi.bi_buffer); + #endif + if (fp != NULL) + fclose(fp); +*** ../vim-7.4.398/src/testdir/test71.in 2013-07-01 20:47:58.000000000 +0200 +--- src/testdir/test71.in 2014-08-09 15:12:57.997364196 +0200 +*************** +*** 13,18 **** +--- 13,20 ---- + :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,41 **** +--- 38,55 ---- + :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,63 **** +--- 71,90 ---- + :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 +*** ../vim-7.4.398/src/testdir/test71.ok 2010-05-21 15:21:48.000000000 +0200 +--- src/testdir/test71.ok 2014-08-09 15:28:07.349357660 +0200 +*************** +*** 4,10 **** +--- 4,15 ---- + 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ábbccddeëff + asdfasdfasdf + 0001112223333 ++ abcdefghijklmnopqrstuvwxyz ++ !@#$%^&*()_+=-`~ +*** ../vim-7.4.398/src/testdir/test71a.in 2013-07-01 20:45:58.000000000 +0200 +--- src/testdir/test71a.in 2014-08-09 15:49:07.125348605 +0200 +*************** +*** 12,14 **** +--- 12,18 ---- + start of cm=blowfish bytes + VimCrypt~02!k)¾—#ÝSœõ=ºàÈ#¥M´†JÃAÍ¥M´†!€›õáÒ‚˜÷ Ú + end of cm=blowfish bytes ++ ++ start of cm=blowfish2 bytes ++ VimCrypt~03!ÑNã;ÓÀ ^C)÷.¶«FSà‹6Ò[T˧…ؾ9 2 Q³Ì@—ߚ­Ivª.ØÉîž`½$¯%Ð ++ end of cm=blowfish2 bytes +*** ../vim-7.4.398/src/testdir/test72.in 2014-03-12 16:51:35.060792541 +0100 +--- src/testdir/test72.in 2014-08-09 15:12:58.001364196 +0200 +*************** +*** 81,86 **** +--- 81,87 ---- + :" + :" With encryption, cryptmethod=blowfish + :e! Xtestfile ++ rubbish + :set undofile cm=blowfish + ggdGijan + feb +*************** +*** 100,105 **** +--- 101,132 ---- + :set key= + /bar + :.w >>test.out ++ 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 +*** ../vim-7.4.398/src/testdir/test72.ok 2012-01-04 19:04:17.000000000 +0100 +--- src/testdir/test72.ok 2014-08-09 15:12:58.001364196 +0200 +*************** +*** 25,27 **** +--- 25,31 ---- + apr + foo mar + mar ++ bar apr ++ apr ++ foo mar ++ mar +*** ../vim-7.4.398/src/version.c 2014-08-07 13:55:05.898639758 +0200 +--- src/version.c 2014-08-09 15:11:28.665364838 +0200 +*************** +*** 743,744 **** +--- 743,746 ---- + { /* Add new patch number below this line */ ++ /**/ ++ 399, + /**/ + +-- +hundred-and-one symptoms of being an internet addict: +16. You step out of your room and realize that your parents have moved and + you don't have a clue when it happened. + + /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ +/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ +\\\ an exciting new programming language -- http://www.Zimbu.org /// + \\\ help me help AIDS victims -- http://ICCF-Holland.org ///