Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Crypt the swapfile.

--HG--
branch : vim73
  • Loading branch information...
commit 1a0457e4311ee1c222323d3be53f6fba607a8395 1 parent b89b824
authored June 21, 2010
10  runtime/doc/editing.txt
@@ -1332,10 +1332,12 @@ There are a few things to remember when editing binary files:
1332 1332
 Vim is able to write files encrypted, and read them back.  The encrypted text
1333 1333
 cannot be read without the right key.
1334 1334
 
1335  
-Note: The swapfile and text in memory is not encrypted.  A system
1336  
-administrator will be able to see your text while you are editing it.
1337  
-When filtering text with ":!filter" or using ":w !command" the text is not
1338  
-encrypted, this may reveal it to others.
  1335
+The text in the swap file and the undo file is also encrypted.
  1336
+
  1337
+Note: The text in memory is not encrypted.  A system administrator may be able
  1338
+to see your text while you are editing it.  When filtering text with
  1339
+":!filter" or using ":w !command" the text is not encrypted, this may reveal
  1340
+it to others.  The 'viminfo' file is not encrypted.
1339 1341
 
1340 1342
 WARNING: If you make a typo when entering the key and then write the file and
1341 1343
 exit, the text will be lost!
22  runtime/doc/helphelp.txt
@@ -119,9 +119,9 @@ Help on help files					*helphelp*
119 119
 							*:lh* *:lhelpgrep*
120 120
 :lh[elpgrep] {pattern}[@xx]
121 121
 			Same as ":helpgrep", except the location list is used
122  
-			instead of the quickfix list. If the help window is
  122
+			instead of the quickfix list.  If the help window is
123 123
 			already opened, then the location list for that window
124  
-			is used. Otherwise, a new help window is opened and
  124
+			is used.  Otherwise, a new help window is opened and
125 125
 			the location list for that window is set.  The
126 126
 			location list for the current window is not changed.
127 127
 
@@ -281,9 +281,9 @@ The first line in a help file should have the following format:
281 281
 
282 282
 *helpfile_name.txt*	For Vim version 7.3	Last change: 2010 June 4
283 283
 
284  
-The first field is a link to the help file name. The second field describes
285  
-the applicable Vim version. The last field specifies the last modification
286  
-date of the file. Each field is separated by a tab.
  284
+The first field is a link to the help file name.  The second field describes
  285
+the applicable Vim version.  The last field specifies the last modification
  286
+date of the file.  Each field is separated by a tab.
287 287
 
288 288
 At the bottom of the help file, place a Vim modeline to set the 'textwidth'
289 289
 and 'tabstop' options and the 'filetype' to 'help'.  Never set a global option
@@ -295,30 +295,30 @@ TAGS
295 295
 
296 296
 To define a help tag, place the name between asterisks (*tag-name*).  The
297 297
 tag-name should be different from all the Vim help tag names and ideally
298  
-should begin with the name of the Vim plugin. The tag name is usually right
  298
+should begin with the name of the Vim plugin.  The tag name is usually right
299 299
 aligned on a line.
300 300
 
301 301
 When referring to an existing help tag and to create a hot-link, place the
302 302
 name between two bars (|) eg. |help-writing|.
303 303
 
304 304
 When referring to a Vim option in the help file, place the option name between
305  
-two single quotes. eg. 'statusline'
  305
+two single quotes, eg. 'statusline'
306 306
 
307 307
 
308 308
 HIGHLIGHTING
309 309
 
310  
-To define a column heading, use a tilde character at the end of the line. This
311  
-will highlight the column heading in a different color. E.g.
  310
+To define a column heading, use a tilde character at the end of the line.
  311
+This will highlight the column heading in a different color.  E.g.
312 312
 
313 313
 Column heading~
314 314
 
315 315
 To separate sections in a help file, place a series of '=' characters in a
316  
-line starting from the first column. The section separator line is highlighted
  316
+line starting from the first column.  The section separator line is highlighted
317 317
 differently.
318 318
 
319 319
 To quote a block of ex-commands verbatim, place a greater than (>) character
320 320
 at the end of the line before the block and a less than (<) character as the
321  
-first non-blank on a line following the block. Any line starting in column 1
  321
+first non-blank on a line following the block.  Any line starting in column 1
322 322
 also implicitly stops the block of ex-commands before it.  E.g. >
323 323
     function Example_Func()
324 324
 	echo "Example"
39  runtime/doc/recover.txt
@@ -188,4 +188,43 @@ will continue to get warning messages that the ".swp" file already exists.
188 188
 
189 189
 {Vi: recovers in another way and sends mail if there is something to recover}
190 190
 
  191
+
  192
+ENCRYPTION AND THE SWAP FILE				*:recover-crypt*
  193
+
  194
+When the text file is encrypted the swap file is encrypted as well.  This
  195
+makes recovery a bit more complicated.  When recovering from a swap file and
  196
+encryption has been used, you will be asked to enter one or two crypt keys.
  197
+
  198
+If the text file does not exist you will only be asked to enter the crypt key
  199
+for the swap file.
  200
+
  201
+If the text file does exist, it may be encrypted in a different way than the
  202
+swap file.  You will be asked for the crypt key twice:
  203
+
  204
+	Need encryption key for "/tmp/tt" ~
  205
+	Enter encryption key: ****** ~
  206
+	"/tmp/tt" [crypted] 23200L, 522129C ~
  207
+	Using swap file "/tmp/.tt.swp" ~
  208
+	Original file "/tmp/tt" ~
  209
+	Swap file is encrypted: "/tmp/.tt.swp" ~
  210
+	If you entered a new crypt key but did not write the text file, ~
  211
+	enter the new crypt key. ~
  212
+	If you wrote the text file after changing the crypt key press enter ~
  213
+	to use the same key for text file and swap file ~
  214
+	Enter encryption key:  ~
  215
+
  216
+You can be in one of these two situations:
  217
+
  218
+1. The encryption key was not changed, or after changing the key the text file
  219
+   was written.  You will be prompted for the crypt key twice.  The second
  220
+   time you can simply press Enter.  That means the same key is used for the
  221
+   text file and the swap file.
  222
+2. You entered a new encryption key, but did not save the text file.  Vim will
  223
+   then use the new key for the swap file, and the text file will still be
  224
+   encrypted with the old key.  At the second prompt enter the new key.
  225
+
  226
+Note that after recovery the key of the swap file will be used for the text
  227
+file.  Thus if you write the text file, you need to use that new key.
  228
+
  229
+
191 230
  vim:tw=78:ts=8:ft=help:norl:
