Blame SOURCES/vim-7.4-blowfish2.patch

8b9a1c
diff -up vim74/runtime/doc/editing.txt.blowfish2 vim74/runtime/doc/editing.txt
8b9a1c
--- vim74/runtime/doc/editing.txt.blowfish2	2013-08-10 13:24:53.000000000 +0200
8b9a1c
+++ vim74/runtime/doc/editing.txt	2017-09-05 14:47:34.915912305 +0200
8b9a1c
@@ -1364,8 +1364,13 @@ The text in the swap file and the undo f
8b9a1c
 
8b9a1c
 Note: The text in memory is not encrypted.  A system administrator may be able
8b9a1c
 to see your text while you are editing it.  When filtering text with
8b9a1c
-":!filter" or using ":w !command" the text is not encrypted, this may reveal
8b9a1c
-it to others.  The 'viminfo' file is not encrypted.
8b9a1c
+":!filter" or using ":w !command" the text is also not encrypted, this may
8b9a1c
+reveal it to others.  The 'viminfo' file is not encrypted.
8b9a1c
+
8b9a1c
+You could do this to edit very secret text: >
8b9a1c
+       :set noundofile viminfo=
8b9a1c
+       :noswapfile edit secrets.txt
8b9a1c
+Keep in mind that without a swap file you risk loosing your work in a crash.
8b9a1c
 
8b9a1c
 WARNING: If you make a typo when entering the key and then write the file and
8b9a1c
 exit, the text will be lost!
8b9a1c
@@ -1392,18 +1397,24 @@ To disable the encryption, reset the 'ke
8b9a1c
 	:set key=
8b9a1c
 
8b9a1c
 You can use the 'cryptmethod' option to select the type of encryption, use one
8b9a1c
-of these two: >
8b9a1c
-	:setlocal cm=zip       " weak method, backwards compatible
8b9a1c
-	:setlocal cm=blowfish  " strong method
8b9a1c
+of these: >
8b9a1c
+       :setlocal cm=zip        " weak method, backwards compatible
8b9a1c
+       :setlocal cm=blowfish   " method with flaws
8b9a1c
+       :setlocal cm=blowfish2  " medium strong method
8b9a1c
+
8b9a1c
 Do this before writing the file.  When reading an encrypted file it will be
8b9a1c
 set automatically to the method used when that file was written.  You can
8b9a1c
 change 'cryptmethod' before writing that file to change the method.
8b9a1c
 To set the default method, used for new files, use one of these in your
8b9a1c
 |vimrc| file: >
8b9a1c
 	set cm=zip
8b9a1c
-	set cm=blowfish
8b9a1c
+        set cm=blowfish2
8b9a1c
+Use the first one if you need to be compatible with Vim 7.2 and older.  Using
8b9a1c
+"blowfish2" is highly recommended if you can use a Vim version that supports
8b9a1c
+it.
8b9a1c
+
8b9a1c
 The message given for reading and writing a file will show "[crypted]" when
8b9a1c
-using zip, "[blowfish]" when using blowfish.
8b9a1c
+using zip, "[blowfish]" when using blowfish, etc.
8b9a1c
 
8b9a1c
 When writing an undo file, the same key and method will be used for the text
8b9a1c
 in the undo file. |persistent-undo|.
8b9a1c
@@ -1438,7 +1449,7 @@ lines to "/etc/magic", "/usr/share/misc/
8b9a1c
      0	string	VimCrypt~	Vim encrypted file
8b9a1c
      >9	string	01	- "zip" cryptmethod
8b9a1c
      >9	string	02	- "blowfish" cryptmethod
8b9a1c
-
8b9a1c
+     >9        string  03      - "blowfish2" cryptmethod
8b9a1c
 
8b9a1c
 Notes:
8b9a1c
 - Encryption is not possible when doing conversion with 'charconvert'.
8b9a1c
@@ -1462,6 +1473,10 @@ Notes:
8b9a1c
 - Pkzip uses the same encryption as 'cryptmethod' "zip", and US Govt has no
8b9a1c
   objection to its export.  Pkzip's public file APPNOTE.TXT describes this
8b9a1c
   algorithm in detail.
8b9a1c
+- The implementation of 'cryptmethod' "blowfish" has a flaw.  It is possible to
8b9a1c
+  crack the first 64 bytes of a file and in some circumstances more of the
8b9a1c
+  file. Use of it is not recommended, but it's still the strongest method
8b9a1c
+  supported by Vim 7.3 and 7.4.  The "zip" method is even weaker.
8b9a1c
 - Vim originates from the Netherlands.  That is where the sources come from.
8b9a1c
   Thus the encryption code is not exported from the USA.
8b9a1c
 
8b9a1c
diff -up vim74/runtime/doc/options.txt.blowfish2 vim74/runtime/doc/options.txt
8b9a1c
--- vim74/runtime/doc/options.txt.blowfish2	2017-09-05 14:47:33.976919884 +0200
8b9a1c
+++ vim74/runtime/doc/options.txt	2017-09-05 14:47:34.925912224 +0200
8b9a1c
@@ -2197,10 +2197,18 @@ A jump table for the options with a shor
8b9a1c
 	   zip		PkZip compatible method.  A weak kind of encryption.
8b9a1c
 			Backwards compatible with Vim 7.2 and older.
8b9a1c
 							*blowfish*
8b9a1c
-	   blowfish	Blowfish method.  Strong encryption.  Requires Vim 7.3
8b9a1c
-			or later, files can NOT be read by Vim 7.2 and older.
8b9a1c
-			This adds a "seed" to the file, every time you write
8b9a1c
-			the file the encrypted bytes will be different.
8b9a1c
+          blowfish     Blowfish method.  Medium strong encryption but it has
8b9a1c
+                       an implementation flaw.  Requires Vim 7.3 or later,
8b9a1c
+                       files can NOT be read by Vim 7.2 and older.  This adds
8b9a1c
+                       a "seed" to the file, every time you write the file
8b9a1c
+                       the encrypted bytes will be different.
8b9a1c
+                                                       *blowfish2*
8b9a1c
+          blowfish2    Blowfish method.  Medium strong encryption.  Requires
8b9a1c
+                       Vim 7.4.399 or later, files can NOT be read by Vim 7.3
8b9a1c
+                       and older.  This adds a "seed" to the file, every time
8b9a1c
+                       you write the file the encrypted bytes will be
8b9a1c
+                       different.  The whole undo file is encrypted, not just
8b9a1c
+                       the pieces of text.
8b9a1c
 
8b9a1c
 	When reading an encrypted file 'cryptmethod' will be set automatically
8b9a1c
 	to the detected method of the file being read.  Thus if you write it
8b9a1c
diff -up vim74/src/blowfish.c.blowfish2 vim74/src/blowfish.c
8b9a1c
--- vim74/src/blowfish.c.blowfish2	2010-12-17 19:58:18.000000000 +0100
8b9a1c
+++ vim74/src/blowfish.c	2017-09-05 14:47:34.926912216 +0200
8b9a1c
@@ -9,17 +9,25 @@
8b9a1c
  * Blowfish encryption for Vim; in Blowfish output feedback mode.
8b9a1c
  * Contributed by Mohsin Ahmed, http://www.cs.albany.edu/~mosh
8b9a1c
  * Based on http://www.schneier.com/blowfish.html by Bruce Schneier.
8b9a1c
+ *
8b9a1c
+ * There are two variants:
8b9a1c
+ * - The old one "blowfish" has a flaw which makes it much easier to crack the
8b9a1c
+ *   key.  To see this, make a text file with one line of 1000 "x" characters
8b9a1c
+ *   and write it encrypted.  Use "xxd" to inspect the bytes in the file.  You
8b9a1c
+ *   will see that a block of 8 bytes repeats 8 times.
8b9a1c
+ * - The new one "blowfish2" is better.  It uses an 8 byte CFB to avoid the
8b9a1c
+ *   repeats.
8b9a1c
  */
8b9a1c
 
8b9a1c
 #include "vim.h"
8b9a1c
 
8b9a1c
-#if defined(FEAT_CRYPT)
8b9a1c
+#if defined(FEAT_CRYPT) || defined(PROTO)
8b9a1c
 
8b9a1c
 #define ARRAY_LENGTH(A)      (sizeof(A)/sizeof(A[0]))
8b9a1c
 
8b9a1c
 #define BF_BLOCK    8
8b9a1c
 #define BF_BLOCK_MASK 7
8b9a1c
-#define BF_OFB_LEN  (8*(BF_BLOCK))
8b9a1c
+#define BF_MAX_CFB_LEN  (8 * BF_BLOCK)
8b9a1c
 
