| To: vim_dev@googlegroups.com |
| Subject: Patch 7.4.399 |
| Fcc: outbox |
| From: Bram Moolenaar <Bram@moolenaar.net> |
| 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 |
| |
| |
| |
| |
| |
| *** 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 |
| |
| |
| |
| *** 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 |
| |
| |
| |
| *** 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 \ |
| |
| |
| |
| *** 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); |
| } |
| |
| /* |
| |
| |
| |
| |
| --- 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 */ |
| |
| |
| |
| |
| --- 1,158 ---- |
| + /* vi:set ts=8 sts=4 sw=4: |
| + * |
| + * VIM - Vi IMproved by Bram Moolenaar |
| + * |
| + * Do ":help uganda" in Vim to read copying and usage conditions. |
| + * Do ":help credits" in Vim to see a list of people who contributed. |
| + * See README.txt for an overview of the Vim source code. |
| + */ |
| + |
| + /* |
| + * crypt_zip.c: Zip encryption support. |
| + */ |
| + #include "vim.h" |
| + |
| + #if defined(FEAT_CRYPT) || defined(PROTO) |
| + /* |
| + * Optional encryption support. |
| + * Mohsin Ahmed, mosh@sasi.com, 98-09-24 |
| + * Based on zip/crypt sources. |
| + * |
| + * NOTE FOR USA: Since 2000 exporting this code from the USA is allowed to |
| + * most countries. There are a few exceptions, but that still should not be a |
| + * problem since this code was originally created in Europe and India. |
| + */ |
| + |
| + /* Need a type that should be 32 bits. 64 also works but wastes space. */ |
| + # if VIM_SIZEOF_INT >= 4 |
| + typedef unsigned int u32_T; /* int is at least 32 bits */ |
| + # else |
| + typedef unsigned long u32_T; /* long should be 32 bits or more */ |
| + # endif |
| + |
| + /* The state of encryption, referenced by cryptstate_T. */ |
| + typedef struct { |
| + u32_T keys[3]; |
| + } zip_state_T; |
| + |
| + |
| + static void make_crc_tab __ARGS((void)); |
| + |
| + static u32_T crc_32_table[256]; |
| + |
| + /* |
| + * Fill the CRC table, if not done already. |
| + */ |
| + static void |
| + make_crc_tab() |
| + { |
| + u32_T s, t, v; |
| + static int done = FALSE; |
| + |
| + if (done) |
| + return; |
| + for (t = 0; t < 256; t++) |
| + { |
| + v = t; |
| + for (s = 0; s < 8; s++) |
| + v = (v >> 1) ^ ((v & 1) * (u32_T)0xedb88320L); |
| + crc_32_table[t] = v; |
| + } |
| + done = TRUE; |
| + } |
| + |
| + #define CRC32(c, b) (crc_32_table[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8)) |
| + |
| + /* |
| + * Return the next byte in the pseudo-random sequence. |
| + */ |
| + #define DECRYPT_BYTE_ZIP(keys, t) { \ |
| + short_u temp = (short_u)keys[2] | 2; \ |
| + t = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff); \ |
| + } |
| + |
| + /* |
| + * Update the encryption keys with the next byte of plain text. |
| + */ |
| + #define UPDATE_KEYS_ZIP(keys, c) { \ |
| + keys[0] = CRC32(keys[0], (c)); \ |
| + keys[1] += keys[0] & 0xff; \ |
| + keys[1] = keys[1] * 134775813L + 1; \ |
| + keys[2] = CRC32(keys[2], (int)(keys[1] >> 24)); \ |
| + } |
| + |
| + /* |
| + * Initialize for encryption/decryption. |
| + */ |
| + void |
| + crypt_zip_init(state, key, salt, salt_len, seed, seed_len) |
| + cryptstate_T *state; |
| + char_u *key; |
| + char_u *salt UNUSED; |
| + int salt_len UNUSED; |
| + char_u *seed UNUSED; |
| + int seed_len UNUSED; |
| + { |
| + char_u *p; |
| + zip_state_T *zs; |
| + |
| + zs = (zip_state_T *)alloc(sizeof(zip_state_T)); |
| + state->method_state = zs; |
| + |
| + make_crc_tab(); |
| + zs->keys[0] = 305419896L; |
| + zs->keys[1] = 591751049L; |
| + zs->keys[2] = 878082192L; |
| + for (p = key; *p != NUL; ++p) |
| + { |
| + UPDATE_KEYS_ZIP(zs->keys, (int)*p); |
| + } |
| + } |
| + |
| + /* |
| + * Encrypt "from[len]" into "to[len]". |
| + * "from" and "to" can be equal to encrypt in place. |
| + */ |
| + void |
| + crypt_zip_encode(state, from, len, to) |
| + cryptstate_T *state; |
| + char_u *from; |
| + size_t len; |
| + char_u *to; |
| + { |
| + zip_state_T *zs = state->method_state; |
| + size_t i; |
| + int ztemp, t; |
| + |
| + for (i = 0; i < len; ++i) |
| + { |
| + ztemp = from[i]; |
| + DECRYPT_BYTE_ZIP(zs->keys, t); |
| + UPDATE_KEYS_ZIP(zs->keys, ztemp); |
| + to[i] = t ^ ztemp; |
| + } |
| + } |
| + |
| + /* |
| + * Decrypt "from[len]" into "to[len]". |
| + */ |
| + void |
| + crypt_zip_decode(state, from, len, to) |
| + cryptstate_T *state; |
| + char_u *from; |
| + size_t len; |
| + char_u *to; |
| + { |
| + zip_state_T *zs = state->method_state; |
| + size_t i; |
| + short_u temp; |
| + |
| + for (i = 0; i < len; ++i) |
| + { |
| + temp = (short_u)zs->keys[2] | 2; |
| + temp = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff); |
| + UPDATE_KEYS_ZIP(zs->keys, to[i] = from[i] ^ temp); |
| + } |
| + } |
| + |
| + #endif /* FEAT_CRYPT */ |
| |
| |
| |
| *** 11506,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 |
| |
| |
| |
| |
| *** 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); |
| |
| |
| |
| *** 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 ---- |
| |
| |
| |
| *** 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 |
| |
| |
| |
| *** 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 |
| |
| |
| |
| *** 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; |
| } |
| } |
| } |
| |
| |
| |
| *** 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)); |
| } |
| } |
| } |
| |
| |
| |
| *** 70,75 **** |
| --- 70,77 ---- |
| |
| # ifdef FEAT_CRYPT |
| # include "blowfish.pro" |
| + # include "crypt.pro" |
| + # include "crypt_zip.pro" |
| # endif |
| # include "buffer.pro" |
| # include "charset.pro" |
| |
| |
| |
| *** 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 : */ |
| |
| |
| |
| |
| --- 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 : */ |
| |
| |
| |
| |
| --- 1,5 ---- |
| + /* crypt_zip.c */ |
| + void crypt_zip_init __ARGS((cryptstate_T *state, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len)); |
| + void crypt_zip_encode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to)); |
| + void crypt_zip_decode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to)); |
| + /* vim: set ft=c : */ |
| |
| |
| |
| *** 4,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 ---- |
| |
| |
| |
| *** 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 : */ |
| |
| |
| |
| *** 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 |
| |
| |
| |
| *** 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); |
| |
| |
| |
| *** 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 |
| |
| |
| |
| *** 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 |
| |
| |
| |
| *** 25,27 **** |
| --- 25,31 ---- |
| apr |
| foo mar |
| mar |
| + bar apr |
| + apr |
| + foo mar |
| + mar |
| diff -up src/testdir/test71.ok.kh src/testdir/test71.ok |
| |
| |
| @@ -4,7 +4,12 @@ line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
| OK 01234567890123456789012345678901234567 |
| OK line 2 foo bar blah |
| OK line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
| +OK OK 01234567890123456789012345678901234567 |
| +OK OK line 2 foo bar blah |
| +OK OK line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
| 1234567890 |
| aábbccddeëff |
| asdfasdfasdf |
| 0001112223333 |
| +abcdefghijklmnopqrstuvwxyz |
| +!@#$%^&*()_+=-`~ |
| diff -up src/testdir/test71a.in.kh src/testdir/test71a.in |
| |
| |
| @@ -12,3 +12,7 @@ end of cm=zip bytes |
| 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Â2Q³Ã@ÂÃÂÂIvª.ÃÃîÂ`½$¯%à |
| +end of cm=blowfish2 bytes |
| |
| |
| |
| *** 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 /// |