4  runtime/doc/tags
@@ -2577,6 +2577,7 @@ $VIMRUNTIME	starting.txt	/*$VIMRUNTIME*
2577 2577
 :read!	insert.txt	/*:read!*
2578 2578
 :rec	recover.txt	/*:rec*
2579 2579
 :recover	recover.txt	/*:recover*
  2580
+:recover-crypt	recover.txt	/*:recover-crypt*
2580 2581
 :red	undo.txt	/*:red*
2581 2582
 :redi	various.txt	/*:redi*
2582 2583
 :redir	various.txt	/*:redir*
@@ -6914,7 +6915,6 @@ os_unix.txt	os_unix.txt	/*os_unix.txt*
6914 6915
 os_vms.txt	os_vms.txt	/*os_vms.txt*
6915 6916
 os_win32.txt	os_win32.txt	/*os_win32.txt*
6916 6917
 other-features	vi_diff.txt	/*other-features*
6917  
-ownsyntax	eval.txt	/*ownsyntax*
6918 6918
 p	change.txt	/*p*
6919 6919
 page-down	intro.txt	/*page-down*
6920 6920
 page-up	intro.txt	/*page-up*
@@ -8220,7 +8220,7 @@ vt100-cursor-keys	term.txt	/*vt100-cursor-keys*
8220 8220
 vt100-function-keys	term.txt	/*vt100-function-keys*
8221 8221
 w	motion.txt	/*w*
8222 8222
 w32-clientserver	remote.txt	/*w32-clientserver*
8223  
-w:ownsyntax-variable	eval.txt	/*w:ownsyntax-variable*
  8223
+w:current_syntax	syntax.txt	/*w:current_syntax*
8224 8224
 w:var	eval.txt	/*w:var*
8225 8225
 warningmsg-variable	eval.txt	/*warningmsg-variable*
8226 8226
 white-space	pattern.txt	/*white-space*
22  runtime/doc/todo.txt
@@ -1088,18 +1088,16 @@ Vim 7.3:
1088 1088
 - using NSIS 2.46: install on Windows 7 works, but no "Edit with Vim" menu.
1089 1089
    Use register_shell_extension()? (George Reilly, 2010 May 26)
1090 1090
    Ron's version: http://dev.ronware.org/p/vim/finfo?name=gvim.nsi
1091  
-- Also crypt the swap file, each block separately.  Change mf_write() and
1092  
-    mf_read().
1093  
-    - How to get b_p_key to these functions?  -> Store buf_T pointer in mfp.
1094  
-    - Generate a salt and seed for the swapfile, put it in block 0.
1095  
-    - For each block, use password + seed + byte offset to crypt/decrypt.
1096  
-    - When changing the password need to read back with the old password and
1097  
-      write again with the new one.
1098  
-    - Fill the gaps in the block with random bytes, otherwise it's easy to
1099  
-      check for correct password by finding NUL bytes.
1100  
-    - Verify recovery works.
  1091
+- Also crypt the swap file, each block separately:
  1092
+    - When changing the password or 'cryptmethod' need to read back with the
  1093
+      old password and write again with the new one.
  1094
+      Problem: when the file is not written, key differs between text file and
  1095
+      swap file!
  1096
+- Patch for :ownsyntax completion (Dominique Pelle, 2010 Jun 20)
1101 1097
 - Patch for conceal feature and 'foldcolumn'. (Dominique Pelle, 2010 Jun 10,
1102 1098
   second patch)
  1099
+  Also patch from Vince, 2010 Jun 15.  And another June 16.
  1100
+  However: more generic patch on the way.
1103 1101
 - patch for conceal feature and 'modifiable'. (Dominique Pelle, 2010 Jun 9)
1104 1102
 - undofile: keep markers where the file was written/read, so that it's easy to
1105 1103
   go back to a saved version of the file:  ":earlier 1f" (f for file)?
@@ -1110,6 +1108,7 @@ Vim 7.3:
1110 1108
   dictionary: {'nr': 2, 'time': 1234, 'saved': 1}
1111 1109
 - Remove support for GTK 1?  Patch by James Vega, Jun 11.
1112 1110
 Patches to include:
  1111
+- Patch for X clibboard CurrentTime, (Fries, 2010 Jun 20)
1113 1112
 - Patch for Lisp support with ECL (Mikael Jansson, 2008 Oct 25)
1114 1113
 - Minor patches from Dominique Pelle, 2010 May 15
1115 1114
 - Gvimext patch to support wide file names. (Szabolcs Horvat 2008 Sep 10)
@@ -1117,8 +1116,9 @@ Patches to include:
1117 1116
 - Patch to support clipboard for Mac terminal. (Jjgod Jiang, 2009 Aug 1)
1118 1117
 - Patch to support :browse for more commands. (Lech Lorens, 2009 Jul 18)
1119 1118
 - Patch to improve javascript indenting. (Hari Kumar G, 2010 May 22)
  1119
+- Patch to use return value of 'formatexpr'. (James Vega, 2010 Jun 16)
1120 1120
 - Patch to make CTRL-L work better with 'ignorecase' and 'smarcase'. (Martin
1121  
-  Toft, 2010 Jun 8)
  1121
+  Toft, 2010 Jun 8, Jun 16)
1122 1122
 - Patch to add diff functionality to 2html.vim. (Christian Brabandt, 2009 Dec
1123 1123
   15)
1124 1124
 - Win32: patch for better font scaling. (George Reilly, 2009 Mar 26) 
2  runtime/doc/usr_11.txt
@@ -283,6 +283,8 @@ machines.  Therefore, don't rely on Vim always warning you.
283 283
 If you really don't want to see this message, you can add the 'A' flag to the
284 284
 'shortmess' option.  But it's very unusual that you need this.
285 285
 
  286
+For remarks about encryption and the swap file, see |:recover-crypt|.
  287
+
286 288
 ==============================================================================
287 289
 *11.4*	Further reading
288 290
 
2  runtime/syntax/c.vim
@@ -270,7 +270,7 @@ if !exists("c_no_c99") " ISO C99
270 270
 endif
271 271
 
272 272
 " Accept %: for # (C99)
273  
-syn region	cPreCondit	start="^\s*\(%:\|#\)\s*\(if\|ifdef\|ifndef\|elif\)\>" skip="\\$" end="$"  contains=cComment,cCommentL,cCppString,cCharacter,cCppParen,cParenError,cNumbers,cCommentError,cSpaceError
  273
+syn region      cPreCondit      start="^\s*\(%:\|#\)\s*\(if\|ifdef\|ifndef\|elif\)\>" skip="\\$" end="$"  keepend contains=cComment,cCommentL,cCppString,cCharacter,cCppParen,cParenError,cNumbers,cCommentError,cSpaceError
274 274
 syn match	cPreCondit	display "^\s*\(%:\|#\)\s*\(else\|endif\)\>"
275 275
 if !exists("c_no_if0")
276 276
   if !exists("c_no_if0_fold")
42  src/blowfish.c
@@ -436,13 +436,7 @@ bf_key_init(password, salt, salt_len)
436 436
         key[i] = j;
437 437
     }
438 438
 
439  
-    for (i = 0; i < 256; ++i)
440  
-    {
441  
-	sbx[0][i] = sbi[0][i];
442  
-	sbx[1][i] = sbi[1][i];
443  
-	sbx[2][i] = sbi[2][i];
444  
-	sbx[3][i] = sbi[3][i];
445  
-    }
  439
+    mch_memmove(sbx, sbi, 4 * 4 * 256);
446 440
 
447 441
     for (i = 0; i < 18; ++i)
448 442
     {
@@ -655,6 +649,40 @@ bf_crypt_init_keys(passwd)
655 649
     }
656 650
 }
657 651
 
  652
+static int save_randbyte_offset;
  653
+static int save_update_offset;
  654
+static char_u save_ofb_buffer[BF_OFB_LEN];
  655
+static UINT32_T save_pax[18];
  656
+static UINT32_T save_sbx[4][256];
  657
+
  658
+/*
  659
+ * Save the current crypt state.  Can only be used once before
  660
+ * bf_crypt_restore().
  661
+ */
  662
+    void
  663
+bf_crypt_save()
  664
+{
  665
+    save_randbyte_offset = randbyte_offset;
  666
+    save_update_offset = update_offset;
  667
+    mch_memmove(save_ofb_buffer, ofb_buffer, BF_OFB_LEN);
  668
+    mch_memmove(save_pax, pax, 4 * 18);
  669
+    mch_memmove(save_sbx, sbx, 4 * 4 * 256);
  670
+}
  671