8b9a1c
 typedef union {
8b9a1c
     UINT32_T ul[2];
8b9a1c
@@ -37,14 +45,26 @@ typedef union {
8b9a1c
 # endif
8b9a1c
 #endif
8b9a1c
 
8b9a1c
-static void bf_e_block __ARGS((UINT32_T *p_xl, UINT32_T *p_xr));
8b9a1c
-static void bf_e_cblock __ARGS((char_u *block));
8b9a1c
-static int bf_check_tables __ARGS((UINT32_T a_ipa[18], UINT32_T a_sbi[4][256], UINT32_T val));
8b9a1c
+/* The state of encryption, referenced by cryptstate_T. */
8b9a1c
+typedef struct {
8b9a1c
+    UINT32_T	pax[18];	    /* P-array */
8b9a1c
+    UINT32_T	sbx[4][256];	    /* S-boxes */
8b9a1c
+    int		randbyte_offset;
8b9a1c
+    int		update_offset;
8b9a1c
+    char_u	cfb_buffer[BF_MAX_CFB_LEN]; /* up to 64 bytes used */
8b9a1c
+    int		cfb_len;	    /* size of cfb_buffer actually used */
8b9a1c
+} bf_state_T;
8b9a1c
+
8b9a1c
+
8b9a1c
+static void bf_e_block __ARGS((bf_state_T *state, UINT32_T *p_xl, UINT32_T *p_xr));
8b9a1c
+static void bf_e_cblock __ARGS((bf_state_T *state, char_u *block));
8b9a1c
+static int bf_check_tables __ARGS((UINT32_T pax[18], UINT32_T sbx[4][256], UINT32_T val));
8b9a1c
 static int bf_self_test __ARGS((void));
8b9a1c
+static void bf_key_init __ARGS((bf_state_T *state, char_u *password, char_u *salt, int salt_len));
8b9a1c
+static void bf_cfb_init __ARGS((bf_state_T *state, char_u *seed, int seed_len));
8b9a1c
 
8b9a1c
 /* Blowfish code */
8b9a1c
-static UINT32_T pax[18];
8b9a1c
-static UINT32_T ipa[18] = {
8b9a1c
+static UINT32_T pax_init[18] = {
8b9a1c
     0x243f6a88u, 0x85a308d3u, 0x13198a2eu,
8b9a1c
     0x03707344u, 0xa4093822u, 0x299f31d0u,
8b9a1c
     0x082efa98u, 0xec4e6c89u, 0x452821e6u,
8b9a1c
@@ -53,8 +73,7 @@ static UINT32_T ipa[18] = {
8b9a1c
     0xb5470917u, 0x9216d5d9u, 0x8979fb1bu
8b9a1c
 };
8b9a1c
 
8b9a1c
-static UINT32_T sbx[4][256];
8b9a1c
-static UINT32_T sbi[4][256] = {
8b9a1c
+static UINT32_T sbx_init[4][256] = {
8b9a1c
    {0xd1310ba6u, 0x98dfb5acu, 0x2ffd72dbu, 0xd01adfb7u,
8b9a1c
     0xb8e1afedu, 0x6a267e96u, 0xba7c9045u, 0xf12c7f99u,
8b9a1c
     0x24a19947u, 0xb3916cf7u, 0x0801f2e2u, 0x858efc16u,
8b9a1c
@@ -314,33 +333,40 @@ static UINT32_T sbi[4][256] = {
8b9a1c
  }
8b9a1c
 };
8b9a1c
 
8b9a1c
-
8b9a1c
 #define F1(i) \
8b9a1c
-    xl ^= pax[i]; \
8b9a1c
-    xr ^= ((sbx[0][xl >> 24] + \
8b9a1c
-    sbx[1][(xl & 0xFF0000) >> 16]) ^ \
8b9a1c
-    sbx[2][(xl & 0xFF00) >> 8]) + \
8b9a1c
-    sbx[3][xl & 0xFF];
8b9a1c
+    xl ^= bfs->pax[i]; \
8b9a1c
+    xr ^= ((bfs->sbx[0][xl >> 24] + \
8b9a1c
+    bfs->sbx[1][(xl & 0xFF0000) >> 16]) ^ \
8b9a1c
+    bfs->sbx[2][(xl & 0xFF00) >> 8]) + \
8b9a1c
+    bfs->sbx[3][xl & 0xFF];
8b9a1c
 
8b9a1c
 #define F2(i) \
8b9a1c
-    xr ^= pax[i]; \
8b9a1c
-    xl ^= ((sbx[0][xr >> 24] + \
8b9a1c
-    sbx[1][(xr & 0xFF0000) >> 16]) ^ \
8b9a1c
-    sbx[2][(xr & 0xFF00) >> 8]) + \
8b9a1c
-    sbx[3][xr & 0xFF];
8b9a1c
-
8b9a1c
+    xr ^= bfs->pax[i]; \
8b9a1c
+    xl ^= ((bfs->sbx[0][xr >> 24] + \
8b9a1c
+    bfs->sbx[1][(xr & 0xFF0000) >> 16]) ^ \
8b9a1c
+    bfs->sbx[2][(xr & 0xFF00) >> 8]) + \
8b9a1c
+    bfs->sbx[3][xr & 0xFF];
8b9a1c
 
8b9a1c
     static void
8b9a1c
-bf_e_block(p_xl, p_xr)
8b9a1c
+bf_e_block(bfs, p_xl, p_xr)
8b9a1c
+    bf_state_T *bfs;
8b9a1c
     UINT32_T *p_xl;
8b9a1c
     UINT32_T *p_xr;
8b9a1c
 {
8b9a1c
-    UINT32_T temp, xl = *p_xl, xr = *p_xr;
8b9a1c
-
8b9a1c
-    F1(0) F2(1) F1(2) F2(3) F1(4) F2(5) F1(6) F2(7)
8b9a1c
-    F1(8) F2(9) F1(10) F2(11) F1(12) F2(13) F1(14) F2(15)
8b9a1c
-    xl ^= pax[16];
8b9a1c
-    xr ^= pax[17];
8b9a1c
+    UINT32_T temp;
8b9a1c
+    UINT32_T xl = *p_xl;
8b9a1c
+    UINT32_T xr = *p_xr;
8b9a1c
+
8b9a1c
+    F1(0) F2(1)
8b9a1c
+    F1(2) F2(3)
8b9a1c
+    F1(4) F2(5)
8b9a1c
+    F1(6) F2(7)
8b9a1c
+    F1(8) F2(9)
8b9a1c
+    F1(10) F2(11)
8b9a1c
+    F1(12) F2(13)
8b9a1c
+    F1(14) F2(15)
8b9a1c
+    xl ^= bfs->pax[16];
8b9a1c
+    xr ^= bfs->pax[17];
8b9a1c
     temp = xl;
8b9a1c
     xl = xr;
8b9a1c
     xr = temp;
8b9a1c
@@ -348,23 +374,6 @@ bf_e_block(p_xl, p_xr)
8b9a1c
     *p_xr = xr;
8b9a1c
 }
8b9a1c
 
8b9a1c
-#if 0  /* not used */
8b9a1c
-    static void
8b9a1c
-bf_d_block(p_xl, p_xr)
8b9a1c
-    UINT32_T *p_xl;
8b9a1c
-    UINT32_T *p_xr;
8b9a1c
-{
8b9a1c
-    UINT32_T temp, xl = *p_xl, xr = *p_xr;
8b9a1c
-    F1(17) F2(16) F1(15) F2(14) F1(13) F2(12) F1(11) F2(10)
8b9a1c
-    F1(9) F2(8) F1(7) F2(6) F1(5) F2(4) F1(3) F2(2)
8b9a1c
-    xl ^= pax[1];
8b9a1c
-    xr ^= pax[0];
8b9a1c
-    temp = xl; xl = xr; xr = temp;
8b9a1c
-    *p_xl = xl; *p_xr = xr;
8b9a1c
-}
8b9a1c
-#endif
8b9a1c
-
8b9a1c
-
8b9a1c
 #ifdef WORDS_BIGENDIAN
8b9a1c
 # define htonl2(x) \
8b9a1c
     x = ((((x) &     0xffL) << 24) | (((x) & 0xff00L)     <<  8) | \
8b9a1c
@@ -374,7 +383,8 @@ bf_d_block(p_xl, p_xr)
8b9a1c
 #endif
8b9a1c
 
8b9a1c
     static void
8b9a1c
-bf_e_cblock(block)
8b9a1c
+bf_e_cblock(bfs, block)
8b9a1c
+    bf_state_T *bfs;
8b9a1c
     char_u *block;
8b9a1c
 {
8b9a1c
     block8	bk;
8b9a1c
@@ -382,35 +392,22 @@ bf_e_cblock(block)
8b9a1c
     memcpy(bk.uc, block, 8);
8b9a1c
     htonl2(bk.ul[0]);
8b9a1c
     htonl2(bk.ul[1]);
8b9a1c
-    bf_e_block(&bk.ul[0], &bk.ul[1]);
8b9a1c
+    bf_e_block(bfs, &bk.ul[0], &bk.ul[1]);
8b9a1c
     htonl2(bk.ul[0]);
8b9a1c
     htonl2(bk.ul[1]);
8b9a1c
     memcpy(block, bk.uc, 8);
8b9a1c
 }
8b9a1c
 
8b9a1c
-#if 0  /* not used */
8b9a1c
-    void
8b9a1c
-bf_d_cblock(block)
8b9a1c
-    char_u *block;
8b9a1c
-{
8b9a1c
-    block8 bk;
8b9a1c
-    memcpy(bk.uc, block, 8);
8b9a1c
-    htonl2(bk.ul[0]); htonl2(bk.ul[1]);
8b9a1c
-    bf_d_block(&bk.ul[0], &bk.ul[1]);
8b9a1c
-    htonl2(bk.ul[0]); htonl2(bk.ul[1]);
8b9a1c
-    memcpy(block, bk.uc, 8);
8b9a1c
-}
8b9a1c
-#endif
8b9a1c
-
8b9a1c
 /*
8b9a1c
  * Initialize the crypt method using "password" as the encryption key and
8b9a1c
  * "salt[salt_len]" as the salt.
8b9a1c
  */
8b9a1c
-    void
8b9a1c
-bf_key_init(password, salt, salt_len)
8b9a1c
-    char_u *password;
8b9a1c
-    char_u *salt;
8b9a1c
-    int    salt_len;
8b9a1c
+    static void
8b9a1c
+bf_key_init(bfs, password, salt, salt_len)
8b9a1c
+    bf_state_T	*bfs;
8b9a1c
+    char_u	*password;
8b9a1c
+    char_u	*salt;
8b9a1c
+    int		salt_len;
8b9a1c
 {
8b9a1c
     int      i, j, keypos = 0;
8b9a1c
     unsigned u;
8b9a1c
@@ -418,7 +415,7 @@ bf_key_init(password, salt, salt_len)
8b9a1c
     char_u   *key;
8b9a1c
     int      keylen;
8b9a1c
 
8b9a1c
-    /* Process the key 1000 times.
8b9a1c
+    /* Process the key 1001 times.
8b9a1c
      * See http://en.wikipedia.org/wiki/Key_strengthening. */
8b9a1c
     key = sha256_key(password, salt, salt_len);
8b9a1c
     for (i = 0; i < 1000; i++)
8b9a1c
@@ -437,52 +434,54 @@ bf_key_init(password, salt, salt_len)
8b9a1c
 	key[i] = u;
8b9a1c
     }
8b9a1c
 
8b9a1c
-    mch_memmove(sbx, sbi, 4 * 4 * 256);
8b9a1c
+    /* Use "key" to initialize the P-array ("pax") and S-boxes ("sbx") of
8b9a1c
+     * Blowfish. */
8b9a1c
+    mch_memmove(bfs->sbx, sbx_init, 4 * 4 * 256);
8b9a1c
 
8b9a1c
     for (i = 0; i < 18; ++i)
8b9a1c
     {
8b9a1c
 	val = 0;
8b9a1c
 	for (j = 0; j < 4; ++j)
8b9a1c
 	    val = (val << 8) | key[keypos++ % keylen];
8b9a1c
-	pax[i] = ipa[i] ^ val;
8b9a1c
+	bfs->pax[i] = pax_init[i] ^ val;
8b9a1c
     }
8b9a1c
 
8b9a1c
     data_l = data_r = 0;
8b9a1c
     for (i = 0; i < 18; i += 2)
8b9a1c
     {
8b9a1c
-	bf_e_block(&data_l, &data_r);
8b9a1c
-	pax[i + 0] = data_l;
8b9a1c
-	pax[i + 1] = data_r;
8b9a1c
+	bf_e_block(bfs, &data_l, &data_r);
8b9a1c
+	bfs->pax[i + 0] = data_l;
8b9a1c
+	bfs->pax[i + 1] = data_r;
8b9a1c
     }
8b9a1c
 
8b9a1c
     for (i = 0; i < 4; ++i)
8b9a1c
     {
8b9a1c
 	for (j = 0; j < 256; j += 2)
8b9a1c
 	{
8b9a1c
-	    bf_e_block(&data_l, &data_r);
8b9a1c
-	    sbx[i][j + 0] = data_l;
8b9a1c
-	    sbx[i][j + 1] = data_r;
8b9a1c
+	    bf_e_block(bfs, &data_l, &data_r);
8b9a1c
+	    bfs->sbx[i][j + 0] = data_l;
8b9a1c
+	    bfs->sbx[i][j + 1] = data_r;
8b9a1c
 	}
8b9a1c
     }
8b9a1c
 }
8b9a1c
 
8b9a1c
 /*
8b9a1c
- * BF Self test for corrupted tables or instructions
8b9a1c
+ * Blowfish self-test for corrupted tables or instructions.
8b9a1c
  */
8b9a1c
     static int
8b9a1c
-bf_check_tables(a_ipa, a_sbi, val)
8b9a1c
-    UINT32_T a_ipa[18];
8b9a1c
-    UINT32_T a_sbi[4][256];
8b9a1c
+bf_check_tables(pax, sbx, val)
8b9a1c
+    UINT32_T pax[18];
8b9a1c
+    UINT32_T sbx[4][256];
8b9a1c
     UINT32_T val;
8b9a1c
 {
8b9a1c
     int i, j;
8b9a1c
     UINT32_T c = 0;
8b9a1c
 
8b9a1c
     for (i = 0; i < 18; i++)
8b9a1c
-	c ^= a_ipa[i];
8b9a1c
+	c ^= pax[i];
8b9a1c
     for (i = 0; i < 4; i++)
8b9a1c
 	for (j = 0; j < 256; j++)
8b9a1c
-	    c ^= a_sbi[i][j];
8b9a1c
+	    c ^= sbx[i][j];
8b9a1c
     return c == val;
8b9a1c
 }
8b9a1c
 
8b9a1c
@@ -520,6 +519,10 @@ bf_self_test()
8b9a1c
     int    err = 0;
8b9a1c
     block8 bk;
8b9a1c
     UINT32_T ui = 0xffffffffUL;
8b9a1c
+    bf_state_T state;
8b9a1c
+
8b9a1c
+    vim_memset(&state, 0, sizeof(bf_state_T));
8b9a1c
+    state.cfb_len = BF_MAX_CFB_LEN;
8b9a1c
 
8b9a1c
     /* We can't simply use sizeof(UINT32_T), it would generate a compiler
8b9a1c
      * warning. */
8b9a1c
@@ -528,21 +531,21 @@ bf_self_test()
8b9a1c
 	EMSG(_("E820: sizeof(uint32_t) != 4"));
8b9a1c
     }
8b9a1c
 
8b9a1c
-    if (!bf_check_tables(ipa, sbi, 0x6ffa520a))
8b9a1c
+    if (!bf_check_tables(pax_init, sbx_init, 0x6ffa520a))
8b9a1c
 	err++;
8b9a1c
 
8b9a1c
     bn = ARRAY_LENGTH(bf_test_data);
8b9a1c
     for (i = 0; i < bn; i++)
8b9a1c
     {
8b9a1c
-	bf_key_init((char_u *)(bf_test_data[i].password),
8b9a1c
+	bf_key_init(&state, (char_u *)(bf_test_data[i].password),
8b9a1c
 		    bf_test_data[i].salt,
8b9a1c
 		    (int)STRLEN(bf_test_data[i].salt));
8b9a1c
-	if (!bf_check_tables(pax, sbx, bf_test_data[i].keysum))
8b9a1c
+	if (!bf_check_tables(state.pax, state.sbx, bf_test_data[i].keysum))
8b9a1c
 	    err++;
8b9a1c
 
8b9a1c
 	/* Don't modify bf_test_data[i].plaintxt, self test is idempotent. */
8b9a1c
 	memcpy(bk.uc, bf_test_data[i].plaintxt, 8);
8b9a1c
-	bf_e_cblock(bk.uc);
8b9a1c
+	bf_e_cblock(&state, bk.uc);
8b9a1c
 	if (memcmp(bk.uc, bf_test_data[i].cryptxt, 8) != 0)
8b9a1c
 	{
8b9a1c
 	    if (err == 0 && memcmp(bk.uc, bf_test_data[i].badcryptxt, 8) == 0)
8b9a1c
@@ -554,43 +557,43 @@ bf_self_test()
8b9a1c
     return err > 0 ? FAIL : OK;
8b9a1c
 }
8b9a1c
 
8b9a1c
-/* Output feedback mode. */
8b9a1c
-static int randbyte_offset = 0;
8b9a1c
-static int update_offset = 0;
8b9a1c
-static char_u ofb_buffer[BF_OFB_LEN]; /* 64 bytes */
8b9a1c
+/*
8b9a1c
+ * CFB: Cipher Feedback Mode.
8b9a1c
+ */
8b9a1c
 
8b9a1c
 /*
8b9a1c
- * Initialize with seed "iv[iv_len]".
8b9a1c
+ * Initialize with seed "seed[seed_len]".
8b9a1c
  */
8b9a1c
-    void
8b9a1c
-bf_ofb_init(iv, iv_len)
8b9a1c
-    char_u *iv;
8b9a1c
-    int    iv_len;
8b9a1c
+    static void
8b9a1c
+bf_cfb_init(bfs, seed, seed_len)
8b9a1c
+    bf_state_T	*bfs;
8b9a1c
+    char_u	*seed;
8b9a1c
+    int		seed_len;
8b9a1c
 {
8b9a1c
     int i, mi;
8b9a1c
 
8b9a1c
-    randbyte_offset = update_offset = 0;
8b9a1c
-    vim_memset(ofb_buffer, 0, BF_OFB_LEN);
8b9a1c
-    if (iv_len > 0)
8b9a1c
+    bfs->randbyte_offset = bfs->update_offset = 0;
8b9a1c
+    vim_memset(bfs->cfb_buffer, 0, bfs->cfb_len);
8b9a1c
+    if (seed_len > 0)
8b9a1c
     {
8b9a1c
-	mi = iv_len > BF_OFB_LEN ? iv_len : BF_OFB_LEN;
8b9a1c
+	mi = seed_len > bfs->cfb_len ? seed_len : bfs->cfb_len;
8b9a1c
 	for (i = 0; i < mi; i++)
8b9a1c
-	    ofb_buffer[i % BF_OFB_LEN] ^= iv[i % iv_len];
8b9a1c
+	    bfs->cfb_buffer[i % bfs->cfb_len] ^= seed[i % seed_len];
8b9a1c
     }
8b9a1c
 }
8b9a1c
 
8b9a1c
-#define BF_OFB_UPDATE(c) { \
8b9a1c
-    ofb_buffer[update_offset] ^= (char_u)c; \
8b9a1c
-    if (++update_offset == BF_OFB_LEN) \
8b9a1c
-	update_offset = 0; \
8b9a1c
+#define BF_CFB_UPDATE(bfs, c) { \
8b9a1c
+    bfs->cfb_buffer[bfs->update_offset] ^= (char_u)c; \
8b9a1c
+    if (++bfs->update_offset == bfs->cfb_len) \
8b9a1c
+	bfs->update_offset = 0; \
8b9a1c
 }
8b9a1c
 
8b9a1c
-#define BF_RANBYTE(t) { \
8b9a1c
-    if ((randbyte_offset & BF_BLOCK_MASK) == 0) \
8b9a1c
-	bf_e_cblock(&ofb_buffer[randbyte_offset]); \
8b9a1c
-    t = ofb_buffer[randbyte_offset]; \
8b9a1c
-    if (++randbyte_offset == BF_OFB_LEN) \
8b9a1c
-	randbyte_offset = 0; \
8b9a1c
+#define BF_RANBYTE(bfs, t) { \
8b9a1c
+    if ((bfs->randbyte_offset & BF_BLOCK_MASK) == 0) \
8b9a1c
+	bf_e_cblock(bfs, &(bfs->cfb_buffer[bfs->randbyte_offset])); \
8b9a1c
+    t = bfs->cfb_buffer[bfs->randbyte_offset]; \
8b9a1c
+    if (++bfs->randbyte_offset == bfs->cfb_len) \
8b9a1c
+	bfs->randbyte_offset = 0; \
8b9a1c
 }
8b9a1c
 
8b9a1c
 /*
8b9a1c
@@ -598,90 +601,69 @@ bf_ofb_init(iv, iv_len)
8b9a1c
  * "from" and "to" can be equal to encrypt in place.
8b9a1c
  */
8b9a1c
     void
8b9a1c
-bf_crypt_encode(from, len, to)
8b9a1c
+crypt_blowfish_encode(state, from, len, to)
8b9a1c
+    cryptstate_T *state;
8b9a1c
     char_u	*from;
8b9a1c
     size_t	len;
8b9a1c
     char_u	*to;
8b9a1c
 {
8b9a1c
+    bf_state_T *bfs = state->method_state;
8b9a1c
     size_t	i;
8b9a1c
     int		ztemp, t;
8b9a1c
 
8b9a1c
     for (i = 0; i < len; ++i)
8b9a1c
     {
8b9a1c
 	ztemp = from[i];
8b9a1c
-	BF_RANBYTE(t);
8b9a1c
-	BF_OFB_UPDATE(ztemp);
8b9a1c
+	BF_RANBYTE(bfs, t);
8b9a1c
+	BF_CFB_UPDATE(bfs, ztemp);
8b9a1c
 	to[i] = t ^ ztemp;
8b9a1c
     }
8b9a1c
 }
8b9a1c
 
8b9a1c
 /*
8b9a1c
- * Decrypt "ptr[len]" in place.
8b9a1c
+ * Decrypt "from[len]" into "to[len]".
8b9a1c
  */
8b9a1c
     void
8b9a1c
-bf_crypt_decode(ptr, len)
8b9a1c
-    char_u	*ptr;
8b9a1c
-    long	len;
8b9a1c
+crypt_blowfish_decode(state, from, len, to)
8b9a1c
+    cryptstate_T *state;
8b9a1c
+    char_u	*from;
8b9a1c
+    size_t	len;
8b9a1c
+    char_u	*to;
8b9a1c
 {
8b9a1c
-    char_u	*p;
8b9a1c
+    bf_state_T *bfs = state->method_state;
8b9a1c
+    size_t	i;
8b9a1c
     int		t;
8b9a1c
 
8b9a1c
-    for (p = ptr; p < ptr + len; ++p)
8b9a1c
+    for (i = 0; i < len; ++i)
8b9a1c
     {
8b9a1c
-	BF_RANBYTE(t);
8b9a1c
-	*p ^= t;
8b9a1c
-	BF_OFB_UPDATE(*p);
8b9a1c
+	BF_RANBYTE(bfs, t);
8b9a1c
+	to[i] = from[i] ^ t;
8b9a1c
+	BF_CFB_UPDATE(bfs, to[i]);
8b9a1c
     }
8b9a1c
 }
8b9a1c
 
8b9a1c
-/*
8b9a1c
- * Initialize the encryption keys and the random header according to
8b9a1c
- * the given password.
8b9a1c
- */
8b9a1c
     void
8b9a1c
-bf_crypt_init_keys(passwd)
8b9a1c
-    char_u *passwd;		/* password string with which to modify keys */
8b9a1c
-{
8b9a1c
-    char_u *p;
8b9a1c
-
8b9a1c
-    for (p = passwd; *p != NUL; ++p)
8b9a1c
-    {
8b9a1c
-	BF_OFB_UPDATE(*p);
8b9a1c
-    }
8b9a1c
-}
8b9a1c
+crypt_blowfish_init(state, key, salt, salt_len, seed, seed_len)
8b9a1c
+    cryptstate_T	*state;
8b9a1c
+    char_u*		key;
8b9a1c
+    char_u*		salt;
8b9a1c
+    int			salt_len;
8b9a1c
+    char_u*		seed;
8b9a1c
+    int			seed_len;
8b9a1c
+{
8b9a1c
+    bf_state_T	*bfs = (bf_state_T *)alloc_clear(sizeof(bf_state_T));
8b9a1c
+
8b9a1c
+    state->method_state = bfs;
8b9a1c
+
8b9a1c
+    /* "blowfish" uses a 64 byte buffer, causing it to repeat 8 byte groups 8
8b9a1c
+     * times.  "blowfish2" uses a 8 byte buffer to avoid repeating. */
8b9a1c
+    bfs->cfb_len = state->method_nr == CRYPT_M_BF ? BF_MAX_CFB_LEN : BF_BLOCK;
8b9a1c
 
8b9a1c
-static int save_randbyte_offset;
8b9a1c
-static int save_update_offset;
8b9a1c
-static char_u save_ofb_buffer[BF_OFB_LEN];
8b9a1c
-static UINT32_T save_pax[18];
8b9a1c
-static UINT32_T save_sbx[4][256];
8b9a1c
-
8b9a1c
-/*
8b9a1c
- * Save the current crypt state.  Can only be used once before
8b9a1c
- * bf_crypt_restore().
8b9a1c
- */
8b9a1c
-    void
8b9a1c
-bf_crypt_save()
8b9a1c
-{
8b9a1c
-    save_randbyte_offset = randbyte_offset;
8b9a1c
-    save_update_offset = update_offset;
8b9a1c
-    mch_memmove(save_ofb_buffer, ofb_buffer, BF_OFB_LEN);
8b9a1c
-    mch_memmove(save_pax, pax, 4 * 18);
8b9a1c
-    mch_memmove(save_sbx, sbx, 4 * 4 * 256);
8b9a1c
-}
8b9a1c
+    if (blowfish_self_test() == FAIL)
8b9a1c
+	return;
8b9a1c
 
8b9a1c
-/*
8b9a1c
- * Restore the current crypt state.  Can only be used after
8b9a1c
- * bf_crypt_save().
8b9a1c
- */
8b9a1c
-    void
8b9a1c
-bf_crypt_restore()
8b9a1c
-{
8b9a1c
-    randbyte_offset = save_randbyte_offset;
8b9a1c
-    update_offset = save_update_offset;
8b9a1c
-    mch_memmove(ofb_buffer, save_ofb_buffer, BF_OFB_LEN);
8b9a1c
-    mch_memmove(pax, save_pax, 4 * 18);
8b9a1c
-    mch_memmove(sbx, save_sbx, 4 * 4 * 256);
8b9a1c
+    bf_key_init(bfs, key, salt, salt_len);
8b9a1c
+    bf_cfb_init(bfs, seed, seed_len);
8b9a1c
 }
8b9a1c
 
8b9a1c
 /*
8b9a1c
diff -up vim74/src/crypt.c.blowfish2 vim74/src/crypt.c
8b9a1c
--- vim74/src/crypt.c.blowfish2	2017-09-05 14:47:34.933912159 +0200
8b9a1c
+++ vim74/src/crypt.c	2017-09-05 14:47:34.933912159 +0200
8b9a1c
@@ -0,0 +1,585 @@
8b9a1c
+/* vi:set ts=8 sts=4 sw=4:
8b9a1c
+ *
8b9a1c
+ * VIM - Vi IMproved	by Bram Moolenaar
8b9a1c
+ *
8b9a1c
+ * Do ":help uganda"  in Vim to read copying and usage conditions.
8b9a1c
+ * Do ":help credits" in Vim to see a list of people who contributed.
8b9a1c
+ * See README.txt for an overview of the Vim source code.
8b9a1c
+ */
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * crypt.c: Generic encryption support.
8b9a1c
+ */
8b9a1c
+#include "vim.h"
8b9a1c
+
8b9a1c
+#if defined(FEAT_CRYPT) || defined(PROTO)
8b9a1c
+/*
8b9a1c
+ * Optional encryption support.
8b9a1c
+ * Mohsin Ahmed, mosh@sasi.com, 1998-09-24
8b9a1c
+ * Based on zip/crypt sources.
8b9a1c
+ * Refactored by David Leadbeater, 2014.
8b9a1c
+ *
8b9a1c
+ * NOTE FOR USA: Since 2000 exporting this code from the USA is allowed to
8b9a1c
+ * most countries.  There are a few exceptions, but that still should not be a
8b9a1c
+ * problem since this code was originally created in Europe and India.
8b9a1c
+ *
8b9a1c
+ * Blowfish addition originally made by Mohsin Ahmed,
8b9a1c
+ * http://www.cs.albany.edu/~mosh 2010-03-14
8b9a1c
+ * Based on blowfish by Bruce Schneier (http://www.schneier.com/blowfish.html)
8b9a1c
+ * and sha256 by Christophe Devine.
8b9a1c
+ */
8b9a1c
+
8b9a1c
+typedef struct {
8b9a1c
+    char    *name;	/* encryption name as used in 'cryptmethod' */
8b9a1c
+    char    *magic;	/* magic bytes stored in file header */
8b9a1c
+    int	    salt_len;	/* length of salt, or 0 when not using salt */
8b9a1c
+    int	    seed_len;	/* length of seed, or 0 when not using salt */
8b9a1c
+    int	    works_inplace; /* encryption/decryption can be done in-place */
8b9a1c
+    int	    whole_undofile; /* whole undo file is encrypted */
8b9a1c
+
8b9a1c
+    /* Optional function pointer for a self-test. */
8b9a1c
+    int (* self_test_fn)();
8b9a1c
+
8b9a1c
+    /* Function pointer for initializing encryption/decription. */
8b9a1c
+    void (* init_fn)(cryptstate_T *state, char_u *key,
8b9a1c
+		      char_u *salt, int salt_len, char_u *seed, int seed_len);
8b9a1c
+
8b9a1c
+    /* Function pointers for encoding/decoding from one buffer into another.
8b9a1c
+     * Optional, however, these or the _buffer ones should be configured. */
8b9a1c
+    void (*encode_fn)(cryptstate_T *state, char_u *from, size_t len,
8b9a1c
+								  char_u *to);
8b9a1c
+    void (*decode_fn)(cryptstate_T *state, char_u *from, size_t len,
8b9a1c
+								  char_u *to);
8b9a1c
+
8b9a1c
+    /* Function pointers for encoding and decoding, can buffer data if needed.
8b9a1c
+     * Optional (however, these or the above should be configured). */
8b9a1c
+    long (*encode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
8b9a1c
+							     char_u **newptr);
8b9a1c
+    long (*decode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
8b9a1c
+							     char_u **newptr);
8b9a1c
+
8b9a1c
+    /* Function pointers for in-place encoding and decoding, used for
8b9a1c
+     * crypt_*_inplace(). "from" and "to" arguments will be equal.
8b9a1c
+     * These may be the same as decode_fn and encode_fn above, however an
8b9a1c
+     * algorithm may implement them in a way that is not interchangeable with
8b9a1c
+     * the crypt_(en|de)code() interface (for example because it wishes to add
8b9a1c
+     * padding to files).
8b9a1c
+     * This method is used for swap and undo files which have a rigid format.
8b9a1c
+     */
8b9a1c
+    void (*encode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
8b9a1c
+								  char_u *p2);
8b9a1c
+    void (*decode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
8b9a1c
+								  char_u *p2);
8b9a1c
+} cryptmethod_T;
8b9a1c
+
8b9a1c
+/* index is method_nr of cryptstate_T, CRYPT_M_* */
8b9a1c
+static cryptmethod_T cryptmethods[CRYPT_M_COUNT] = {
8b9a1c
+    /* PK_Zip; very weak */
8b9a1c
+    {
8b9a1c
+	"zip",
8b9a1c
+	"VimCrypt~01!",
8b9a1c
+	0,
8b9a1c
+	0,
8b9a1c
+	TRUE,
8b9a1c
+	FALSE,
8b9a1c
+	NULL,
8b9a1c
+	crypt_zip_init,
8b9a1c
+	crypt_zip_encode, crypt_zip_decode,
8b9a1c
+	NULL, NULL,
8b9a1c
+	crypt_zip_encode, crypt_zip_decode,
8b9a1c
+    },
8b9a1c
+
8b9a1c
+    /* Blowfish/CFB + SHA-256 custom key derivation; implementation issues. */
8b9a1c
+    {
8b9a1c
+	"blowfish",
8b9a1c
+	"VimCrypt~02!",
8b9a1c
+	8,
8b9a1c
+	8,
8b9a1c
+	TRUE,
8b9a1c
+	FALSE,
8b9a1c
+	blowfish_self_test,
8b9a1c
+	crypt_blowfish_init,
8b9a1c
+	crypt_blowfish_encode, crypt_blowfish_decode,
8b9a1c
+	NULL, NULL,
8b9a1c
+	crypt_blowfish_encode, crypt_blowfish_decode,
8b9a1c
+    },
8b9a1c
+
8b9a1c
+    /* Blowfish/CFB + SHA-256 custom key derivation; fixed. */
8b9a1c
+    {
8b9a1c
+	"blowfish2",
8b9a1c
+	"VimCrypt~03!",
8b9a1c
+	8,
8b9a1c
+	8,
8b9a1c
+	TRUE,
8b9a1c
+	TRUE,
8b9a1c
+	blowfish_self_test,
8b9a1c
+	crypt_blowfish_init,
8b9a1c
+	crypt_blowfish_encode, crypt_blowfish_decode,
8b9a1c
+	NULL, NULL,
8b9a1c
+	crypt_blowfish_encode, crypt_blowfish_decode,
8b9a1c
+    },
8b9a1c
+};
8b9a1c
+
8b9a1c
+#define CRYPT_MAGIC_LEN	12	/* cannot change */
8b9a1c
+static char	crypt_magic_head[] = "VimCrypt~";
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Return int value for crypt method name.
8b9a1c
+ * 0 for "zip", the old method.  Also for any non-valid value.
8b9a1c
+ * 1 for "blowfish".
8b9a1c
+ * 2 for "blowfish2".
8b9a1c
+ */
8b9a1c
+    int
8b9a1c
+crypt_method_nr_from_name(name)
8b9a1c
+    char_u  *name;
8b9a1c
+{
8b9a1c
+    int i;
8b9a1c
+
8b9a1c
+    for (i = 0; i < CRYPT_M_COUNT; ++i)
8b9a1c
+	if (STRCMP(name, cryptmethods[i].name) == 0)
8b9a1c
+	    return i;
8b9a1c
+    return 0;
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Get the crypt method used for a file from "ptr[len]", the magic text at the
8b9a1c
+ * start of the file.
8b9a1c
+ * Returns -1 when no encryption used.
8b9a1c
+ */
8b9a1c
+    int
8b9a1c
+crypt_method_nr_from_magic(ptr, len)
8b9a1c
+    char  *ptr;
8b9a1c
+    int   len;
8b9a1c
+{
8b9a1c
+    int i;
8b9a1c
+
8b9a1c
+    if (len < CRYPT_MAGIC_LEN)
8b9a1c
+	return -1;
8b9a1c
+
8b9a1c
+    for (i = 0; i < CRYPT_M_COUNT; i++)
8b9a1c
+	if (memcmp(ptr, cryptmethods[i].magic, CRYPT_MAGIC_LEN) == 0)
8b9a1c
+	    return i;
8b9a1c
+
8b9a1c
+    i = (int)STRLEN(crypt_magic_head);
8b9a1c
+    if (len >= i && memcmp(ptr, crypt_magic_head, i) == 0)
8b9a1c
+	EMSG(_("E821: File is encrypted with unknown method"));
8b9a1c
+
8b9a1c
+    return -1;
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Return TRUE if the crypt method for "method_nr" can be done in-place.
8b9a1c
+ */
8b9a1c
+    int
8b9a1c
+crypt_works_inplace(state)
8b9a1c
+    cryptstate_T *state;
8b9a1c
+{
8b9a1c
+    return cryptmethods[state->method_nr].works_inplace;
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Get the crypt method for buffer "buf" as a number.
8b9a1c
+ */
8b9a1c
+    int
8b9a1c
+crypt_get_method_nr(buf)
8b9a1c
+    buf_T *buf;
8b9a1c
+{
8b9a1c
+    return crypt_method_nr_from_name(*buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Return TRUE when the buffer uses an encryption method that encrypts the
8b9a1c
+ * whole undo file, not only the text.
8b9a1c
+ */
8b9a1c
+    int
8b9a1c
+crypt_whole_undofile(method_nr)
8b9a1c
+    int method_nr;
8b9a1c
+{
8b9a1c
+    return cryptmethods[method_nr].whole_undofile;
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Get crypt method specifc length of the file header in bytes.
8b9a1c
+ */
8b9a1c
+    int
8b9a1c
+crypt_get_header_len(method_nr)
8b9a1c
+    int method_nr;
8b9a1c
+{
8b9a1c
+    return CRYPT_MAGIC_LEN
8b9a1c
+	+ cryptmethods[method_nr].salt_len
8b9a1c
+	+ cryptmethods[method_nr].seed_len;
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Set the crypt method for buffer "buf" to "method_nr" using the int value as
8b9a1c
+ * returned by crypt_method_nr_from_name().
8b9a1c
+ */
8b9a1c
+    void
8b9a1c
+crypt_set_cm_option(buf, method_nr)
8b9a1c
+    buf_T   *buf;
8b9a1c
+    int	    method_nr;
8b9a1c
+{
8b9a1c
+    free_string_option(buf->b_p_cm);
8b9a1c
+    buf->b_p_cm = vim_strsave((char_u *)cryptmethods[method_nr].name);
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * If the crypt method for the current buffer has a self-test, run it and
8b9a1c
+ * return OK/FAIL.
8b9a1c
+ */
8b9a1c
+    int
8b9a1c
+crypt_self_test()
8b9a1c
+{
8b9a1c
+    int method_nr = crypt_get_method_nr(curbuf);
8b9a1c
+
8b9a1c
+    if (cryptmethods[method_nr].self_test_fn == NULL)
8b9a1c
+	return OK;
8b9a1c
+    return cryptmethods[method_nr].self_test_fn();
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Allocate a crypt state and initialize it.
8b9a1c
+ */
8b9a1c
+    cryptstate_T *
8b9a1c
+crypt_create(method_nr, key, salt, salt_len, seed, seed_len)
8b9a1c
+    int		method_nr;
8b9a1c
+    char_u	*key;
8b9a1c
+    char_u	*salt;
8b9a1c
+    int		salt_len;
8b9a1c
+    char_u	*seed;
8b9a1c
+    int		seed_len;
8b9a1c
+{
8b9a1c
+    cryptstate_T *state = (cryptstate_T *)alloc((int)sizeof(cryptstate_T));
8b9a1c
+
8b9a1c
+    state->method_nr = method_nr;
8b9a1c
+    cryptmethods[method_nr].init_fn(state, key, salt, salt_len, seed, seed_len);
8b9a1c
+    return state;
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Allocate a crypt state from a file header and initialize it.
8b9a1c
+ * Assumes that header contains at least the number of bytes that
8b9a1c
+ * crypt_get_header_len() returns for "method_nr".
8b9a1c
+ */
8b9a1c
+    cryptstate_T *
8b9a1c
+crypt_create_from_header(method_nr, key, header)
8b9a1c
+    int		method_nr;
8b9a1c
+    char_u	*key;
8b9a1c
+    char_u	*header;
8b9a1c
+{
8b9a1c
+    char_u	*salt = NULL;
8b9a1c
+    char_u	*seed = NULL;
8b9a1c
+    int		salt_len = cryptmethods[method_nr].salt_len;
8b9a1c
+    int		seed_len = cryptmethods[method_nr].seed_len;
8b9a1c
+
8b9a1c
+    if (salt_len > 0)
8b9a1c
+	salt = header + CRYPT_MAGIC_LEN;
8b9a1c
+    if (seed_len > 0)
8b9a1c
+	seed = header + CRYPT_MAGIC_LEN + salt_len;
8b9a1c
+
8b9a1c
+    return crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Read the crypt method specific header data from "fp".
8b9a1c
+ * Return an allocated cryptstate_T or NULL on error.
8b9a1c
+ */
8b9a1c
+    cryptstate_T *
8b9a1c
+crypt_create_from_file(fp, key)
8b9a1c
+    FILE    *fp;
8b9a1c
+    char_u  *key;
8b9a1c
+{
8b9a1c
+    int		method_nr;
8b9a1c
+    int		header_len;
8b9a1c
+    char	magic_buffer[CRYPT_MAGIC_LEN];
8b9a1c
+    char_u	*buffer;
8b9a1c
+    cryptstate_T *state;
8b9a1c
+
8b9a1c
+    if (fread(magic_buffer, CRYPT_MAGIC_LEN, 1, fp) != 1)
8b9a1c
+	return NULL;
8b9a1c
+    method_nr = crypt_method_nr_from_magic(magic_buffer, CRYPT_MAGIC_LEN);
8b9a1c
+    if (method_nr < 0)
8b9a1c
+	return NULL;
8b9a1c
+
8b9a1c
+    header_len = crypt_get_header_len(method_nr);
8b9a1c
+    if ((buffer = alloc(header_len)) == NULL)
8b9a1c
+	return NULL;
8b9a1c
+    mch_memmove(buffer, magic_buffer, CRYPT_MAGIC_LEN);
8b9a1c
+    if (header_len > CRYPT_MAGIC_LEN
8b9a1c
+	    && fread(buffer + CRYPT_MAGIC_LEN,
8b9a1c
+				    header_len - CRYPT_MAGIC_LEN, 1, fp) != 1)
8b9a1c
+    {
8b9a1c
+	vim_free(buffer);
8b9a1c
+	return NULL;
8b9a1c
+    }
8b9a1c
+
8b9a1c
+    state = crypt_create_from_header(method_nr, key, buffer);
8b9a1c
+    vim_free(buffer);
8b9a1c
+    return state;
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Allocate a cryptstate_T for writing and initialize it with "key".
8b9a1c
+ * Allocates and fills in the header and stores it in "header", setting
8b9a1c
+ * "header_len".  The header may include salt and seed, depending on
8b9a1c
+ * cryptmethod.  Caller must free header.
8b9a1c
+ * Returns the state or NULL on failure.
8b9a1c
+ */
8b9a1c
+    cryptstate_T *
8b9a1c
+crypt_create_for_writing(method_nr, key, header, header_len)
8b9a1c
+    int	    method_nr;
8b9a1c
+    char_u  *key;
8b9a1c
+    char_u  **header;
8b9a1c
+    int	    *header_len;
8b9a1c
+{
8b9a1c
+    int	    len = crypt_get_header_len(method_nr);
8b9a1c
+    char_u  *salt = NULL;
8b9a1c
+    char_u  *seed = NULL;
8b9a1c
+    int	    salt_len = cryptmethods[method_nr].salt_len;
8b9a1c
+    int	    seed_len = cryptmethods[method_nr].seed_len;
8b9a1c
+    cryptstate_T *state;
8b9a1c
+
8b9a1c
+    *header_len = len;
8b9a1c
+    *header = alloc(len);
8b9a1c
+    if (*header == NULL)
8b9a1c
+	return NULL;
8b9a1c
+
8b9a1c
+    mch_memmove(*header, cryptmethods[method_nr].magic, CRYPT_MAGIC_LEN);
8b9a1c
+    if (salt_len > 0 || seed_len > 0)
8b9a1c
+    {
8b9a1c
+	if (salt_len > 0)
8b9a1c
+	    salt = *header + CRYPT_MAGIC_LEN;
8b9a1c
+	if (seed_len > 0)
8b9a1c
+	    seed = *header + CRYPT_MAGIC_LEN + salt_len;
8b9a1c
+
8b9a1c
+	/* TODO: Should this be crypt method specific? (Probably not worth
8b9a1c
+	 * it).  sha2_seed is pretty bad for large amounts of entropy, so make
8b9a1c
+	 * that into something which is suitable for anything. */
8b9a1c
+	sha2_seed(salt, salt_len, seed, seed_len);
8b9a1c
+    }
8b9a1c
+
8b9a1c
+    state = crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
8b9a1c
+    if (state == NULL)
8b9a1c
+    {
8b9a1c
+	vim_free(*header);
8b9a1c
+	*header = NULL;
8b9a1c
+    }
8b9a1c
+    return state;
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Free the crypt state.
8b9a1c
+ */
8b9a1c
+    void
8b9a1c
+crypt_free_state(state)
8b9a1c
+    cryptstate_T	*state;
8b9a1c
+{
8b9a1c
+    vim_free(state->method_state);
8b9a1c
+    vim_free(state);
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Encode "from[len]" and store the result in a newly allocated buffer, which
8b9a1c
+ * is stored in "newptr".
8b9a1c
+ * Return number of bytes in "newptr", 0 for need more or -1 on error.
8b9a1c
+ */
8b9a1c
+    long
8b9a1c
+crypt_encode_alloc(state, from, len, newptr)
8b9a1c
+    cryptstate_T *state;
8b9a1c
+    char_u	*from;
8b9a1c
+    size_t	len;
8b9a1c
+    char_u	**newptr;
8b9a1c
+{
8b9a1c
+    cryptmethod_T *method = &cryptmethods[state->method_nr];
8b9a1c
+
8b9a1c
+    if (method->encode_buffer_fn != NULL)
8b9a1c
+	/* Has buffer function, pass through. */
8b9a1c
+	return method->encode_buffer_fn(state, from, len, newptr);
8b9a1c
+    if (len == 0)
8b9a1c
+	/* Not buffering, just return EOF. */
8b9a1c
+	return len;
8b9a1c
+
8b9a1c
+    *newptr = alloc(len);
8b9a1c
+    if (*newptr == NULL)
8b9a1c
+	return -1;
8b9a1c
+    method->encode_fn(state, from, len, *newptr);
8b9a1c
+    return len;
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Decrypt "ptr[len]" and store the result in a newly allocated buffer, which
8b9a1c
+ * is stored in "newptr".
8b9a1c
+ * Return number of bytes in "newptr", 0 for need more or -1 on error.
8b9a1c
+ */
8b9a1c
+    long
8b9a1c
+crypt_decode_alloc(state, ptr, len, newptr)
8b9a1c
+    cryptstate_T *state;
8b9a1c
+    char_u	*ptr;
8b9a1c
+    long	len;
8b9a1c
+    char_u      **newptr;
8b9a1c
+{
8b9a1c
+    cryptmethod_T *method = &cryptmethods[state->method_nr];
8b9a1c
+
8b9a1c
+    if (method->decode_buffer_fn != NULL)
8b9a1c
+	/* Has buffer function, pass through. */
8b9a1c
+	return method->decode_buffer_fn(state, ptr, len, newptr);
8b9a1c
+
8b9a1c
+    if (len == 0)
8b9a1c
+	/* Not buffering, just return EOF. */
8b9a1c
+	return len;
8b9a1c
+
8b9a1c
+    *newptr = alloc(len);
8b9a1c
+    if (*newptr == NULL)
8b9a1c
+	return -1;
8b9a1c
+    method->decode_fn(state, ptr, len, *newptr);
8b9a1c
+    return len;
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Encrypting "from[len]" into "to[len]".
8b9a1c
+ */
8b9a1c
+    void
8b9a1c
+crypt_encode(state, from, len, to)
8b9a1c
+    cryptstate_T *state;
8b9a1c
+    char_u	*from;
8b9a1c
+    size_t	len;
8b9a1c
+    char_u	*to;
8b9a1c
+{
8b9a1c
+    cryptmethods[state->method_nr].encode_fn(state, from, len, to);
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * decrypting "from[len]" into "to[len]".
8b9a1c
+ */
8b9a1c
+    void
8b9a1c
+crypt_decode(state, from, len, to)
8b9a1c
+    cryptstate_T *state;
8b9a1c
+    char_u	*from;
8b9a1c
+    size_t	len;
8b9a1c
+    char_u	*to;
8b9a1c
+{
8b9a1c
+    cryptmethods[state->method_nr].decode_fn(state, from, len, to);
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Simple inplace encryption, modifies "buf[len]" in place.
8b9a1c
+ */
8b9a1c
+    void
8b9a1c
+crypt_encode_inplace(state, buf, len)
8b9a1c
+    cryptstate_T *state;
8b9a1c
+    char_u	*buf;
8b9a1c
+    size_t	len;
8b9a1c
+{
8b9a1c
+    cryptmethods[state->method_nr].encode_inplace_fn(state, buf, len, buf);
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Simple inplace decryption, modifies "buf[len]" in place.
8b9a1c
+ */
8b9a1c
+    void
8b9a1c
+crypt_decode_inplace(state, buf, len)
8b9a1c
+    cryptstate_T *state;
8b9a1c
+    char_u	*buf;
8b9a1c
+    size_t	len;
8b9a1c
+{
8b9a1c
+    cryptmethods[state->method_nr].decode_inplace_fn(state, buf, len, buf);
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Free an allocated crypt key.  Clear the text to make sure it doesn't stay
8b9a1c
+ * in memory anywhere.
8b9a1c
+ */
8b9a1c
+    void
8b9a1c
+crypt_free_key(key)
8b9a1c
+    char_u *key;
8b9a1c
+{
8b9a1c
+    char_u *p;
8b9a1c
+
8b9a1c
+    if (key != NULL)
8b9a1c
+    {
8b9a1c
+	for (p = key; *p != NUL; ++p)
8b9a1c
+	    *p = 0;
8b9a1c
+	vim_free(key);
8b9a1c
+    }
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Ask the user for a crypt key.
8b9a1c
+ * When "store" is TRUE, the new key is stored in the 'key' option, and the
8b9a1c
+ * 'key' option value is returned: Don't free it.
8b9a1c
+ * When "store" is FALSE, the typed key is returned in allocated memory.
8b9a1c
+ * Returns NULL on failure.
8b9a1c
+ */
8b9a1c
+    char_u *
8b9a1c
+crypt_get_key(store, twice)
8b9a1c
+    int		store;
8b9a1c
+    int		twice;	    /* Ask for the key twice. */
8b9a1c
+{
8b9a1c
+    char_u	*p1, *p2 = NULL;
8b9a1c
+    int		round;
8b9a1c
+
8b9a1c
+    for (round = 0; ; ++round)
8b9a1c
+    {
8b9a1c
+	cmdline_star = TRUE;
8b9a1c
+	cmdline_row = msg_row;
8b9a1c
+	p1 = getcmdline_prompt(NUL, round == 0
8b9a1c
+		? (char_u *)_("Enter encryption key: ")
8b9a1c
+		: (char_u *)_("Enter same key again: "), 0, EXPAND_NOTHING,
8b9a1c
+		NULL);
8b9a1c
+	cmdline_star = FALSE;
8b9a1c
+
8b9a1c
+	if (p1 == NULL)
8b9a1c
+	    break;
8b9a1c
+
8b9a1c
+	if (round == twice)
8b9a1c
+	{
8b9a1c
+	    if (p2 != NULL && STRCMP(p1, p2) != 0)
8b9a1c
+	    {
8b9a1c
+		MSG(_("Keys don't match!"));
8b9a1c
+		crypt_free_key(p1);
8b9a1c
+		crypt_free_key(p2);
8b9a1c
+		p2 = NULL;
8b9a1c
+		round = -1;		/* do it again */
8b9a1c
+		continue;
8b9a1c
+	    }
8b9a1c
+
8b9a1c
+	    if (store)
8b9a1c
+	    {
8b9a1c
+		set_option_value((char_u *)"key", 0L, p1, OPT_LOCAL);
8b9a1c
+		crypt_free_key(p1);
8b9a1c
+		p1 = curbuf->b_p_key;
8b9a1c
+	    }
8b9a1c
+	    break;
8b9a1c
+	}
8b9a1c
+	p2 = p1;
8b9a1c
+    }
8b9a1c
+
8b9a1c
+    /* since the user typed this, no need to wait for return */
8b9a1c
+    if (msg_didout)
8b9a1c
+	msg_putchar('\n');
8b9a1c
+    need_wait_return = FALSE;
8b9a1c
+    msg_didout = FALSE;
8b9a1c
+
8b9a1c
+    crypt_free_key(p2);
8b9a1c
+    return p1;
8b9a1c
+}
8b9a1c
+
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Append a message to IObuff for the encryption/decryption method being used.
8b9a1c
+ */
8b9a1c
+    void
8b9a1c
+crypt_append_msg(buf)
8b9a1c
+    buf_T *buf;
8b9a1c
+{
8b9a1c
+    if (crypt_get_method_nr(buf) == 0)
8b9a1c
+	STRCAT(IObuff, _("[crypted]"));
8b9a1c
+    else
8b9a1c
+    {
8b9a1c
+	STRCAT(IObuff, "[");
8b9a1c
+	STRCAT(IObuff, *buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
8b9a1c
+	STRCAT(IObuff, "]");
8b9a1c
+    }
8b9a1c
+}
8b9a1c
+
8b9a1c
+#endif /* FEAT_CRYPT */
8b9a1c
diff -up vim74/src/crypt_zip.c.blowfish2 vim74/src/crypt_zip.c
8b9a1c
--- vim74/src/crypt_zip.c.blowfish2	2017-09-05 14:47:34.934912151 +0200
8b9a1c
+++ vim74/src/crypt_zip.c	2017-09-05 14:47:34.934912151 +0200
8b9a1c
@@ -0,0 +1,158 @@
8b9a1c
+/* vi:set ts=8 sts=4 sw=4:
8b9a1c
+ *
8b9a1c
+ * VIM - Vi IMproved	by Bram Moolenaar
8b9a1c
+ *
8b9a1c
+ * Do ":help uganda"  in Vim to read copying and usage conditions.
8b9a1c
+ * Do ":help credits" in Vim to see a list of people who contributed.
8b9a1c
+ * See README.txt for an overview of the Vim source code.
8b9a1c
+ */
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * crypt_zip.c: Zip encryption support.
8b9a1c
+ */
8b9a1c
+#include "vim.h"
8b9a1c
+
8b9a1c
+#if defined(FEAT_CRYPT) || defined(PROTO)
8b9a1c
+/*
8b9a1c
+ * Optional encryption support.
8b9a1c
+ * Mohsin Ahmed, mosh@sasi.com, 98-09-24
8b9a1c
+ * Based on zip/crypt sources.
8b9a1c
+ *
8b9a1c
+ * NOTE FOR USA: Since 2000 exporting this code from the USA is allowed to
8b9a1c
+ * most countries.  There are a few exceptions, but that still should not be a
8b9a1c
+ * problem since this code was originally created in Europe and India.
8b9a1c
+ */
8b9a1c
+
8b9a1c
+/* Need a type that should be 32 bits. 64 also works but wastes space. */
8b9a1c
+# if VIM_SIZEOF_INT >= 4
8b9a1c
+typedef unsigned int u32_T;	/* int is at least 32 bits */
8b9a1c
+# else
8b9a1c
+typedef unsigned long u32_T;	/* long should be 32 bits or more */
8b9a1c
+# endif
8b9a1c
+
8b9a1c
+/* The state of encryption, referenced by cryptstate_T. */
8b9a1c
+typedef struct {
8b9a1c
+    u32_T keys[3];
8b9a1c
+} zip_state_T;
8b9a1c
+
8b9a1c
+
8b9a1c
+static void make_crc_tab __ARGS((void));
8b9a1c
+
8b9a1c
+static u32_T crc_32_table[256];
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Fill the CRC table, if not done already.
8b9a1c
+ */
8b9a1c
+    static void
8b9a1c
+make_crc_tab()
8b9a1c
+{
8b9a1c
+    u32_T	s, t, v;
8b9a1c
+    static int	done = FALSE;
8b9a1c
+
8b9a1c
+    if (done)
8b9a1c
+	return;
8b9a1c
+    for (t = 0; t < 256; t++)
8b9a1c
+    {
8b9a1c
+	v = t;
8b9a1c
+	for (s = 0; s < 8; s++)
8b9a1c
+	    v = (v >> 1) ^ ((v & 1) * (u32_T)0xedb88320L);
8b9a1c
+	crc_32_table[t] = v;
8b9a1c
+    }
8b9a1c
+    done = TRUE;
8b9a1c
+}
8b9a1c
+
8b9a1c
+#define CRC32(c, b) (crc_32_table[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Return the next byte in the pseudo-random sequence.
8b9a1c
+ */
8b9a1c
+#define DECRYPT_BYTE_ZIP(keys, t) { \
8b9a1c
+    short_u temp = (short_u)keys[2] | 2; \
8b9a1c
+    t = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff); \
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Update the encryption keys with the next byte of plain text.
8b9a1c
+ */
8b9a1c
+#define UPDATE_KEYS_ZIP(keys, c) { \
8b9a1c
+    keys[0] = CRC32(keys[0], (c)); \
8b9a1c
+    keys[1] += keys[0] & 0xff; \
8b9a1c
+    keys[1] = keys[1] * 134775813L + 1; \
8b9a1c
+    keys[2] = CRC32(keys[2], (int)(keys[1] >> 24)); \
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Initialize for encryption/decryption.
8b9a1c
+ */
8b9a1c
+    void
8b9a1c
+crypt_zip_init(state, key, salt, salt_len, seed, seed_len)
8b9a1c
+    cryptstate_T    *state;
8b9a1c
+    char_u	    *key;
8b9a1c
+    char_u	    *salt UNUSED;
8b9a1c
+    int		    salt_len UNUSED;
8b9a1c
+    char_u	    *seed UNUSED;
8b9a1c
+    int		    seed_len UNUSED;
8b9a1c
+{
8b9a1c
+    char_u	*p;
8b9a1c
+    zip_state_T	*zs;
8b9a1c
+
8b9a1c
+    zs = (zip_state_T *)alloc(sizeof(zip_state_T));
8b9a1c
+    state->method_state = zs;
8b9a1c
+
8b9a1c
+    make_crc_tab();
8b9a1c
+    zs->keys[0] = 305419896L;
8b9a1c
+    zs->keys[1] = 591751049L;
8b9a1c
+    zs->keys[2] = 878082192L;
8b9a1c
+    for (p = key; *p != NUL; ++p)
8b9a1c
+    {
8b9a1c
+	UPDATE_KEYS_ZIP(zs->keys, (int)*p);
8b9a1c
+    }
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Encrypt "from[len]" into "to[len]".
8b9a1c
+ * "from" and "to" can be equal to encrypt in place.
8b9a1c
+ */
8b9a1c
+    void
8b9a1c
+crypt_zip_encode(state, from, len, to)
8b9a1c
+    cryptstate_T *state;
8b9a1c
+    char_u	*from;
8b9a1c
+    size_t	len;
8b9a1c
+    char_u	*to;
8b9a1c
+{
8b9a1c
+    zip_state_T *zs = state->method_state;
8b9a1c
+    size_t	i;
8b9a1c
+    int		ztemp, t;
8b9a1c
+
8b9a1c
+    for (i = 0; i < len; ++i)
8b9a1c
+    {
8b9a1c
+	ztemp = from[i];
8b9a1c
+	DECRYPT_BYTE_ZIP(zs->keys, t);
8b9a1c
+	UPDATE_KEYS_ZIP(zs->keys, ztemp);
8b9a1c
+	to[i] = t ^ ztemp;
8b9a1c
+    }
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Decrypt "from[len]" into "to[len]".
8b9a1c
+ */
8b9a1c
+    void
8b9a1c
+crypt_zip_decode(state, from, len, to)
8b9a1c
+    cryptstate_T *state;
8b9a1c
+    char_u	*from;
8b9a1c
+    size_t	len;
8b9a1c
+    char_u	*to;
8b9a1c
+{
8b9a1c
+    zip_state_T *zs = state->method_state;
8b9a1c
+    size_t	i;
8b9a1c
+    short_u	temp;
8b9a1c
+
8b9a1c
+    for (i = 0; i < len; ++i)
8b9a1c
+    {
8b9a1c
+	temp = (short_u)zs->keys[2] | 2;
8b9a1c
+	temp = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff);
8b9a1c
+	UPDATE_KEYS_ZIP(zs->keys, to[i] = from[i] ^ temp);
8b9a1c
+    }
8b9a1c
+}
8b9a1c
+
8b9a1c
+#endif /* FEAT_CRYPT */
8b9a1c
diff -up vim74/src/eval.c.blowfish2 vim74/src/eval.c
8b9a1c
--- vim74/src/eval.c.blowfish2	2017-09-05 14:47:34.837912934 +0200
8b9a1c
+++ vim74/src/eval.c	2017-09-05 14:47:34.939912111 +0200
8b9a1c
@@ -12228,6 +12228,8 @@ f_has(argvars, rettv)
8b9a1c
 #endif
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
 	"cryptv",
8b9a1c
+	"crypt-blowfish",
8b9a1c
+	"crypt-blowfish2",
8b9a1c
 #endif
8b9a1c
 #ifdef FEAT_CSCOPE
8b9a1c
 	"cscope",
8b9a1c
diff -up vim74/src/ex_docmd.c.blowfish2 vim74/src/ex_docmd.c
8b9a1c
--- vim74/src/ex_docmd.c.blowfish2	2017-09-05 14:47:34.782913378 +0200
8b9a1c
+++ vim74/src/ex_docmd.c	2017-09-05 14:47:34.945912063 +0200
8b9a1c
@@ -11497,8 +11497,7 @@ ex_match(eap)
8b9a1c
 ex_X(eap)
8b9a1c
     exarg_T	*eap UNUSED;
8b9a1c
 {
8b9a1c
-    if (get_crypt_method(curbuf) == 0 || blowfish_self_test() == OK)
8b9a1c
-	(void)get_crypt_key(TRUE, TRUE);
8b9a1c
+    (void)crypt_get_key(TRUE, TRUE);
8b9a1c
 }
8b9a1c
 #endif
8b9a1c
 
8b9a1c
diff -up vim74/src/fileio.c.blowfish2 vim74/src/fileio.c
8b9a1c
--- vim74/src/fileio.c.blowfish2	2017-09-05 14:47:34.245917713 +0200
8b9a1c
+++ vim74/src/fileio.c	2017-09-05 14:47:34.947912046 +0200
8b9a1c
@@ -24,20 +24,6 @@
8b9a1c
 #define BUFSIZE		8192	/* size of normal write buffer */
8b9a1c
 #define SMBUFSIZE	256	/* size of emergency write buffer */
8b9a1c
 
8b9a1c
-#ifdef FEAT_CRYPT
8b9a1c
-/* crypt_magic[0] is pkzip crypt, crypt_magic[1] is sha2+blowfish */
8b9a1c
-static char	*crypt_magic[] = {"VimCrypt~01!", "VimCrypt~02!"};
8b9a1c
-static char	crypt_magic_head[] = "VimCrypt~";
8b9a1c
-# define CRYPT_MAGIC_LEN	12		/* must be multiple of 4! */
8b9a1c
-
8b9a1c
-/* For blowfish, after the magic header, we store 8 bytes of salt and then 8
8b9a1c
- * bytes of seed (initialisation vector). */
8b9a1c
-static int	crypt_salt_len[] = {0, 8};
8b9a1c
-static int	crypt_seed_len[] = {0, 8};
8b9a1c
-#define CRYPT_SALT_LEN_MAX 8
8b9a1c
-#define CRYPT_SEED_LEN_MAX 8
8b9a1c
-#endif
8b9a1c
-
8b9a1c
 /* Is there any system that doesn't have access()? */
8b9a1c
 #define USE_MCH_ACCESS
8b9a1c
 
8b9a1c
@@ -55,7 +41,6 @@ static char_u *readfile_charconvert __AR
8b9a1c
 static void check_marks_read __ARGS((void));
8b9a1c
 #endif
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
-static int crypt_method_from_magic __ARGS((char *ptr, int len));
8b9a1c
 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));
8b9a1c
 #endif
8b9a1c
 #ifdef UNIX
8b9a1c
@@ -116,6 +101,9 @@ struct bw_info
8b9a1c
 #ifdef HAS_BW_FLAGS
8b9a1c
     int		bw_flags;	/* FIO_ flags */
8b9a1c
 #endif
8b9a1c
+#ifdef FEAT_CRYPT
8b9a1c
+    buf_T	*bw_buffer;	/* buffer being written */
8b9a1c
+#endif
8b9a1c
 #ifdef FEAT_MBYTE
8b9a1c
     char_u	bw_rest[CONV_RESTLEN]; /* not converted bytes */
8b9a1c
     int		bw_restlen;	/* nr of bytes in bw_rest[] */
8b9a1c
@@ -250,7 +238,6 @@ readfile(fname, sfname, from, lines_to_s
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
     char_u	*cryptkey = NULL;
8b9a1c
     int		did_ask_for_key = FALSE;
8b9a1c
-    int		crypt_method_used;
8b9a1c
 #endif
8b9a1c
 #ifdef FEAT_PERSISTENT_UNDO
8b9a1c
     context_sha256_T sha_ctx;
8b9a1c
@@ -966,13 +953,6 @@ retry:
8b9a1c
 #endif
8b9a1c
     }
8b9a1c
 
8b9a1c
-#ifdef FEAT_CRYPT
8b9a1c
-    if (cryptkey != NULL)
8b9a1c
-	/* Need to reset the state, but keep the key, don't want to ask for it
8b9a1c
-	 * again. */
8b9a1c
-	crypt_pop_state();
8b9a1c
-#endif
8b9a1c
-
8b9a1c
     /*
8b9a1c
      * When retrying with another "fenc" and the first time "fileformat"
8b9a1c
      * will be reset.
8b9a1c
@@ -1175,6 +1155,15 @@ retry:
8b9a1c
 	if (read_undo_file)
8b9a1c
 	    sha256_start(&sha_ctx);
8b9a1c
 #endif
8b9a1c
+#ifdef FEAT_CRYPT
8b9a1c
+	if (curbuf->b_cryptstate != NULL)
8b9a1c
+	{
8b9a1c
+	    /* Need to free the state, but keep the key, don't want to ask for
8b9a1c
+	     * it again. */
8b9a1c
+	    crypt_free_state(curbuf->b_cryptstate);
8b9a1c
+	    curbuf->b_cryptstate = NULL;
8b9a1c
+	}
8b9a1c
+#endif
8b9a1c
     }
8b9a1c
 
8b9a1c
     while (!error && !got_int)
8b9a1c
@@ -1339,6 +1328,76 @@ retry:
8b9a1c
 		    size = read_eintr(fd, ptr, size);
8b9a1c
 		}
8b9a1c
 
8b9a1c
+#ifdef FEAT_CRYPT
8b9a1c
+		/*
8b9a1c
+		 * At start of file: Check for magic number of encryption.
8b9a1c
+		 */
8b9a1c
+		if (filesize == 0 && size > 0)
8b9a1c
+		    cryptkey = check_for_cryptkey(cryptkey, ptr, &size,
8b9a1c
+						  &filesize, newfile, sfname,
8b9a1c
+						  &did_ask_for_key);
8b9a1c
+		/*
8b9a1c
+		 * Decrypt the read bytes.  This is done before checking for
8b9a1c
+		 * EOF because the crypt layer may be buffering.
8b9a1c
+		 */
8b9a1c
+		if (cryptkey != NULL && curbuf->b_cryptstate != NULL && size > 0)
8b9a1c
+		{
8b9a1c
+		    if (crypt_works_inplace(curbuf->b_cryptstate))
8b9a1c
+		    {
8b9a1c
+			crypt_decode_inplace(curbuf->b_cryptstate, ptr, size);
8b9a1c
+		    }
8b9a1c
+		    else
8b9a1c
+		    {
8b9a1c
+			char_u	*newptr = NULL;
8b9a1c
+			int	decrypted_size;
8b9a1c
+
8b9a1c
+			decrypted_size = crypt_decode_alloc(
8b9a1c
+				    curbuf->b_cryptstate, ptr, size, &newptr);
8b9a1c
+
8b9a1c
+			/* If the crypt layer is buffering, not producing
8b9a1c
+			 * anything yet, need to read more. */
8b9a1c
+			if (size > 0 && decrypted_size == 0)
8b9a1c
+			    continue;
8b9a1c
+
8b9a1c
+			if (linerest == 0)
8b9a1c
+			{
8b9a1c
+			    /* Simple case: reuse returned buffer (may be
8b9a1c
+			     * NULL, checked later). */
8b9a1c
+			    new_buffer = newptr;
8b9a1c
+			}
8b9a1c
+			else
8b9a1c
+			{
8b9a1c
+			    long_u	new_size;
8b9a1c
+
8b9a1c
+			    /* Need new buffer to add bytes carried over. */
8b9a1c
+			    new_size = (long_u)(decrypted_size + linerest + 1);
8b9a1c
+			    new_buffer = lalloc(new_size, FALSE);
8b9a1c
+			    if (new_buffer == NULL)
8b9a1c
+			    {
8b9a1c
+				do_outofmem_msg(new_size);
8b9a1c
+				error = TRUE;
8b9a1c
+				break;
8b9a1c
+			    }
8b9a1c
+
8b9a1c
+			    mch_memmove(new_buffer, buffer, linerest);
8b9a1c
+			    if (newptr != NULL)
8b9a1c
+				mch_memmove(new_buffer + linerest, newptr,
8b9a1c
+							      decrypted_size);
8b9a1c
+			}
8b9a1c
+
8b9a1c
+			if (new_buffer != NULL)
8b9a1c
+			{
8b9a1c
+			    vim_free(buffer);
8b9a1c
+			    buffer = new_buffer;
8b9a1c
+			    new_buffer = NULL;
8b9a1c
+			    line_start = buffer;
8b9a1c
+			    ptr = buffer + linerest;
8b9a1c
+			}
8b9a1c
+			size = decrypted_size;
8b9a1c
+		    }
8b9a1c
+		}
8b9a1c
+#endif
8b9a1c
+
8b9a1c
 		if (size <= 0)
8b9a1c
 		{
8b9a1c
 		    if (size < 0)		    /* read error */
8b9a1c
@@ -1403,21 +1462,6 @@ retry:
8b9a1c
 		    }
8b9a1c
 #endif
8b9a1c
 		}
8b9a1c
-
8b9a1c
-#ifdef FEAT_CRYPT
8b9a1c
-		/*
8b9a1c
-		 * At start of file: Check for magic number of encryption.
8b9a1c
-		 */
8b9a1c
-		if (filesize == 0)
8b9a1c
-		    cryptkey = check_for_cryptkey(cryptkey, ptr, &size,
8b9a1c
-					&filesize, newfile, sfname,
8b9a1c
-					&did_ask_for_key);
8b9a1c
-		/*
8b9a1c
-		 * Decrypt the read bytes.
8b9a1c
-		 */
8b9a1c
-		if (cryptkey != NULL && size > 0)
8b9a1c
-		    crypt_decode(ptr, size);
8b9a1c
-#endif
8b9a1c
 	    }
8b9a1c
 	    skip_read = FALSE;
8b9a1c
 
8b9a1c
@@ -1430,10 +1474,9 @@ retry:
8b9a1c
 	     */
8b9a1c
 	    if ((filesize == 0
8b9a1c
 # ifdef FEAT_CRYPT
8b9a1c
-		   || (filesize == (CRYPT_MAGIC_LEN
8b9a1c
-					   + crypt_salt_len[use_crypt_method]
8b9a1c
-					   + crypt_seed_len[use_crypt_method])
8b9a1c
-							  && cryptkey != NULL)
8b9a1c
+		   || (cryptkey != NULL
8b9a1c
+			&& filesize == crypt_get_header_len(
8b9a1c
+						 crypt_get_method_nr(curbuf)))
8b9a1c
 # endif
8b9a1c
 		       )
8b9a1c
 		    && (fio_flags == FIO_UCSBOM
8b9a1c
@@ -2262,15 +2305,15 @@ failed:
8b9a1c
 	save_file_ff(curbuf);		/* remember the current file format */
8b9a1c
 
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
-    crypt_method_used = use_crypt_method;
8b9a1c
-    if (cryptkey != NULL)
8b9a1c
+    if (curbuf->b_cryptstate != NULL)
8b9a1c
     {
8b9a1c
-	crypt_pop_state();
8b9a1c
-	if (cryptkey != curbuf->b_p_key)
8b9a1c
-	    free_crypt_key(cryptkey);
8b9a1c
-	/* don't set cryptkey to NULL, it's used below as a flag that
8b9a1c
-	 * encryption was used */
8b9a1c
+	crypt_free_state(curbuf->b_cryptstate);
8b9a1c
+	curbuf->b_cryptstate = NULL;
8b9a1c
     }
8b9a1c
+    if (cryptkey != NULL && cryptkey != curbuf->b_p_key)
8b9a1c
+	crypt_free_key(cryptkey);
8b9a1c
+    /* Don't set cryptkey to NULL, it's used below as a flag that
8b9a1c
+     * encryption was used. */
8b9a1c
 #endif
8b9a1c
 
8b9a1c
 #ifdef FEAT_MBYTE
8b9a1c
@@ -2457,10 +2500,7 @@ failed:
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
 	    if (cryptkey != NULL)
8b9a1c
 	    {
8b9a1c
-		if (crypt_method_used == 1)
8b9a1c
-		    STRCAT(IObuff, _("[blowfish]"));
8b9a1c
-		else
8b9a1c
-		    STRCAT(IObuff, _("[crypted]"));
8b9a1c
+		crypt_append_msg(curbuf);
8b9a1c
 		c = TRUE;
8b9a1c
 	    }
8b9a1c
 #endif
8b9a1c
@@ -2489,9 +2529,7 @@ failed:
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
 	    if (cryptkey != NULL)
8b9a1c
 		msg_add_lines(c, (long)linecnt, filesize
8b9a1c
-			- CRYPT_MAGIC_LEN
8b9a1c
-			- crypt_salt_len[use_crypt_method]
8b9a1c
-			- crypt_seed_len[use_crypt_method]);
8b9a1c
+			 - crypt_get_header_len(crypt_get_method_nr(curbuf)));
8b9a1c
 	    else
8b9a1c
 #endif
8b9a1c
 		msg_add_lines(c, (long)linecnt, filesize);
8b9a1c
@@ -2882,33 +2920,6 @@ check_marks_read()
8b9a1c
 
8b9a1c
 #if defined(FEAT_CRYPT) || defined(PROTO)
8b9a1c
 /*
8b9a1c
- * Get the crypt method used for a file from "ptr[len]", the magic text at the
8b9a1c
- * start of the file.
8b9a1c
- * Returns -1 when no encryption used.
8b9a1c
- */
8b9a1c
-    static int
8b9a1c
-crypt_method_from_magic(ptr, len)
8b9a1c
-    char  *ptr;
8b9a1c
-    int   len;
8b9a1c
-{
8b9a1c
-    int i;
8b9a1c
-
8b9a1c
-    for (i = 0; i < (int)(sizeof(crypt_magic) / sizeof(crypt_magic[0])); i++)
8b9a1c
-    {
8b9a1c
-	if (len < (CRYPT_MAGIC_LEN + crypt_salt_len[i] + crypt_seed_len[i]))
8b9a1c
-	    continue;
8b9a1c
-	if (memcmp(ptr, crypt_magic[i], CRYPT_MAGIC_LEN) == 0)
8b9a1c
-	    return i;
8b9a1c
-    }
8b9a1c
-
8b9a1c
-    i = (int)STRLEN(crypt_magic_head);
8b9a1c
-    if (len >= i && memcmp(ptr, crypt_magic_head, i) == 0)
8b9a1c
-	EMSG(_("E821: File is encrypted with unknown method"));
8b9a1c
-
8b9a1c
-    return -1;
8b9a1c
-}
8b9a1c
-
8b9a1c
-/*
8b9a1c
  * Check for magic number used for encryption.  Applies to the current buffer.
8b9a1c
  * If found, the magic number is removed from ptr[*sizep] and *sizep and
8b9a1c
  * *filesizep are updated.
8b9a1c
@@ -2924,7 +2935,7 @@ check_for_cryptkey(cryptkey, ptr, sizep,
8b9a1c
     char_u	*fname;		/* file name to display */
8b9a1c
     int		*did_ask;	/* flag: whether already asked for key */
8b9a1c
 {
8b9a1c
-    int method = crypt_method_from_magic((char *)ptr, *sizep);
8b9a1c
+    int method = crypt_method_nr_from_magic((char *)ptr, *sizep);
8b9a1c
     int b_p_ro = curbuf->b_p_ro;
8b9a1c
 
8b9a1c
     if (method >= 0)
8b9a1c
@@ -2933,9 +2944,8 @@ check_for_cryptkey(cryptkey, ptr, sizep,
8b9a1c
 	 * Avoids accidentally overwriting the file with garbage. */
8b9a1c
 	curbuf->b_p_ro = TRUE;
8b9a1c
 
8b9a1c
-	set_crypt_method(curbuf, method);
8b9a1c
-	if (method > 0)
8b9a1c
-	    (void)blowfish_self_test();
8b9a1c
+        /* Set the cryptmethod local to the buffer. */
8b9a1c
+	crypt_set_cm_option(curbuf, method);
8b9a1c
 	if (cryptkey == NULL && !*did_ask)
8b9a1c
 	{
8b9a1c
 	    if (*curbuf->b_p_key)
8b9a1c
@@ -2948,7 +2958,7 @@ check_for_cryptkey(cryptkey, ptr, sizep,
8b9a1c
 		 * Happens when retrying to detect encoding. */
8b9a1c
 		smsg((char_u *)_(need_key_msg), fname);
8b9a1c
 		msg_scroll = TRUE;
8b9a1c
-		cryptkey = get_crypt_key(newfile, FALSE);
8b9a1c
+		cryptkey = crypt_get_key(newfile, FALSE);
8b9a1c
 		*did_ask = TRUE;
8b9a1c
 
8b9a1c
 		/* check if empty key entered */
8b9a1c
@@ -2963,24 +2973,18 @@ check_for_cryptkey(cryptkey, ptr, sizep,
8b9a1c
 
8b9a1c
 	if (cryptkey != NULL)
8b9a1c
 	{
8b9a1c
-	    int seed_len = crypt_seed_len[method];
8b9a1c
-	    int salt_len = crypt_salt_len[method];
8b9a1c
+	    int header_len;
8b9a1c
 
8b9a1c
-	    crypt_push_state();
8b9a1c
-	    use_crypt_method = method;
8b9a1c
-	    if (method == 0)
8b9a1c
-		crypt_init_keys(cryptkey);
8b9a1c
-	    else
8b9a1c
-	    {
8b9a1c
-		bf_key_init(cryptkey, ptr + CRYPT_MAGIC_LEN, salt_len);
8b9a1c
-		bf_ofb_init(ptr + CRYPT_MAGIC_LEN + salt_len, seed_len);
8b9a1c
-	    }
8b9a1c
+	    curbuf->b_cryptstate = crypt_create_from_header(
8b9a1c
+						       method, cryptkey, ptr);
8b9a1c
+	    crypt_set_cm_option(curbuf, method);
8b9a1c
+
8b9a1c
+	    /* Remove cryptmethod specific header from the text. */
8b9a1c
+	    header_len = crypt_get_header_len(method);
8b9a1c
+	    *filesizep += header_len;
8b9a1c
+	    *sizep -= header_len;
8b9a1c
+	    mch_memmove(ptr, ptr + header_len, (size_t)*sizep);
8b9a1c
 
8b9a1c
-	    /* Remove magic number from the text */
8b9a1c
-	    *filesizep += CRYPT_MAGIC_LEN + salt_len + seed_len;
8b9a1c
-	    *sizep -= CRYPT_MAGIC_LEN + salt_len + seed_len;
8b9a1c
-	    mch_memmove(ptr, ptr + CRYPT_MAGIC_LEN + salt_len + seed_len,
8b9a1c
-							      (size_t)*sizep);
8b9a1c
 	    /* Restore the read-only flag. */
8b9a1c
 	    curbuf->b_p_ro = b_p_ro;
8b9a1c
 	}
8b9a1c
@@ -2992,85 +2996,6 @@ check_for_cryptkey(cryptkey, ptr, sizep,
8b9a1c
 
8b9a1c
     return cryptkey;
8b9a1c
 }
8b9a1c
-
8b9a1c
-/*
8b9a1c
- * Check for magic number used for encryption.  Applies to the current buffer.
8b9a1c
- * If found and decryption is possible returns OK;
8b9a1c
- */
8b9a1c
-    int
8b9a1c
-prepare_crypt_read(fp)
8b9a1c
-    FILE	*fp;
8b9a1c
-{
8b9a1c
-    int		method;
8b9a1c
-    char_u	buffer[CRYPT_MAGIC_LEN + CRYPT_SALT_LEN_MAX
8b9a1c
-						    + CRYPT_SEED_LEN_MAX + 2];
8b9a1c
-
8b9a1c
-    if (fread(buffer, CRYPT_MAGIC_LEN, 1, fp) != 1)
8b9a1c
-	return FAIL;
8b9a1c
-    method = crypt_method_from_magic((char *)buffer,
8b9a1c
-					CRYPT_MAGIC_LEN +
8b9a1c
-					CRYPT_SEED_LEN_MAX +
8b9a1c
-					CRYPT_SALT_LEN_MAX);
8b9a1c
-    if (method < 0 || method != get_crypt_method(curbuf))
8b9a1c
-	return FAIL;
8b9a1c
-
8b9a1c
-    crypt_push_state();
8b9a1c
-    if (method == 0)
8b9a1c
-	crypt_init_keys(curbuf->b_p_key);
8b9a1c
-    else
8b9a1c
-    {
8b9a1c
-	int salt_len = crypt_salt_len[method];
8b9a1c
-	int seed_len = crypt_seed_len[method];
8b9a1c
-
8b9a1c
-	if (fread(buffer, salt_len + seed_len, 1, fp) != 1)
8b9a1c
-	    return FAIL;
8b9a1c
-	bf_key_init(curbuf->b_p_key, buffer, salt_len);
8b9a1c
-	bf_ofb_init(buffer + salt_len, seed_len);
8b9a1c
-    }
8b9a1c
-    return OK;
8b9a1c
-}
8b9a1c
-
8b9a1c
-/*
8b9a1c
- * Prepare for writing encrypted bytes for buffer "buf".
8b9a1c
- * Returns a pointer to an allocated header of length "*lenp".
8b9a1c
- * When out of memory returns NULL.
8b9a1c
- * Otherwise calls crypt_push_state(), call crypt_pop_state() later.
8b9a1c
- */
8b9a1c
-    char_u *
8b9a1c
-prepare_crypt_write(buf, lenp)
8b9a1c
-    buf_T *buf;
8b9a1c
-    int   *lenp;
8b9a1c
-{
8b9a1c
-    char_u  *header;
8b9a1c
-    int	    seed_len = crypt_seed_len[get_crypt_method(buf)];
8b9a1c
-    int     salt_len = crypt_salt_len[get_crypt_method(buf)];
8b9a1c
-    char_u  *salt;
8b9a1c
-    char_u  *seed;
8b9a1c
-
8b9a1c
-    header = alloc_clear(CRYPT_MAGIC_LEN + CRYPT_SALT_LEN_MAX
8b9a1c
-						    + CRYPT_SEED_LEN_MAX + 2);
8b9a1c
-    if (header != NULL)
8b9a1c
-    {
8b9a1c
-	crypt_push_state();
8b9a1c
-	use_crypt_method = get_crypt_method(buf);  /* select zip or blowfish */
8b9a1c
-	vim_strncpy(header, (char_u *)crypt_magic[use_crypt_method],
8b9a1c
-							     CRYPT_MAGIC_LEN);
8b9a1c
-	if (use_crypt_method == 0)
8b9a1c
-	    crypt_init_keys(buf->b_p_key);
8b9a1c
-	else
8b9a1c
-	{
8b9a1c
-	    /* Using blowfish, add salt and seed. */
8b9a1c
-	    salt = header + CRYPT_MAGIC_LEN;
8b9a1c
-	    seed = salt + salt_len;
8b9a1c
-	    sha2_seed(salt, salt_len, seed, seed_len);
8b9a1c
-	    bf_key_init(buf->b_p_key, salt, salt_len);
8b9a1c
-	    bf_ofb_init(seed, seed_len);
8b9a1c
-	}
8b9a1c
-    }
8b9a1c
-    *lenp = CRYPT_MAGIC_LEN + salt_len + seed_len;
8b9a1c
-    return header;
8b9a1c
-}
8b9a1c
-
8b9a1c
 #endif  /* FEAT_CRYPT */
8b9a1c
 
8b9a1c
 #ifdef UNIX
8b9a1c
@@ -3224,9 +3149,6 @@ buf_write(buf, fname, sfname, start, end
8b9a1c
     int		    write_undo_file = FALSE;
8b9a1c
     context_sha256_T sha_ctx;
8b9a1c
 #endif
8b9a1c
-#ifdef FEAT_CRYPT
8b9a1c
-    int		    crypt_method_used;
8b9a1c
-#endif
8b9a1c
 
8b9a1c
     if (fname == NULL || *fname == NUL)	/* safety check */
8b9a1c
 	return FAIL;
8b9a1c
@@ -3262,6 +3184,9 @@ buf_write(buf, fname, sfname, start, end
8b9a1c
     write_info.bw_iconv_fd = (iconv_t)-1;
8b9a1c
 # endif
8b9a1c
 #endif
8b9a1c
+#ifdef FEAT_CRYPT
8b9a1c
+    write_info.bw_buffer = buf;
8b9a1c
+#endif
8b9a1c
 
8b9a1c
     /* After writing a file changedtick changes but we don't want to display
8b9a1c
      * the line. */
8b9a1c
@@ -4505,17 +4430,17 @@ restore_backup:
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
     if (*buf->b_p_key != NUL && !filtering)
8b9a1c
     {
8b9a1c
-	char_u *header;
8b9a1c
-	int    header_len;
8b9a1c
+	char_u		*header;
8b9a1c
+	int		header_len;
8b9a1c
 
8b9a1c
-	header = prepare_crypt_write(buf, &header_len);
8b9a1c
-	if (header == NULL)
8b9a1c
+	buf->b_cryptstate = crypt_create_for_writing(crypt_get_method_nr(buf),
8b9a1c
+					  buf->b_p_key, &header, &header_len);
8b9a1c
+	if (buf->b_cryptstate == NULL || header == NULL)
8b9a1c
 	    end = 0;
8b9a1c
 	else
8b9a1c
 	{
8b9a1c
-	    /* Write magic number, so that Vim knows that this file is
8b9a1c
-	     * encrypted when reading it again.  This also undergoes utf-8 to
8b9a1c
-	     * ucs-2/4 conversion when needed. */
8b9a1c
+	    /* Write magic number, so that Vim knows how this file is
8b9a1c
+	     * encrypted when reading it back. */
8b9a1c
 	    write_info.bw_buf = header;
8b9a1c
 	    write_info.bw_len = header_len;
8b9a1c
 	    write_info.bw_flags = FIO_NOCONVERT;
8b9a1c
@@ -4769,9 +4694,11 @@ restore_backup:
8b9a1c
 	mch_set_acl(wfname, acl);
8b9a1c
 #endif
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
-    crypt_method_used = use_crypt_method;
8b9a1c
-    if (wb_flags & FIO_ENCRYPTED)
8b9a1c
-	crypt_pop_state();
8b9a1c
+    if (buf->b_cryptstate != NULL)
8b9a1c
+    {
8b9a1c
+	crypt_free_state(buf->b_cryptstate);
8b9a1c
+	buf->b_cryptstate = NULL;
8b9a1c
+    }
8b9a1c
 #endif
8b9a1c
 
8b9a1c
 
8b9a1c
@@ -4924,10 +4851,7 @@ restore_backup:
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
 	if (wb_flags & FIO_ENCRYPTED)
8b9a1c
 	{
8b9a1c
-	    if (crypt_method_used == 1)
8b9a1c
-		STRCAT(IObuff, _("[blowfish]"));
8b9a1c
-	    else
8b9a1c
-		STRCAT(IObuff, _("[crypted]"));
8b9a1c
+	    crypt_append_msg(buf);
8b9a1c
 	    c = TRUE;
8b9a1c
 	}
8b9a1c
 #endif
8b9a1c
@@ -5740,8 +5664,26 @@ buf_write_bytes(ip)
8b9a1c
 #endif /* FEAT_MBYTE */
8b9a1c
 
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
-    if (flags & FIO_ENCRYPTED)		/* encrypt the data */
8b9a1c
-	crypt_encode(buf, len, buf);
8b9a1c
+    if (flags & FIO_ENCRYPTED)
8b9a1c
+    {
8b9a1c
+	/* Encrypt the data. Do it in-place if possible, otherwise use an
8b9a1c
+	 * allocated buffer. */
8b9a1c
+	if (crypt_works_inplace(ip->bw_buffer->b_cryptstate))
8b9a1c
+	{
8b9a1c
+	    crypt_encode_inplace(ip->bw_buffer->b_cryptstate, buf, len);
8b9a1c
+	}
8b9a1c
+	else
8b9a1c
+	{
8b9a1c
+	    char_u *outbuf;
8b9a1c
+
8b9a1c
+	    len = crypt_encode_alloc(curbuf->b_cryptstate, buf, len, &outbuf);
8b9a1c
+	    if (len == 0)
8b9a1c
+		return OK;  /* Crypt layer is buffering, will flush later. */
8b9a1c
+	    wlen = write_eintr(ip->bw_fd, outbuf, len);
8b9a1c
+	    vim_free(outbuf);
8b9a1c
+	    return (wlen < len) ? FAIL : OK;
8b9a1c
+	}
8b9a1c
+    }
8b9a1c
 #endif
8b9a1c
 
8b9a1c
     wlen = write_eintr(ip->bw_fd, buf, len);
8b9a1c
diff -up vim74/src/globals.h.blowfish2 vim74/src/globals.h
8b9a1c
--- vim74/src/globals.h.blowfish2	2017-09-05 14:47:33.909920425 +0200
8b9a1c
+++ vim74/src/globals.h	2017-09-05 14:47:34.950912022 +0200
8b9a1c
@@ -105,10 +105,6 @@ EXTERN int	exec_from_reg INIT(= FALSE);
8b9a1c
 
8b9a1c
 EXTERN int	screen_cleared INIT(= FALSE);	/* screen has been cleared */
8b9a1c
 
8b9a1c
-#ifdef FEAT_CRYPT
8b9a1c
-EXTERN int      use_crypt_method INIT(= 0);
8b9a1c
-#endif
8b9a1c
-
8b9a1c
 /*
8b9a1c
  * When '$' is included in 'cpoptions' option set:
8b9a1c
  * When a change command is given that deletes only part of a line, a dollar
8b9a1c
diff -up vim74/src/main.c.blowfish2 vim74/src/main.c
8b9a1c
--- vim74/src/main.c.blowfish2	2017-09-05 14:47:34.571915081 +0200
8b9a1c
+++ vim74/src/main.c	2017-09-05 14:47:34.955911982 +0200
8b9a1c
@@ -845,8 +845,7 @@ vim_main2(int argc UNUSED, char **argv U
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
     if (params.ask_for_key)
8b9a1c
     {
8b9a1c
-	(void)blowfish_self_test();
8b9a1c
-	(void)get_crypt_key(TRUE, TRUE);
8b9a1c
+	(void)crypt_get_key(TRUE, TRUE);
8b9a1c
 	TIME_MSG("getting crypt key");
8b9a1c
     }
8b9a1c
 #endif
8b9a1c
diff -up vim74/src/Makefile.blowfish2 vim74/src/Makefile
8b9a1c
--- vim74/src/Makefile.blowfish2	2017-09-05 14:47:34.847912854 +0200
8b9a1c
+++ vim74/src/Makefile	2017-09-05 14:47:34.956911974 +0200
8b9a1c
@@ -1427,6 +1427,8 @@ BASIC_SRC = \
8b9a1c
 	blowfish.c \
8b9a1c
 	buffer.c \
8b9a1c
 	charset.c \
8b9a1c
+	crypt.c \
8b9a1c
+	crypt_zip.c \
8b9a1c
 	diff.c \
8b9a1c
 	digraph.c \
8b9a1c
 	edit.c \
8b9a1c
@@ -1516,6 +1518,8 @@ OBJ_COMMON = \
8b9a1c
 	objects/buffer.o \
8b9a1c
 	objects/blowfish.o \
8b9a1c
 	objects/charset.o \
8b9a1c
+	objects/crypt.o \
8b9a1c
+	objects/crypt_zip.o \
8b9a1c
 	objects/diff.o \
8b9a1c
 	objects/digraph.o \
8b9a1c
 	objects/edit.o \
8b9a1c
@@ -1585,6 +1589,8 @@ PRO_AUTO = \
8b9a1c
 	blowfish.pro \
8b9a1c
 	buffer.pro \
8b9a1c
 	charset.pro \
8b9a1c
+	crypt.pro \
8b9a1c
+	crypt_zip.pro \
8b9a1c
 	diff.pro \
8b9a1c
 	digraph.pro \
8b9a1c
 	edit.pro \
8b9a1c
@@ -1745,10 +1751,11 @@ xxd/xxd$(EXEEXT): xxd/xxd.c
8b9a1c
 languages:
8b9a1c
 	@if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \
8b9a1c
 		cd $(PODIR); \
8b9a1c
-		CC="$(CC)" $(MAKE) prefix=$(DESTDIR)$(prefix); \
8b9a1c
+		  CC="$(CC)" $(MAKE) prefix=$(DESTDIR)$(prefix); \
8b9a1c
 	fi
8b9a1c
 	-@if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \
8b9a1c
-		cd $(PODIR); CC="$(CC)" $(MAKE) prefix=$(DESTDIR)$(prefix) converted; \
8b9a1c
+		cd $(PODIR); \
8b9a1c
+		  CC="$(CC)" $(MAKE) prefix=$(DESTDIR)$(prefix) converted; \
8b9a1c
 	fi
8b9a1c
 
8b9a1c
 # Update the *.po files for changes in the sources.  Only run manually.
8b9a1c
@@ -1874,6 +1881,12 @@ unittest unittests: $(UNITTEST_TARGETS)
8b9a1c
 
8b9a1c
 # Run individual test, assuming that Vim was already compiled.
8b9a1c
 test1 test2 test3 test4 test5 test6 test7 test8 test9 \
8b9a1c
+	test_breakindent \
8b9a1c
+	test_changelist \
8b9a1c
+	test_insertcount \
8b9a1c
+	test_listlbr \
8b9a1c
+	test_listlbr_utf8 \
8b9a1c
+	test_qf_title \
8b9a1c
 	test10 test11 test12 test13 test14 test15 test16 test17 test18 test19 \
8b9a1c
 	test20 test21 test22 test23 test24 test25 test26 test27 test28 test29 \
8b9a1c
 	test30 test31 test32 test33 test34 test35 test36 test37 test38 test39 \
8b9a1c
@@ -2494,6 +2507,12 @@ objects/buffer.o: buffer.c
8b9a1c
 objects/charset.o: charset.c
8b9a1c
 	$(CCC) -o $@ charset.c
8b9a1c
 
8b9a1c
+objects/crypt.o: crypt.c
8b9a1c
+	$(CCC) -o $@ crypt.c
8b9a1c
+
8b9a1c
+objects/crypt_zip.o: crypt_zip.c
8b9a1c
+	$(CCC) -o $@ crypt_zip.c
8b9a1c
+
8b9a1c
 objects/diff.o: diff.c
8b9a1c
 	$(CCC) -o $@ diff.c
8b9a1c
 
8b9a1c
@@ -2843,6 +2862,14 @@ objects/charset.o: charset.c vim.h auto/
8b9a1c
  ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
8b9a1c
  gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \
8b9a1c
  arabic.h
8b9a1c
+objects/crypt.o: crypt.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \
8b9a1c
+ ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
8b9a1c
+ gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \
8b9a1c
+ arabic.h
8b9a1c
+objects/crypt_zip.o: crypt_zip.c vim.h auto/config.h feature.h os_unix.h \
8b9a1c
+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
8b9a1c
+ regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
8b9a1c
+ globals.h farsi.h arabic.h
8b9a1c
 objects/diff.o: diff.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \
8b9a1c
  ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
8b9a1c
  gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \
8b9a1c
diff -up vim74/src/memline.c.blowfish2 vim74/src/memline.c
8b9a1c
--- vim74/src/memline.c.blowfish2	2017-09-05 14:47:34.217917939 +0200
8b9a1c
+++ vim74/src/memline.c	2017-09-05 14:47:34.957911966 +0200
8b9a1c
@@ -63,6 +63,15 @@ typedef struct pointer_entry	PTR_EN;
8b9a1c
 #define BLOCK0_ID1     '0'		    /* block 0 id 1 */
8b9a1c
 #define BLOCK0_ID1_C0  'c'		    /* block 0 id 1 'cm' 0 */
8b9a1c
 #define BLOCK0_ID1_C1  'C'		    /* block 0 id 1 'cm' 1 */
8b9a1c
+#define BLOCK0_ID1_C2  'd'		    /* block 0 id 1 'cm' 2 */
8b9a1c
+
8b9a1c
+#if defined(FEAT_CRYPT)
8b9a1c
+static int id1_codes[] = {
8b9a1c
+    BLOCK0_ID1_C0,  /* CRYPT_M_ZIP */
8b9a1c
+    BLOCK0_ID1_C1,  /* CRYPT_M_BF */
8b9a1c
+    BLOCK0_ID1_C2,  /* CRYPT_M_BF2 */
8b9a1c
+};
8b9a1c
+#endif
8b9a1c
 
8b9a1c
 /*
8b9a1c
  * pointer to a block, used in a pointer block
8b9a1c
@@ -151,7 +160,7 @@ struct data_block
8b9a1c
 struct block0
8b9a1c
 {
8b9a1c
     char_u	b0_id[2];	/* id for block 0: BLOCK0_ID0 and BLOCK0_ID1,
8b9a1c
-				 * BLOCK0_ID1_C0, BLOCK0_ID1_C1 */
8b9a1c
+				 * BLOCK0_ID1_C0, BLOCK0_ID1_C1, etc. */
8b9a1c
     char_u	b0_version[10];	/* Vim version string */
8b9a1c
     char_u	b0_page_size[4];/* number of bytes per page */
8b9a1c
     char_u	b0_mtime[4];	/* last modification time of file */
8b9a1c
@@ -226,6 +235,7 @@ typedef enum {
8b9a1c
 } upd_block0_T;
8b9a1c
 
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
+static void ml_set_mfp_crypt __ARGS((buf_T *buf));
8b9a1c
 static void ml_set_b0_crypt __ARGS((buf_T *buf, ZERO_BL *b0p));
8b9a1c
 #endif
8b9a1c
 static int ml_check_b0_id __ARGS((ZERO_BL *b0p));
8b9a1c
@@ -256,7 +266,7 @@ static long char_to_long __ARGS((char_u
8b9a1c
 static char_u *make_percent_swname __ARGS((char_u *dir, char_u *name));
8b9a1c
 #endif
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
-static void ml_crypt_prepare __ARGS((memfile_T *mfp, off_t offset, int reading));
8b9a1c
+static cryptstate_T *ml_crypt_prepare __ARGS((memfile_T *mfp, off_t offset, int reading));
8b9a1c
 #endif
8b9a1c
 #ifdef FEAT_BYTEOFF
8b9a1c
 static void ml_updatechunk __ARGS((buf_T *buf, long line, long len, int updtype));
8b9a1c
@@ -356,8 +366,7 @@ ml_open(buf)
8b9a1c
 	b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL;
8b9a1c
 	long_to_char(mch_get_pid(), b0p->b0_pid);
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
-	if (*buf->b_p_key != NUL)
8b9a1c
-	    ml_set_b0_crypt(buf, b0p);
8b9a1c
+	ml_set_b0_crypt(buf, b0p);
8b9a1c
 #endif
8b9a1c
     }
8b9a1c
 
8b9a1c
@@ -422,6 +431,25 @@ error:
8b9a1c
 
8b9a1c
 #if defined(FEAT_CRYPT) || defined(PROTO)
8b9a1c
 /*
8b9a1c
+ * Prepare encryption for "buf" for the current key and method.
8b9a1c
+ */
8b9a1c
+    static void
8b9a1c
+ml_set_mfp_crypt(buf)
8b9a1c
+    buf_T	*buf;
8b9a1c
+{
8b9a1c
+    if (*buf->b_p_key != NUL)
8b9a1c
+    {
8b9a1c
+	int method_nr = crypt_get_method_nr(buf);
8b9a1c
+
8b9a1c
+	if (method_nr > CRYPT_M_ZIP)
8b9a1c
+	{
8b9a1c
+	    /* Generate a seed and store it in the memfile. */
8b9a1c
+	    sha2_seed(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN, NULL, 0);
8b9a1c
+	}
8b9a1c
+    }
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
  * Prepare encryption for "buf" with block 0 "b0p".
8b9a1c
  */
8b9a1c
     static void
8b9a1c
@@ -433,11 +461,11 @@ ml_set_b0_crypt(buf, b0p)
8b9a1c
 	b0p->b0_id[1] = BLOCK0_ID1;
8b9a1c
     else
8b9a1c
     {
8b9a1c
-	if (get_crypt_method(buf) == 0)
8b9a1c
-	    b0p->b0_id[1] = BLOCK0_ID1_C0;
8b9a1c
-	else
8b9a1c
+	int method_nr = crypt_get_method_nr(buf);
8b9a1c
+
8b9a1c
+	b0p->b0_id[1] = id1_codes[method_nr];
8b9a1c
+	if (method_nr > CRYPT_M_ZIP)
8b9a1c
 	{
8b9a1c
-	    b0p->b0_id[1] = BLOCK0_ID1_C1;
8b9a1c
 	    /* Generate a seed and store it in block 0 and in the memfile. */
8b9a1c
 	    sha2_seed(&b0p->b0_seed, MF_SEED_LEN, NULL, 0);
8b9a1c
 	    mch_memmove(buf->b_ml.ml_mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
8b9a1c
@@ -884,7 +912,8 @@ ml_check_b0_id(b0p)
8b9a1c
     if (b0p->b0_id[0] != BLOCK0_ID0
8b9a1c
 	    || (b0p->b0_id[1] != BLOCK0_ID1
8b9a1c
 		&& b0p->b0_id[1] != BLOCK0_ID1_C0
8b9a1c
-		&& b0p->b0_id[1] != BLOCK0_ID1_C1)
8b9a1c
+		&& b0p->b0_id[1] != BLOCK0_ID1_C1
8b9a1c
+		&& b0p->b0_id[1] != BLOCK0_ID1_C2)
8b9a1c
 	    )
8b9a1c
 	return FAIL;
8b9a1c
     return OK;
8b9a1c
@@ -903,8 +932,19 @@ ml_upd_block0(buf, what)
8b9a1c
     ZERO_BL	*b0p;
8b9a1c
 
8b9a1c
     mfp = buf->b_ml.ml_mfp;
8b9a1c
-    if (mfp == NULL || (hp = mf_get(mfp, (blocknr_T)0, 1)) == NULL)
8b9a1c
+    if (mfp == NULL)
8b9a1c
+	return;
8b9a1c
+    hp = mf_get(mfp, (blocknr_T)0, 1);
8b9a1c
+    if (hp == NULL)
8b9a1c
+    {
8b9a1c
+#ifdef FEAT_CRYPT
8b9a1c
+	/* Possibly update the seed in the memfile before there is a block0. */
8b9a1c
+	if (what == UB_CRYPT)
8b9a1c
+	    ml_set_mfp_crypt(buf);
8b9a1c
+#endif
8b9a1c
 	return;
8b9a1c
+    }
8b9a1c
+
8b9a1c
     b0p = (ZERO_BL *)(hp->bh_data);
8b9a1c
     if (ml_check_b0_id(b0p) == FAIL)
8b9a1c
 	EMSG(_("E304: ml_upd_block0(): Didn't get block 0??"));
8b9a1c
@@ -1252,14 +1292,12 @@ ml_recover()
8b9a1c
     }
8b9a1c
 
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
-    if (b0p->b0_id[1] == BLOCK0_ID1_C0)
8b9a1c
-	b0_cm = 0;
8b9a1c
-    else if (b0p->b0_id[1] == BLOCK0_ID1_C1)
8b9a1c
-    {
8b9a1c
-	b0_cm = 1;
8b9a1c
+    for (i = 0; i < (int)(sizeof(id1_codes) / sizeof(int)); ++i)
8b9a1c
+	if (id1_codes[i] == b0p->b0_id[1])
8b9a1c
+	    b0_cm = i;
8b9a1c
+    if (b0_cm > 0)
8b9a1c
 	mch_memmove(mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
8b9a1c
-    }
8b9a1c
-    set_crypt_method(buf, b0_cm);
8b9a1c
+    crypt_set_cm_option(buf, b0_cm < 0 ? 0 : b0_cm);
8b9a1c
 #else
8b9a1c
     if (b0p->b0_id[1] != BLOCK0_ID1)
8b9a1c
     {
8b9a1c
@@ -1386,7 +1424,7 @@ ml_recover()
8b9a1c
 	}
8b9a1c
 	else
8b9a1c
 	    smsg((char_u *)_(need_key_msg), fname_used);
8b9a1c
-	buf->b_p_key = get_crypt_key(FALSE, FALSE);
8b9a1c
+	buf->b_p_key = crypt_get_key(FALSE, FALSE);
8b9a1c
 	if (buf->b_p_key == NULL)
8b9a1c
 	    buf->b_p_key = curbuf->b_p_key;
8b9a1c
 	else if (*buf->b_p_key == NUL)
8b9a1c
@@ -4813,6 +4851,7 @@ ml_encrypt_data(mfp, data, offset, size)
8b9a1c
     char_u	*text_start;
8b9a1c
     char_u	*new_data;
8b9a1c
     int		text_len;
8b9a1c
+    cryptstate_T *state;
8b9a1c
 
8b9a1c
     if (dp->db_id != DATA_ID)
8b9a1c
 	return data;
8b9a1c
@@ -4828,10 +4867,9 @@ ml_encrypt_data(mfp, data, offset, size)
8b9a1c
     mch_memmove(new_data, dp, head_end - (char_u *)dp);
8b9a1c
 
8b9a1c
     /* Encrypt the text. */
8b9a1c
-    crypt_push_state();
8b9a1c
-    ml_crypt_prepare(mfp, offset, FALSE);
8b9a1c
-    crypt_encode(text_start, text_len, new_data + dp->db_txt_start);
8b9a1c
-    crypt_pop_state();
8b9a1c
+    state = ml_crypt_prepare(mfp, offset, FALSE);
8b9a1c
+    crypt_encode(state, text_start, text_len, new_data + dp->db_txt_start);
8b9a1c
+    crypt_free_state(state);
8b9a1c
 
8b9a1c
     /* Clear the gap. */
8b9a1c
     if (head_end < text_start)
8b9a1c
@@ -4854,6 +4892,7 @@ ml_decrypt_data(mfp, data, offset, size)
8b9a1c
     char_u	*head_end;
8b9a1c
     char_u	*text_start;
8b9a1c
     int		text_len;
8b9a1c
+    cryptstate_T *state;
8b9a1c
 
8b9a1c
     if (dp->db_id == DATA_ID)
8b9a1c
     {
8b9a1c
@@ -4866,17 +4905,17 @@ ml_decrypt_data(mfp, data, offset, size)
8b9a1c
 	    return;  /* data was messed up */
8b9a1c
 
8b9a1c
 	/* Decrypt the text in place. */
8b9a1c
-	crypt_push_state();
8b9a1c
-	ml_crypt_prepare(mfp, offset, TRUE);
8b9a1c
-	crypt_decode(text_start, text_len);
8b9a1c
-	crypt_pop_state();
8b9a1c
+	state = ml_crypt_prepare(mfp, offset, TRUE);
8b9a1c
+	crypt_decode_inplace(state, text_start, text_len);
8b9a1c
+	crypt_free_state(state);
8b9a1c
     }
8b9a1c
 }
8b9a1c
 
8b9a1c
 /*
8b9a1c
  * Prepare for encryption/decryption, using the key, seed and offset.
8b9a1c
+ * Return an allocated cryptstate_T *.
8b9a1c
  */
8b9a1c
-    static void
8b9a1c
+    static cryptstate_T *
8b9a1c
 ml_crypt_prepare(mfp, offset, reading)
8b9a1c
     memfile_T	*mfp;
8b9a1c
     off_t	offset;
8b9a1c
@@ -4884,38 +4923,37 @@ ml_crypt_prepare(mfp, offset, reading)
8b9a1c
 {
8b9a1c
     buf_T	*buf = mfp->mf_buffer;
8b9a1c
     char_u	salt[50];
8b9a1c
-    int		method;
8b9a1c
+    int		method_nr;
8b9a1c
     char_u	*key;
8b9a1c
     char_u	*seed;
8b9a1c
 
8b9a1c
     if (reading && mfp->mf_old_key != NULL)
8b9a1c
     {
8b9a1c
 	/* Reading back blocks with the previous key/method/seed. */
8b9a1c
-	method = mfp->mf_old_cm;
8b9a1c
+	method_nr = mfp->mf_old_cm;
8b9a1c
 	key = mfp->mf_old_key;
8b9a1c
 	seed = mfp->mf_old_seed;
8b9a1c
     }
8b9a1c
     else
8b9a1c
     {
8b9a1c
-	method = get_crypt_method(buf);
8b9a1c
+	method_nr = crypt_get_method_nr(buf);
8b9a1c
 	key = buf->b_p_key;
8b9a1c
 	seed = mfp->mf_seed;
8b9a1c
     }
8b9a1c
 
8b9a1c
-    use_crypt_method = method;  /* select pkzip or blowfish */
8b9a1c
-    if (method == 0)
8b9a1c
+    if (method_nr == CRYPT_M_ZIP)
8b9a1c
     {
8b9a1c
+	/* For PKzip: Append the offset to the key, so that we use a different
8b9a1c
+	 * key for every block. */
8b9a1c
 	vim_snprintf((char *)salt, sizeof(salt), "%s%ld", key, (long)offset);
8b9a1c
-	crypt_init_keys(salt);
8b9a1c
-    }
8b9a1c
-    else
8b9a1c
-    {
8b9a1c
-	/* Using blowfish, add salt and seed. We use the byte offset of the
8b9a1c
-	 * block for the salt. */
8b9a1c
-	vim_snprintf((char *)salt, sizeof(salt), "%ld", (long)offset);
8b9a1c
-	bf_key_init(key, salt, (int)STRLEN(salt));
8b9a1c
-	bf_ofb_init(seed, MF_SEED_LEN);
8b9a1c
+	return crypt_create(method_nr, salt, NULL, 0, NULL, 0);
8b9a1c
     }
8b9a1c
+
8b9a1c
+    /* Using blowfish or better: add salt and seed. We use the byte offset
8b9a1c
+     * of the block for the salt. */
8b9a1c
+    vim_snprintf((char *)salt, sizeof(salt), "%ld", (long)offset);
8b9a1c
+    return crypt_create(method_nr, key, salt, (int)STRLEN(salt),
8b9a1c
+							   seed, MF_SEED_LEN);
8b9a1c
 }
8b9a1c
 
8b9a1c
 #endif
8b9a1c
diff -up vim74/src/misc2.c.blowfish2 vim74/src/misc2.c
8b9a1c
--- vim74/src/misc2.c.blowfish2	2017-09-05 14:47:34.461915969 +0200
8b9a1c
+++ vim74/src/misc2.c	2017-09-05 14:47:34.959911949 +0200
8b9a1c
@@ -3803,322 +3803,6 @@ update_mouseshape(shape_idx)
8b9a1c
 #endif /* CURSOR_SHAPE */
8b9a1c
 
8b9a1c
 
8b9a1c
-#ifdef FEAT_CRYPT
8b9a1c
-/*
8b9a1c
- * Optional encryption support.
8b9a1c
- * Mohsin Ahmed, mosh@sasi.com, 98-09-24
8b9a1c
- * Based on zip/crypt sources.
8b9a1c
- *
8b9a1c
- * NOTE FOR USA: Since 2000 exporting this code from the USA is allowed to
8b9a1c
- * most countries.  There are a few exceptions, but that still should not be a
8b9a1c
- * problem since this code was originally created in Europe and India.
8b9a1c
- *
8b9a1c
- * Blowfish addition originally made by Mohsin Ahmed,
8b9a1c
- * http://www.cs.albany.edu/~mosh 2010-03-14
8b9a1c
- * Based on blowfish by Bruce Schneier (http://www.schneier.com/blowfish.html)
8b9a1c
- * and sha256 by Christophe Devine.
8b9a1c
- */
8b9a1c
-
8b9a1c
-/* from zip.h */
8b9a1c
-
8b9a1c
-typedef unsigned short ush;	/* unsigned 16-bit value */
8b9a1c
-typedef unsigned long  ulg;	/* unsigned 32-bit value */
8b9a1c
-
8b9a1c
-static void make_crc_tab __ARGS((void));
8b9a1c
-
8b9a1c
-static ulg crc_32_tab[256];
8b9a1c
-
8b9a1c
-/*
8b9a1c
- * Fill the CRC table.
8b9a1c
- */
8b9a1c
-    static void
8b9a1c
-make_crc_tab()
8b9a1c
-{
8b9a1c
-    ulg		s,t,v;
8b9a1c
-    static int	done = FALSE;
8b9a1c
-
8b9a1c
-    if (done)
8b9a1c
-	return;
8b9a1c
-    for (t = 0; t < 256; t++)
8b9a1c
-    {
8b9a1c
-	v = t;
8b9a1c
-	for (s = 0; s < 8; s++)
8b9a1c
-	    v = (v >> 1) ^ ((v & 1) * (ulg)0xedb88320L);
8b9a1c
-	crc_32_tab[t] = v;
8b9a1c
-    }
8b9a1c
-    done = TRUE;
8b9a1c
-}
8b9a1c
-
8b9a1c
-#define CRC32(c, b) (crc_32_tab[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
8b9a1c
-
8b9a1c
-static ulg keys[3]; /* keys defining the pseudo-random sequence */
8b9a1c
-
8b9a1c
-/*
8b9a1c
- * Return the next byte in the pseudo-random sequence.
8b9a1c
- */
8b9a1c
-#define DECRYPT_BYTE_ZIP(t) { \
8b9a1c
-    ush temp; \
8b9a1c
- \
8b9a1c
-    temp = (ush)keys[2] | 2; \
8b9a1c
-    t = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff); \
8b9a1c
-}
8b9a1c
-
8b9a1c
-/*
8b9a1c
- * Update the encryption keys with the next byte of plain text.
8b9a1c
- */
8b9a1c
-#define UPDATE_KEYS_ZIP(c) { \
8b9a1c
-    keys[0] = CRC32(keys[0], (c)); \
8b9a1c
-    keys[1] += keys[0] & 0xff; \
8b9a1c
-    keys[1] = keys[1] * 134775813L + 1; \
8b9a1c
-    keys[2] = CRC32(keys[2], (int)(keys[1] >> 24)); \
8b9a1c
-}
8b9a1c
-
8b9a1c
-static int crypt_busy = 0;
8b9a1c
-static ulg saved_keys[3];
8b9a1c
-static int saved_crypt_method;
8b9a1c
-
8b9a1c
-/*
8b9a1c
- * Return int value for crypt method string:
8b9a1c
- * 0 for "zip", the old method.  Also for any non-valid value.
8b9a1c
- * 1 for "blowfish".
8b9a1c
- */
8b9a1c
-    int
8b9a1c
-crypt_method_from_string(s)
8b9a1c
-    char_u  *s;
8b9a1c
-{
8b9a1c
-    return *s == 'b' ? 1 : 0;
8b9a1c
-}
8b9a1c
-
8b9a1c
-/*
8b9a1c
- * Get the crypt method for buffer "buf" as a number.
8b9a1c
- */
8b9a1c
-    int
8b9a1c
-get_crypt_method(buf)
8b9a1c
-    buf_T *buf;
8b9a1c
-{
8b9a1c
-    return crypt_method_from_string(*buf->b_p_cm == NUL ? p_cm : buf->b_p_cm);
8b9a1c
-}
8b9a1c
-
8b9a1c
-/*
8b9a1c
- * Set the crypt method for buffer "buf" to "method" using the int value as
8b9a1c
- * returned by crypt_method_from_string().
8b9a1c
- */
8b9a1c
-    void
8b9a1c
-set_crypt_method(buf, method)
8b9a1c
-    buf_T   *buf;
8b9a1c
-    int	    method;
8b9a1c
-{
8b9a1c
-    free_string_option(buf->b_p_cm);
8b9a1c
-    buf->b_p_cm = vim_strsave((char_u *)(method == 0 ? "zip" : "blowfish"));
8b9a1c
-}
8b9a1c
-
8b9a1c
-/*
8b9a1c
- * Prepare for initializing encryption.  If already doing encryption then save
8b9a1c
- * the state.
8b9a1c
- * Must always be called symmetrically with crypt_pop_state().
8b9a1c
- */
8b9a1c
-    void
8b9a1c
-crypt_push_state()
8b9a1c
-{
8b9a1c
-    if (crypt_busy == 1)
8b9a1c
-    {
8b9a1c
-	/* save the state */
8b9a1c
-	if (use_crypt_method == 0)
8b9a1c
-	{
8b9a1c
-	    saved_keys[0] = keys[0];
8b9a1c
-	    saved_keys[1] = keys[1];
8b9a1c
-	    saved_keys[2] = keys[2];
8b9a1c
-	}
8b9a1c
-	else
8b9a1c
-	    bf_crypt_save();
8b9a1c
-	saved_crypt_method = use_crypt_method;
8b9a1c
-    }
8b9a1c
-    else if (crypt_busy > 1)
8b9a1c
-	EMSG2(_(e_intern2), "crypt_push_state()");
8b9a1c
-    ++crypt_busy;
8b9a1c
-}
8b9a1c
-
8b9a1c
-/*
8b9a1c
- * End encryption.  If doing encryption before crypt_push_state() then restore
8b9a1c
- * the saved state.
8b9a1c
- * Must always be called symmetrically with crypt_push_state().
8b9a1c
- */
8b9a1c
-    void
8b9a1c
-crypt_pop_state()
8b9a1c
-{
8b9a1c
-    --crypt_busy;
8b9a1c
-    if (crypt_busy == 1)
8b9a1c
-    {
8b9a1c
-	use_crypt_method = saved_crypt_method;
8b9a1c
-	if (use_crypt_method == 0)
8b9a1c
-	{
8b9a1c
-	    keys[0] = saved_keys[0];
8b9a1c
-	    keys[1] = saved_keys[1];
8b9a1c
-	    keys[2] = saved_keys[2];
8b9a1c
-	}
8b9a1c
-	else
8b9a1c
-	    bf_crypt_restore();
8b9a1c
-    }
8b9a1c
-}
8b9a1c
-
8b9a1c
-/*
8b9a1c
- * Encrypt "from[len]" into "to[len]".
8b9a1c
- * "from" and "to" can be equal to encrypt in place.
8b9a1c
- */
8b9a1c
-    void
8b9a1c
-crypt_encode(from, len, to)
8b9a1c
-    char_u	*from;
8b9a1c
-    size_t	len;
8b9a1c
-    char_u	*to;
8b9a1c
-{
8b9a1c
-    size_t	i;
8b9a1c
-    int		ztemp, t;
8b9a1c
-
8b9a1c
-    if (use_crypt_method == 0)
8b9a1c
-	for (i = 0; i < len; ++i)
8b9a1c
-	{
8b9a1c
-	    ztemp = from[i];
8b9a1c
-	    DECRYPT_BYTE_ZIP(t);
8b9a1c
-	    UPDATE_KEYS_ZIP(ztemp);
8b9a1c
-	    to[i] = t ^ ztemp;
8b9a1c
-	}
8b9a1c
-    else
8b9a1c
-	bf_crypt_encode(from, len, to);
8b9a1c
-}
8b9a1c
-
8b9a1c
-/*
8b9a1c
- * Decrypt "ptr[len]" in place.
8b9a1c
- */
8b9a1c
-    void
8b9a1c
-crypt_decode(ptr, len)
8b9a1c
-    char_u	*ptr;
8b9a1c
-    long	len;
8b9a1c
-{
8b9a1c
-    char_u *p;
8b9a1c
-
8b9a1c
-    if (use_crypt_method == 0)
8b9a1c
-	for (p = ptr; p < ptr + len; ++p)
8b9a1c
-	{
8b9a1c
-	    ush temp;
8b9a1c
-
8b9a1c
-	    temp = (ush)keys[2] | 2;
8b9a1c
-	    temp = (int)(((unsigned)(temp * (temp ^ 1U)) >> 8) & 0xff);
8b9a1c
-	    UPDATE_KEYS_ZIP(*p ^= temp);
8b9a1c
-	}
8b9a1c
-    else
8b9a1c
-	bf_crypt_decode(ptr, len);
8b9a1c
-}
8b9a1c
-
8b9a1c
-/*
8b9a1c
- * Initialize the encryption keys and the random header according to
8b9a1c
- * the given password.
8b9a1c
- * If "passwd" is NULL or empty, don't do anything.
8b9a1c
- */
8b9a1c
-    void
8b9a1c
-crypt_init_keys(passwd)
8b9a1c
-    char_u *passwd;		/* password string with which to modify keys */
8b9a1c
-{
8b9a1c
-    if (passwd != NULL && *passwd != NUL)
8b9a1c
-    {
8b9a1c
-	if (use_crypt_method == 0)
8b9a1c
-	{
8b9a1c
-	    char_u *p;
8b9a1c
-
8b9a1c
-	    make_crc_tab();
8b9a1c
-	    keys[0] = 305419896L;
8b9a1c
-	    keys[1] = 591751049L;
8b9a1c
-	    keys[2] = 878082192L;
8b9a1c
-	    for (p = passwd; *p!= NUL; ++p)
8b9a1c
-	    {
8b9a1c
-		UPDATE_KEYS_ZIP((int)*p);
8b9a1c
-	    }
8b9a1c
-	}
8b9a1c
-	else
8b9a1c
-	    bf_crypt_init_keys(passwd);
8b9a1c
-    }
8b9a1c
-}
8b9a1c
-
8b9a1c
-/*
8b9a1c
- * Free an allocated crypt key.  Clear the text to make sure it doesn't stay
8b9a1c
- * in memory anywhere.
8b9a1c
- */
8b9a1c
-    void
8b9a1c
-free_crypt_key(key)
8b9a1c
-    char_u *key;
8b9a1c
-{
8b9a1c
-    char_u *p;
8b9a1c
-
8b9a1c
-    if (key != NULL)
8b9a1c
-    {
8b9a1c
-	for (p = key; *p != NUL; ++p)
8b9a1c
-	    *p = 0;
8b9a1c
-	vim_free(key);
8b9a1c
-    }
8b9a1c
-}
8b9a1c
-
8b9a1c
-/*
8b9a1c
- * Ask the user for a crypt key.
8b9a1c
- * When "store" is TRUE, the new key is stored in the 'key' option, and the
8b9a1c
- * 'key' option value is returned: Don't free it.
8b9a1c
- * When "store" is FALSE, the typed key is returned in allocated memory.
8b9a1c
- * Returns NULL on failure.
8b9a1c
- */
8b9a1c
-    char_u *
8b9a1c
-get_crypt_key(store, twice)
8b9a1c
-    int		store;
8b9a1c
-    int		twice;	    /* Ask for the key twice. */
8b9a1c
-{
8b9a1c
-    char_u	*p1, *p2 = NULL;
8b9a1c
-    int		round;
8b9a1c
-
8b9a1c
-    for (round = 0; ; ++round)
8b9a1c
-    {
8b9a1c
-	cmdline_star = TRUE;
8b9a1c
-	cmdline_row = msg_row;
8b9a1c
-	p1 = getcmdline_prompt(NUL, round == 0
8b9a1c
-		? (char_u *)_("Enter encryption key: ")
8b9a1c
-		: (char_u *)_("Enter same key again: "), 0, EXPAND_NOTHING,
8b9a1c
-		NULL);
8b9a1c
-	cmdline_star = FALSE;
8b9a1c
-
8b9a1c
-	if (p1 == NULL)
8b9a1c
-	    break;
8b9a1c
-
8b9a1c
-	if (round == twice)
8b9a1c
-	{
8b9a1c
-	    if (p2 != NULL && STRCMP(p1, p2) != 0)
8b9a1c
-	    {
8b9a1c
-		MSG(_("Keys don't match!"));
8b9a1c
-		free_crypt_key(p1);
8b9a1c
-		free_crypt_key(p2);
8b9a1c
-		p2 = NULL;
8b9a1c
-		round = -1;		/* do it again */
8b9a1c
-		continue;
8b9a1c
-	    }
8b9a1c
-
8b9a1c
-	    if (store)
8b9a1c
-	    {
8b9a1c
-		set_option_value((char_u *)"key", 0L, p1, OPT_LOCAL);
8b9a1c
-		free_crypt_key(p1);
8b9a1c
-		p1 = curbuf->b_p_key;
8b9a1c
-	    }
8b9a1c
-	    break;
8b9a1c
-	}
8b9a1c
-	p2 = p1;
8b9a1c
-    }
8b9a1c
-
8b9a1c
-    /* since the user typed this, no need to wait for return */
8b9a1c
-    if (msg_didout)
8b9a1c
-	msg_putchar('\n');
8b9a1c
-    need_wait_return = FALSE;
8b9a1c
-    msg_didout = FALSE;
8b9a1c
-
8b9a1c
-    free_crypt_key(p2);
8b9a1c
-    return p1;
8b9a1c
-}
8b9a1c
-
8b9a1c
-#endif /* FEAT_CRYPT */
8b9a1c
-
8b9a1c
 /* TODO: make some #ifdef for this */
8b9a1c
 /*--------[ file searching ]-------------------------------------------------*/
8b9a1c
 /*
8b9a1c
@@ -6588,8 +6272,23 @@ put_time(fd, the_time)
8b9a1c
     FILE	*fd;
8b9a1c
     time_t	the_time;
8b9a1c
 {
8b9a1c
+    char_u	buf[8];
8b9a1c
+
8b9a1c
+    time_to_bytes(the_time, buf);
8b9a1c
+    fwrite(buf, (size_t)8, (size_t)1, fd);
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Write time_t to "buf[8]".
8b9a1c
+ */
8b9a1c
+    void
8b9a1c
+time_to_bytes(the_time, buf)
8b9a1c
+    time_t	the_time;
8b9a1c
+    char_u	*buf;
8b9a1c
+{
8b9a1c
     int		c;
8b9a1c
     int		i;
8b9a1c
+    int		bi = 0;
8b9a1c
     time_t	wtime = the_time;
8b9a1c
 
8b9a1c
     /* time_t can be up to 8 bytes in size, more than long_u, thus we
8b9a1c
@@ -6603,7 +6302,7 @@ put_time(fd, the_time)
8b9a1c
     {
8b9a1c
 	if (i + 1 > (int)sizeof(time_t))
8b9a1c
 	    /* ">>" doesn't work well when shifting more bits than avail */
8b9a1c
-	    putc(0, fd);
8b9a1c
+	    buf[bi++] = 0;
8b9a1c
 	else
8b9a1c
 	{
8b9a1c
 #if defined(SIZEOF_TIME_T) && SIZEOF_TIME_T > 4
8b9a1c
@@ -6611,7 +6310,7 @@ put_time(fd, the_time)
8b9a1c
 #else
8b9a1c
 	    c = (int)((long_u)wtime >> (i * 8));
8b9a1c
 #endif
8b9a1c
-	    putc(c, fd);
8b9a1c
+	    buf[bi++] = c;
8b9a1c
 	}
8b9a1c
     }
8b9a1c
 }
8b9a1c
diff -up vim74/src/option.c.blowfish2 vim74/src/option.c
8b9a1c
--- vim74/src/option.c.blowfish2	2017-09-05 14:47:34.899912434 +0200
8b9a1c
+++ vim74/src/option.c	2017-09-05 14:47:34.961911933 +0200
8b9a1c
@@ -2969,7 +2969,7 @@ static char *(p_bg_values[]) = {"light",
8b9a1c
 static char *(p_nf_values[]) = {"octal", "hex", "alpha", NULL};
8b9a1c
 static char *(p_ff_values[]) = {FF_UNIX, FF_DOS, FF_MAC, NULL};
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
-static char *(p_cm_values[]) = {"zip", "blowfish", NULL};
8b9a1c
+static char *(p_cm_values[]) = {"zip", "blowfish", "blowfish2", NULL};
8b9a1c
 #endif
8b9a1c
 #ifdef FEAT_CMDL_COMPL
8b9a1c
 static char *(p_wop_values[]) = {"tagfile", NULL};
8b9a1c
@@ -6156,7 +6156,7 @@ did_set_string_option(opt_idx, varp, new
8b9a1c
 # endif
8b9a1c
 	if (STRCMP(curbuf->b_p_key, oldval) != 0)
8b9a1c
 	    /* Need to update the swapfile. */
8b9a1c
-	    ml_set_crypt_key(curbuf, oldval, get_crypt_method(curbuf));
8b9a1c
+	    ml_set_crypt_key(curbuf, oldval, crypt_get_method_nr(curbuf));
8b9a1c
     }
8b9a1c
 
8b9a1c
     else if (gvarp == &p_cm)
8b9a1c
@@ -6167,7 +6167,7 @@ did_set_string_option(opt_idx, varp, new
8b9a1c
 	    p = p_cm;
8b9a1c
 	if (check_opt_strings(p, p_cm_values, TRUE) != OK)
8b9a1c
 	    errmsg = e_invarg;
8b9a1c
-	else if (get_crypt_method(curbuf) > 0 && blowfish_self_test() == FAIL)
8b9a1c
+	else if (crypt_self_test() == FAIL)
8b9a1c
 	    errmsg = e_invarg;
8b9a1c
 	else
8b9a1c
 	{
8b9a1c
@@ -6179,6 +6179,14 @@ did_set_string_option(opt_idx, varp, new
8b9a1c
 		p_cm = vim_strsave((char_u *)"zip");
8b9a1c
 		new_value_alloced = TRUE;
8b9a1c
 	    }
8b9a1c
+	    /* When using ":set cm=name" the local value is going to be empty.
8b9a1c
+	     * Do that here, otherwise the crypt functions will still use the
8b9a1c
+	     * local value. */
8b9a1c
+	    if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
8b9a1c
+	    {
8b9a1c
+		free_string_option(curbuf->b_p_cm);
8b9a1c
+		curbuf->b_p_cm = empty_option;
8b9a1c
+	    }
8b9a1c
 
8b9a1c
 	    /* Need to update the swapfile when the effective method changed.
8b9a1c
 	     * Set "s" to the effective old value, "p" to the effective new
8b9a1c
@@ -6193,7 +6201,7 @@ did_set_string_option(opt_idx, varp, new
8b9a1c
 		p = curbuf->b_p_cm;
8b9a1c
 	    if (STRCMP(s, p) != 0)
8b9a1c
 		ml_set_crypt_key(curbuf, curbuf->b_p_key,
8b9a1c
-						 crypt_method_from_string(s));
8b9a1c
+						crypt_method_nr_from_name(s));
8b9a1c
 
8b9a1c
 	    /* If the global value changes need to update the swapfile for all
8b9a1c
 	     * buffers using that value. */
8b9a1c
@@ -6204,7 +6212,7 @@ did_set_string_option(opt_idx, varp, new
8b9a1c
 		for (buf = firstbuf; buf != NULL; buf = buf->b_next)
8b9a1c
 		    if (buf != curbuf && *buf->b_p_cm == NUL)
8b9a1c
 			ml_set_crypt_key(buf, buf->b_p_key,
8b9a1c
-					    crypt_method_from_string(oldval));
8b9a1c
+					   crypt_method_nr_from_name(oldval));
8b9a1c
 	    }
8b9a1c
 	}
8b9a1c
     }
8b9a1c
diff -up vim74/src/proto/blowfish.pro.blowfish2 vim74/src/proto/blowfish.pro
8b9a1c
--- vim74/src/proto/blowfish.pro.blowfish2	2013-08-10 13:37:06.000000000 +0200
8b9a1c
+++ vim74/src/proto/blowfish.pro	2017-09-05 14:47:34.964911909 +0200
8b9a1c
@@ -1,10 +1,6 @@
8b9a1c
 /* blowfish.c */
8b9a1c
-void bf_key_init __ARGS((char_u *password, char_u *salt, int salt_len));
8b9a1c
-void bf_ofb_init __ARGS((char_u *iv, int iv_len));
8b9a1c
-void bf_crypt_encode __ARGS((char_u *from, size_t len, char_u *to));
8b9a1c
-void bf_crypt_decode __ARGS((char_u *ptr, long len));
8b9a1c
-void bf_crypt_init_keys __ARGS((char_u *passwd));
8b9a1c
-void bf_crypt_save __ARGS((void));
8b9a1c
-void bf_crypt_restore __ARGS((void));
8b9a1c
+void crypt_blowfish_encode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to));
8b9a1c
+void crypt_blowfish_decode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to));
8b9a1c
+void crypt_blowfish_init __ARGS((cryptstate_T *state, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len));
8b9a1c
 int blowfish_self_test __ARGS((void));
8b9a1c
 /* vim: set ft=c : */
8b9a1c
diff -up vim74/src/proto/crypt.pro.blowfish2 vim74/src/proto/crypt.pro
8b9a1c
--- vim74/src/proto/crypt.pro.blowfish2	2017-09-05 14:47:34.965911901 +0200
8b9a1c
+++ vim74/src/proto/crypt.pro	2017-09-05 14:47:34.965911901 +0200
8b9a1c
@@ -0,0 +1,24 @@
8b9a1c
+/* crypt.c */
8b9a1c
+int crypt_method_nr_from_name __ARGS((char_u *name));
8b9a1c
+int crypt_method_nr_from_magic __ARGS((char *ptr, int len));
8b9a1c
+int crypt_works_inplace __ARGS((cryptstate_T *state));
8b9a1c
+int crypt_get_method_nr __ARGS((buf_T *buf));
8b9a1c
+int crypt_whole_undofile __ARGS((int method_nr));
8b9a1c
+int crypt_get_header_len __ARGS((int method_nr));
8b9a1c
+void crypt_set_cm_option __ARGS((buf_T *buf, int method_nr));
8b9a1c
+int crypt_self_test __ARGS((void));
8b9a1c
+cryptstate_T *crypt_create __ARGS((int method_nr, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len));
8b9a1c
+cryptstate_T *crypt_create_from_header __ARGS((int method_nr, char_u *key, char_u *header));
8b9a1c
+cryptstate_T *crypt_create_from_file __ARGS((FILE *fp, char_u *key));
8b9a1c
+cryptstate_T *crypt_create_for_writing __ARGS((int method_nr, char_u *key, char_u **header, int *header_len));
8b9a1c
+void crypt_free_state __ARGS((cryptstate_T *state));
8b9a1c
+long crypt_encode_alloc __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u **newptr));
8b9a1c
+long crypt_decode_alloc __ARGS((cryptstate_T *state, char_u *ptr, long len, char_u **newptr));
8b9a1c
+void crypt_encode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to));
8b9a1c
+void crypt_decode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to));
8b9a1c
+void crypt_encode_inplace __ARGS((cryptstate_T *state, char_u *buf, size_t len));
8b9a1c
+void crypt_decode_inplace __ARGS((cryptstate_T *state, char_u *buf, size_t len));
8b9a1c
+void crypt_free_key __ARGS((char_u *key));
8b9a1c
+char_u *crypt_get_key __ARGS((int store, int twice));
8b9a1c
+void crypt_append_msg __ARGS((buf_T *buf));
8b9a1c
+/* vim: set ft=c : */
8b9a1c
diff -up vim74/src/proto/crypt_zip.pro.blowfish2 vim74/src/proto/crypt_zip.pro
8b9a1c
--- vim74/src/proto/crypt_zip.pro.blowfish2	2017-09-05 14:47:34.965911901 +0200
8b9a1c
+++ vim74/src/proto/crypt_zip.pro	2017-09-05 14:47:34.965911901 +0200
8b9a1c
@@ -0,0 +1,5 @@
8b9a1c
+/* crypt_zip.c */
8b9a1c
+void crypt_zip_init __ARGS((cryptstate_T *state, char_u *key, char_u *salt, int salt_len, char_u *seed, int seed_len));
8b9a1c
+void crypt_zip_encode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to));
8b9a1c
+void crypt_zip_decode __ARGS((cryptstate_T *state, char_u *from, size_t len, char_u *to));
8b9a1c
+/* vim: set ft=c : */
8b9a1c
diff -up vim74/src/proto/fileio.pro.blowfish2 vim74/src/proto/fileio.pro
8b9a1c
--- vim74/src/proto/fileio.pro.blowfish2	2013-08-10 13:37:11.000000000 +0200
8b9a1c
+++ vim74/src/proto/fileio.pro	2017-09-05 14:47:34.965911901 +0200
8b9a1c
@@ -4,8 +4,6 @@ int readfile __ARGS((char_u *fname, char
8b9a1c
 int prep_exarg __ARGS((exarg_T *eap, buf_T *buf));
8b9a1c
 void set_file_options __ARGS((int set_options, exarg_T *eap));
8b9a1c
 void set_forced_fenc __ARGS((exarg_T *eap));
8b9a1c
-int prepare_crypt_read __ARGS((FILE *fp));
8b9a1c
-char_u *prepare_crypt_write __ARGS((buf_T *buf, int *lenp));
8b9a1c
 int check_file_readonly __ARGS((char_u *fname, int perm));
8b9a1c
 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));
8b9a1c
 void msg_add_fname __ARGS((buf_T *buf, char_u *fname));
8b9a1c
diff -up vim74/src/proto.h.blowfish2 vim74/src/proto.h
8b9a1c
--- vim74/src/proto.h.blowfish2	2013-02-26 14:18:19.000000000 +0100
8b9a1c
+++ vim74/src/proto.h	2017-09-05 14:47:34.966911893 +0200
8b9a1c
@@ -70,6 +70,8 @@ extern int _stricoll __ARGS((char *a, ch
8b9a1c
 
8b9a1c
 # ifdef FEAT_CRYPT
8b9a1c
 #  include "blowfish.pro"
8b9a1c
+#  include "crypt.pro"
8b9a1c
+#  include "crypt_zip.pro"
8b9a1c
 # endif
8b9a1c
 # include "buffer.pro"
8b9a1c
 # include "charset.pro"
8b9a1c
diff -up vim74/src/proto/misc2.pro.blowfish2 vim74/src/proto/misc2.pro
8b9a1c
--- vim74/src/proto/misc2.pro.blowfish2	2013-08-10 13:37:20.000000000 +0200
8b9a1c
+++ vim74/src/proto/misc2.pro	2017-09-05 14:47:34.966911893 +0200
8b9a1c
@@ -84,16 +84,6 @@ int illegal_slash __ARGS((char *name));
8b9a1c
 char_u *parse_shape_opt __ARGS((int what));
8b9a1c
 int get_shape_idx __ARGS((int mouse));
8b9a1c
 void update_mouseshape __ARGS((int shape_idx));
8b9a1c
-int crypt_method_from_string __ARGS((char_u *s));
8b9a1c
-int get_crypt_method __ARGS((buf_T *buf));
8b9a1c
-void set_crypt_method __ARGS((buf_T *buf, int method));
8b9a1c
-void crypt_push_state __ARGS((void));
8b9a1c
-void crypt_pop_state __ARGS((void));
8b9a1c
-void crypt_encode __ARGS((char_u *from, size_t len, char_u *to));
8b9a1c
-void crypt_decode __ARGS((char_u *ptr, long len));
8b9a1c
-void crypt_init_keys __ARGS((char_u *passwd));
8b9a1c
-void free_crypt_key __ARGS((char_u *key));
8b9a1c
-char_u *get_crypt_key __ARGS((int store, int twice));
8b9a1c
 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));
8b9a1c
 char_u *vim_findfile_stopdir __ARGS((char_u *buf));
8b9a1c
 void vim_findfile_cleanup __ARGS((void *ctx));
8b9a1c
@@ -116,5 +106,6 @@ time_t get8ctime __ARGS((FILE *fd));
8b9a1c
 char_u *read_string __ARGS((FILE *fd, int cnt));
8b9a1c
 int put_bytes __ARGS((FILE *fd, long_u nr, int len));
8b9a1c
 void put_time __ARGS((FILE *fd, time_t the_time));
8b9a1c
+void time_to_bytes __ARGS((time_t the_time, char_u *buf));
8b9a1c
 int has_non_ascii __ARGS((char_u *s));
8b9a1c
 /* vim: set ft=c : */
8b9a1c
diff -up vim74/src/structs.h.blowfish2 vim74/src/structs.h
8b9a1c
--- vim74/src/structs.h.blowfish2	2017-09-05 14:47:34.839912918 +0200
8b9a1c
+++ vim74/src/structs.h	2017-09-05 14:47:34.967911885 +0200
8b9a1c
@@ -1240,6 +1240,24 @@ typedef struct {
8b9a1c
 } syn_time_T;
8b9a1c
 #endif
8b9a1c
 
8b9a1c
+#ifdef FEAT_CRYPT
8b9a1c
+/*
8b9a1c
+ * Structure to hold the type of encryption and the state of encryption or
8b9a1c
+ * decryption.
8b9a1c
+ */
8b9a1c
+typedef struct {
8b9a1c
+    int	    method_nr;
8b9a1c
+    void    *method_state;  /* method-specific state information */
8b9a1c
+} cryptstate_T;
8b9a1c
+
8b9a1c
+/* values for method_nr */
8b9a1c
+# define CRYPT_M_ZIP	0
8b9a1c
+# define CRYPT_M_BF	1
8b9a1c
+# define CRYPT_M_BF2	2
8b9a1c
+# define CRYPT_M_COUNT	3 /* number of crypt methods */
8b9a1c
+#endif
8b9a1c
+
8b9a1c
+
8b9a1c
 /*
8b9a1c
  * These are items normally related to a buffer.  But when using ":ownsyntax"
8b9a1c
  * a window may have its own instance.
8b9a1c
@@ -1765,7 +1783,12 @@ struct file_buffer
8b9a1c
     int		b_was_netbeans_file;/* TRUE if b_netbeans_file was once set */
8b9a1c
 #endif
8b9a1c
 
8b9a1c
-};
8b9a1c
+#ifdef FEAT_CRYPT
8b9a1c
+    cryptstate_T *b_cryptstate;	/* Encryption state while reading or writing
8b9a1c
+				 * the file. NULL when not using encryption. */
8b9a1c
+#endif
8b9a1c
+
8b9a1c
+}; /* file_buffer */
8b9a1c
 
8b9a1c
 
8b9a1c
 #ifdef FEAT_DIFF
8b9a1c
diff -up vim74/src/testdir/test72.in.blowfish2 vim74/src/testdir/test72.in
8b9a1c
--- vim74/src/testdir/test72.in.blowfish2	2012-01-04 19:04:17.000000000 +0100
8b9a1c
+++ vim74/src/testdir/test72.in	2017-09-05 15:23:47.590060199 +0200
8b9a1c
@@ -4,6 +4,7 @@ undo-able pieces.  Do that by setting 'u
8b9a1c
 
8b9a1c
 STARTTEST
8b9a1c
 :so small.vim
8b9a1c
+:set belloff=all
8b9a1c
 :"
8b9a1c
 :" Test 'undofile': first a simple one-line change.
8b9a1c
 :set nocompatible viminfo+=nviminfo visualbell
8b9a1c
@@ -25,7 +26,6 @@ u:.w! test.out
8b9a1c
 :set undofile
8b9a1c
 :bwipe!
8b9a1c
 :e Xtestfile
8b9a1c
-:" TODO: this beeps
8b9a1c
 u:.w >>test.out
8b9a1c
 :"
8b9a1c
 :" Test 'undofile', add 10 lines, delete 6 lines, undo 3
8b9a1c
@@ -81,7 +81,8 @@ uu:w >>test.out
8b9a1c
 :"
8b9a1c
 :" With encryption, cryptmethod=blowfish
8b9a1c
 :e! Xtestfile
8b9a1c
-:set undofile cm=blowfish
8b9a1c
+rubbish
8b9a1c
+:set undofile cm=blowfish ff&
8b9a1c
 ggdGijan
8b9a1c
 feb
8b9a1c
 mar
8b9a1c
@@ -104,8 +105,38 @@ u:.w >>test.out
8b9a1c
 u:.w >>test.out
8b9a1c
 u:.w >>test.out
8b9a1c
 :"
8b9a1c
+:" With encryption, cryptmethod=blowfish2
8b9a1c
+:e! Xtestfile
8b9a1c
+rubbish
8b9a1c
+:set undofile cm=blowfish2 ff&
8b9a1c
+ggdGijan
8b9a1c
+feb
8b9a1c
+mar
8b9a1c
+apr
8b9a1c
+jun?:set ul=100
8b9a1c
+kk0ifoo ?:set ul=100
8b9a1c
+dd:set ul=100
8b9a1c
+ibar ?:set ul=100
8b9a1c
+:X
8b9a1c
+foo2bar
8b9a1c
+foo2bar
8b9a1c
+:w!
8b9a1c
+:bwipe!
8b9a1c
+:e Xtestfile
8b9a1c
+foo2bar
8b9a1c
+:set key=
8b9a1c
+/bar
8b9a1c
+:.w >>test.out
8b9a1c
+u:.w >>test.out
8b9a1c
+u:.w >>test.out
8b9a1c
+u:.w >>test.out
8b9a1c
+:"
8b9a1c
 :" Rename the undo file so that it gets cleaned up.
8b9a1c
-:call rename(".Xtestfile.un~", "Xtestundo")
8b9a1c
+:if has("vms")
8b9a1c
+: call rename("_un_Xtestfile", "Xtestundo")
8b9a1c
+:else
8b9a1c
+: call rename(".Xtestfile.un~", "Xtestundo")
8b9a1c
+:endif
8b9a1c
 :qa!
8b9a1c
 ENDTEST
8b9a1c
 
8b9a1c
diff -up vim74/src/testdir/test72.ok.blowfish2 vim74/src/testdir/test72.ok
8b9a1c
--- vim74/src/testdir/test72.ok.blowfish2	2012-01-04 19:04:17.000000000 +0100
8b9a1c
+++ vim74/src/testdir/test72.ok	2017-09-05 15:23:47.596060147 +0200
8b9a1c
@@ -25,3 +25,7 @@ bar apr
8b9a1c
 apr
8b9a1c
 foo mar
8b9a1c
 mar
8b9a1c
+bar apr
8b9a1c
+apr
8b9a1c
+foo mar
8b9a1c
+mar
8b9a1c
diff -up vim74/src/undo.c.blowfish2 vim74/src/undo.c
8b9a1c
--- vim74/src/undo.c.blowfish2	2017-09-05 14:47:34.740913717 +0200
8b9a1c
+++ vim74/src/undo.c	2017-09-05 14:47:34.973911836 +0200
8b9a1c
@@ -81,8 +81,25 @@
8b9a1c
 #define UH_MAGIC 0x18dade	/* value for uh_magic when in use */
8b9a1c
 #define UE_MAGIC 0xabc123	/* value for ue_magic when in use */
8b9a1c
 
8b9a1c
+/* Size of buffer used for encryption. */
8b9a1c
+#define CRYPT_BUF_SIZE 8192
8b9a1c
+
8b9a1c
 #include "vim.h"
8b9a1c
 
8b9a1c
+/* Structure passed around between functions.
8b9a1c
+ * Avoids passing cryptstate_T when encryption not available. */
8b9a1c
+typedef struct {
8b9a1c
+    buf_T	*bi_buf;
8b9a1c
+    FILE	*bi_fp;
8b9a1c
+#ifdef FEAT_CRYPT
8b9a1c
+    cryptstate_T *bi_state;
8b9a1c
+    char_u	*bi_buffer; /* CRYPT_BUF_SIZE, NULL when not buffering */
8b9a1c
+    size_t	bi_used;    /* bytes written to/read from bi_buffer */
8b9a1c
+    size_t	bi_avail;   /* bytes available in bi_buffer */
8b9a1c
+#endif
8b9a1c
+} bufinfo_T;
8b9a1c
+
8b9a1c
+
8b9a1c
 static long get_undolevel __ARGS((void));
8b9a1c
 static void u_unch_branch __ARGS((u_header_T *uhp));
8b9a1c
 static u_entry_T *u_get_headentry __ARGS((void));
8b9a1c
@@ -98,18 +115,26 @@ static void u_freeentry __ARGS((u_entry_
8b9a1c
 #ifdef FEAT_PERSISTENT_UNDO
8b9a1c
 static void corruption_error __ARGS((char *mesg, char_u *file_name));
8b9a1c
 static void u_free_uhp __ARGS((u_header_T *uhp));
8b9a1c
-static size_t fwrite_crypt __ARGS((buf_T *buf UNUSED, char_u *ptr, size_t len, FILE *fp));
8b9a1c
-static char_u *read_string_decrypt __ARGS((buf_T *buf UNUSED, FILE *fd, int len));
8b9a1c
-static int serialize_header __ARGS((FILE *fp, buf_T *buf, char_u *hash));
8b9a1c
-static int serialize_uhp __ARGS((FILE *fp, buf_T *buf, u_header_T *uhp));
8b9a1c
-static u_header_T *unserialize_uhp __ARGS((FILE *fp, char_u *file_name));
8b9a1c
-static int serialize_uep __ARGS((FILE *fp, buf_T *buf, u_entry_T *uep));
8b9a1c
-static u_entry_T *unserialize_uep __ARGS((FILE *fp, int *error, char_u *file_name));
8b9a1c
-static void serialize_pos __ARGS((pos_T pos, FILE *fp));
8b9a1c
-static void unserialize_pos __ARGS((pos_T *pos, FILE *fp));
8b9a1c
-static void serialize_visualinfo __ARGS((visualinfo_T *info, FILE *fp));
8b9a1c
-static void unserialize_visualinfo __ARGS((visualinfo_T *info, FILE *fp));
8b9a1c
-static void put_header_ptr __ARGS((FILE	*fp, u_header_T *uhp));
8b9a1c
+static int undo_write __ARGS((bufinfo_T *bi, char_u *ptr, size_t len));
8b9a1c
+static int undo_flush __ARGS((bufinfo_T *bi));
8b9a1c
+static int fwrite_crypt __ARGS((bufinfo_T *bi, char_u *ptr, size_t len));
8b9a1c
+static int undo_write_bytes __ARGS((bufinfo_T *bi, long_u nr, int len));
8b9a1c
+static void put_header_ptr __ARGS((bufinfo_T *bi, u_header_T *uhp));
8b9a1c
+static int undo_read_4c __ARGS((bufinfo_T *bi));
8b9a1c
+static int undo_read_2c __ARGS((bufinfo_T *bi));
8b9a1c
+static int undo_read_byte __ARGS((bufinfo_T *bi));
8b9a1c
+static time_t undo_read_time __ARGS((bufinfo_T *bi));
8b9a1c
+static int undo_read __ARGS((bufinfo_T *bi, char_u *buffer, size_t size));
8b9a1c
+static char_u *read_string_decrypt __ARGS((bufinfo_T *bi, int len));
8b9a1c
+static int serialize_header __ARGS((bufinfo_T *bi, char_u *hash));
8b9a1c
+static int serialize_uhp __ARGS((bufinfo_T *bi, u_header_T *uhp));
8b9a1c
+static u_header_T *unserialize_uhp __ARGS((bufinfo_T *bi, char_u *file_name));
8b9a1c
+static int serialize_uep __ARGS((bufinfo_T *bi, u_entry_T *uep));
8b9a1c
+static u_entry_T *unserialize_uep __ARGS((bufinfo_T *bi, int *error, char_u *file_name));
8b9a1c
+static void serialize_pos __ARGS((bufinfo_T *bi, pos_T pos));
8b9a1c
+static void unserialize_pos __ARGS((bufinfo_T *bi, pos_T *pos));
8b9a1c
+static void serialize_visualinfo __ARGS((bufinfo_T *bi, visualinfo_T *info));
8b9a1c
+static void unserialize_visualinfo __ARGS((bufinfo_T *bi, visualinfo_T *info));
8b9a1c
 #endif
8b9a1c
 
8b9a1c
 #define U_ALLOC_LINE(size) lalloc((long_u)(size), FALSE)
8b9a1c
@@ -850,68 +875,294 @@ u_free_uhp(uhp)
8b9a1c
 }
8b9a1c
 
8b9a1c
 /*
8b9a1c
- * Like fwrite() but crypt the bytes when 'key' is set.
8b9a1c
- * Returns 1 if successful.
8b9a1c
+ * Write a sequence of bytes to the undo file.
8b9a1c
+ * Buffers and encrypts as needed.
8b9a1c
+ * Returns OK or FAIL.
8b9a1c
  */
8b9a1c
-    static size_t
8b9a1c
-fwrite_crypt(buf, ptr, len, fp)
8b9a1c
-    buf_T	*buf UNUSED;
8b9a1c
+    static int
8b9a1c
+undo_write(bi, ptr, len)
8b9a1c
+    bufinfo_T	*bi;
8b9a1c
+    char_u	*ptr;
8b9a1c
+    size_t	len;
8b9a1c
+{
8b9a1c
+#ifdef FEAT_CRYPT
8b9a1c
+    if (bi->bi_buffer != NULL)
8b9a1c
+    {
8b9a1c
+	size_t	len_todo = len;
8b9a1c
+	char_u  *p = ptr;
8b9a1c
+
8b9a1c
+	while (bi->bi_used + len_todo >= CRYPT_BUF_SIZE)
8b9a1c
+	{
8b9a1c
+	    size_t	n = CRYPT_BUF_SIZE - bi->bi_used;
8b9a1c
+
8b9a1c
+	    mch_memmove(bi->bi_buffer + bi->bi_used, p, n);
8b9a1c
+	    len_todo -= n;
8b9a1c
+	    p += n;
8b9a1c
+	    bi->bi_used = CRYPT_BUF_SIZE;
8b9a1c
+	    if (undo_flush(bi) == FAIL)
8b9a1c
+		return FAIL;
8b9a1c
+	}
8b9a1c
+	if (len_todo > 0)
8b9a1c
+	{
8b9a1c
+	    mch_memmove(bi->bi_buffer + bi->bi_used, p, len_todo);
8b9a1c
+	    bi->bi_used += len_todo;
8b9a1c
+	}
8b9a1c
+	return OK;
8b9a1c
+    }
8b9a1c
+#endif
8b9a1c
+    if (fwrite(ptr, len, (size_t)1, bi->bi_fp) != 1)
8b9a1c
+	return FAIL;
8b9a1c
+    return OK;
8b9a1c
+}
8b9a1c
+
8b9a1c
+#ifdef FEAT_CRYPT
8b9a1c
+    static int
8b9a1c
+undo_flush(bi)
8b9a1c
+    bufinfo_T	*bi;
8b9a1c
+{
8b9a1c
+    if (bi->bi_buffer != NULL && bi->bi_state != NULL && bi->bi_used > 0)
8b9a1c
+    {
8b9a1c
+	crypt_encode_inplace(bi->bi_state, bi->bi_buffer, bi->bi_used);
8b9a1c
+	if (fwrite(bi->bi_buffer, bi->bi_used, (size_t)1, bi->bi_fp) != 1)
8b9a1c
+	    return FAIL;
8b9a1c
+	bi->bi_used = 0;
8b9a1c
+    }
8b9a1c
+    return OK;
8b9a1c
+}
8b9a1c
+#endif
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Write "ptr[len]" and crypt the bytes when needed.
8b9a1c
+ * Returns OK or FAIL.
8b9a1c
+ */
8b9a1c
+    static int
8b9a1c
+fwrite_crypt(bi, ptr, len)
8b9a1c
+    bufinfo_T	*bi;
8b9a1c
     char_u	*ptr;
8b9a1c
     size_t	len;
8b9a1c
-    FILE	*fp;
8b9a1c
 {
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
     char_u  *copy;
8b9a1c
     char_u  small_buf[100];
8b9a1c
     size_t  i;
8b9a1c
 
8b9a1c
-    if (*buf->b_p_key == NUL)
8b9a1c
-	return fwrite(ptr, len, (size_t)1, fp);
8b9a1c
-    if (len < 100)
8b9a1c
-	copy = small_buf;  /* no malloc()/free() for short strings */
8b9a1c
-    else
8b9a1c
+    if (bi->bi_state != NULL && bi->bi_buffer == NULL)
8b9a1c
     {
8b9a1c
-	copy = lalloc(len, FALSE);
8b9a1c
-	if (copy == NULL)
8b9a1c
-	    return 0;
8b9a1c
-    }
8b9a1c
-    crypt_encode(ptr, len, copy);
8b9a1c
-    i = fwrite(copy, len, (size_t)1, fp);
8b9a1c
-    if (copy != small_buf)
8b9a1c
-	vim_free(copy);
8b9a1c
-    return i;
8b9a1c
-#else
8b9a1c
-    return fwrite(ptr, len, (size_t)1, fp);
8b9a1c
+	/* crypting every piece of text separately */
8b9a1c
+	if (len < 100)
8b9a1c
+	    copy = small_buf;  /* no malloc()/free() for short strings */
8b9a1c
+	else
8b9a1c
+	{
8b9a1c
+	    copy = lalloc(len, FALSE);
8b9a1c
+	    if (copy == NULL)
8b9a1c
+		return 0;
8b9a1c
+	}
8b9a1c
+	crypt_encode(bi->bi_state, ptr, len, copy);
8b9a1c
+	i = fwrite(copy, len, (size_t)1, bi->bi_fp);
8b9a1c
+	if (copy != small_buf)
8b9a1c
+	    vim_free(copy);
8b9a1c
+	return i == 1 ? OK : FAIL;
8b9a1c
+    }
8b9a1c
 #endif
8b9a1c
+    return undo_write(bi, ptr, len);
8b9a1c
 }
8b9a1c
 
8b9a1c
 /*
8b9a1c
- * Read a string of length "len" from "fd".
8b9a1c
- * When 'key' is set decrypt the bytes.
8b9a1c
+ * Write a number, MSB first, in "len" bytes.
8b9a1c
+ * Must match with undo_read_?c() functions.
8b9a1c
+ * Returns OK or FAIL.
8b9a1c
  */
8b9a1c
-    static char_u *
8b9a1c
-read_string_decrypt(buf, fd, len)
8b9a1c
-    buf_T   *buf UNUSED;
8b9a1c
-    FILE    *fd;
8b9a1c
+    static int
8b9a1c
+undo_write_bytes(bi, nr, len)
8b9a1c
+    bufinfo_T *bi;
8b9a1c
+    long_u  nr;
8b9a1c
     int	    len;
8b9a1c
 {
8b9a1c
-    char_u  *ptr;
8b9a1c
+    char_u  buf[8];
8b9a1c
+    int	    i;
8b9a1c
+    int	    bufi = 0;
8b9a1c
+
8b9a1c
+    for (i = len - 1; i >= 0; --i)
8b9a1c
+	buf[bufi++] = nr >> (i * 8);
8b9a1c
+    return undo_write(bi, buf, (size_t)len);
8b9a1c
+}
8b9a1c
 
8b9a1c
-    ptr = read_string(fd, len);
8b9a1c
+/*
8b9a1c
+ * Write the pointer to an undo header.  Instead of writing the pointer itself
8b9a1c
+ * we use the sequence number of the header.  This is converted back to
8b9a1c
+ * pointers when reading. */
8b9a1c
+    static void
8b9a1c
+put_header_ptr(bi, uhp)
8b9a1c
+    bufinfo_T	*bi;
8b9a1c
+    u_header_T	*uhp;
8b9a1c
+{
8b9a1c
+    undo_write_bytes(bi, (long_u)(uhp != NULL ? uhp->uh_seq : 0), 4);
8b9a1c
+}
8b9a1c
+
8b9a1c
+    static int
8b9a1c
+undo_read_4c(bi)
8b9a1c
+    bufinfo_T	*bi;
8b9a1c
+{
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
-    if (ptr != NULL && *buf->b_p_key != NUL)
8b9a1c
-	crypt_decode(ptr, len);
8b9a1c
+    if (bi->bi_buffer != NULL)
8b9a1c
+    {
8b9a1c
+	char_u  buf[4];
8b9a1c
+	int	n;
8b9a1c
+
8b9a1c
+	undo_read(bi, buf, (size_t)4);
8b9a1c
+	n = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
8b9a1c
+	return n;
8b9a1c
+    }
8b9a1c
 #endif
8b9a1c
+    return get4c(bi->bi_fp);
8b9a1c
+}
8b9a1c
+
8b9a1c
+    static int
8b9a1c
+undo_read_2c(bi)
8b9a1c
+    bufinfo_T	*bi;
8b9a1c
+{
8b9a1c
+#ifdef FEAT_CRYPT
8b9a1c
+    if (bi->bi_buffer != NULL)
8b9a1c
+    {
8b9a1c
+	char_u  buf[2];
8b9a1c
+	int	n;
8b9a1c
+
8b9a1c
+	undo_read(bi, buf, (size_t)2);
8b9a1c
+	n = (buf[0] << 8) + buf[1];
8b9a1c
+	return n;
8b9a1c
+    }
8b9a1c
+#endif
8b9a1c
+    return get2c(bi->bi_fp);
8b9a1c
+}
8b9a1c
+
8b9a1c
+    static int
8b9a1c
+undo_read_byte(bi)
8b9a1c
+    bufinfo_T	*bi;
8b9a1c
+{
8b9a1c
+#ifdef FEAT_CRYPT
8b9a1c
+    if (bi->bi_buffer != NULL)
8b9a1c
+    {
8b9a1c
+	char_u  buf[1];
8b9a1c
+
8b9a1c
+	undo_read(bi, buf, (size_t)1);
8b9a1c
+	return buf[0];
8b9a1c
+    }
8b9a1c
+#endif
8b9a1c
+    return getc(bi->bi_fp);
8b9a1c
+}
8b9a1c
+
8b9a1c
+    static time_t
8b9a1c
+undo_read_time(bi)
8b9a1c
+    bufinfo_T	*bi;
8b9a1c
+{
8b9a1c
+#ifdef FEAT_CRYPT
8b9a1c
+    if (bi->bi_buffer != NULL)
8b9a1c
+    {
8b9a1c
+	char_u  buf[8];
8b9a1c
+	time_t	n = 0;
8b9a1c
+	int	i;
8b9a1c
+
8b9a1c
+	undo_read(bi, buf, (size_t)8);
8b9a1c
+	for (i = 0; i < 8; ++i)
8b9a1c
+	    n = (n << 8) + buf[i];
8b9a1c
+	return n;
8b9a1c
+    }
8b9a1c
+#endif
8b9a1c
+    return get8ctime(bi->bi_fp);
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Read "buffer[size]" from the undo file.
8b9a1c
+ * Return OK or FAIL.
8b9a1c
+ */
8b9a1c
+    static int
8b9a1c
+undo_read(bi, buffer, size)
8b9a1c
+    bufinfo_T   *bi;
8b9a1c
+    char_u	*buffer;
8b9a1c
+    size_t	size;
8b9a1c
+{
8b9a1c
+#ifdef FEAT_CRYPT
8b9a1c
+    if (bi->bi_buffer != NULL)
8b9a1c
+    {
8b9a1c
+	int	size_todo = size;
8b9a1c
+	char_u	*p = buffer;
8b9a1c
+
8b9a1c
+	while (size_todo > 0)
8b9a1c
+	{
8b9a1c
+	    size_t n;
8b9a1c
+
8b9a1c
+	    if (bi->bi_used >= bi->bi_avail)
8b9a1c
+	    {
8b9a1c
+		n = fread(bi->bi_buffer, 1, (size_t)CRYPT_BUF_SIZE, bi->bi_fp);
8b9a1c
+		if (n <= 0)
8b9a1c
+		{
8b9a1c
+		    /* Error may be checked for only later.  Fill with zeros,
8b9a1c
+		     * so that the reader won't use garbage. */
8b9a1c
+		    vim_memset(p, 0, size_todo);
8b9a1c
+		    return FAIL;
8b9a1c
+		}
8b9a1c
+		bi->bi_avail = n;
8b9a1c
+		bi->bi_used = 0;
8b9a1c
+		crypt_decode_inplace(bi->bi_state, bi->bi_buffer, bi->bi_avail);
8b9a1c
+	    }
8b9a1c
+	    n = size_todo;
8b9a1c
+	    if (n > bi->bi_avail - bi->bi_used)
8b9a1c
+		n = bi->bi_avail - bi->bi_used;
8b9a1c
+	    mch_memmove(p, bi->bi_buffer + bi->bi_used, n);
8b9a1c
+	    bi->bi_used += n;
8b9a1c
+	    size_todo -= n;
8b9a1c
+	    p += n;
8b9a1c
+	}
8b9a1c
+	return OK;
8b9a1c
+    }
8b9a1c
+#endif
8b9a1c
+    if (fread(buffer, (size_t)size, 1, bi->bi_fp) != 1)
8b9a1c
+	return FAIL;
8b9a1c
+    return OK;
8b9a1c
+}
8b9a1c
+
8b9a1c
+/*
8b9a1c
+ * Read a string of length "len" from "bi->bi_fd".
8b9a1c
+ * "len" can be zero to allocate an empty line.
8b9a1c
+ * Decrypt the bytes if needed.
8b9a1c
+ * Append a NUL.
8b9a1c
+ * Returns a pointer to allocated memory or NULL for failure.
8b9a1c
+ */
8b9a1c
+    static char_u *
8b9a1c
+read_string_decrypt(bi, len)
8b9a1c
+    bufinfo_T	*bi;
8b9a1c
+    int		len;
8b9a1c
+{
8b9a1c
+    char_u  *ptr = alloc((unsigned)len + 1);
8b9a1c
+
8b9a1c
+    if (ptr != NULL)
8b9a1c
+    {
8b9a1c
+	if (len > 0 && undo_read(bi, ptr, len) == FAIL)
8b9a1c
+	{
8b9a1c
+	    vim_free(ptr);
8b9a1c
+	    return NULL;
8b9a1c
+	}
8b9a1c
+	ptr[len] = NUL;
8b9a1c
+#ifdef FEAT_CRYPT
8b9a1c
+	if (bi->bi_state != NULL && bi->bi_buffer == NULL)
8b9a1c
+	    crypt_decode_inplace(bi->bi_state, ptr, len);
8b9a1c
+#endif
8b9a1c
+    }
8b9a1c
     return ptr;
8b9a1c
 }
8b9a1c
 
8b9a1c
+/*
8b9a1c
+ * Writes the (not encrypted) header and initializes encryption if needed.
8b9a1c
+ */
8b9a1c
     static int
8b9a1c
-serialize_header(fp, buf, hash)
8b9a1c
-    FILE	*fp;
8b9a1c
-    buf_T	*buf;
8b9a1c
+serialize_header(bi, hash)
8b9a1c
+    bufinfo_T	*bi;
8b9a1c
     char_u	*hash;
8b9a1c
 {
8b9a1c
-    int len;
8b9a1c
+    int		len;
8b9a1c
+    buf_T	*buf = bi->bi_buf;
8b9a1c
+    FILE	*fp = bi->bi_fp;
8b9a1c
+    char_u	time_buf[8];
8b9a1c
 
8b9a1c
     /* Start writing, first the magic marker and undo info version. */
8b9a1c
     if (fwrite(UF_START_MAGIC, (size_t)UF_START_MAGIC_LEN, (size_t)1, fp) != 1)
8b9a1c
@@ -925,117 +1176,124 @@ serialize_header(fp, buf, hash)
8b9a1c
 	char_u *header;
8b9a1c
 	int    header_len;
8b9a1c
 
8b9a1c
-	put_bytes(fp, (long_u)UF_VERSION_CRYPT, 2);
8b9a1c
-	header = prepare_crypt_write(buf, &header_len);
8b9a1c
-	if (header == NULL)
8b9a1c
+	undo_write_bytes(bi, (long_u)UF_VERSION_CRYPT, 2);
8b9a1c
+	bi->bi_state = crypt_create_for_writing(crypt_get_method_nr(buf),
8b9a1c
+					  buf->b_p_key, &header, &header_len);
8b9a1c
+	if (bi->bi_state == NULL)
8b9a1c
 	    return FAIL;
8b9a1c
 	len = (int)fwrite(header, (size_t)header_len, (size_t)1, fp);
8b9a1c
 	vim_free(header);
8b9a1c
 	if (len != 1)
8b9a1c
 	{
8b9a1c
-	    crypt_pop_state();
8b9a1c
+	    crypt_free_state(bi->bi_state);
8b9a1c
+	    bi->bi_state = NULL;
8b9a1c
 	    return FAIL;
8b9a1c
 	}
8b9a1c
+
8b9a1c
+	if (crypt_whole_undofile(crypt_get_method_nr(buf)))
8b9a1c
+	{
8b9a1c
+	    bi->bi_buffer = alloc(CRYPT_BUF_SIZE);
8b9a1c
+	    if (bi->bi_buffer == NULL)
8b9a1c
+	    {
8b9a1c
+		crypt_free_state(bi->bi_state);
8b9a1c
+		bi->bi_state = NULL;
8b9a1c
+		return FAIL;
8b9a1c
+	    }
8b9a1c
+	    bi->bi_used = 0;
8b9a1c
+	}
8b9a1c
     }
8b9a1c
     else
8b9a1c
 #endif
8b9a1c
-	put_bytes(fp, (long_u)UF_VERSION, 2);
8b9a1c
+	undo_write_bytes(bi, (long_u)UF_VERSION, 2);
8b9a1c
 
8b9a1c
 
8b9a1c
     /* Write a hash of the buffer text, so that we can verify it is still the
8b9a1c
      * same when reading the buffer text. */
8b9a1c
-    if (fwrite(hash, (size_t)UNDO_HASH_SIZE, (size_t)1, fp) != 1)
8b9a1c
+    if (undo_write(bi, hash, (size_t)UNDO_HASH_SIZE) == FAIL)
8b9a1c
 	return FAIL;
8b9a1c
 
8b9a1c
     /* buffer-specific data */
8b9a1c
-    put_bytes(fp, (long_u)buf->b_ml.ml_line_count, 4);
8b9a1c
+    undo_write_bytes(bi, (long_u)buf->b_ml.ml_line_count, 4);
8b9a1c
     len = buf->b_u_line_ptr != NULL ? (int)STRLEN(buf->b_u_line_ptr) : 0;
8b9a1c
-    put_bytes(fp, (long_u)len, 4);
8b9a1c
-    if (len > 0 && fwrite_crypt(buf, buf->b_u_line_ptr, (size_t)len, fp) != 1)
8b9a1c
+    undo_write_bytes(bi, (long_u)len, 4);
8b9a1c
+    if (len > 0 && fwrite_crypt(bi, buf->b_u_line_ptr, (size_t)len) == FAIL)
8b9a1c
 	return FAIL;
8b9a1c
-    put_bytes(fp, (long_u)buf->b_u_line_lnum, 4);
8b9a1c
-    put_bytes(fp, (long_u)buf->b_u_line_colnr, 4);
8b9a1c
+    undo_write_bytes(bi, (long_u)buf->b_u_line_lnum, 4);
8b9a1c
+    undo_write_bytes(bi, (long_u)buf->b_u_line_colnr, 4);
8b9a1c
 
8b9a1c
     /* Undo structures header data */
8b9a1c
-    put_header_ptr(fp, buf->b_u_oldhead);
8b9a1c
-    put_header_ptr(fp, buf->b_u_newhead);
8b9a1c
-    put_header_ptr(fp, buf->b_u_curhead);
8b9a1c
-
8b9a1c
-    put_bytes(fp, (long_u)buf->b_u_numhead, 4);
8b9a1c
-    put_bytes(fp, (long_u)buf->b_u_seq_last, 4);
8b9a1c
-    put_bytes(fp, (long_u)buf->b_u_seq_cur, 4);
8b9a1c
-    put_time(fp, buf->b_u_time_cur);
8b9a1c
+    put_header_ptr(bi, buf->b_u_oldhead);
8b9a1c
+    put_header_ptr(bi, buf->b_u_newhead);
8b9a1c
+    put_header_ptr(bi, buf->b_u_curhead);
8b9a1c
+
8b9a1c
+    undo_write_bytes(bi, (long_u)buf->b_u_numhead, 4);
8b9a1c
+    undo_write_bytes(bi, (long_u)buf->b_u_seq_last, 4);
8b9a1c
+    undo_write_bytes(bi, (long_u)buf->b_u_seq_cur, 4);
8b9a1c
+    time_to_bytes(buf->b_u_time_cur, time_buf);
8b9a1c
+    undo_write(bi, time_buf, 8);
8b9a1c
 
8b9a1c
     /* Optional fields. */
8b9a1c
-    putc(4, fp);
8b9a1c
-    putc(UF_LAST_SAVE_NR, fp);
8b9a1c
-    put_bytes(fp, (long_u)buf->b_u_save_nr_last, 4);
8b9a1c
+    undo_write_bytes(bi, 4, 1);
8b9a1c
+    undo_write_bytes(bi, UF_LAST_SAVE_NR, 1);
8b9a1c
+    undo_write_bytes(bi, (long_u)buf->b_u_save_nr_last, 4);
8b9a1c
 
8b9a1c
-    putc(0, fp);  /* end marker */
8b9a1c
+    undo_write_bytes(bi, 0, 1);  /* end marker */
8b9a1c
 
8b9a1c
     return OK;
8b9a1c
 }
8b9a1c
 
8b9a1c
     static int
8b9a1c
-serialize_uhp(fp, buf, uhp)
8b9a1c
-    FILE	*fp;
8b9a1c
-    buf_T	*buf;
8b9a1c
+serialize_uhp(bi, uhp)
8b9a1c
+    bufinfo_T	*bi;
8b9a1c
     u_header_T	*uhp;
8b9a1c
 {
8b9a1c
     int		i;
8b9a1c
     u_entry_T	*uep;
8b9a1c
+    char_u	time_buf[8];
8b9a1c
 
8b9a1c
-    if (put_bytes(fp, (long_u)UF_HEADER_MAGIC, 2) == FAIL)
8b9a1c
+    if (undo_write_bytes(bi, (long_u)UF_HEADER_MAGIC, 2) == FAIL)
8b9a1c
 	return FAIL;
8b9a1c
 
8b9a1c
-    put_header_ptr(fp, uhp->uh_next.ptr);
8b9a1c
-    put_header_ptr(fp, uhp->uh_prev.ptr);
8b9a1c
-    put_header_ptr(fp, uhp->uh_alt_next.ptr);
8b9a1c
-    put_header_ptr(fp, uhp->uh_alt_prev.ptr);
8b9a1c
-    put_bytes(fp, uhp->uh_seq, 4);
8b9a1c
-    serialize_pos(uhp->uh_cursor, fp);
8b9a1c
+    put_header_ptr(bi, uhp->uh_next.ptr);
8b9a1c
+    put_header_ptr(bi, uhp->uh_prev.ptr);
8b9a1c
+    put_header_ptr(bi, uhp->uh_alt_next.ptr);
8b9a1c
+    put_header_ptr(bi, uhp->uh_alt_prev.ptr);
8b9a1c
+    undo_write_bytes(bi, uhp->uh_seq, 4);
8b9a1c
+    serialize_pos(bi, uhp->uh_cursor);
8b9a1c
 #ifdef FEAT_VIRTUALEDIT
8b9a1c
-    put_bytes(fp, (long_u)uhp->uh_cursor_vcol, 4);
8b9a1c
+    undo_write_bytes(bi, (long_u)uhp->uh_cursor_vcol, 4);
8b9a1c
 #else
8b9a1c
-    put_bytes(fp, (long_u)0, 4);
8b9a1c
+    undo_write_bytes(bi, (long_u)0, 4);
8b9a1c
 #endif
8b9a1c
-    put_bytes(fp, (long_u)uhp->uh_flags, 2);
8b9a1c
+    undo_write_bytes(bi, (long_u)uhp->uh_flags, 2);
8b9a1c
     /* Assume NMARKS will stay the same. */
8b9a1c
     for (i = 0; i < NMARKS; ++i)
8b9a1c
-	serialize_pos(uhp->uh_namedm[i], fp);
8b9a1c
-#ifdef FEAT_VISUAL
8b9a1c
-    serialize_visualinfo(&uhp->uh_visual, fp);
8b9a1c
-#else
8b9a1c
-    {
8b9a1c
-	visualinfo_T info;
8b9a1c
-
8b9a1c
-	memset(&info, 0, sizeof(visualinfo_T));
8b9a1c
-	serialize_visualinfo(&info, fp);
8b9a1c
-    }
8b9a1c
-#endif
8b9a1c
-    put_time(fp, uhp->uh_time);
8b9a1c
+	serialize_pos(bi, uhp->uh_namedm[i]);
8b9a1c
+    serialize_visualinfo(bi, &uhp->uh_visual);
8b9a1c
+    time_to_bytes(uhp->uh_time, time_buf);
8b9a1c
+    undo_write(bi, time_buf, 8);
8b9a1c
 
8b9a1c
     /* Optional fields. */
8b9a1c
-    putc(4, fp);
8b9a1c
-    putc(UHP_SAVE_NR, fp);
8b9a1c
-    put_bytes(fp, (long_u)uhp->uh_save_nr, 4);
8b9a1c
+    undo_write_bytes(bi, 4, 1);
8b9a1c
+    undo_write_bytes(bi, UHP_SAVE_NR, 1);
8b9a1c
+    undo_write_bytes(bi, (long_u)uhp->uh_save_nr, 4);
8b9a1c
 
8b9a1c
-    putc(0, fp);  /* end marker */
8b9a1c
+    undo_write_bytes(bi, 0, 1);  /* end marker */
8b9a1c
 
8b9a1c
     /* Write all the entries. */
8b9a1c
     for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next)
8b9a1c
     {
8b9a1c
-	put_bytes(fp, (long_u)UF_ENTRY_MAGIC, 2);
8b9a1c
-	if (serialize_uep(fp, buf, uep) == FAIL)
8b9a1c
+	undo_write_bytes(bi, (long_u)UF_ENTRY_MAGIC, 2);
8b9a1c
+	if (serialize_uep(bi, uep) == FAIL)
8b9a1c
 	    return FAIL;
8b9a1c
     }
8b9a1c
-    put_bytes(fp, (long_u)UF_ENTRY_END_MAGIC, 2);
8b9a1c
+    undo_write_bytes(bi, (long_u)UF_ENTRY_END_MAGIC, 2);
8b9a1c
     return OK;
8b9a1c
 }
8b9a1c
 
8b9a1c
     static u_header_T *
8b9a1c
-unserialize_uhp(fp, file_name)
8b9a1c
-    FILE	*fp;
8b9a1c
+unserialize_uhp(bi, file_name)
8b9a1c
+    bufinfo_T	*bi;
8b9a1c
     char_u	*file_name;
8b9a1c
 {
8b9a1c
     u_header_T	*uhp;
8b9a1c
@@ -1051,63 +1309,56 @@ unserialize_uhp(fp, file_name)
8b9a1c
 #ifdef U_DEBUG
8b9a1c
     uhp->uh_magic = UH_MAGIC;
8b9a1c
 #endif
8b9a1c
-    uhp->uh_next.seq = get4c(fp);
8b9a1c
-    uhp->uh_prev.seq = get4c(fp);
8b9a1c
-    uhp->uh_alt_next.seq = get4c(fp);
8b9a1c
-    uhp->uh_alt_prev.seq = get4c(fp);
8b9a1c
-    uhp->uh_seq = get4c(fp);
8b9a1c
+    uhp->uh_next.seq = undo_read_4c(bi);
8b9a1c
+    uhp->uh_prev.seq = undo_read_4c(bi);
8b9a1c
+    uhp->uh_alt_next.seq = undo_read_4c(bi);
8b9a1c
+    uhp->uh_alt_prev.seq = undo_read_4c(bi);
8b9a1c
+    uhp->uh_seq = undo_read_4c(bi);
8b9a1c
     if (uhp->uh_seq <= 0)
8b9a1c
     {
8b9a1c
 	corruption_error("uh_seq", file_name);
8b9a1c
 	vim_free(uhp);
8b9a1c
 	return NULL;
8b9a1c
     }
8b9a1c
-    unserialize_pos(&uhp->uh_cursor, fp);
8b9a1c
+    unserialize_pos(bi, &uhp->uh_cursor);
8b9a1c
 #ifdef FEAT_VIRTUALEDIT
8b9a1c
-    uhp->uh_cursor_vcol = get4c(fp);
8b9a1c
+    uhp->uh_cursor_vcol = undo_read_4c(bi);
8b9a1c
 #else
8b9a1c
-    (void)get4c(fp);
8b9a1c
+    (void)undo_read_4c(bi);
8b9a1c
 #endif
8b9a1c
-    uhp->uh_flags = get2c(fp);
8b9a1c
+    uhp->uh_flags = undo_read_2c(bi);
8b9a1c
     for (i = 0; i < NMARKS; ++i)
8b9a1c
-	unserialize_pos(&uhp->uh_namedm[i], fp);
8b9a1c
-#ifdef FEAT_VISUAL
8b9a1c
-    unserialize_visualinfo(&uhp->uh_visual, fp);
8b9a1c
-#else
8b9a1c
-    {
8b9a1c
-	visualinfo_T info;
8b9a1c
-	unserialize_visualinfo(&info, fp);
8b9a1c
-    }
8b9a1c
-#endif
8b9a1c
-    uhp->uh_time = get8ctime(fp);
8b9a1c
+	unserialize_pos(bi, &uhp->uh_namedm[i]);
8b9a1c
+    unserialize_visualinfo(bi, &uhp->uh_visual);
8b9a1c
+    uhp->uh_time = undo_read_time(bi);
8b9a1c
 
8b9a1c
     /* Optional fields. */
8b9a1c
     for (;;)
8b9a1c
     {
8b9a1c
-	int len = getc(fp);
8b9a1c
+	int len = undo_read_byte(bi);
8b9a1c
 	int what;
8b9a1c
 
8b9a1c
 	if (len == 0)
8b9a1c
 	    break;
8b9a1c
-	what = getc(fp);
8b9a1c
+	what = undo_read_byte(bi);
8b9a1c
 	switch (what)
8b9a1c
 	{
8b9a1c
 	    case UHP_SAVE_NR:
8b9a1c
-		uhp->uh_save_nr = get4c(fp);
8b9a1c
+		uhp->uh_save_nr = undo_read_4c(bi);
8b9a1c
 		break;
8b9a1c
 	    default:
8b9a1c
 		/* field not supported, skip */
8b9a1c
 		while (--len >= 0)
8b9a1c
-		    (void)getc(fp);
8b9a1c
+		    (void)undo_read_byte(bi);
8b9a1c
 	}
8b9a1c
     }
8b9a1c
 
8b9a1c
     /* Unserialize the uep list. */
8b9a1c
     last_uep = NULL;
8b9a1c
-    while ((c = get2c(fp)) == UF_ENTRY_MAGIC)
8b9a1c
+    while ((c = undo_read_2c(bi)) == UF_ENTRY_MAGIC)
8b9a1c
     {
8b9a1c
 	error = FALSE;
8b9a1c
-	uep = unserialize_uep(fp, &error, file_name);
8b9a1c
+	uep = unserialize_uep(bi, &error, file_name);
8b9a1c
 	if (last_uep == NULL)
8b9a1c
 	    uhp->uh_entry = uep;
8b9a1c
 	else
8b9a1c
@@ -1130,35 +1381,34 @@ unserialize_uhp(fp, file_name)
8b9a1c
 }
8b9a1c
 
8b9a1c
 /*
8b9a1c
- * Serialize "uep" to "fp".
8b9a1c
+ * Serialize "uep".
8b9a1c
  */
8b9a1c
     static int
8b9a1c
-serialize_uep(fp, buf, uep)
8b9a1c
-    FILE	*fp;
8b9a1c
-    buf_T	*buf;
8b9a1c
+serialize_uep(bi, uep)
8b9a1c
+    bufinfo_T	*bi;
8b9a1c
     u_entry_T	*uep;
8b9a1c
 {
8b9a1c
     int		i;
8b9a1c
     size_t	len;
8b9a1c
 
8b9a1c
-    put_bytes(fp, (long_u)uep->ue_top, 4);
8b9a1c
-    put_bytes(fp, (long_u)uep->ue_bot, 4);
8b9a1c
-    put_bytes(fp, (long_u)uep->ue_lcount, 4);
8b9a1c
-    put_bytes(fp, (long_u)uep->ue_size, 4);
8b9a1c
+    undo_write_bytes(bi, (long_u)uep->ue_top, 4);
8b9a1c
+    undo_write_bytes(bi, (long_u)uep->ue_bot, 4);
8b9a1c
+    undo_write_bytes(bi, (long_u)uep->ue_lcount, 4);
8b9a1c
+    undo_write_bytes(bi, (long_u)uep->ue_size, 4);
8b9a1c
     for (i = 0; i < uep->ue_size; ++i)
8b9a1c
     {
8b9a1c
 	len = STRLEN(uep->ue_array[i]);
8b9a1c
-	if (put_bytes(fp, (long_u)len, 4) == FAIL)
8b9a1c
+	if (undo_write_bytes(bi, (long_u)len, 4) == FAIL)
8b9a1c
 	    return FAIL;
8b9a1c
-	if (len > 0 && fwrite_crypt(buf, uep->ue_array[i], len, fp) != 1)
8b9a1c
+	if (len > 0 && fwrite_crypt(bi, uep->ue_array[i], len) == FAIL)
8b9a1c
 	    return FAIL;
8b9a1c
     }
8b9a1c
     return OK;
8b9a1c
 }
8b9a1c
 
8b9a1c
     static u_entry_T *
8b9a1c
-unserialize_uep(fp, error, file_name)
8b9a1c
-    FILE	*fp;
8b9a1c
+unserialize_uep(bi, error, file_name)
8b9a1c
+    bufinfo_T	*bi;
8b9a1c
     int		*error;
8b9a1c
     char_u	*file_name;
8b9a1c
 {
8b9a1c
@@ -1175,10 +1425,10 @@ unserialize_uep(fp, error, file_name)
8b9a1c
 #ifdef U_DEBUG
8b9a1c
     uep->ue_magic = UE_MAGIC;
8b9a1c
 #endif
8b9a1c
-    uep->ue_top = get4c(fp);
8b9a1c
-    uep->ue_bot = get4c(fp);
8b9a1c
-    uep->ue_lcount = get4c(fp);
8b9a1c
-    uep->ue_size = get4c(fp);
8b9a1c
+    uep->ue_top = undo_read_4c(bi);
8b9a1c
+    uep->ue_bot = undo_read_4c(bi);
8b9a1c
+    uep->ue_lcount = undo_read_4c(bi);
8b9a1c
+    uep->ue_size = undo_read_4c(bi);
8b9a1c
     if (uep->ue_size > 0)
8b9a1c
     {
8b9a1c
 	array = (char_u **)U_ALLOC_LINE(sizeof(char_u *) * uep->ue_size);
8b9a1c
@@ -1195,9 +1445,9 @@ unserialize_uep(fp, error, file_name)
8b9a1c
 
8b9a1c
     for (i = 0; i < uep->ue_size; ++i)
8b9a1c
     {
8b9a1c
-	line_len = get4c(fp);
8b9a1c
+	line_len = undo_read_4c(bi);
8b9a1c
 	if (line_len >= 0)
8b9a1c
-	    line = read_string_decrypt(curbuf, fp, line_len);
8b9a1c
+	    line = read_string_decrypt(bi, line_len);
8b9a1c
 	else
8b9a1c
 	{
8b9a1c
 	    line = NULL;
8b9a1c
@@ -1214,83 +1464,71 @@ unserialize_uep(fp, error, file_name)
8b9a1c
 }
8b9a1c
 
8b9a1c
 /*
8b9a1c
- * Serialize "pos" to "fp".
8b9a1c
+ * Serialize "pos".
8b9a1c
  */
8b9a1c
     static void
8b9a1c
-serialize_pos(pos, fp)
8b9a1c
+serialize_pos(bi, pos)
8b9a1c
+    bufinfo_T *bi;
8b9a1c
     pos_T pos;
8b9a1c
-    FILE  *fp;
8b9a1c
 {
8b9a1c
-    put_bytes(fp, (long_u)pos.lnum, 4);
8b9a1c
-    put_bytes(fp, (long_u)pos.col, 4);
8b9a1c
+    undo_write_bytes(bi, (long_u)pos.lnum, 4);
8b9a1c
+    undo_write_bytes(bi, (long_u)pos.col, 4);
8b9a1c
 #ifdef FEAT_VIRTUALEDIT
8b9a1c
-    put_bytes(fp, (long_u)pos.coladd, 4);
8b9a1c
+    undo_write_bytes(bi, (long_u)pos.coladd, 4);
8b9a1c
 #else
8b9a1c
-    put_bytes(fp, (long_u)0, 4);
8b9a1c
+    undo_write_bytes(bi, (long_u)0, 4);
8b9a1c
 #endif
8b9a1c
 }
8b9a1c
 
8b9a1c
 /*
8b9a1c
- * Unserialize the pos_T at the current position in fp.
8b9a1c
+ * Unserialize the pos_T at the current position.
8b9a1c
  */
8b9a1c
     static void
8b9a1c
-unserialize_pos(pos, fp)
8b9a1c
+unserialize_pos(bi, pos)
8b9a1c
+    bufinfo_T *bi;
8b9a1c
     pos_T *pos;
8b9a1c
-    FILE  *fp;
8b9a1c
 {
8b9a1c
-    pos->lnum = get4c(fp);
8b9a1c
+    pos->lnum = undo_read_4c(bi);
8b9a1c
     if (pos->lnum < 0)
8b9a1c
 	pos->lnum = 0;
8b9a1c
-    pos->col = get4c(fp);
8b9a1c
+    pos->col = undo_read_4c(bi);
8b9a1c
     if (pos->col < 0)
8b9a1c
 	pos->col = 0;
8b9a1c
 #ifdef FEAT_VIRTUALEDIT
8b9a1c
-    pos->coladd = get4c(fp);
8b9a1c
+    pos->coladd = undo_read_4c(bi);
8b9a1c
     if (pos->coladd < 0)
8b9a1c
 	pos->coladd = 0;
8b9a1c
 #else
8b9a1c
-    (void)get4c(fp);
8b9a1c
+    (void)undo_read_4c(bi);
8b9a1c
 #endif
8b9a1c
 }
8b9a1c
 
8b9a1c
 /*
8b9a1c
- * Serialize "info" to "fp".
8b9a1c
+ * Serialize "info".
8b9a1c
  */
8b9a1c
     static void
8b9a1c
-serialize_visualinfo(info, fp)
8b9a1c
+serialize_visualinfo(bi, info)
8b9a1c
+    bufinfo_T	    *bi;
8b9a1c
     visualinfo_T    *info;
8b9a1c
-    FILE	    *fp;
8b9a1c
 {
8b9a1c
-    serialize_pos(info->vi_start, fp);
8b9a1c
-    serialize_pos(info->vi_end, fp);
8b9a1c
-    put_bytes(fp, (long_u)info->vi_mode, 4);
8b9a1c
-    put_bytes(fp, (long_u)info->vi_curswant, 4);
8b9a1c
+    serialize_pos(bi, info->vi_start);
8b9a1c
+    serialize_pos(bi, info->vi_end);
8b9a1c
+    undo_write_bytes(bi, (long_u)info->vi_mode, 4);
8b9a1c
+    undo_write_bytes(bi, (long_u)info->vi_curswant, 4);
8b9a1c
 }
8b9a1c
 
8b9a1c
 /*
8b9a1c
- * Unserialize the visualinfo_T at the current position in fp.
8b9a1c
+ * Unserialize the visualinfo_T at the current position.
8b9a1c
  */
8b9a1c
     static void
8b9a1c
-unserialize_visualinfo(info, fp)
8b9a1c
+unserialize_visualinfo(bi, info)
8b9a1c
+    bufinfo_T	    *bi;
8b9a1c
     visualinfo_T    *info;
8b9a1c
-    FILE	    *fp;
8b9a1c
-{
8b9a1c
-    unserialize_pos(&info->vi_start, fp);
8b9a1c
-    unserialize_pos(&info->vi_end, fp);
8b9a1c
-    info->vi_mode = get4c(fp);
8b9a1c
-    info->vi_curswant = get4c(fp);
8b9a1c
-}
8b9a1c
-
8b9a1c
-/*
8b9a1c
- * Write the pointer to an undo header.  Instead of writing the pointer itself
8b9a1c
- * we use the sequence number of the header.  This is converted back to
8b9a1c
- * pointers when reading. */
8b9a1c
-    static void
8b9a1c
-put_header_ptr(fp, uhp)
8b9a1c
-    FILE	*fp;
8b9a1c
-    u_header_T	*uhp;
8b9a1c
 {
8b9a1c
-    put_bytes(fp, (long_u)(uhp != NULL ? uhp->uh_seq : 0), 4);
8b9a1c
+    unserialize_pos(bi, &info->vi_start);
8b9a1c
+    unserialize_pos(bi, &info->vi_end);
8b9a1c
+    info->vi_mode = undo_read_4c(bi);
8b9a1c
+    info->vi_curswant = undo_read_4c(bi);
8b9a1c
 }
8b9a1c
 
8b9a1c
 /*
8b9a1c
@@ -1324,9 +1562,9 @@ u_write_undo(name, forceit, buf, hash)
8b9a1c
     struct stat	st_old;
8b9a1c
     struct stat	st_new;
8b9a1c
 #endif
8b9a1c
-#ifdef FEAT_CRYPT
8b9a1c
-    int		do_crypt = FALSE;
8b9a1c
-#endif
8b9a1c
+    bufinfo_T	bi;
8b9a1c
+
8b9a1c
+    vim_memset(&bi, 0, sizeof(bi));
8b9a1c
 
8b9a1c
     if (name == NULL)
8b9a1c
     {
8b9a1c
@@ -1481,14 +1719,12 @@ u_write_undo(name, forceit, buf, hash)
8b9a1c
     u_sync(TRUE);
8b9a1c
 
8b9a1c
     /*
8b9a1c
-     * Write the header.
8b9a1c
+     * Write the header.  Initializes encryption, if enabled.
8b9a1c
      */
8b9a1c
-    if (serialize_header(fp, buf, hash) == FAIL)
8b9a1c
+    bi.bi_buf = buf;
8b9a1c
+    bi.bi_fp = fp;
8b9a1c
+    if (serialize_header(&bi, hash) == FAIL)
8b9a1c
 	goto write_error;
8b9a1c
-#ifdef FEAT_CRYPT
8b9a1c
-    if (*buf->b_p_key != NUL)
8b9a1c
-	do_crypt = TRUE;
8b9a1c
-#endif
8b9a1c
 
8b9a1c
     /*
8b9a1c
      * Iteratively serialize UHPs and their UEPs from the top down.
8b9a1c
@@ -1504,7 +1740,7 @@ u_write_undo(name, forceit, buf, hash)
8b9a1c
 #ifdef U_DEBUG
8b9a1c
 	    ++headers_written;
8b9a1c
 #endif
8b9a1c
-	    if (serialize_uhp(fp, buf, uhp) == FAIL)
8b9a1c
+	    if (serialize_uhp(&bi, uhp) == FAIL)
8b9a1c
 		goto write_error;
8b9a1c
 	}
8b9a1c
 
8b9a1c
@@ -1523,7 +1759,7 @@ u_write_undo(name, forceit, buf, hash)
8b9a1c
 	    uhp = uhp->uh_next.ptr;
8b9a1c
     }
8b9a1c
 
8b9a1c
-    if (put_bytes(fp, (long_u)UF_HEADER_END_MAGIC, 2) == OK)
8b9a1c
+    if (undo_write_bytes(&bi, (long_u)UF_HEADER_END_MAGIC, 2) == OK)
8b9a1c
 	write_ok = TRUE;
8b9a1c
 #ifdef U_DEBUG
8b9a1c
     if (headers_written != buf->b_u_numhead)
8b9a1c
@@ -1533,6 +1769,11 @@ u_write_undo(name, forceit, buf, hash)
8b9a1c
     }
8b9a1c
 #endif
8b9a1c
 
8b9a1c
+#ifdef FEAT_CRYPT
8b9a1c
+    if (bi.bi_state != NULL && undo_flush(&bi) == FAIL)
8b9a1c
+	write_ok = FALSE;
8b9a1c
+#endif
8b9a1c
+
8b9a1c
 write_error:
8b9a1c
     fclose(fp);
8b9a1c
     if (!write_ok)
8b9a1c
@@ -1558,8 +1799,9 @@ write_error:
8b9a1c
 
8b9a1c
 theend:
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
-    if (do_crypt)
8b9a1c
-	crypt_pop_state();
8b9a1c
+    if (bi.bi_state != NULL)
8b9a1c
+	crypt_free_state(bi.bi_state);
8b9a1c
+    vim_free(bi.bi_buffer);
8b9a1c
 #endif
8b9a1c
     if (file_name != name)
8b9a1c
 	vim_free(file_name);
8b9a1c
@@ -1605,10 +1847,9 @@ u_read_undo(name, hash, orig_name)
8b9a1c
     struct stat	st_orig;
8b9a1c
     struct stat	st_undo;
8b9a1c
 #endif
8b9a1c
-#ifdef FEAT_CRYPT
8b9a1c
-    int		do_decrypt = FALSE;
8b9a1c
-#endif
8b9a1c
+    bufinfo_T	bi;
8b9a1c
 
8b9a1c
+    vim_memset(&bi, 0, sizeof(bi));
8b9a1c
     if (name == NULL)
8b9a1c
     {
8b9a1c
 	file_name = u_get_undo_file_name(curbuf->b_ffname, TRUE);
8b9a1c
@@ -1651,6 +1892,8 @@ u_read_undo(name, hash, orig_name)
8b9a1c
 	    EMSG2(_("E822: Cannot open undo file for reading: %s"), file_name);
8b9a1c
 	goto error;
8b9a1c
     }
8b9a1c
+    bi.bi_buf = curbuf;
8b9a1c
+    bi.bi_fp = fp;
8b9a1c
 
8b9a1c
     /*
8b9a1c
      * Read the undo file header.
8b9a1c
@@ -1671,12 +1914,24 @@ u_read_undo(name, hash, orig_name)
8b9a1c
 								   file_name);
8b9a1c
 	    goto error;
8b9a1c
 	}
8b9a1c
-	if (prepare_crypt_read(fp) == FAIL)
8b9a1c
+	bi.bi_state = crypt_create_from_file(fp, curbuf->b_p_key);
8b9a1c
+	if (bi.bi_state == NULL)
8b9a1c
 	{
8b9a1c
 	    EMSG2(_("E826: Undo file decryption failed: %s"), file_name);
8b9a1c
 	    goto error;
8b9a1c
 	}
8b9a1c
-	do_decrypt = TRUE;
8b9a1c
+	if (crypt_whole_undofile(bi.bi_state->method_nr))
8b9a1c
+	{
8b9a1c
+	    bi.bi_buffer = alloc(CRYPT_BUF_SIZE);
8b9a1c
+	    if (bi.bi_buffer == NULL)
8b9a1c
+	    {
8b9a1c
+		crypt_free_state(bi.bi_state);
8b9a1c
+		bi.bi_state = NULL;
8b9a1c
+		goto error;
8b9a1c
+	    }
8b9a1c
+	    bi.bi_avail = 0;
8b9a1c
+	    bi.bi_used = 0;
8b9a1c
+	}
8b9a1c
 #else
8b9a1c
 	EMSG2(_("E827: Undo file is encrypted: %s"), file_name);
8b9a1c
 	goto error;
8b9a1c
@@ -1688,12 +1943,12 @@ u_read_undo(name, hash, orig_name)
8b9a1c
 	goto error;
8b9a1c
     }
8b9a1c
 
8b9a1c
-    if (fread(read_hash, UNDO_HASH_SIZE, 1, fp) != 1)
8b9a1c
+    if (undo_read(&bi, read_hash, (size_t)UNDO_HASH_SIZE) == FAIL)
8b9a1c
     {
8b9a1c
 	corruption_error("hash", file_name);
8b9a1c
 	goto error;
8b9a1c
     }
8b9a1c
-    line_count = (linenr_T)get4c(fp);
8b9a1c
+    line_count = (linenr_T)undo_read_4c(&bi);
8b9a1c
     if (memcmp(hash, read_hash, UNDO_HASH_SIZE) != 0
8b9a1c
 				  || line_count != curbuf->b_ml.ml_line_count)
8b9a1c
     {
8b9a1c
@@ -1710,13 +1965,13 @@ u_read_undo(name, hash, orig_name)
8b9a1c
     }
8b9a1c
 
8b9a1c
     /* Read undo data for "U" command. */
8b9a1c
-    str_len = get4c(fp);
8b9a1c
+    str_len = undo_read_4c(&bi);
8b9a1c
     if (str_len < 0)
8b9a1c
 	goto error;
8b9a1c
     if (str_len > 0)
8b9a1c
-	line_ptr = read_string_decrypt(curbuf, fp, str_len);
8b9a1c
-    line_lnum = (linenr_T)get4c(fp);
8b9a1c
-    line_colnr = (colnr_T)get4c(fp);
8b9a1c
+	line_ptr = read_string_decrypt(&bi, str_len);
8b9a1c
+    line_lnum = (linenr_T)undo_read_4c(&bi);
8b9a1c
+    line_colnr = (colnr_T)undo_read_4c(&bi);
8b9a1c
     if (line_lnum < 0 || line_colnr < 0)
8b9a1c
     {
8b9a1c
 	corruption_error("line lnum/col", file_name);
8b9a1c
@@ -1724,32 +1979,32 @@ u_read_undo(name, hash, orig_name)
8b9a1c
     }
8b9a1c
 
8b9a1c
     /* Begin general undo data */
8b9a1c
-    old_header_seq = get4c(fp);
8b9a1c
-    new_header_seq = get4c(fp);
8b9a1c
-    cur_header_seq = get4c(fp);
8b9a1c
-    num_head = get4c(fp);
8b9a1c
-    seq_last = get4c(fp);
8b9a1c
-    seq_cur = get4c(fp);
8b9a1c
-    seq_time = get8ctime(fp);
8b9a1c
+    old_header_seq = undo_read_4c(&bi);
8b9a1c
+    new_header_seq = undo_read_4c(&bi);
8b9a1c
+    cur_header_seq = undo_read_4c(&bi);
8b9a1c
+    num_head = undo_read_4c(&bi);
8b9a1c
+    seq_last = undo_read_4c(&bi);
8b9a1c
+    seq_cur = undo_read_4c(&bi);
8b9a1c
+    seq_time = undo_read_time(&bi);
8b9a1c
 
8b9a1c
     /* Optional header fields. */
8b9a1c
     for (;;)
8b9a1c
     {
8b9a1c
-	int len = getc(fp);
8b9a1c
+	int len = undo_read_byte(&bi);
8b9a1c
 	int what;
8b9a1c
 
8b9a1c
 	if (len == 0 || len == EOF)
8b9a1c
 	    break;
8b9a1c
-	what = getc(fp);
8b9a1c
+	what = undo_read_byte(&bi);
8b9a1c
 	switch (what)
8b9a1c
 	{
8b9a1c
 	    case UF_LAST_SAVE_NR:
8b9a1c
-		last_save_nr = get4c(fp);
8b9a1c
+		last_save_nr = undo_read_4c(&bi);
8b9a1c
 		break;
8b9a1c
 	    default:
8b9a1c
 		/* field not supported, skip */
8b9a1c
 		while (--len >= 0)
8b9a1c
-		    (void)getc(fp);
8b9a1c
+		    (void)undo_read_byte(&bi);
8b9a1c
 	}
8b9a1c
     }
8b9a1c
 
8b9a1c
@@ -1765,7 +2020,7 @@ u_read_undo(name, hash, orig_name)
8b9a1c
 	    goto error;
8b9a1c
     }
8b9a1c
 
8b9a1c
-    while ((c = get2c(fp)) == UF_HEADER_MAGIC)
8b9a1c
+    while ((c = undo_read_2c(&bi)) == UF_HEADER_MAGIC)
8b9a1c
     {
8b9a1c
 	if (num_read_uhps >= num_head)
8b9a1c
 	{
8b9a1c
@@ -1773,7 +2028,7 @@ u_read_undo(name, hash, orig_name)
8b9a1c
 	    goto error;
8b9a1c
 	}
8b9a1c
 
8b9a1c
-	uhp = unserialize_uhp(fp, file_name);
8b9a1c
+	uhp = unserialize_uhp(&bi, file_name);
8b9a1c
 	if (uhp == NULL)
8b9a1c
 	    goto error;
8b9a1c
 	uhp_table[num_read_uhps++] = uhp;
8b9a1c
@@ -1905,8 +2160,9 @@ error:
8b9a1c
 
8b9a1c
 theend:
8b9a1c
 #ifdef FEAT_CRYPT
8b9a1c
-    if (do_decrypt)
8b9a1c
-	crypt_pop_state();
8b9a1c
+    if (bi.bi_state != NULL)
8b9a1c
+	crypt_free_state(bi.bi_state);
8b9a1c
+    vim_free(bi.bi_buffer);
8b9a1c
 #endif
8b9a1c
     if (fp != NULL)
8b9a1c
 	fclose(fp);
8b9a1c
diff -up vim74/src/version.c.blowfish2 vim74/src/version.c
8b9a1c
--- vim74/src/version.c.blowfish2	2017-09-05 14:47:34.768913491 +0200
8b9a1c
+++ vim74/src/version.c	2017-09-05 14:47:34.973911836 +0200
8b9a1c
@@ -739,6 +739,14 @@ static char *(features[]) =
8b9a1c
 static int included_patches[] =
8b9a1c
 {   /* Add new patch number below this line */
8b9a1c
 /**/
8b9a1c
+    1099,
8b9a1c
+/**/
8b9a1c
+    403,
8b9a1c
+/**/
8b9a1c
+    402,
8b9a1c
+/**/
8b9a1c
+    399,
8b9a1c
+/**/
8b9a1c
     160,
8b9a1c
 /**/
8b9a1c
     159,