+
  672
+/*
  673
+ * Restore the current crypt state.  Can only be used after
  674
+ * bf_crypt_save().
  675
+ */
  676
+    void
  677
+bf_crypt_restore()
  678
+{
  679
+    randbyte_offset = save_randbyte_offset;
  680
+    update_offset = save_update_offset;
  681
+    mch_memmove(ofb_buffer, save_ofb_buffer, BF_OFB_LEN);
  682
+    mch_memmove(pax, save_pax, 4 * 18);
  683
+    mch_memmove(sbx, save_sbx, 4 * 4 * 256);
  684
+}
  685
+
658 686
 /*
659 687
  * Run a test to check if the encryption works as expected.
660 688
  * Give an error and return FAIL when not.
43  src/fileio.c
@@ -64,7 +64,7 @@ static void check_marks_read __ARGS((void));
64 64
 #endif
65 65
 #ifdef FEAT_CRYPT
66 66
 static int get_crypt_method __ARGS((char *ptr, int len));
67  
-static char_u *check_for_cryptkey __ARGS((char_u *cryptkey, char_u *ptr, long *sizep, off_t *filesizep, int newfile, int *did_ask));
  67
+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));
68 68
 #endif
69 69
 #ifdef UNIX
70 70
 static void set_file_time __ARGS((char_u *fname, time_t atime, time_t mtime));
@@ -995,6 +995,13 @@ readfile(fname, sfname, from, lines_to_skip, lines_to_read, eap, flags)
995 995
 #endif
996 996
     }
997 997
 
  998
+#ifdef FEAT_CRYPT
  999
+    if (cryptkey != NULL)
  1000
+	/* Need to reset the state, but keep the key, don't want to ask for it
  1001
+	 * again. */
  1002
+	crypt_pop_state();
  1003
+#endif
  1004
+
998 1005
     /*
999 1006
      * When retrying with another "fenc" and the first time "fileformat"
1000 1007
      * will be reset.
@@ -1426,7 +1433,8 @@ readfile(fname, sfname, from, lines_to_skip, lines_to_read, eap, flags)
1426 1433
 		 */
1427 1434
 		if (filesize == 0)
1428 1435
 		    cryptkey = check_for_cryptkey(cryptkey, ptr, &size,
1429  
-					&filesize, newfile, &did_ask_for_key);
  1436
+					&filesize, newfile, sfname,
  1437
+					&did_ask_for_key);
1430 1438
 		/*
1431 1439
 		 * Decrypt the read bytes.
1432 1440
 		 */
@@ -2277,8 +2285,14 @@ readfile(fname, sfname, from, lines_to_skip, lines_to_read, eap, flags)
2277 2285
 	save_file_ff(curbuf);		/* remember the current file format */
2278 2286
 
2279 2287
 #ifdef FEAT_CRYPT
2280  
-    if (cryptkey != curbuf->b_p_key)
2281  
-	free_crypt_key(cryptkey);
  2288
+    if (cryptkey != NULL)
  2289
+    {
  2290
+	crypt_pop_state();
  2291
+	if (cryptkey != curbuf->b_p_key)
  2292
+	    free_crypt_key(cryptkey);
  2293
+	/* don't set cryptkey to NULL, it's used below as a flag that
  2294
+	 * encryption was used */
  2295
+    }
2282 2296
 #endif
2283 2297
 
2284 2298
 #ifdef FEAT_MBYTE
@@ -2869,12 +2883,13 @@ get_crypt_method(ptr, len)
2869 2883
  * Return the (new) encryption key, NULL for no encryption.
2870 2884
  */
2871 2885
     static char_u *
2872  
-check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile, did_ask)
  2886
+check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile, fname, did_ask)
2873 2887
     char_u	*cryptkey;	/* previous encryption key or NULL */
2874 2888
     char_u	*ptr;		/* pointer to read bytes */
2875 2889
     long	*sizep;		/* length of read bytes */
2876 2890
     off_t	*filesizep;	/* nr of bytes used from file */
2877 2891
     int		newfile;	/* editing a new buffer */
  2892
+    char_u	*fname;		/* file name to display */
2878 2893
     int		*did_ask;	/* flag: whether already asked for key */
2879 2894
 {
2880 2895
     int method = get_crypt_method((char *)ptr, *sizep);
@@ -2882,7 +2897,6 @@ check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile, did_ask)
2882 2897
     if (method >= 0)
2883 2898
     {
2884 2899
 	curbuf->b_p_cm = method;
2885  
-	use_crypt_method = method;
2886 2900
 	if (method > 0)
2887 2901
 	    (void)blowfish_self_test();
2888 2902
 	if (cryptkey == NULL && !*did_ask)
@@ -2895,6 +2909,8 @@ check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile, did_ask)
2895 2909
 		 * option and don't free it.  bf needs hash of the key saved.
2896 2910
 		 * Don't ask for the key again when first time Enter was hit.
2897 2911
 		 * Happens when retrying to detect encoding. */
  2912
+		smsg((char_u *)_(need_key_msg), fname);
  2913
+		msg_scroll = TRUE;
2898 2914
 		cryptkey = get_crypt_key(newfile, FALSE);
2899 2915
 		*did_ask = TRUE;
2900 2916
 
@@ -2913,6 +2929,8 @@ check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile, did_ask)
2913 2929
 	    int seed_len = crypt_seed_len[method];
2914 2930
 	    int salt_len = crypt_salt_len[method];
2915 2931
 
  2932
+	    crypt_push_state();
  2933
+	    use_crypt_method = method;
2916 2934
 	    if (method == 0)
2917 2935
 		crypt_init_keys(cryptkey);
2918 2936
 	    else
@@ -2924,7 +2942,8 @@ check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile, did_ask)
2924 2942
 	    /* Remove magic number from the text */
2925 2943
 	    *filesizep += CRYPT_MAGIC_LEN + salt_len + seed_len;
2926 2944
 	    *sizep -= CRYPT_MAGIC_LEN + salt_len + seed_len;
2927  
-	    mch_memmove(ptr, ptr + CRYPT_MAGIC_LEN + salt_len + seed_len, (size_t)*sizep);
  2945
+	    mch_memmove(ptr, ptr + CRYPT_MAGIC_LEN + salt_len + seed_len,
  2946
+							      (size_t)*sizep);
2928 2947
 	}
2929 2948
     }
2930 2949
     /* When starting to edit a new file which does not have encryption, clear
@@ -2956,6 +2975,7 @@ prepare_crypt_read(fp)
2956 2975
     if (method < 0 || method != curbuf->b_p_cm)
2957 2976
 	return FAIL;
2958 2977
 
  2978
+    crypt_push_state();
2959 2979
     if (method == 0)
2960 2980
 	crypt_init_keys(curbuf->b_p_key);
2961 2981
     else
@@ -2974,6 +2994,8 @@ prepare_crypt_read(fp)
2974 2994
 /*
2975 2995
  * Prepare for writing encrypted bytes for buffer "buf".
2976 2996
  * Returns a pointer to an allocated header of length "*lenp".
  2997
+ * When out of memory returns NULL.
  2998
+ * Otherwise calls crypt_push_state(), call crypt_pop_state() later.
2977 2999
  */
2978 3000
     char_u *
2979 3001
 prepare_crypt_write(buf, lenp)
@@ -2990,6 +3012,7 @@ prepare_crypt_write(buf, lenp)
2990 3012
 						    + CRYPT_SEED_LEN_MAX + 2);
2991 3013
     if (header != NULL)
2992 3014
     {
  3015
+	crypt_push_state();
2993 3016
 	use_crypt_method = buf->b_p_cm;  /* select pkzip or blowfish */
2994 3017
 	vim_strncpy(header, (char_u *)crypt_magic[use_crypt_method],
2995 3018
 							     CRYPT_MAGIC_LEN);
@@ -4404,7 +4427,7 @@ buf_write(buf, fname, sfname, start, end, eap, append, forceit,
4404 4427
     write_info.bw_fd = fd;
4405 4428
 
4406 4429
 #ifdef FEAT_CRYPT
4407  
-    if (*buf->b_p_key && !filtering)
  4430
+    if (*buf->b_p_key != NUL && !filtering)
4408 4431
     {
4409 4432
 	char_u *header;
4410 4433
 	int    header_len;
@@ -4674,6 +4697,10 @@ buf_write(buf, fname, sfname, start, end, eap, append, forceit,
4674 4697
     if (!backup_copy)
4675 4698
 	mch_set_acl(wfname, acl);
4676 4699
 #endif
  4700
+#ifdef FEAT_CRYPT
  4701
+    if (wb_flags & FIO_ENCRYPTED)
  4702
+	crypt_pop_state();
  4703
+#endif
4677 4704
 
4678 4705
 
4679 4706
 #if defined(FEAT_MBYTE) && defined(FEAT_EVAL)
4  src/globals.h
@@ -1564,6 +1564,10 @@ EXTERN short disallow_gui	INIT(= FALSE);
1564 1564
 EXTERN char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM"));
1565 1565
 EXTERN char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP"));
1566 1566
 
  1567
+#ifdef FEAT_CRYPT
  1568
+EXTERN char need_key_msg[] INIT(= N_("Need encryption key for \"%s\""));
  1569
+#endif
  1570
+
1567 1571
 /*
1568 1572
  * Comms. with the session manager (XSMP)
1569 1573
  */
2  src/main.c
@@ -595,7 +595,7 @@ main
595 595
      */
596 596
     if (recoverymode && fname == NULL)
597 597
     {
598  
-	recover_names(NULL, TRUE, 0);
  598
+	recover_names(NULL, TRUE, 0, NULL);
599 599
 	mch_exit(0);
600 600
     }
601 601
 
54  src/memfile.c
@@ -85,6 +85,7 @@ static void mf_ins_free __ARGS((memfile_T *, bhdr_T *));
85 85
 static bhdr_T *mf_rem_free __ARGS((memfile_T *));
86 86
 static int  mf_read __ARGS((memfile_T *, bhdr_T *));
87 87
 static int  mf_write __ARGS((memfile_T *, bhdr_T *));
  88
+static int  mf_write_block __ARGS((memfile_T *mfp, bhdr_T *hp, off_t offset, unsigned size));
88 89
 static int  mf_trans_add __ARGS((memfile_T *, bhdr_T *));
89 90
 static void mf_do_open __ARGS((memfile_T *, char_u *, int));
90 91
 
@@ -161,6 +162,9 @@ mf_open(fname, flags)
161 162
 	mfp->mf_trans[i] = NULL;	/* trans lists are empty */
162 163
     }
163 164
     mfp->mf_page_size = MEMFILE_PAGE_SIZE;
  165
+#ifdef FEAT_CRYPT
  166
+    mfp->mf_old_key = NULL;
  167
+#endif
164 168
 
165 169
 #ifdef USE_FSTATFS
166 170
     /*
@@ -422,7 +426,7 @@ mf_new(mfp, negative, page_count)
422 426
 }
423 427
 
424 428
 /*
425  
- * get existing block 'nr' with 'page_count' pages
  429
+ * Get existing block "nr" with "page_count" pages.
426 430
  *
427 431
  * Note: The caller should first check a negative nr with mf_trans_del()
428 432
  */
@@ -1050,6 +1054,13 @@ mf_read(mfp, hp)
1050 1054
 	PERROR(_("E295: Read error in swap file"));
1051 1055
 	return FAIL;
1052 1056
     }
  1057
+
  1058
+#ifdef FEAT_CRYPT
  1059
+    /* Decrypt if 'key' is set and this is a data block. */
  1060
+    if (*mfp->mf_buffer->b_p_key != NUL)
  1061
+	ml_decrypt_data(mfp, hp->bh_data, offset, size);
  1062
+#endif
  1063
+
1053 1064
     return OK;
1054 1065
 }
1055 1066
 
@@ -1107,8 +1118,7 @@ mf_write(mfp, hp)
1107 1118
 	else
1108 1119
 	    page_count = hp2->bh_page_count;
1109 1120
 	size = page_size * page_count;
1110  
-	if ((unsigned)vim_write(mfp->mf_fd,
1111  
-	     (hp2 == NULL ? hp : hp2)->bh_data, size) != size)
  1121
+	if (mf_write_block(mfp, hp2 == NULL ? hp : hp2, offset, size) == FAIL)
1112 1122
 	{
1113 1123
 	    /*
1114 1124
 	     * Avoid repeating the error message, this mostly happens when the
@@ -1134,6 +1144,42 @@ mf_write(mfp, hp)
1134 1144
 }
1135 1145
 
1136 1146
 /*
  1147
+ * Write block "hp" with data size "size" to file "mfp->mf_fd".
  1148
+ * Takes care of encryption.
  1149
+ * Return FAIL or OK.
  1150
+ */
  1151
+    static int
  1152
+mf_write_block(mfp, hp, offset, size)
  1153
+    memfile_T	*mfp;
  1154
+    bhdr_T	*hp;
  1155
+    off_t	offset UNUSED;
  1156
+    unsigned	size;
  1157
+{
  1158
+    char_u	*data = hp->bh_data;
  1159
+    int		result = OK;
  1160
+
  1161
+#ifdef FEAT_CRYPT
  1162
+    /* Encrypt if 'key' is set and this is a data block. */
  1163
+    if (*mfp->mf_buffer->b_p_key != NUL)
  1164
+    {
  1165
+	data = ml_encrypt_data(mfp, data, offset, size);
  1166
+	if (data == NULL)
  1167
+	    return FAIL;
  1168
+    }
  1169
+#endif
  1170
+
  1171
+    if ((unsigned)vim_write(mfp->mf_fd, data, size) != size)
  1172
+	result = FAIL;
  1173
+
  1174
+#ifdef FEAT_CRYPT
  1175
+    if (data != hp->bh_data)
  1176
+	vim_free(data);
  1177
+#endif
  1178
+
  1179
+    return result;
  1180
+}
  1181
+
  1182
+/*
1137 1183
  * Make block number for *hp positive and add it to the translation list
1138 1184
  *
1139 1185
  * Return FAIL for failure, OK otherwise
@@ -1156,7 +1202,7 @@ mf_trans_add(mfp, hp)
1156 1202
 	return FAIL;
1157 1203
 
1158 1204
 /*
1159  
- * get a new number for the block.
  1205
+ * Get a new number for the block.
1160 1206
  * If the first item in the free list has sufficient pages, use its number
1161 1207
  * Otherwise use mf_blocknr_max.
1162 1208
  */
599  src/memline.c
@@ -65,10 +65,12 @@ typedef struct pointer_block	PTR_BL;	    /* contents of a pointer block */
65 65
 typedef struct data_block	DATA_BL;    /* contents of a data block */
66 66
 typedef struct pointer_entry	PTR_EN;	    /* block/line-count pair */
67 67
 
68  
-#define DATA_ID	    (('d' << 8) + 'a')	    /* data block id */
69  
-#define PTR_ID	    (('p' << 8) + 't')	    /* pointer block id */
70  
-#define BLOCK0_ID0  'b'			    /* block 0 id 0 */
71  
-#define BLOCK0_ID1  '0'			    /* block 0 id 1 */
  68
+#define DATA_ID	       (('d' << 8) + 'a')   /* data block id */
  69
+#define PTR_ID	       (('p' << 8) + 't')   /* pointer block id */
  70
+#define BLOCK0_ID0     'b'		    /* block 0 id 0 */
  71
+#define BLOCK0_ID1     '0'		    /* block 0 id 1 */
  72
+#define BLOCK0_ID1_C0  'c'		    /* block 0 id 1 'cm' 0 */
  73
+#define BLOCK0_ID1_C1  'C'		    /* block 0 id 1 'cm' 1 */
72 74
 
73 75
 /*
74 76
  * pointer to a block, used in a pointer block
@@ -128,7 +130,8 @@ struct data_block
128 130
 #define HEADER_SIZE (sizeof(DATA_BL) - INDEX_SIZE)  /* size of data block header */
129 131
 
130 132
 #define B0_FNAME_SIZE_ORG	900	/* what it was in older versions */
131  
-#define B0_FNAME_SIZE		898
  133
+#define B0_FNAME_SIZE_NOCRYPT	898	/* 2 bytes used for other things */
  134
+#define B0_FNAME_SIZE_CRYPT	890	/* 10 bytes used for other things */
132 135
 #define B0_UNAME_SIZE		40
133 136
 #define B0_HNAME_SIZE		40
134 137
 /*
@@ -155,7 +158,8 @@ struct data_block
155 158
  */
156 159
 struct block0
157 160
 {
158  
-    char_u	b0_id[2];	/* id for block 0: BLOCK0_ID0 and BLOCK0_ID1 */
  161
+    char_u	b0_id[2];	/* id for block 0: BLOCK0_ID0 and BLOCK0_ID1,
  162
+				 * BLOCK0_ID1_C0, BLOCK0_ID1_C1 */
159 163
     char_u	b0_version[10];	/* Vim version string */
160 164
     char_u	b0_page_size[4];/* number of bytes per page */
161 165
     char_u	b0_mtime[4];	/* last modification time of file */
@@ -177,12 +181,18 @@ struct block0
177 181
  * when there is room, for very long file names it's omitted.
178 182
  */
179 183
 #define B0_DIRTY	0x55
180  
-#define b0_dirty	b0_fname[B0_FNAME_SIZE_ORG-1]
  184
+#define b0_dirty	b0_fname[B0_FNAME_SIZE_ORG - 1]
181 185
 
182 186
 /*
183 187
  * The b0_flags field is new in Vim 7.0.
184 188
  */
185  
-#define b0_flags	b0_fname[B0_FNAME_SIZE_ORG-2]
  189
+#define b0_flags	b0_fname[B0_FNAME_SIZE_ORG - 2]
  190
+
  191
+/*
  192
+ * Crypt seed goes here, 8 bytes.  New in Vim 7.3.
  193
+ * Without encryption these bytes may be used for 'fenc'.
  194
+ */
  195
+#define b0_seed		b0_fname[B0_FNAME_SIZE_ORG - 2 - MF_SEED_LEN]
186 196
 
187 197
 /* The lowest two bits contain the fileformat.  Zero means it's not set
188 198
  * (compatible with Vim 6.x), otherwise it's EOL_UNIX + 1, EOL_DOS + 1 or
@@ -216,7 +226,18 @@ static linenr_T	lowest_marked = 0;
216 226
 #define ML_FLUSH	0x02	    /* flush locked block */
217 227
 #define ML_SIMPLE(x)	(x & 0x10)  /* DEL, INS or FIND */
218 228
 
219  
-static void ml_upd_block0 __ARGS((buf_T *buf, int set_fname));
  229
+/* argument for ml_upd_block0() */
  230
+typedef enum {
  231
+      UB_FNAME = 0	/* update timestamp and filename */
  232
+    , UB_SAME_DIR       /* update the B0_SAME_DIR flag */
  233
+    , UB_CRYPT		/* update crypt key */
  234
+} upd_block0_T;
  235
+
  236
+#ifdef FEAT_CRYPT
  237
+static void ml_set_b0_crypt __ARGS((buf_T *buf, ZERO_BL *b0p));
  238
+#endif
  239
+static int ml_check_b0_id __ARGS((ZERO_BL *b0p));
  240
+static void ml_upd_block0 __ARGS((buf_T *buf, upd_block0_T what));
220 241
 static void set_b0_fname __ARGS((ZERO_BL *, buf_T *buf));
221 242
 static void set_b0_dir_flag __ARGS((ZERO_BL *b0p, buf_T *buf));
222 243
 #ifdef FEAT_MBYTE
@@ -242,6 +263,9 @@ static long char_to_long __ARGS((char_u *));
242 263
 #if defined(UNIX) || defined(WIN3264)
243 264
 static char_u *make_percent_swname __ARGS((char_u *dir, char_u *name));
244 265
 #endif
  266
+#ifdef FEAT_CRYPT
  267
+static void ml_crypt_prepare __ARGS((memfile_T *mfp, off_t offset, int reading));
  268
+#endif
245 269
 #ifdef FEAT_BYTEOFF
246 270
 static void ml_updatechunk __ARGS((buf_T *buf, long line, long len, int updtype));
247 271
 #endif
@@ -264,7 +288,7 @@ ml_open(buf)
264 288
     /*
265 289
      * init fields in memline struct
266 290
      */
267  
-    buf->b_ml.ml_stack_size = 0;	/* no stack yet */
  291
+    buf->b_ml.ml_stack_size = 0; /* no stack yet */
268 292
     buf->b_ml.ml_stack = NULL;	/* no stack yet */
269 293
     buf->b_ml.ml_stack_top = 0;	/* nothing in the stack */
270 294
     buf->b_ml.ml_locked = NULL;	/* no cached block */
@@ -289,6 +313,9 @@ ml_open(buf)
289 313
 	goto error;
290 314
 
291 315
     buf->b_ml.ml_mfp = mfp;
  316
+#ifdef FEAT_CRYPT
  317
+    mfp->mf_buffer = buf;
  318
+#endif
292 319
     buf->b_ml.ml_flags = ML_EMPTY;
293 320
     buf->b_ml.ml_line_count = 1;
294 321
 #ifdef FEAT_LINEBREAK
@@ -336,12 +363,16 @@ ml_open(buf)
336 363
 	mch_get_host_name(b0p->b0_hname, B0_HNAME_SIZE);
337 364
 	b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL;
338 365
 	long_to_char(mch_get_pid(), b0p->b0_pid);
  366
+#ifdef FEAT_CRYPT
  367
+	if (*buf->b_p_key != NUL)
  368
+	    ml_set_b0_crypt(buf, b0p);
  369
+#endif
339 370
     }
340 371
 
341 372
     /*
342 373
      * Always sync block number 0 to disk, so we can check the file name in
343  
-     * the swap file in findswapname(). Don't do this for help files though
344  
-     * and spell buffer though.
  374
+     * the swap file in findswapname(). Don't do this for a help files or
  375
+     * a spell buffer though.
345 376
      * Only works when there's a swapfile, otherwise it's done when the file
346 377
      * is created.
347 378
      */
@@ -397,6 +428,165 @@ ml_open(buf)
397 428
     return FAIL;
398 429
 }
399 430
 
  431
+#if defined(FEAT_CRYPT) || defined(PROTO)
  432
+/*
  433
+ * Prepare encryption for "buf" with block 0 "b0p".
  434
+ */
  435
+    static void
  436
+ml_set_b0_crypt(buf, b0p)
  437
+    buf_T	*buf;
  438
+    ZERO_BL	*b0p;
  439
+{
  440
+    if (*buf->b_p_key == NUL)
  441
+	b0p->b0_id[1] = BLOCK0_ID1;
  442
+    else
  443
+    {
  444
+	if (buf->b_p_cm == 0)
  445
+	    b0p->b0_id[1] = BLOCK0_ID1_C0;
  446
+	else
  447
+	{
  448
+	    b0p->b0_id[1] = BLOCK0_ID1_C1;
  449
+	    /* Generate a seed and store it in block 0 and in the memfile. */
  450
+	    sha2_seed(&b0p->b0_seed, MF_SEED_LEN, NULL, 0);
  451
+	    mch_memmove(buf->b_ml.ml_mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
  452
+	}
  453
+    }
  454
+}
  455
+
  456
+/*
  457
+ * Called after the crypt key or 'cryptmethod' was changed for "buf".
  458
+ * Will apply this to the swapfile.
  459
+ * "old_key" is the previous key.  It is equal to buf->b_p_key when
  460
+ * 'cryptmethod' is changed.
  461
+ * "old_cm" is the previous 'cryptmethod'.  It is equal to buf->b_p_cm when
  462
+ * 'key' is changed.
  463
+ */
  464
+    void
  465
+ml_set_crypt_key(buf, old_key, old_cm)
  466
+    buf_T	*buf;
  467
+    char_u	*old_key;
  468
+    int		old_cm;
  469
+{
  470
+    memfile_T	*mfp = buf->b_ml.ml_mfp;
  471
+    bhdr_T	*hp;
  472
+    int		page_count;
  473
+    int		idx;
  474
+    long	error;
  475
+    infoptr_T	*ip;
  476
+    PTR_BL	*pp;
  477
+    DATA_BL	*dp;
  478
+    blocknr_T	bnum;
  479
+    int		top;
  480
+
  481
+    if (mfp == NULL || mfp->mf_fd < 0)
  482
+	return;  /* no memfile yet, nothing to do */
  483
+
  484
+    /* Set the key, method and seed to be used for reading, these must be the
  485
+     * old values. */
  486
+    mfp->mf_old_key = old_key;
  487
+    mfp->mf_old_cm = old_cm;
  488
+    if (old_cm > 0)
  489
+	mch_memmove(mfp->mf_old_seed, mfp->mf_seed, MF_SEED_LEN);
  490
+
  491
+    /* Update block 0 with the crypt flag and may set a new seed. */
  492
+    ml_upd_block0(buf, UB_CRYPT);
  493
+
  494
+    if (mfp->mf_infile_count > 2)
  495
+    {
  496
+	/*
  497
+	 * Need to read back all data blocks from disk, decrypt them with the
  498
+	 * old key/method and mark them to be written. The algorithm is
  499
+	 * similar to what happens in ml_recover(), but we skip negative block
  500
+	 * numbers.
  501
+	 */
  502
+	ml_flush_line(buf);		    /* flush buffered line */
  503
+	(void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); /* flush locked block */
  504
+
  505
+	hp = NULL;
  506
+	bnum = 1;		/* start with block 1 */
  507
+	page_count = 1;		/* which is 1 page */
  508
+	idx = 0;		/* start with first index in block 1 */
  509
+	error = 0;
  510
+	buf->b_ml.ml_stack_top = 0;
  511
+	buf->b_ml.ml_stack = NULL;
  512
+	buf->b_ml.ml_stack_size = 0;	/* no stack yet */
  513
+
  514
+	for ( ; !got_int; line_breakcheck())
  515
+	{
  516
+	    if (hp != NULL)
  517
+		mf_put(mfp, hp, FALSE, FALSE);	/* release previous block */
  518
+
  519
+	    /* get the block (pointer or data) */
  520
+	    if ((hp = mf_get(mfp, (blocknr_T)bnum, page_count)) == NULL)
  521
+	    {
  522
+		if (bnum == 1)
  523
+		    break;
  524
+		++error;
  525
+	    }
  526
+	    else
  527
+	    {
  528
+		pp = (PTR_BL *)(hp->bh_data);
  529
+		if (pp->pb_id == PTR_ID)	/* it is a pointer block */
  530
+		{
  531
+		    if (pp->pb_count == 0)
  532
+		    {
  533
+			/* empty block? */
  534
+			++error;
  535
+		    }
  536
+		    else if (idx < (int)pp->pb_count)	/* go a block deeper */
  537
+		    {
  538
+			if (pp->pb_pointer[idx].pe_bnum < 0)
  539
+			{
  540
+			    /* Skip data block with negative block number. */
  541
+			    ++idx;    /* get same block again for next index */
  542
+			    continue;
  543
+			}
  544
+
  545
+			/* going one block deeper in the tree, new entry in
  546
+			 * stack */
  547
+			if ((top = ml_add_stack(buf)) < 0)
  548
+			{
  549
+			    ++error;
  550
+			    break;		    /* out of memory */
  551
+			}
  552
+			ip = &(buf->b_ml.ml_stack[top]);
  553
+			ip->ip_bnum = bnum;
  554
+			ip->ip_index = idx;
  555
+
  556
+			bnum = pp->pb_pointer[idx].pe_bnum;
  557
+			page_count = pp->pb_pointer[idx].pe_page_count;
  558
+			continue;
  559
+		    }
  560
+		}
  561
+		else	    /* not a pointer block */
  562
+		{
  563
+		    dp = (DATA_BL *)(hp->bh_data);
  564
+		    if (dp->db_id != DATA_ID)	/* block id wrong */
  565
+			++error;
  566
+		    else
  567
+		    {
  568
+			/* It is a data block, need to write it back to disk. */
  569
+			mf_put(mfp, hp, TRUE, FALSE);
  570
+			hp = NULL;
  571
+		    }
  572
+		}
  573
+	    }
  574
+
  575
+	    if (buf->b_ml.ml_stack_top == 0)	/* finished */
  576
+		break;
  577
+
  578
+	    /* go one block up in the tree */
  579
+	    ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]);
  580
+	    bnum = ip->ip_bnum;
  581
+	    idx = ip->ip_index + 1;	    /* go to next index */
  582
+	    page_count = 1;
  583
+	}
  584
+    }
  585
+
  586
+    mfp->mf_old_key = NULL;
  587
+}
  588
+#endif
  589
+
400 590
 /*
401 591
  * ml_setname() is called when the file name of "buf" has been changed.
402 592
  * It may rename the swap file.
@@ -475,7 +665,7 @@ ml_setname(buf)
475 665
 #else
476 666
 	    mf_set_ffname(mfp);
477 667
 #endif
478  
-	    ml_upd_block0(buf, FALSE);
  668
+	    ml_upd_block0(buf, UB_SAME_DIR);
479 669
 	    break;
480 670
 	}
481 671
 	vim_free(fname);	    /* this fname didn't work, try another */
@@ -569,7 +759,7 @@ ml_open_file(buf)
569 759
 	     */
570 760
 	    mf_fullname(mfp);
571 761
 #endif
572  
-	    ml_upd_block0(buf, FALSE);
  762
+	    ml_upd_block0(buf, UB_SAME_DIR);
573 763
 
574 764
 	    /* Flush block zero, so others can read it */
575 765
 	    if (mf_sync(mfp, MFS_ZERO) == OK)
@@ -680,16 +870,32 @@ ml_close_notmod()
680 870
 ml_timestamp(buf)
681 871
     buf_T	*buf;
682 872
 {
683  
-    ml_upd_block0(buf, TRUE);
  873
+    ml_upd_block0(buf, UB_FNAME);
  874
+}
  875
+
  876
+/*
  877
+ * Return FAIL when the ID of "b0p" is wrong.
  878
+ */
  879
+    static int
  880
+ml_check_b0_id(b0p)
  881
+    ZERO_BL	*b0p;
  882
+{
  883
+    if (b0p->b0_id[0] != BLOCK0_ID0
  884
+	    || (b0p->b0_id[1] != BLOCK0_ID1
  885
+		&& b0p->b0_id[1] != BLOCK0_ID1_C0
  886
+		&& b0p->b0_id[1] != BLOCK0_ID1_C1)
  887
+	    )
  888
+	return FAIL;
  889
+    return OK;
684 890
 }
685 891
 
686 892
 /*
687 893
  * Update the timestamp or the B0_SAME_DIR flag of the .swp file.
688 894
  */
689 895
     static void
690  
-ml_upd_block0(buf, set_fname)
  896
+ml_upd_block0(buf, what)
691 897
     buf_T	*buf;
692  
-    int		set_fname;
  898
+    upd_block0_T what;
693 899
 {
694 900
     memfile_T	*mfp;
695 901
     bhdr_T	*hp;
@@ -699,13 +905,17 @@ ml_upd_block0(buf, set_fname)
699 905
     if (mfp == NULL || (hp = mf_get(mfp, (blocknr_T)0, 1)) == NULL)
700 906
 	return;
701 907
     b0p = (ZERO_BL *)(hp->bh_data);
702  
-    if (b0p->b0_id[0] != BLOCK0_ID0 || b0p->b0_id[1] != BLOCK0_ID1)
  908
+    if (ml_check_b0_id(b0p) == FAIL)
703 909
 	EMSG(_("E304: ml_upd_block0(): Didn't get block 0??"));
704 910
     else
705 911
     {
706  
-	if (set_fname)
  912
+	if (what == UB_FNAME)
707 913
 	    set_b0_fname(b0p, buf);
708  
-	else
  914
+#ifdef FEAT_CRYPT
  915
+	else if (what == UB_CRYPT)
  916
+	    ml_set_b0_crypt(buf, b0p);
  917
+#endif
  918
+	else /* what == UB_SAME_DIR */
709 919
 	    set_b0_dir_flag(b0p, buf);
710 920
     }
711 921
     mf_put(mfp, hp, TRUE, FALSE);
@@ -731,7 +941,7 @@ set_b0_fname(b0p, buf)
731 941
 	/* Systems that cannot translate "~user" back into a path: copy the
732 942
 	 * file name unmodified.  Do use slashes instead of backslashes for
733 943
 	 * portability. */
734  
-	vim_strncpy(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE - 1);
  944
+	vim_strncpy(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE_CRYPT - 1);
735 945
 # ifdef BACKSLASH_IN_FILENAME
736 946
 	forward_slash(b0p->b0_fname);
737 947
 # endif
@@ -746,14 +956,16 @@ set_b0_fname(b0p, buf)
746 956
 	 * First replace home dir path with "~/" with home_replace().
747 957
 	 * Then insert the user name to get "~user/".
748 958
 	 */
749  
-	home_replace(NULL, buf->b_ffname, b0p->b0_fname, B0_FNAME_SIZE, TRUE);
  959
+	home_replace(NULL, buf->b_ffname, b0p->b0_fname,
  960
+						   B0_FNAME_SIZE_CRYPT, TRUE);
750 961
 	if (b0p->b0_fname[0] == '~')
751 962
 	{
752 963
 	    flen = STRLEN(b0p->b0_fname);
753 964
 	    /* If there is no user name or it is too long, don't use "~/" */
754 965
 	    if (get_user_name(uname, B0_UNAME_SIZE) == FAIL
755  
-			 || (ulen = STRLEN(uname)) + flen > B0_FNAME_SIZE - 1)
756  
-		vim_strncpy(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE - 1);
  966
+		   || (ulen = STRLEN(uname)) + flen > B0_FNAME_SIZE_CRYPT - 1)
  967
+		vim_strncpy(b0p->b0_fname, buf->b_ffname,
  968
+						     B0_FNAME_SIZE_CRYPT - 1);
757 969
 	    else
758 970
 	    {
759 971
 		mch_memmove(b0p->b0_fname + ulen + 1, b0p->b0_fname + 1, flen);
@@ -816,15 +1028,24 @@ add_b0_fenc(b0p, buf)
816 1028
     buf_T	*buf;
817 1029
 {
818 1030
     int		n;
  1031
+    int		size = B0_FNAME_SIZE_NOCRYPT;
  1032
+
  1033
+# ifdef FEAT_CRYPT
  1034
+    /* Without encryption use the same offset as in Vim 7.2 to be compatible.
  1035
+     * With encryption it's OK to move elsewhere, the swap file is not
  1036
+     * compatible anyway. */
  1037
+    if (*buf->b_p_key != NUL)
  1038
+	size = B0_FNAME_SIZE_CRYPT;
  1039
+# endif
819 1040
 
820 1041
     n = (int)STRLEN(buf->b_p_fenc);
821  
-    if (STRLEN(b0p->b0_fname) + n + 1 > B0_FNAME_SIZE)
  1042
+    if ((int)STRLEN(b0p->b0_fname) + n + 1 > size)
822 1043
 	b0p->b0_flags &= ~B0_HAS_FENC;
823 1044
     else
824 1045
     {
825  
-	mch_memmove((char *)b0p->b0_fname + B0_FNAME_SIZE - n,
  1046
+	mch_memmove((char *)b0p->b0_fname + size - n,
826 1047
 					    (char *)buf->b_p_fenc, (size_t)n);
827  
-	*(b0p->b0_fname + B0_FNAME_SIZE - n - 1) = NUL;
  1048
+	*(b0p->b0_fname + size - n - 1) = NUL;
828 1049
 	b0p->b0_flags |= B0_HAS_FENC;
829 1050
     }
830 1051
 }
@@ -832,7 +1053,7 @@ add_b0_fenc(b0p, buf)
832 1053
 
833 1054
 
834 1055
 /*
835  
- * try to recover curbuf from the .swp file
  1056
+ * Try to recover curbuf from the .swp file.
836 1057
  */
837 1058
     void
838 1059
 ml_recover()
@@ -840,10 +1061,14 @@ ml_recover()
840 1061
     buf_T	*buf = NULL;
841 1062
     memfile_T	*mfp = NULL;
842 1063
     char_u	*fname;
  1064
+    char_u	*fname_used = NULL;
843 1065
     bhdr_T	*hp = NULL;
844 1066
     ZERO_BL	*b0p;
845 1067
     int		b0_ff;
846 1068
     char_u	*b0_fenc = NULL;
  1069
+#ifdef FEAT_CRYPT
  1070
+    int		b0_cm = -1;
  1071
+#endif
847 1072
     PTR_BL	*pp;
848 1073
     DATA_BL	*dp;
849 1074
     infoptr_T	*ip;
@@ -892,14 +1117,14 @@ ml_recover()
892 1117
 		&& ASCII_ISALPHA(fname[len - 1]))
893 1118
     {
894 1119
 	directly = TRUE;
895  
-	fname = vim_strsave(fname); /* make a copy for mf_open() */
  1120
+	fname_used = vim_strsave(fname); /* make a copy for mf_open() */
896 1121
     }
897 1122
     else
898 1123
     {
899 1124
 	directly = FALSE;
900 1125
 
901 1126
 	/* count the number of matching swap files */
902  
-	len = recover_names(&fname, FALSE, 0);
  1127
+	len = recover_names(fname, FALSE, 0, NULL);
903 1128
 	if (len == 0)		    /* no swap files found */
904 1129
 	{
905 1130
 	    EMSG2(_("E305: No swap file found for %s"), fname);
@@ -910,7 +1135,7 @@ ml_recover()
910 1135
 	else			    /* several swap files found, choose */
911 1136
 	{
912 1137
 	    /* list the names of the swap files */
913  
-	    (void)recover_names(&fname, TRUE, 0);
  1138
+	    (void)recover_names(fname, TRUE, 0, NULL);
914 1139
 	    msg_putchar('\n');
915 1140
 	    MSG_PUTS(_("Enter number of swap file to use (0 to quit): "));
916 1141
 	    i = get_number(FALSE, NULL);
@@ -918,28 +1143,26 @@ ml_recover()
918 1143
 		goto theend;
919 1144
 	}
920 1145
 	/* get the swap file name that will be used */
921  
-	(void)recover_names(&fname, FALSE, i);
  1146
+	(void)recover_names(fname, FALSE, i, &fname_used);
922 1147
     }
923  
-    if (fname == NULL)
  1148
+    if (fname_used == NULL)
924 1149
 	goto theend;			/* out of memory */
925 1150
 
926 1151
     /* When called from main() still need to initialize storage structure */
927 1152
     if (called_from_main && ml_open(curbuf) == FAIL)
928 1153
 	getout(1);
929 1154
 
930  
-/*
931  
- * allocate a buffer structure (only the memline in it is really used)
932  
- */
  1155
+    /*
  1156
+     * Allocate a buffer structure for the swap file that is used for recovery.
  1157
+     * Only the memline in it is really used.
  1158
+     */
933 1159
     buf = (buf_T *)alloc((unsigned)sizeof(buf_T));
934 1160
     if (buf == NULL)
935  
-    {
936  
-	vim_free(fname);
937 1161
 	goto theend;
938  
-    }
939 1162
 
940  
-/*
941  
- * init fields in memline struct
942  
- */
  1163
+    /*
  1164
+     * init fields in memline struct
  1165
+     */
943 1166
     buf->b_ml.ml_stack_size = 0;	/* no stack yet */
944 1167
     buf->b_ml.ml_stack = NULL;		/* no stack yet */
945 1168
     buf->b_ml.ml_stack_top = 0;		/* nothing in the stack */
@@ -947,23 +1170,24 @@ ml_recover()
947 1170
     buf->b_ml.ml_locked = NULL;		/* no locked block */
948 1171
     buf->b_ml.ml_flags = 0;
949 1172
 
950  
-/*
951  
- * open the memfile from the old swap file
952  
- */
953  
-    p = vim_strsave(fname);		/* save fname for the message
954  
-					   (mf_open() may free fname) */
955  
-    mfp = mf_open(fname, O_RDONLY);	/* consumes fname! */
  1173
+    /*
  1174
+     * open the memfile from the old swap file
  1175
+     */
  1176
+    p = vim_strsave(fname_used); /* save "fname_used" for the message:
  1177
+				    mf_open() will consume "fname_used"! */
  1178
+    mfp = mf_open(fname_used, O_RDONLY);
  1179
+    fname_used = p;
956 1180
     if (mfp == NULL || mfp->mf_fd < 0)
957 1181
     {
958  
-	if (p != NULL)
959  
-	{
960  
-	    EMSG2(_("E306: Cannot open %s"), p);
961  
-	    vim_free(p);
962  
-	}
  1182
+	if (fname_used != NULL)
  1183
+	    EMSG2(_("E306: Cannot open %s"), fname_used);
963 1184
 	goto theend;
964 1185
     }
965  
-    vim_free(p);
966 1186
     buf->b_ml.ml_mfp = mfp;
  1187
+#ifdef FEAT_CRYPT
  1188
+    mfp->mf_buffer = buf;
  1189
+    buf->b_p_key = empty_option;
  1190
+#endif
967 1191
 
968 1192
     /*
969 1193
      * The page size set in mf_open() might be different from the page size
@@ -973,16 +1197,15 @@ ml_recover()
973 1197
      */
974 1198
     mfp->mf_page_size = MIN_SWAP_PAGE_SIZE;
975 1199
 
976  
-/*
977  
- * try to read block 0
978  
- */
  1200
+    /*
  1201
+     * try to read block 0
  1202
+     */
979 1203
     if ((hp = mf_get(mfp, (blocknr_T)0, 1)) == NULL)
980 1204
     {
981 1205
 	msg_start();
982 1206
 	MSG_PUTS_ATTR(_("Unable to read block 0 from "), attr | MSG_HIST);
983 1207
 	msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
984  
-	MSG_PUTS_ATTR(
985  
-	   _("\nMaybe no changes were made or Vim did not update the swap file."),
  1208
+	MSG_PUTS_ATTR(_("\nMaybe no changes were made or Vim did not update the swap file."),
986 1209
 		attr | MSG_HIST);
987 1210
 	msg_end();
988 1211
 	goto theend;
@@ -998,7 +1221,7 @@ ml_recover()
998 1221
 	msg_end();
999 1222
 	goto theend;
1000 1223
     }
1001  
-    if (b0p->b0_id[0] != BLOCK0_ID0 || b0p->b0_id[1] != BLOCK0_ID1)
  1224
+    if (ml_check_b0_id(b0p) == FAIL)
1002 1225
     {
1003 1226
 	EMSG2(_("E307: %s does not look like a Vim swap file"), mfp->mf_fname);
1004 1227
 	goto theend;
@@ -1024,6 +1247,22 @@ ml_recover()
1024 1247
 	goto theend;
1025 1248
     }
1026 1249
 
  1250
+#ifdef FEAT_CRYPT
  1251
+    if (b0p->b0_id[1] == BLOCK0_ID1_C0)
  1252
+	buf->b_p_cm = b0_cm = 0;
  1253
+    else if (b0p->b0_id[1] == BLOCK0_ID1_C1)
  1254
+    {
  1255
+	buf->b_p_cm = b0_cm = 1;
  1256
+	mch_memmove(mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
  1257
+    }
  1258
+#else
  1259
+    if (b0p->b0_id[1] != BLOCK0_ID1)
  1260
+    {
  1261
+	EMSG2(_("E000: %s is encrypted and this version of Vim does not support encryption"), mfp->mf_fname);
  1262
+	goto theend;
  1263
+    }
  1264
+#endif
  1265
+
1027 1266
     /*
1028 1267
      * If we guessed the wrong page size, we have to recalculate the
1029 1268
      * highest block number in the file.
@@ -1058,9 +1297,9 @@ ml_recover()
1058 1297
 	b0p = (ZERO_BL *)(hp->bh_data);
1059 1298
     }
1060 1299
 
1061  
-/*
1062  
- * If .swp file name given directly, use name from swap file for buffer.
1063  
- */
  1300
+    /*
  1301
+     * If .swp file name given directly, use name from swap file for buffer.
  1302
+     */
1064 1303
     if (directly)
1065 1304
     {
1066 1305
 	expand_env(b0p->b0_fname, NameBuff, MAXPATHL);
@@ -1078,9 +1317,9 @@ ml_recover()
1078 1317
     smsg((char_u *)_("Original file \"%s\""), NameBuff);
1079 1318
     msg_putchar('\n');
1080 1319
 
1081  
-/*
1082  
- * check date of swap file and original file