Patch 8.2.3022
Problem:    Available encryption methods are not strong enough.
Solution:   Add initial support for xchaha20. (Christian Brabandt,
            closes #8394)
Files:      .github/workflows/ci.yml, runtime/doc/eval.txt,
            runtime/doc/options.txt, runtime/doc/various.txt,
            src/INSTALLpc.txt, src/Make_cyg_ming.mak, src/Make_mvc.mak,
            src/auto/configure, src/blowfish.c, src/bufwrite.c,
            src/config.h.in, src/configure.ac, src/crypt.c, src/crypt_zip.c,
            src/errors.h, src/evalfunc.c, src/feature.h, src/fileio.c,
            src/memline.c, src/option.c, src/optionstr.c,
            src/proto/blowfish.pro, src/proto/crypt.pro,
            src/proto/crypt_zip.pro, src/structs.h,
            src/testdir/samples/crypt_sodium_invalid.txt,
            src/testdir/test_crypt.vim, src/undo.c, src/version.c


*** ../vim-8.2.3021/.github/workflows/ci.yml    2021-02-13 17:08:29.903796267 
+0100
--- .github/workflows/ci.yml    2021-06-20 12:51:47.132478459 +0200
***************
*** 71,77 ****
              cscope \
              libgtk2.0-dev \
              desktop-file-utils \
!             libtool-bin
  
        - name: Install clang-11
          if: matrix.compiler == 'clang'
--- 71,78 ----
              cscope \
              libgtk2.0-dev \
              desktop-file-utils \
!             libtool-bin \
!             libsodium-dev
  
        - name: Install clang-11
          if: matrix.compiler == 'clang'
*** ../vim-8.2.3021/runtime/doc/eval.txt        2021-06-19 20:45:07.349511367 
+0200
--- runtime/doc/eval.txt        2021-06-20 12:51:47.136478444 +0200
***************
*** 11951,11956 ****
--- 11971,11977 ----
  showcmd                       Compiled with 'showcmd' support.
  signs                 Compiled with |:sign| support.
  smartindent           Compiled with 'smartindent' support.
+ sodium                        Compiled with libsodium for better crypt support
  sound                 Compiled with sound support, e.g. `sound_playevent()`
  spell                 Compiled with spell checking support |spell|.
  startuptime           Compiled with |--startuptime| support.
*** ../vim-8.2.3021/runtime/doc/options.txt     2021-05-31 18:40:45.996805282 
+0200
--- runtime/doc/options.txt     2021-06-20 13:02:04.578532122 +0200
***************
*** 2380,2385 ****
--- 2384,2406 ----
                        you write the file the encrypted bytes will be
                        different.  The whole undo file is encrypted, not just
                        the pieces of text.
+                                       *E1193* *E1194* *E1195* *E1196*
+                                       *E1197* *E1198* *E1199* *E1200* *E1201*
+          xchacha20    XChaCha20 Cipher with Poly1305 Message Authentication
+                       Code.  Medium strong till strong encryption.
+                       Encryption is provided by the libsodium library, it
+                       requires Vim to be built with |+sodium|
+                       It adds a seed and a message authentication code (MAC)
+                       to the file.  This needs at least a Vim 8.2.3022 to
+                       read the encrypted file.
+                       Encryption of swap files is not supported, therefore
+                       no swap file will be used when xchacha20 encryption is
+                       enabled.
+                       Encryption of undo files is not yet supported,
+                       therefore no undo file will currently be written.
+                       CURRENTLY EXPERIMENTAL: Files written with this method
+                       might have to be read back with the same version of
+                       Vim if the binary format changes later.
  
        You should use "blowfish2", also to re-encrypt older files.
  
*** ../vim-8.2.3021/runtime/doc/various.txt     2021-01-31 17:02:06.266490126 
+0100
--- runtime/doc/various.txt     2021-06-20 12:51:47.136478444 +0200
***************
*** 444,449 ****
--- 444,450 ----
  T  *+scrollbind*      |'scrollbind'|
  B  *+signs*           |:sign|
  N  *+smartindent*     |'smartindent'|
+ B  *+sodium*          compiled with libsodium for better encryption support
  B  *+sound*           |sound_playevent()|, |sound_playfile()| functions, etc.
  N  *+spell*           spell checking support, see |spell|
  N  *+startuptime*     |--startuptime| argument
*** ../vim-8.2.3021/src/INSTALLpc.txt   2020-11-14 21:04:29.213262892 +0100
--- src/INSTALLpc.txt   2021-06-20 12:51:47.136478444 +0200
***************
*** 322,327 ****
--- 322,330 ----
  
      $ pacman -S git
  
+ For enabling libsodium support, you also need to install the package
+ 
+     $ pacman -S mingw-w64-x86_64-libsodium
  
  2.3. Keep the build environment up-to-date
  
*** ../vim-8.2.3021/src/Make_cyg_ming.mak       2021-06-02 17:07:02.276398163 
+0200
--- src/Make_cyg_ming.mak       2021-06-20 12:51:47.140478432 +0200
***************
*** 41,46 ****
--- 41,49 ----
  # set to yes to measure code coverage
  COVERAGE=no
  
+ # better encryption support using libsodium
+ #SODIUM=yes
+ 
  # set to SIZE for size, SPEED for speed, MAXSPEED for maximum optimization
  OPTIMIZE=MAXSPEED
  
***************
*** 517,522 ****
--- 520,529 ----
  WINDRES_FLAGS =
  EXTRA_LIBS =
  
+ ifdef SODIUM
+ DEFINES += -DHAVE_SODIUM
+ endif
+ 
  ifdef GETTEXT
  DEFINES += -DHAVE_GETTEXT -DHAVE_LOCALE_H
  GETTEXTINCLUDE = $(GETTEXT)/include
***************
*** 660,665 ****
--- 667,676 ----
   endif
  endif
  
+ ifeq ($(SODIUM),yes)
+ SODIUMLIB = -lsodium
+ endif
+ 
  # Only allow XPM for a GUI build.
  ifeq (yes, $(GUI))
  
***************
*** 1064,1070 ****
  
  ifeq ($(VIMDLL),yes)
  $(TARGET): $(OBJ)
!       $(LINK) $(CFLAGS) $(LFLAGS) -o $@ $(OBJ) $(LIB) -lole32 -luuid -lgdi32 
$(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(PYTHON3LIB) 
$(RUBYLIB)
  
  $(GVIMEXE): $(EXEOBJG) $(VIMDLLBASE).dll
        $(CC) -L. $(EXELFLAGS) -mwindows -o $@ $(EXEOBJG) -l$(VIMDLLBASE)
--- 1075,1081 ----
  
  ifeq ($(VIMDLL),yes)
  $(TARGET): $(OBJ)
!       $(LINK) $(CFLAGS) $(LFLAGS) -o $@ $(OBJ) $(LIB) -lole32 -luuid -lgdi32 
$(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(PYTHON3LIB) 
$(RUBYLIB) $(SODIUMLIB)
  
  $(GVIMEXE): $(EXEOBJG) $(VIMDLLBASE).dll
        $(CC) -L. $(EXELFLAGS) -mwindows -o $@ $(EXEOBJG) -l$(VIMDLLBASE)
***************
*** 1073,1079 ****
        $(CC) -L. $(EXELFLAGS) -o $@ $(EXEOBJC) -l$(VIMDLLBASE)
  else
  $(TARGET): $(OBJ)
!       $(LINK) $(CFLAGS) $(LFLAGS) -o $@ $(OBJ) $(LIB) -lole32 -luuid 
$(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(PYTHON3LIB) 
$(RUBYLIB)
  endif
  
  upx: exes
--- 1084,1090 ----
        $(CC) -L. $(EXELFLAGS) -o $@ $(EXEOBJC) -l$(VIMDLLBASE)
  else
  $(TARGET): $(OBJ)
!       $(LINK) $(CFLAGS) $(LFLAGS) -o $@ $(OBJ) $(LIB) -lole32 -luuid 
$(LUA_LIB) $(MZSCHEME_LIBDIR) $(MZSCHEME_LIB) $(PYTHONLIB) $(PYTHON3LIB) 
$(RUBYLIB) $(SODIUMLIB)
  endif
  
  upx: exes
*** ../vim-8.2.3021/src/Make_mvc.mak    2021-06-02 17:07:02.276398163 +0200
--- src/Make_mvc.mak    2021-06-20 13:02:42.326416497 +0200
***************
*** 41,46 ****
--- 41,49 ----
  #
  #     Sound support: SOUND=yes (default is yes)
  #
+ #     Sodium support: SODIUM=[Path to Sodium directory]
+ #      You need to install the msvc package from 
https://download.libsodium.org/libsodium/releases/
+ #
  #     DLL support (EXPERIMENTAL): VIMDLL=yes (default is no)
  #       Creates vim{32,64}.dll, and stub gvim.exe and vim.exe.
  #       The shared codes between the GUI and the console are built into
***************
*** 372,377 ****
--- 375,400 ----
  ! endif
  !endif
  
+ !ifndef SODIUM
+ SODIUM = no
+ !endif
+ 
+ !if "$(SODIUM)" != "no"
+ ! if "$(CPU)" == "AMD64"
+ SOD_LIB               = $(SODIUM)\x64\Release\v140\dynamic
+ ! elseif "$(CPU)" == "i386"
+ SOD_LIB               = $(SODIUM)\x86\Release\v140\dynamic
+ ! else
+ SODIUM = no
+ ! endif
+ !endif
+ 
+ !if "$(SODIUM)" != "no"
+ SOD_INC               = -I $(SODIUM)\include
+ SOD_DEFS      = -DFEAT_SODIUM
+ SOD_LIB               = $(SOD_LIB)\libsodium.lib
+ !endif
+ 
  !ifndef NETBEANS
  NETBEANS = $(GUI)
  !endif
***************
*** 491,497 ****
  
  CFLAGS = -c /W3 /GF /nologo $(CVARS) -I. -Iproto -DHAVE_PATHDEF -DWIN32 \
                $(CSCOPE_DEFS) $(TERM_DEFS) $(SOUND_DEFS) $(NETBEANS_DEFS) 
$(CHANNEL_DEFS) \
!               $(NBDEBUG_DEFS) $(XPM_DEFS) \
                $(DEFINES) -DWINVER=$(WINVER) -D_WIN32_WINNT=$(WINVER)
  
  #>>>>> end of choices
--- 514,520 ----
  
  CFLAGS = -c /W3 /GF /nologo $(CVARS) -I. -Iproto -DHAVE_PATHDEF -DWIN32 \
                $(CSCOPE_DEFS) $(TERM_DEFS) $(SOUND_DEFS) $(NETBEANS_DEFS) 
$(CHANNEL_DEFS) \
!               $(NBDEBUG_DEFS) $(XPM_DEFS) $(SOD_DEFS) \
                $(DEFINES) -DWINVER=$(WINVER) -D_WIN32_WINNT=$(WINVER)
  
  #>>>>> end of choices
***************
*** 703,709 ****
  
  INCL =        vim.h alloc.h ascii.h ex_cmds.h feature.h errors.h globals.h \
        keymap.h macros.h option.h os_dos.h os_win32.h proto.h regexp.h \
!       spell.h structs.h term.h beval.h $(NBDEBUG_INCL)
  
  OBJ = \
        $(OUTDIR)\arabic.obj \
--- 726,732 ----
  
  INCL =        vim.h alloc.h ascii.h ex_cmds.h feature.h errors.h globals.h \
        keymap.h macros.h option.h os_dos.h os_win32.h proto.h regexp.h \
!       spell.h structs.h term.h beval.h $(NBDEBUG_INCL) $(SOD_INC)
  
  OBJ = \
        $(OUTDIR)\arabic.obj \
***************
*** 1282,1288 ****
  LINKARGS1 = $(linkdebug) $(conflags)
  LINKARGS2 = $(CON_LIB) $(GUI_LIB) $(NODEFAULTLIB) $(LIBC) $(OLE_LIB) 
user32.lib \
                $(LUA_LIB) $(MZSCHEME_LIB) $(PERL_LIB) $(PYTHON_LIB) 
$(PYTHON3_LIB) $(RUBY_LIB) \
!               $(TCL_LIB) $(SOUND_LIB) $(NETBEANS_LIB) $(XPM_LIB) $(LINK_PDB)
  
  # Report link time code generation progress if used. 
  !ifdef NODEBUG
--- 1305,1311 ----
  LINKARGS1 = $(linkdebug) $(conflags)
  LINKARGS2 = $(CON_LIB) $(GUI_LIB) $(NODEFAULTLIB) $(LIBC) $(OLE_LIB) 
user32.lib \
                $(LUA_LIB) $(MZSCHEME_LIB) $(PERL_LIB) $(PYTHON_LIB) 
$(PYTHON3_LIB) $(RUBY_LIB) \
!               $(TCL_LIB) $(SOUND_LIB) $(NETBEANS_LIB) $(XPM_LIB) $(SOD_LIB) 
$(LINK_PDB)
  
  # Report link time code generation progress if used. 
  !ifdef NODEBUG
*** ../vim-8.2.3021/src/auto/configure  2021-06-10 18:50:51.806711124 +0200
--- src/auto/configure  2021-06-20 13:36:53.996548337 +0200
***************
*** 839,844 ****
--- 839,845 ----
  with_tlib
  enable_largefile
  enable_canberra
+ enable_libsodium
  enable_acl
  enable_gpm
  enable_sysmouse
***************
*** 1513,1518 ****
--- 1514,1520 ----
    --disable-desktop-database-update  update disabled
    --disable-largefile     omit support for large files
    --disable-canberra      Do not use libcanberra.
+   --disable-libsodium      Do not use libsodium.
    --disable-acl           No check for ACL support.
    --disable-gpm           Don't use gpm (Linux mouse daemon).
    --disable-sysmouse      Don't use sysmouse (mouse in *BSD console).
***************
*** 13005,13010 ****
--- 13007,13076 ----
      conftest$ac_exeext conftest.$ac_ext
  fi
  
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking --enable-libsodium 
argument" >&5
+ $as_echo_n "checking --enable-libsodium argument... " >&6; }
+ # Check whether --enable-libsodium was given.
+ if test "${enable_libsodium+set}" = set; then :
+   enableval=$enable_libsodium;
+ else
+   enable_libsodium="maybe"
+ fi
+ 
+ 
+ if test "$enable_libsodium" = "maybe"; then
+   if test "$features" = "big" -o "$features" = "huge"; then
+     { $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to yes" >&5
+ $as_echo "Defaulting to yes" >&6; }
+     enable_libsodium="yes"
+   else
+     { $as_echo "$as_me:${as_lineno-$LINENO}: result: Defaulting to no" >&5
+ $as_echo "Defaulting to no" >&6; }
+     enable_libsodium="no"
+   fi
+ else
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_libsodium" >&5
+ $as_echo "$enable_libsodium" >&6; }
+ fi
+ if test "$enable_libsodium" = "yes"; then
+   if test "x$PKG_CONFIG" != "xno"; then
+     libsodium_lib=`$PKG_CONFIG --libs libsodium 2>/dev/null`
+     libsodium_cflags=`$PKG_CONFIG --cflags libsodium 2>/dev/null`
+   fi
+   if test "x$libsodium_lib" = "x"; then
+     libsodium_lib=-lsodium
+     libsodium_cflags=
+   fi
+   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libcanberra" >&5
+ $as_echo_n "checking for libcanberra... " >&6; }
+   ac_save_CFLAGS="$CFLAGS"
+   ac_save_LIBS="$LIBS"
+   CFLAGS="$CFLAGS $libsodium_cflags"
+   LIBS="$LIBS $libsodium_lib"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ /* end confdefs.h.  */
+ 
+   # include <sodium.h>
+ 
+ int
+ main ()
+ {
+ 
+      printf("%d", sodium_init());
+   ;
+   return 0;
+ }
+ _ACEOF
+ if ac_fn_c_try_link "$LINENO"; then :
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+ $as_echo "yes" >&6; }; $as_echo "#define HAVE_SODIUM 1" >>confdefs.h
+ 
+ else
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no; try installing 
libsodium-dev" >&5
+ $as_echo "no; try installing libsodium-dev" >&6; }; CFLAGS="$ac_save_CFLAGS"; 
LIBS="$ac_save_LIBS"
+ fi
+ rm -f core conftest.err conftest.$ac_objext \
+     conftest$ac_exeext conftest.$ac_ext
+ fi
  
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for st_blksize" >&5
  $as_echo_n "checking for st_blksize... " >&6; }
*** ../vim-8.2.3021/src/blowfish.c      2021-06-02 13:28:11.423120478 +0200
--- src/blowfish.c      2021-06-20 12:51:47.144478420 +0200
***************
*** 596,602 ****
      cryptstate_T *state,
      char_u    *from,
      size_t    len,
!     char_u    *to)
  {
      bf_state_T *bfs = state->method_state;
      size_t    i;
--- 596,603 ----
      cryptstate_T *state,
      char_u    *from,
      size_t    len,
!     char_u    *to,
!     int               last UNUSED)
  {
      bf_state_T *bfs = state->method_state;
      size_t    i;
***************
*** 619,625 ****
      cryptstate_T *state,
      char_u    *from,
      size_t    len,
!     char_u    *to)
  {
      bf_state_T *bfs = state->method_state;
      size_t    i;
--- 620,627 ----
      cryptstate_T *state,
      char_u    *from,
      size_t    len,
!     char_u    *to,
!     int               last UNUSED)
  {
      bf_state_T *bfs = state->method_state;
      size_t    i;
***************
*** 680,684 ****
      }
      return OK;
  }
- 
  #endif // FEAT_CRYPT
--- 682,685 ----
*** ../vim-8.2.3021/src/bufwrite.c      2021-02-01 20:34:57.249893201 +0100
--- src/bufwrite.c      2021-06-20 12:51:47.152478393 +0200
***************
*** 30,35 ****
--- 30,36 ----
      int               bw_flags;       // FIO_ flags
  #ifdef FEAT_CRYPT
      buf_T     *bw_buffer;     // buffer being written
+     int         bw_finish;      // finish encrypting
  #endif
      char_u    bw_rest[CONV_RESTLEN]; // not converted bytes
      int               bw_restlen;     // nr of bytes in bw_rest[]
***************
*** 493,506 ****
        if (crypt_works_inplace(ip->bw_buffer->b_cryptstate))
        {
  # endif
!           crypt_encode_inplace(ip->bw_buffer->b_cryptstate, buf, len);
  # ifdef CRYPT_NOT_INPLACE
        }
        else
        {
            char_u *outbuf;
  
!           len = crypt_encode_alloc(curbuf->b_cryptstate, buf, len, &outbuf);
            if (len == 0)
                return OK;  // Crypt layer is buffering, will flush later.
            wlen = write_eintr(ip->bw_fd, outbuf, len);
--- 494,507 ----
        if (crypt_works_inplace(ip->bw_buffer->b_cryptstate))
        {
  # endif
!           crypt_encode_inplace(ip->bw_buffer->b_cryptstate, buf, len, 
ip->bw_finish);
  # ifdef CRYPT_NOT_INPLACE
        }
        else
        {
            char_u *outbuf;
  
!           len = crypt_encode_alloc(curbuf->b_cryptstate, buf, len, &outbuf, 
ip->bw_finish);
            if (len == 0)
                return OK;  // Crypt layer is buffering, will flush later.
            wlen = write_eintr(ip->bw_fd, outbuf, len);
***************
*** 724,729 ****
--- 725,731 ----
  #endif
  #ifdef FEAT_CRYPT
      write_info.bw_buffer = buf;
+     write_info.bw_finish = FALSE;
  #endif
  
      // After writing a file changedtick changes but we don't want to display
***************
*** 2015,2020 ****
--- 2017,2029 ----
                ++s;
                if (++len != bufsize)
                    continue;
+ #ifdef FEAT_CRYPT
+               if (write_info.bw_fd > 0 && lnum == end
+                       && (write_info.bw_flags & FIO_ENCRYPTED)
+                       && *buf->b_p_key != NUL && !filtering
+                       && *ptr == NUL)
+                   write_info.bw_finish = TRUE;
+  #endif
                if (buf_write_bytes(&write_info) == FAIL)
                {
                    end = 0;            // write error: break loop
***************
*** 2118,2123 ****
--- 2127,2138 ----
        if (len > 0 && end > 0)
        {
            write_info.bw_len = len;
+ #ifdef FEAT_CRYPT
+           if (write_info.bw_fd > 0 && lnum >= end
+                   && (write_info.bw_flags & FIO_ENCRYPTED)
+                   && *buf->b_p_key != NUL && !filtering)
+               write_info.bw_finish = TRUE;
+  #endif
            if (buf_write_bytes(&write_info) == FAIL)
                end = 0;                    // write error
            nchars += len;
*** ../vim-8.2.3021/src/config.h.in     2021-03-10 21:26:34.148867591 +0100
--- src/config.h.in     2021-06-20 12:51:47.152478393 +0200
***************
*** 208,213 ****
--- 208,214 ----
  #undef HAVE_STRPTIME
  #undef HAVE_STRTOL
  #undef HAVE_CANBERRA
+ #undef HAVE_SODIUM
  #undef HAVE_ST_BLKSIZE
  #undef HAVE_SYSCONF
  #undef HAVE_SYSCTL
*** ../vim-8.2.3021/src/configure.ac    2021-06-10 18:50:51.806711124 +0200
--- src/configure.ac    2021-06-20 13:36:51.308552622 +0200
***************
*** 3767,3772 ****
--- 3767,3809 ----
         AC_MSG_RESULT(no; try installing libcanberra-dev); 
CFLAGS="$ac_save_CFLAGS"; LIBS="$ac_save_LIBS")
  fi
  
+ AC_MSG_CHECKING(--enable-libsodium argument)
+ AC_ARG_ENABLE(libsodium,
+       [  --disable-libsodium      Do not use libsodium.],
+       , [enable_libsodium="maybe"])
+ 
+ if test "$enable_libsodium" = "maybe"; then
+   if test "$features" = "big" -o "$features" = "huge"; then
+     AC_MSG_RESULT(Defaulting to yes)
+     enable_libsodium="yes"
+   else
+     AC_MSG_RESULT(Defaulting to no)
+     enable_libsodium="no"
+   fi
+ else
+   AC_MSG_RESULT($enable_libsodium)
+ fi
+ if test "$enable_libsodium" = "yes"; then
+   if test "x$PKG_CONFIG" != "xno"; then
+     libsodium_lib=`$PKG_CONFIG --libs libsodium 2>/dev/null`
+     libsodium_cflags=`$PKG_CONFIG --cflags libsodium 2>/dev/null`
+   fi
+   if test "x$libsodium_lib" = "x"; then
+     libsodium_lib=-lsodium
+     libsodium_cflags=
+   fi
+   AC_MSG_CHECKING(for libcanberra)
+   ac_save_CFLAGS="$CFLAGS"
+   ac_save_LIBS="$LIBS"
+   CFLAGS="$CFLAGS $libsodium_cflags"
+   LIBS="$LIBS $libsodium_lib"
+   AC_TRY_LINK([
+   # include <sodium.h>
+       ], [
+      printf("%d", sodium_init()); ],
+        AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SODIUM),
+        AC_MSG_RESULT(no; try installing libsodium-dev); 
CFLAGS="$ac_save_CFLAGS"; LIBS="$ac_save_LIBS")
+ fi
  
  dnl fstatfs() can take 2 to 4 arguments, try to use st_blksize if possible
  AC_MSG_CHECKING(for st_blksize)
*** ../vim-8.2.3021/src/crypt.c 2019-11-30 20:50:07.000000000 +0100
--- src/crypt.c 2021-06-20 13:13:43.020361247 +0200
***************
*** 12,17 ****
--- 12,21 ----
   */
  #include "vim.h"
  
+ #ifdef FEAT_SODIUM
+ # include <sodium.h>
+ #endif
+ 
  #if defined(FEAT_CRYPT) || defined(PROTO)
  /*
   * Optional encryption support.
***************
*** 33,39 ****
      char    *name;    // encryption name as used in 'cryptmethod'
      char    *magic;   // magic bytes stored in file header
      int           salt_len;   // length of salt, or 0 when not using salt
!     int           seed_len;   // length of seed, or 0 when not using salt
  #ifdef CRYPT_NOT_INPLACE
      int           works_inplace; // encryption/decryption can be done in-place
  #endif
--- 37,43 ----
      char    *name;    // encryption name as used in 'cryptmethod'
      char    *magic;   // magic bytes stored in file header
      int           salt_len;   // length of salt, or 0 when not using salt
!     int           seed_len;   // length of seed, or 0 when not using seed
  #ifdef CRYPT_NOT_INPLACE
      int           works_inplace; // encryption/decryption can be done in-place
  #endif
***************
*** 49,64 ****
      // Function pointers for encoding/decoding from one buffer into another.
      // Optional, however, these or the _buffer ones should be configured.
      void (*encode_fn)(cryptstate_T *state, char_u *from, size_t len,
!                                                                 char_u *to);
      void (*decode_fn)(cryptstate_T *state, char_u *from, size_t len,
!                                                                 char_u *to);
  
      // Function pointers for encoding and decoding, can buffer data if needed.
      // Optional (however, these or the above should be configured).
      long (*encode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
!                                                            char_u **newptr);
      long (*decode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
!                                                            char_u **newptr);
  
      // Function pointers for in-place encoding and decoding, used for
      // crypt_*_inplace(). "from" and "to" arguments will be equal.
--- 53,68 ----
      // Function pointers for encoding/decoding from one buffer into another.
      // Optional, however, these or the _buffer ones should be configured.
      void (*encode_fn)(cryptstate_T *state, char_u *from, size_t len,
!                                                       char_u *to, int last);
      void (*decode_fn)(cryptstate_T *state, char_u *from, size_t len,
!                                                       char_u *to, int last);
  
      // Function pointers for encoding and decoding, can buffer data if needed.
      // Optional (however, these or the above should be configured).
      long (*encode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
!                                                   char_u **newptr, int last);
      long (*decode_buffer_fn)(cryptstate_T *state, char_u *from, size_t len,
!                                                   char_u **newptr, int last);
  
      // Function pointers for in-place encoding and decoding, used for
      // crypt_*_inplace(). "from" and "to" arguments will be equal.
***************
*** 68,76 ****
      // padding to files).
      // This method is used for swap and undo files which have a rigid format.
      void (*encode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
!                                                                 char_u *p2);
      void (*decode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
!                                                                 char_u *p2);
  } cryptmethod_T;
  
  // index is method_nr of cryptstate_T, CRYPT_M_*
--- 72,80 ----
      // padding to files).
      // This method is used for swap and undo files which have a rigid format.
      void (*encode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
!                                                       char_u *p2, int last);
      void (*decode_inplace_fn)(cryptstate_T *state, char_u *p1, size_t len,
!                                                       char_u *p2, int last);
  } cryptmethod_T;
  
  // index is method_nr of cryptstate_T, CRYPT_M_*
***************
*** 126,135 ****
--- 130,170 ----
        crypt_blowfish_encode, crypt_blowfish_decode,
      },
  
+     // XChaCha20 using libsodium
+     {
+       "xchacha20",
+       "VimCrypt~04!",
+ #ifdef FEAT_SODIUM
+       crypto_pwhash_argon2id_SALTBYTES, // 16
+ #else
+       16,
+ #endif
+       8,
+ #ifdef CRYPT_NOT_INPLACE
+       FALSE,
+ #endif
+       FALSE,
+       NULL,
+       crypt_sodium_init,
+       crypt_sodium_encode, crypt_sodium_decode,
+       crypt_sodium_buffer_encode, crypt_sodium_buffer_decode,
+       crypt_sodium_encode, crypt_sodium_decode,
+     },
+ 
      // NOTE: when adding a new method, use some random bytes for the magic 
key,
      // to avoid that a text file is recognized as encrypted.
  };
  
+ #ifdef FEAT_SODIUM
+ typedef struct {
+     size_t        count;
+     unsigned char   key[crypto_box_SEEDBYTES];
+                 // 32, same as crypto_secretstream_xchacha20poly1305_KEYBYTES
+     crypto_secretstream_xchacha20poly1305_state
+                   state;
+ } sodium_state_T;
+ #endif
+ 
  #define CRYPT_MAGIC_LEN       12      // cannot change
  static char   crypt_magic_head[] = "VimCrypt~";
  
***************
*** 260,266 ****
  
      state->method_nr = method_nr;
      if (cryptmethods[method_nr].init_fn(
!                          state, key, salt, salt_len, seed, seed_len) == FAIL)
      {
          vim_free(state);
          return NULL;
--- 295,301 ----
  
      state->method_nr = method_nr;
      if (cryptmethods[method_nr].init_fn(
!       state, key, salt, salt_len, seed, seed_len) == FAIL)
      {
          vim_free(state);
          return NULL;
***************
*** 365,373 ****
        // TODO: Should this be crypt method specific? (Probably not worth
        // it).  sha2_seed is pretty bad for large amounts of entropy, so make
        // that into something which is suitable for anything.
!       sha2_seed(salt, salt_len, seed, seed_len);
      }
- 
      state = crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
      if (state == NULL)
        VIM_CLEAR(*header);
--- 400,415 ----
        // TODO: Should this be crypt method specific? (Probably not worth
        // it).  sha2_seed is pretty bad for large amounts of entropy, so make
        // that into something which is suitable for anything.
! #ifdef FEAT_SODIUM
!       if (sodium_init() >= 0)
!       {
!           randombytes_buf(salt, salt_len);
!           randombytes_buf(seed, seed_len);
!       }
!       else
! #endif
!           sha2_seed(salt, salt_len, seed, seed_len);
      }
      state = crypt_create(method_nr, key, salt, salt_len, seed, seed_len);
      if (state == NULL)
        VIM_CLEAR(*header);
***************
*** 380,386 ****
      void
  crypt_free_state(cryptstate_T *state)
  {
!     vim_free(state->method_state);
      vim_free(state);
  }
  
--- 422,436 ----
      void
  crypt_free_state(cryptstate_T *state)
  {
! #ifdef FEAT_SODIUM
!     if (state->method_nr == CRYPT_M_SOD)
!     {
!       sodium_memzero(state->method_state, sizeof(sodium_state_T));
!       sodium_free(state->method_state);
!     }
!     else
! #endif
!       vim_free(state->method_state);
      vim_free(state);
  }
  
***************
*** 395,415 ****
      cryptstate_T *state,
      char_u    *from,
      size_t    len,
!     char_u    **newptr)
  {
      cryptmethod_T *method = &cryptmethods[state->method_nr];
  
      if (method->encode_buffer_fn != NULL)
        // Has buffer function, pass through.
!       return method->encode_buffer_fn(state, from, len, newptr);
      if (len == 0)
        // Not buffering, just return EOF.
        return (long)len;
  
!     *newptr = alloc(len);
      if (*newptr == NULL)
        return -1;
!     method->encode_fn(state, from, len, *newptr);
      return (long)len;
  }
  
--- 445,466 ----
      cryptstate_T *state,
      char_u    *from,
      size_t    len,
!     char_u    **newptr,
!     int               last)
  {
      cryptmethod_T *method = &cryptmethods[state->method_nr];
  
      if (method->encode_buffer_fn != NULL)
        // Has buffer function, pass through.
!       return method->encode_buffer_fn(state, from, len, newptr, last);
      if (len == 0)
        // Not buffering, just return EOF.
        return (long)len;
  
!     *newptr = alloc(len + 50);
      if (*newptr == NULL)
        return -1;
!     method->encode_fn(state, from, len, *newptr, last);
      return (long)len;
  }
  
***************
*** 423,435 ****
      cryptstate_T *state,
      char_u    *ptr,
      long      len,
!     char_u      **newptr)
  {
      cryptmethod_T *method = &cryptmethods[state->method_nr];
  
      if (method->decode_buffer_fn != NULL)
        // Has buffer function, pass through.
!       return method->decode_buffer_fn(state, ptr, len, newptr);
  
      if (len == 0)
        // Not buffering, just return EOF.
--- 474,487 ----
      cryptstate_T *state,
      char_u    *ptr,
      long      len,
!     char_u      **newptr,
!     int               last)
  {
      cryptmethod_T *method = &cryptmethods[state->method_nr];
  
      if (method->decode_buffer_fn != NULL)
        // Has buffer function, pass through.
!       return method->decode_buffer_fn(state, ptr, len, newptr, last);
  
      if (len == 0)
        // Not buffering, just return EOF.
***************
*** 438,444 ****
      *newptr = alloc(len);
      if (*newptr == NULL)
        return -1;
!     method->decode_fn(state, ptr, len, *newptr);
      return len;
  }
  #endif
--- 490,496 ----
      *newptr = alloc(len);
      if (*newptr == NULL)
        return -1;
!     method->decode_fn(state, ptr, len, *newptr, last);
      return len;
  }
  #endif
***************
*** 451,459 ****
      cryptstate_T *state,
      char_u    *from,
      size_t    len,
!     char_u    *to)
  {
!     cryptmethods[state->method_nr].encode_fn(state, from, len, to);
  }
  
  #if 0  // unused
--- 503,512 ----
      cryptstate_T *state,
      char_u    *from,
      size_t    len,
!     char_u    *to,
!     int               last)
  {
!     cryptmethods[state->method_nr].encode_fn(state, from, len, to, last);
  }
  
  #if 0  // unused
***************
*** 465,473 ****
      cryptstate_T *state,
      char_u    *from,
      size_t    len,
!     char_u    *to)
  {
!     cryptmethods[state->method_nr].decode_fn(state, from, len, to);
  }
  #endif
  
--- 518,527 ----
      cryptstate_T *state,
      char_u    *from,
      size_t    len,
!     char_u    *to,
!     int               last)
  {
!     cryptmethods[state->method_nr].decode_fn(state, from, len, to, last);
  }
  #endif
  
***************
*** 478,486 ****
  crypt_encode_inplace(
      cryptstate_T *state,
      char_u    *buf,
!     size_t    len)
  {
!     cryptmethods[state->method_nr].encode_inplace_fn(state, buf, len, buf);
  }
  
  /*
--- 532,542 ----
  crypt_encode_inplace(
      cryptstate_T *state,
      char_u    *buf,
!     size_t    len,
!     int         last)
  {
!     cryptmethods[state->method_nr].encode_inplace_fn(state, buf, len,
!                                                                   buf, last);
  }
  
  /*
***************
*** 490,498 ****
  crypt_decode_inplace(
      cryptstate_T *state,
      char_u    *buf,
!     size_t    len)
  {
!     cryptmethods[state->method_nr].decode_inplace_fn(state, buf, len, buf);
  }
  
  /*
--- 546,556 ----
  crypt_decode_inplace(
      cryptstate_T *state,
      char_u    *buf,
!     size_t    len,
!     int               last)
  {
!     cryptmethods[state->method_nr].decode_inplace_fn(state, buf, len,
!                                                                   buf, last);
  }
  
  /*
***************
*** 523,528 ****
--- 581,599 ----
        msg_scroll = TRUE;
        msg(_("Warning: Using a weak encryption method; see :help 'cm'"));
      }
+     if (method == CRYPT_M_SOD)
+     {
+       // encryption uses padding and MAC, that does not work very well with
+       // swap and undo files, so disable them
+       mf_close_file(curbuf, TRUE);    // remove the swap file
+       set_option_value((char_u *)"swf", 0, NULL, OPT_LOCAL);
+ #ifdef FEAT_PERSISTENT_UNDO
+       set_option_value((char_u *)"udf", 0, NULL, OPT_LOCAL);
+ #endif
+ 
+       msg_scroll = TRUE;
+       msg(_("Note: Encryption of swapfile not supported, disabling swap- and 
undofile"));
+     }
  }
  
      void
***************
*** 610,613 ****
--- 681,946 ----
      }
  }
  
+     int
+ crypt_sodium_init(
+     cryptstate_T      *state UNUSED,
+     char_u            *key UNUSED,
+     char_u            *salt UNUSED,
+     int                       salt_len UNUSED,
+     char_u            *seed UNUSED,
+     int                       seed_len UNUSED)
+ {
+ # ifdef FEAT_SODIUM
+     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
+     unsigned char     dkey[crypto_box_SEEDBYTES]; // 32
+     sodium_state_T    *sd_state;
+ 
+     if (sodium_init() < 0)
+       return FAIL;
+ 
+     sd_state = (sodium_state_T *)sodium_malloc(sizeof(sodium_state_T));
+     sodium_memzero(sd_state, sizeof(sodium_state_T));
+ 
+     // derive a key from the password
+     if (crypto_pwhash(dkey, sizeof(dkey), (const char *)key, STRLEN(key), 
salt,
+       crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE,
+       crypto_pwhash_ALG_DEFAULT) != 0)
+     {
+       // out of memory
+       sodium_free(sd_state);
+       return FAIL;
+     }
+     memcpy(sd_state->key, dkey, crypto_box_SEEDBYTES);
+     sd_state->count = 0;
+     state->method_state = sd_state;
+ 
+     return OK;
+ # else
+     emsg(e_libsodium_not_built_in);
+     return FAIL;
+ # endif
+ }
+ 
+ /*
+  * Encrypt "from[len]" into "to[len]".
+  * "from" and "to" can be equal to encrypt in place.
+  * Call needs to ensure that there is enough space in to (for the header)
+  */
+     void
+ crypt_sodium_encode(
+     cryptstate_T *state UNUSED,
+     char_u    *from UNUSED,
+     size_t    len UNUSED,
+     char_u    *to UNUSED,
+     int               last UNUSED)
+ {
+ # ifdef FEAT_SODIUM
+     // crypto_box_SEEDBYTES == crypto_secretstream_xchacha20poly1305_KEYBYTES
+     sodium_state_T *sod_st = state->method_state;
+     unsigned char  tag = last
+                       ? crypto_secretstream_xchacha20poly1305_TAG_FINAL  : 0;
+ 
+     if (sod_st->count == 0)
+     {
+       if (len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES)
+       {
+           emsg(e_libsodium_cannot_encrypt_header);
+           return;
+       }
+       crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state,
+                                                             to, sod_st->key);
+       to += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
+     }
+ 
+     if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES)
+     {
+       emsg(e_libsodium_cannot_encrypt_buffer);
+       return;
+     }
+ 
+     crypto_secretstream_xchacha20poly1305_push(&sod_st->state, to, NULL,
+                                                     from, len, NULL, 0, tag);
+ 
+     sod_st->count++;
+ # endif
+ }
+ 
+ /* TODO: Unused
+  * Decrypt "from[len]" into "to[len]".
+  * "from" and "to" can be equal to encrypt in place.
+  */
+     void
+ crypt_sodium_decode(
+     cryptstate_T *state UNUSED,
+     char_u    *from UNUSED,
+     size_t    len UNUSED,
+     char_u    *to UNUSED,
+     int               last UNUSED)
+ {
+ # ifdef FEAT_SODIUM
+     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
+     sodium_state_T *sod_st = state->method_state;
+     unsigned char  tag;
+     unsigned long long buf_len;
+     char_u *p1 = from;
+     char_u *p2 = to;
+     char_u *buf_out;
+ 
+     if (sod_st->count == 0
+                  && len <= crypto_secretstream_xchacha20poly1305_HEADERBYTES)
+     {
+       emsg(e_libsodium_cannot_decrypt_header);
+       return;
+     }
+ 
+     buf_out = (char_u *)alloc(len);
+ 
+     if (buf_out == NULL)
+     {
+       emsg(e_libsodium_cannot_allocate_buffer);
+       return;
+     }
+     if (sod_st->count == 0)
+     {
+       if (crypto_secretstream_xchacha20poly1305_init_pull(
+                                      &sod_st->state, from, sod_st->key) != 0)
+       {
+           emsg(e_libsodium_decryption_failed_header_incomplete);
+           goto fail;
+       }
+ 
+       from += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
+       len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES;
+ 
+       if (p1 == p2)
+           to += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
+     }
+ 
+     if (sod_st->count && len <= crypto_secretstream_xchacha20poly1305_ABYTES)
+     {
+       emsg(e_libsodium_cannot_decrypt_buffer);
+       return;
+     }
+     if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state,
+                            buf_out, &buf_len, &tag, from, len, NULL, 0) != 0)
+     {
+       emsg(e_libsodium_decription_failed);
+       goto fail;
+     }
+     sod_st->count++;
+ 
+     if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last)
+     {
+       emsg(e_libsodium_decyption_failed_premature);
+       goto fail;
+     }
+     if (p1 == p2)
+       mch_memmove(p2, buf_out, buf_len);
+ 
+ fail:
+     vim_free(buf_out);
+ # endif
+ }
+ 
+ /*
+  * Encrypt "from[len]" into "to[len]".
+  * "from" and "to" can be equal to encrypt in place.
+  */
+     long
+ crypt_sodium_buffer_encode(
+     cryptstate_T *state UNUSED,
+     char_u    *from UNUSED,
+     size_t    len UNUSED,
+     char_u    **buf_out UNUSED,
+     int               last UNUSED)
+ {
+ # ifdef FEAT_SODIUM
+     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
+     unsigned long long        out_len;
+     char_u            *ptr;
+     unsigned char     tag = last
+                       ? crypto_secretstream_xchacha20poly1305_TAG_FINAL  : 0;
+     int                       length;
+     sodium_state_T    *sod_st = state->method_state;
+     int                       first = (sod_st->count == 0);
+ 
+     length = len + crypto_secretstream_xchacha20poly1305_ABYTES
+            + (first ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0);
+     *buf_out = alloc_clear(length);
+     if (*buf_out == NULL)
+     {
+       emsg(e_libsodium_cannot_allocate_buffer);
+       return -1;
+     }
+     ptr = *buf_out;
+ 
+     if (first)
+     {
+       crypto_secretstream_xchacha20poly1305_init_push(&sod_st->state,
+               ptr, sod_st->key);
+       ptr += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
+     }
+ 
+     crypto_secretstream_xchacha20poly1305_push(&sod_st->state, ptr,
+           &out_len, from, len, NULL, 0, tag);
+ 
+     sod_st->count++;
+     return out_len + (first
+                     ? crypto_secretstream_xchacha20poly1305_HEADERBYTES : 0);
+ # else
+     return -1;
+ # endif
+ }
+ 
+ /*
+  * Decrypt "from[len]" into "to[len]".
+  * "from" and "to" can be equal to encrypt in place.
+  */
+     long
+ crypt_sodium_buffer_decode(
+     cryptstate_T *state UNUSED,
+     char_u    *from UNUSED,
+     size_t    len UNUSED,
+     char_u    **buf_out UNUSED,
+     int               last UNUSED)
+ {
+ # ifdef FEAT_SODIUM
+     // crypto_box_SEEDBYTES ==  crypto_secretstream_xchacha20poly1305_KEYBYTES
+     sodium_state_T *sod_st = state->method_state;
+     unsigned char  tag;
+     unsigned long long out_len;
+     *buf_out = alloc_clear(len);
+     if (*buf_out == NULL)
+     {
+       emsg(e_libsodium_cannot_allocate_buffer);
+       return -1;
+     }
+ 
+     if (sod_st->count == 0)
+     {
+       if (crypto_secretstream_xchacha20poly1305_init_pull(&sod_st->state,
+                                                      from, sod_st->key) != 0)
+       {
+           emsg(e_libsodium_decryption_failed_header_incomplete);
+           return -1;
+       }
+       from += crypto_secretstream_xchacha20poly1305_HEADERBYTES;
+       len -= crypto_secretstream_xchacha20poly1305_HEADERBYTES;
+       sod_st->count++;
+     }
+     if (crypto_secretstream_xchacha20poly1305_pull(&sod_st->state,
+                           *buf_out, &out_len, &tag, from, len, NULL, 0) != 0)
+     {
+       emsg(e_libsodium_decription_failed);
+       return -1;
+     }
+ 
+     if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL && !last)
+       emsg(e_libsodium_decyption_failed_premature);
+     return (long) out_len;
+ # else
+     return -1;
+ # endif
+ }
+ 
  #endif // FEAT_CRYPT
*** ../vim-8.2.3021/src/crypt_zip.c     2019-11-30 20:50:30.000000000 +0100
--- src/crypt_zip.c     2021-06-20 12:51:47.152478393 +0200
***************
*** 114,120 ****
      cryptstate_T *state,
      char_u    *from,
      size_t    len,
!     char_u    *to)
  {
      zip_state_T *zs = state->method_state;
      size_t    i;
--- 114,121 ----
      cryptstate_T *state,
      char_u    *from,
      size_t    len,
!     char_u    *to,
!     int               last UNUSED)
  {
      zip_state_T *zs = state->method_state;
      size_t    i;
***************
*** 137,143 ****
      cryptstate_T *state,
      char_u    *from,
      size_t    len,
!     char_u    *to)
  {
      zip_state_T *zs = state->method_state;
      size_t    i;
--- 138,145 ----
      cryptstate_T *state,
      char_u    *from,
      size_t    len,
!     char_u    *to,
!     int               last UNUSED)
  {
      zip_state_T *zs = state->method_state;
      size_t    i;
*** ../vim-8.2.3021/src/errors.h        2021-06-12 12:16:51.478922236 +0200
--- src/errors.h        2021-06-20 12:51:47.152478393 +0200
***************
*** 427,429 ****
--- 427,448 ----
        INIT(= N_("E1191: Call to function that failed to compile: %s"));
  EXTERN char e_empty_function_name[]
        INIT(= N_("E1192: Empty function name"));
+ // libsodium
+ EXTERN char e_libsodium_not_built_in[]
+       INIT(= N_("E1193: cryptmethod xchacha20 not built into this Vim"));
+ EXTERN char e_libsodium_cannot_encrypt_header[]
+       INIT(= N_("E1194: Cannot encrypt header, not enough space"));
+ EXTERN char e_libsodium_cannot_encrypt_buffer[]
+       INIT(= N_("E1195: Cannot encrypt buffer, not enough space"));
+ EXTERN char e_libsodium_cannot_decrypt_header[]
+       INIT(= N_("E1196: Cannot decrypt header, not enough space"));
+ EXTERN char e_libsodium_cannot_allocate_buffer[]
+       INIT(= N_("E1197: Cannot allocate_buffer for encryption"));
+ EXTERN char e_libsodium_decryption_failed_header_incomplete[]
+       INIT(= N_("E1198: Decryption failed: Header incomplete!"));
+ EXTERN char e_libsodium_cannot_decrypt_buffer[]
+       INIT(= N_("E1199: Cannot decrypt buffer, not enough space"));
+ EXTERN char e_libsodium_decription_failed[]
+       INIT(= N_("E1200: Decryption failed: corrupted chunk!"));
+ EXTERN char e_libsodium_decyption_failed_premature[]
+       INIT(= N_("E1201: Decryption failed: pre-mature end of file!"));
*** ../vim-8.2.3021/src/evalfunc.c      2021-06-07 22:04:48.406620074 +0200
--- src/evalfunc.c      2021-06-20 12:51:47.156478381 +0200
***************
*** 5072,5077 ****
--- 5072,5084 ----
                0
  #endif
                },
+       {"sodium",
+ #ifdef FEAT_SODIUM
+               1
+ #else
+               0
+ #endif
+               },
        {"sound",
  #ifdef FEAT_SOUND
                1
*** ../vim-8.2.3021/src/feature.h       2021-03-29 20:49:01.486055361 +0200
--- src/feature.h       2021-06-20 12:51:47.156478381 +0200
***************
*** 593,598 ****
--- 593,605 ----
  # define FEAT_SOUND_CANBERRA
  #endif
  
+ /*
+  * libsodium - add cryptography support
+  */
+ #if defined(HAVE_SODIUM) && defined(FEAT_BIG)
+ # define FEAT_SODIUM
+ #endif
+ 
  // There are two ways to use XPM.
  #if (defined(HAVE_XM_XPMP_H) && defined(FEAT_GUI_MOTIF)) \
                || defined(HAVE_X11_XPM_H)
*** ../vim-8.2.3021/src/fileio.c        2021-06-02 13:28:11.427120469 +0200
--- src/fileio.c        2021-06-20 13:25:03.582216661 +0200
***************
*** 13,18 ****
--- 13,22 ----
  
  #include "vim.h"
  
+ #ifdef FEAT_SODIUM
+ # include <sodium.h>
+ #endif
+ 
  #if defined(__TANDEM)
  # include <limits.h>          // for SSIZE_MAX
  #endif
***************
*** 148,153 ****
--- 152,159 ----
      char_u    *p;
      off_T     filesize = 0;
      int               skip_read = FALSE;
+     off_T       filesize_disk = 0;      // file size read from disk
+     off_T       filesize_count = 0;     // counter
  #ifdef FEAT_CRYPT
      char_u    *cryptkey = NULL;
      int               did_ask_for_key = FALSE;
***************
*** 215,220 ****
--- 221,227 ----
      int               using_b_ffname;
      int               using_b_fname;
      static char *msg_is_a_directory = N_("is a directory");
+     int         eof;
  
      au_did_filetype = FALSE; // reset before triggering any autocommands
  
***************
*** 405,410 ****
--- 412,418 ----
        {
            buf_store_time(curbuf, &st, fname);
            curbuf->b_mtime_read = curbuf->b_mtime;
+           filesize_disk = st.st_size;
  #ifdef UNIX
            /*
             * Use the protection bits of the original file for the swap file.
***************
*** 1080,1085 ****
--- 1088,1094 ----
      {
        linerest = 0;
        filesize = 0;
+       filesize_count = 0;
        skip_count = lines_to_skip;
        read_count = lines_to_read;
        conv_restlen = 0;
***************
*** 1263,1269 ****
--- 1272,1294 ----
                    /*
                     * Read bytes from the file.
                     */
+ # ifdef FEAT_SODIUM
+                   // Let the crypt layer work with a buffer size of 8192
+                   if (filesize == 0)
+                       // set size to 8K + Sodium Crypt Metadata
+                       size = WRITEBUFSIZE + 36
+                    + crypto_secretstream_xchacha20poly1305_HEADERBYTES
+                    + crypto_secretstream_xchacha20poly1305_ABYTES;
+ 
+                   else if (filesize > 0 && (curbuf->b_cryptstate != NULL &&
+                        curbuf->b_cryptstate->method_nr == CRYPT_M_SOD))
+                       size = WRITEBUFSIZE + 
crypto_secretstream_xchacha20poly1305_ABYTES;
+ # endif
+                   eof = size;
                    size = read_eintr(fd, ptr, size);
+                   filesize_count += size;
+                   // hit end of file
+                   eof = (size < eof || filesize_count == filesize_disk);
                }
  
  #ifdef FEAT_CRYPT
***************
*** 1285,1291 ****
                    if (crypt_works_inplace(curbuf->b_cryptstate))
                    {
  # endif
!                       crypt_decode_inplace(curbuf->b_cryptstate, ptr, size);
  # ifdef CRYPT_NOT_INPLACE
                    }
                    else
--- 1310,1317 ----
                    if (crypt_works_inplace(curbuf->b_cryptstate))
                    {
  # endif
!                       crypt_decode_inplace(curbuf->b_cryptstate, ptr,
!                                                                   size, eof);
  # ifdef CRYPT_NOT_INPLACE
                    }
                    else
***************
*** 1294,1301 ****
                        int     decrypted_size;
  
                        decrypted_size = crypt_decode_alloc(
!                                   curbuf->b_cryptstate, ptr, size, &newptr);
  
                        // If the crypt layer is buffering, not producing
                        // anything yet, need to read more.
                        if (decrypted_size == 0)
--- 1320,1335 ----
                        int     decrypted_size;
  
                        decrypted_size = crypt_decode_alloc(
!                                   curbuf->b_cryptstate, ptr, size,
!                                                                &newptr, eof);
  
+                       if (decrypted_size < 0)
+                       {
+                           // error message already given
+                           error = TRUE;
+                           vim_free(newptr);
+                           break;
+                       }
                        // If the crypt layer is buffering, not producing
                        // anything yet, need to read more.
                        if (decrypted_size == 0)
***************
*** 1325,1330 ****
--- 1359,1365 ----
                            if (newptr != NULL)
                                mch_memmove(new_buffer + linerest, newptr,
                                                              decrypted_size);
+                           vim_free(newptr);
                        }
  
                        if (new_buffer != NULL)
***************
*** 1334,1339 ****
--- 1369,1375 ----
                            new_buffer = NULL;
                            line_start = buffer;
                            ptr = buffer + linerest;
+                           real_size = size;
                        }
                        size = decrypted_size;
                    }
*** ../vim-8.2.3021/src/memline.c       2021-06-09 12:33:36.908213351 +0200
--- src/memline.c       2021-06-20 13:18:45.303410360 +0200
***************
*** 48,53 ****
--- 48,58 ----
  # include <time.h>
  #endif
  
+ // for randombytes_buf
+ #ifdef FEAT_SODIUM
+ # include <sodium.h>
+ #endif
+ 
  #if defined(SASC) || defined(__amigaos4__)
  # include <proto/dos.h>           // for Open() and Close()
  #endif
***************
*** 64,75 ****
--- 69,82 ----
  #define BLOCK0_ID1_C0  'c'                // block 0 id 1 'cm' 0
  #define BLOCK0_ID1_C1  'C'                // block 0 id 1 'cm' 1
  #define BLOCK0_ID1_C2  'd'                // block 0 id 1 'cm' 2
+ #define BLOCK0_ID1_C3  'S'                // block 0 id 1 'cm' 3 - but not 
actually used
  
  #if defined(FEAT_CRYPT)
  static int id1_codes[] = {
      BLOCK0_ID1_C0,  // CRYPT_M_ZIP
      BLOCK0_ID1_C1,  // CRYPT_M_BF
      BLOCK0_ID1_C2,  // CRYPT_M_BF2
+     BLOCK0_ID1_C3,  // CRYPT_M_SOD  - Unused!
  };
  #endif
  
***************
*** 426,436 ****
      {
        int method_nr = crypt_get_method_nr(buf);
  
!       if (method_nr > CRYPT_M_ZIP)
        {
            // Generate a seed and store it in the memfile.
            sha2_seed(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN, NULL, 0);
        }
      }
  }
  
--- 433,447 ----
      {
        int method_nr = crypt_get_method_nr(buf);
  
!       if (method_nr > CRYPT_M_ZIP && method_nr < CRYPT_M_SOD)
        {
            // Generate a seed and store it in the memfile.
            sha2_seed(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN, NULL, 0);
        }
+ #ifdef FEAT_SODIUM
+       else if (method_nr == CRYPT_M_SOD)
+           randombytes_buf(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN);
+  #endif
      }
  }
  
***************
*** 447,453 ****
        int method_nr = crypt_get_method_nr(buf);
  
        b0p->b0_id[1] = id1_codes[method_nr];
!       if (method_nr > CRYPT_M_ZIP)
        {
            // Generate a seed and store it in block 0 and in the memfile.
            sha2_seed(&b0p->b0_seed, MF_SEED_LEN, NULL, 0);
--- 458,464 ----
        int method_nr = crypt_get_method_nr(buf);
  
        b0p->b0_id[1] = id1_codes[method_nr];
!       if (method_nr > CRYPT_M_ZIP && method_nr < CRYPT_M_SOD)
        {
            // Generate a seed and store it in block 0 and in the memfile.
            sha2_seed(&b0p->b0_seed, MF_SEED_LEN, NULL, 0);
***************
*** 482,491 ****
      int               top;
      int               old_method;
  
!     if (mfp == NULL)
        return;  // no memfile yet, nothing to do
      old_method = crypt_method_nr_from_name(old_cm);
  
      // First make sure the swapfile is in a consistent state, using the old
      // key and method.
      {
--- 493,509 ----
      int               top;
      int               old_method;
  
!     if (mfp == NULL || mfp->mf_fd < 0)
        return;  // no memfile yet, nothing to do
      old_method = crypt_method_nr_from_name(old_cm);
  
+     if (old_method == CRYPT_M_SOD || crypt_get_method_nr(buf) == CRYPT_M_SOD)
+     {
+       // close the swapfile
+       mf_close_file(buf, TRUE);
+       buf->b_p_swf = FALSE;
+       return;
+     }
      // First make sure the swapfile is in a consistent state, using the old
      // key and method.
      {
***************
*** 911,917 ****
            || (b0p->b0_id[1] != BLOCK0_ID1
                && b0p->b0_id[1] != BLOCK0_ID1_C0
                && b0p->b0_id[1] != BLOCK0_ID1_C1
!               && b0p->b0_id[1] != BLOCK0_ID1_C2)
            )
        return FAIL;
      return OK;
--- 929,936 ----
            || (b0p->b0_id[1] != BLOCK0_ID1
                && b0p->b0_id[1] != BLOCK0_ID1_C0
                && b0p->b0_id[1] != BLOCK0_ID1_C1
!               && b0p->b0_id[1] != BLOCK0_ID1_C2
!               && b0p->b0_id[1] != BLOCK0_ID1_C3)
            )
        return FAIL;
      return OK;
***************
*** 2402,2408 ****
  
      FOR_ALL_BUFFERS(buf)
      {
!       if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL)
            continue;                       // no file
  
        ml_flush_line(buf);                 // flush buffered line
--- 2421,2429 ----
  
      FOR_ALL_BUFFERS(buf)
      {
!       if (buf->b_ml.ml_mfp == NULL
!               || buf->b_ml.ml_mfp->mf_fname == NULL
!               || buf->b_ml.ml_mfp->mf_fd < 0)
            continue;                       // no file
  
        ml_flush_line(buf);                 // flush buffered line
***************
*** 5320,5326 ****
      mch_memmove(new_data, dp, head_end - (char_u *)dp);
  
      // Encrypt the text.
!     crypt_encode(state, text_start, text_len, new_data + dp->db_txt_start);
      crypt_free_state(state);
  
      // Clear the gap.
--- 5341,5348 ----
      mch_memmove(new_data, dp, head_end - (char_u *)dp);
  
      // Encrypt the text.
!     crypt_encode(state, text_start, text_len, new_data + dp->db_txt_start,
!                                                                       FALSE);
      crypt_free_state(state);
  
      // Clear the gap.
***************
*** 5360,5366 ****
        if (state != NULL)
        {
            // Decrypt the text in place.
!           crypt_decode_inplace(state, text_start, text_len);
            crypt_free_state(state);
        }
      }
--- 5382,5388 ----
        if (state != NULL)
        {
            // Decrypt the text in place.
!           crypt_decode_inplace(state, text_start, text_len, FALSE);
            crypt_free_state(state);
        }
      }
***************
*** 5407,5413 ****
      // of the block for the salt.
      vim_snprintf((char *)salt, sizeof(salt), "%ld", (long)offset);
      return crypt_create(method_nr, key, salt, (int)STRLEN(salt),
!                                                          seed, MF_SEED_LEN);
  }
  
  #endif
--- 5429,5435 ----
      // of the block for the salt.
      vim_snprintf((char *)salt, sizeof(salt), "%ld", (long)offset);
      return crypt_create(method_nr, key, salt, (int)STRLEN(salt),
!                                                       seed, MF_SEED_LEN);
  }
  
  #endif
*** ../vim-8.2.3021/src/option.c        2021-06-20 12:40:05.342813034 +0200
--- src/option.c        2021-06-20 12:51:47.156478381 +0200
***************
*** 2713,2718 ****
--- 2713,2722 ----
                                || (opt_flags & OPT_GLOBAL) || opt_flags == 0)
                        && !curbufIsChanged() && curbuf->b_ml.ml_mfp != NULL)
                {
+ #ifdef FEAT_CRYPT
+                   if (crypt_get_method_nr(curbuf) == CRYPT_M_SOD)
+                       continue;
+ #endif
                    u_compute_hash(hash);
                    u_read_undo(NULL, hash, curbuf->b_fname);
                }
*** ../vim-8.2.3021/src/optionstr.c     2021-05-15 17:23:22.882858583 +0200
--- src/optionstr.c     2021-06-20 12:51:47.156478381 +0200
***************
*** 24,30 ****
  static char *(p_nf_values[]) = {"bin", "octal", "hex", "alpha", "unsigned", 
NULL};
  static char *(p_ff_values[]) = {FF_UNIX, FF_DOS, FF_MAC, NULL};
  #ifdef FEAT_CRYPT
! static char *(p_cm_values[]) = {"zip", "blowfish", "blowfish2", NULL};
  #endif
  static char *(p_cmp_values[]) = {"internal", "keepascii", NULL};
  static char *(p_dy_values[]) = {"lastline", "truncate", "uhex", NULL};
--- 24,34 ----
  static char *(p_nf_values[]) = {"bin", "octal", "hex", "alpha", "unsigned", 
NULL};
  static char *(p_ff_values[]) = {FF_UNIX, FF_DOS, FF_MAC, NULL};
  #ifdef FEAT_CRYPT
! static char *(p_cm_values[]) = {"zip", "blowfish", "blowfish2",
!  # ifdef FEAT_SODIUM
!     "xchacha20",
!  # endif
!     NULL};
  #endif
  static char *(p_cmp_values[]) = {"internal", "keepascii", NULL};
  static char *(p_dy_values[]) = {"lastline", "truncate", "uhex", NULL};
*** ../vim-8.2.3021/src/proto/blowfish.pro      2019-12-12 12:55:14.000000000 
+0100
--- src/proto/blowfish.pro      2021-06-20 13:19:20.803298483 +0200
***************
*** 1,6 ****
  /* blowfish.c */
! void crypt_blowfish_encode(cryptstate_T *state, char_u *from, size_t len, 
char_u *to);
! void crypt_blowfish_decode(cryptstate_T *state, char_u *from, size_t len, 
char_u *to);
  int crypt_blowfish_init(cryptstate_T *state, char_u *key, char_u *salt, int 
salt_len, char_u *seed, int seed_len);
  int blowfish_self_test(void);
  /* vim: set ft=c : */
--- 1,6 ----
  /* blowfish.c */
! void crypt_blowfish_encode(cryptstate_T *state, char_u *from, size_t len, 
char_u *to, int last);
! void crypt_blowfish_decode(cryptstate_T *state, char_u *from, size_t len, 
char_u *to, int last);
  int crypt_blowfish_init(cryptstate_T *state, char_u *key, char_u *salt, int 
salt_len, char_u *seed, int seed_len);
  int blowfish_self_test(void);
  /* vim: set ft=c : */
*** ../vim-8.2.3021/src/proto/crypt.pro 2019-12-12 12:55:16.000000000 +0100
--- src/proto/crypt.pro 2021-06-20 13:23:39.386482590 +0200
***************
*** 1,6 ****
--- 1,7 ----
  /* crypt.c */
  int crypt_method_nr_from_name(char_u *name);
  int crypt_method_nr_from_magic(char *ptr, int len);
+ int crypt_works_inplace(cryptstate_T *state);
  int crypt_get_method_nr(buf_T *buf);
  int crypt_whole_undofile(int method_nr);
  int crypt_get_header_len(int method_nr);
***************
*** 11,22 ****
  cryptstate_T *crypt_create_from_file(FILE *fp, char_u *key);
  cryptstate_T *crypt_create_for_writing(int method_nr, char_u *key, char_u 
**header, int *header_len);
  void crypt_free_state(cryptstate_T *state);
! void crypt_encode(cryptstate_T *state, char_u *from, size_t len, char_u *to);
! void crypt_encode_inplace(cryptstate_T *state, char_u *buf, size_t len);
! void crypt_decode_inplace(cryptstate_T *state, char_u *buf, size_t len);
  void crypt_free_key(char_u *key);
  void crypt_check_method(int method);
  void crypt_check_current_method(void);
  char_u *crypt_get_key(int store, int twice);
  void crypt_append_msg(buf_T *buf);
  /* vim: set ft=c : */
--- 12,30 ----
  cryptstate_T *crypt_create_from_file(FILE *fp, char_u *key);
  cryptstate_T *crypt_create_for_writing(int method_nr, char_u *key, char_u 
**header, int *header_len);
  void crypt_free_state(cryptstate_T *state);
! long crypt_encode_alloc(cryptstate_T *state, char_u *from, size_t len, char_u 
**newptr, int last);
! long crypt_decode_alloc(cryptstate_T *state, char_u *ptr, long len, char_u 
**newptr, int last);
! void crypt_encode(cryptstate_T *state, char_u *from, size_t len, char_u *to, 
int last);
! void crypt_encode_inplace(cryptstate_T *state, char_u *buf, size_t len, int 
last);
! void crypt_decode_inplace(cryptstate_T *state, char_u *buf, size_t len, int 
last);
  void crypt_free_key(char_u *key);
  void crypt_check_method(int method);
  void crypt_check_current_method(void);
  char_u *crypt_get_key(int store, int twice);
  void crypt_append_msg(buf_T *buf);
+ int crypt_sodium_init(cryptstate_T *state, char_u *key, char_u *salt, int 
salt_len, char_u *seed, int seed_len);
+ void crypt_sodium_encode(cryptstate_T *state, char_u *from, size_t len, 
char_u *to, int last);
+ void crypt_sodium_decode(cryptstate_T *state, char_u *from, size_t len, 
char_u *to, int last);
+ long crypt_sodium_buffer_encode(cryptstate_T *state, char_u *from, size_t 
len, char_u **buf_out, int last);
+ long crypt_sodium_buffer_decode(cryptstate_T *state, char_u *from, size_t 
len, char_u **buf_out, int last);
  /* vim: set ft=c : */
*** ../vim-8.2.3021/src/proto/crypt_zip.pro     2019-12-12 12:55:16.000000000 
+0100
--- src/proto/crypt_zip.pro     2021-06-20 13:23:49.774449777 +0200
***************
*** 1,5 ****
  /* crypt_zip.c */
  int crypt_zip_init(cryptstate_T *state, char_u *key, char_u *salt, int 
salt_len, char_u *seed, int seed_len);
! void crypt_zip_encode(cryptstate_T *state, char_u *from, size_t len, char_u 
*to);
! void crypt_zip_decode(cryptstate_T *state, char_u *from, size_t len, char_u 
*to);
  /* vim: set ft=c : */
--- 1,5 ----
  /* crypt_zip.c */
  int crypt_zip_init(cryptstate_T *state, char_u *key, char_u *salt, int 
salt_len, char_u *seed, int seed_len);
! void crypt_zip_encode(cryptstate_T *state, char_u *from, size_t len, char_u 
*to, int last);
! void crypt_zip_decode(cryptstate_T *state, char_u *from, size_t len, char_u 
*to, int last);
  /* vim: set ft=c : */
*** ../vim-8.2.3021/src/structs.h       2021-06-10 19:39:07.277697688 +0200
--- src/structs.h       2021-06-20 12:51:47.160478366 +0200
***************
*** 2513,2523 ****
  # define CRYPT_M_ZIP  0
  # define CRYPT_M_BF   1
  # define CRYPT_M_BF2  2
! # define CRYPT_M_COUNT        3 // number of crypt methods
  
  // Currently all crypt methods work inplace.  If one is added that isn't then
  // define this.
! //  # define CRYPT_NOT_INPLACE 1
  #endif
  
  #ifdef FEAT_PROP_POPUP
--- 2513,2524 ----
  # define CRYPT_M_ZIP  0
  # define CRYPT_M_BF   1
  # define CRYPT_M_BF2  2
! # define CRYPT_M_SOD    3
! # define CRYPT_M_COUNT        4 // number of crypt methods
  
  // Currently all crypt methods work inplace.  If one is added that isn't then
  // define this.
! # define CRYPT_NOT_INPLACE 1
  #endif
  
  #ifdef FEAT_PROP_POPUP
*** ../vim-8.2.3021/src/testdir/samples/crypt_sodium_invalid.txt        
2021-06-20 13:58:39.677389885 +0200
--- src/testdir/samples/crypt_sodium_invalid.txt        2021-06-20 
13:55:48.649862857 +0200
***************
*** 0 ****
--- 1,65 ----
+ VimCrypt~04!;ë &mÞÀ  yŽ} ¡)Bb¸  ã¹  7Z«â€ÏĄեbRÊ‘q ¡Z*Qªc}#Qxµ àWÕÇF"rô#A˜pÎ 
&Ÿ©{íàØvAF•FôXï þW– 5›Ñì÷ß4G¶2ݹ@ èõÅÆQ Ï)¾”¬FÑsÕõ–xùÅk9ü˜âΙ®HÚ ‰2B Ÿàþ)³Öã5 
"HÕr»Ô¶æ"÷‘),ÞÒ$‰º„KÈÙrÒHƒ‹U {n þ  !(Aê[¶â ˜ 
 Ÿñ­º— Ïz<k Bín´±5ýz­XN7Ø`A©ªdØ»†òÆËDt DO& Pr ‚¹1¦k
Qàû@r™ % w Á†õå&ô‘.05 ]‘Œ  Wwàokö)Ο$܆¶úÙ]÷ Ø å„Ñ~V"/zŸ•jiÙ  KzE ¡ ³§ ñ 
ËÀÊäˆ 9ŽW<Ä @ܵô$)XsZ–£e³„|ŽA¦eq,ìæMQ …ѬC–¬– Õ½ ‹æ£ñÏ ( ×.ì â{ 6ë÷X™­ë¥«LñT 
·¦»b™H2–Àsµöµë²÷|xC  ¦£çà×е['þÀU=7®2C$? ¦²¢v$÷ œ,aµÃ° œÑ „¡áÌúží: 
+ Tð ^bãQȘ.º,ßô9ª#ç Ô¼´èuóŽ Cñ…1÷%[” /FŸ ÷M=WqOUg†|3AðS³L•wRb¿ÑyÃñ* u€Ï:ܦ… 
;úG³ïø2  èšâ*çØ u­  Z ¿pE•‚ª^žšaP‹ Ûç^
ªóž`rÃ4ûzÅý6 *ÃS8‡\5æ¼Z 7™ ‹qî#hI œü§@Y¶"ì  ±†«+‚j[·Ü‰8F»«k  % B‘t•¤g' 
Šþ3ˆ¨”1ðôíp –Àžjªì žÊcæ“Y”  Wœ ö  lKAšÇR sy‚¸n—ú¾ˆ@O aÛ p›5/àWW3¢áâž W¾MÂΩ×RÑ
+ Í<HoÀ. Áe’  õÆFA7/³I#lLÁ 3—± ±v”">U¿¹š,êÑÔy§F
+ õgÆÿÇæ'Be¾x‹ >µcàºæÌ6 ù TB Áÿadœ! '†˜„÷ }^¡7Ýü‘˜Ù“1›®Öæ"EŽåöÜw÷ C] Ä 
¥13V“èVŽÎƒ = Õ—; õÛq _x¼ž˜ kÕ’ð8’;fdÔºÚþ&¨3P
+ ü© ¤Ï®=‘åH ˆ2 §¸ª­Gþ  
›  àÌua~…Åm -e ¢ð—­C³Q j .º¢À¢EKáôþC ˜å8²Ê—º¶ ¹  1X©×²ÅàºÆ«Ñ¯ ÅW_
+ smB Ýþ׿„I Ï Ä§C¤¿Ø½Æê"šßý– ÝCb"  ‚ ÑW/5ÇQÄ    2 :²…EvÕ'e¨ˆëgƒË¤˜:r TÙ¤ ˜ Œ…  
æ PE ¥e•q¢^^`0be/\t) ˜3EÜÂZ‡CWV*         C¿s&‘[‹"=µ  ˆ_£{ìÔuÆm4€èkEO}ÿì&lãdv¨
©×ÐB#´ÏáÊÞ9EÏûÜ&õ ÎÔÀT ž¢f.~v>·ÓÎ1‘ä
»nf›“.mªÈ áv     8aÌ»—z7ìEºO¥Ž³âç5F=v­/þ ÆUmg|Ì =ÀÓ –-Ž9¨  ?¢ÂG½úOódmþgý€ 8Ü 
ÎìÿÜ-E;ªEzú F¾@8œá Ú
‹Ø• qôR(## –o I* 1æ 탡+¼Ø PoôJ-ó­Uê ¦± hs¢¾JO¯M'
+ ³Ä uuMÓs–9+4­-®%í†ð³êÌ’]@Ðg4( ¾ G sù¼P— –„. #Š´žYî„nIµi» ÌZÓ/’/   à“_›.º 
öH"‘ú ÝWîŽöó þà ãO äoáÌ  }{'ï€"Z1ê)òC‰
 [–ñ CÑÁB€,šG c½ýŽéJß› å¯D '(©;‡Yt­ år›%Ñf°"íŸÖÊùÍÏžÀ²Ù‰ôM²„{ùRYJ ì ŒÂ <а] 
!­èð*.®  s«?¾nÂÅûv¬ßÄ ºÅdz ÇO>   ëm † ”Õn|{ûÞK «^“×Á-çÁ¦  ¯LTÑÿ% EÙ…­ ^eA ò   
„(}:ûPîè/e½Ên¹µ/ö°Ëna¦;Ä ›½°¤  &Ó… #¤ZCgVô•k¦ã4ZéSK ¡šNE -¼q…^p L¢Ù \_6X ~cà¨ì^ 
  ßàH eNPL Œ‚} éTœÃ9’I瓜W7n§€ Ñ ¨³’W@ $mJ Ly§ §qpºÊøßLšžao K• 
+ _œÙ¯ÎD …™àÏl‹]u± `>¯2ú4 ~­
×?p =Ü7 !¿  ÿé ¡ ;jA  Ì­K›] v Wu LÍKèŸ@€Á$,óÓ6è¹_Ëzv¾–ãìµh ¢B ’¼ãe the binary 
content
+   call system('xxd -r >Xtest.txt', a:hex)
+   call feedkeys(":split Xtest.txt\<CR>" . a:key . "\<CR>", 'xt')
+   call assert_equal(a:uncrypted_text, getline(1, len(a:uncrypted_text)))
+   bwipe!
+   call delete('Xtest.txt')
+   set key=
+ endfunc
+ 
  func Test_uncrypt_zip()
    call Uncrypt_stable('zip', 
"VimCrypt~01!\u0006\u001clV'\u00de}Mg\u00a0\u00ea\u00a3V\u00a9\u00e7\u0007E#3\u008e2U\u00e9\u0097",
 "foofoo", ["1234567890", "aábbccddeëff"])
  endfunc
***************
*** 78,87 ****
    call Uncrypt_stable('blowfish', 
"VimCrypt~02!k)\u00be\u0017\u0097#\u0016\u00ddS\u009c\u00f5=\u00ba\u00e0\u00c8#\u00a5M\u00b4\u0086J\u00c3A\u00cd\u00a5M\u00b4\u0086!\u0080\u0015\u009b\u00f5\u000f\u00e1\u00d2\u0019\u0082\u0016\u0098\u00f7\u000d\u00da",
 "barbar", ["asdfasdfasdf", "0001112223333"])
  endfunc
  
! func Test_uncrypt_blowfish2()
    call Uncrypt_stable('blowfish', 
"VimCrypt~03!\u001e\u00d1N\u00e3;\u00d3\u00c0\u00a0^C)\u0004\u00f7\u007f.\u00b6\u00abF\u000eS\u0019\u00e0\u008b6\u00d2[T\u00cb\u00a7\u0085\u00d8\u00be9\u000b\u00812\u000bQ\u00b3\u00cc@\u0097\u000f\u00df\u009a\u00adIv\u00aa.\u00d8\u00c9\u00ee\u009e`\u00bd$\u00af%\u00d0",
 "barburp", ["abcdefghijklmnopqrstuvwxyz", "!@#$%^&*()_+=-`~"])
  endfunc
  
  func Test_uncrypt_unknown_method()
    split Xuncrypt_unknown.txt
    set bin noeol key= fenc=latin1
--- 98,212 ----
    call Uncrypt_stable('blowfish', 
"VimCrypt~02!k)\u00be\u0017\u0097#\u0016\u00ddS\u009c\u00f5=\u00ba\u00e0\u00c8#\u00a5M\u00b4\u0086J\u00c3A\u00cd\u00a5M\u00b4\u0086!\u0080\u0015\u009b\u00f5\u000f\u00e1\u00d2\u0019\u0082\u0016\u0098\u00f7\u000d\u00da",
 "barbar", ["asdfasdfasdf", "0001112223333"])
  endfunc
  
! func Test_uncrypt_blowfish2a()
    call Uncrypt_stable('blowfish', 
"VimCrypt~03!\u001e\u00d1N\u00e3;\u00d3\u00c0\u00a0^C)\u0004\u00f7\u007f.\u00b6\u00abF\u000eS\u0019\u00e0\u008b6\u00d2[T\u00cb\u00a7\u0085\u00d8\u00be9\u000b\u00812\u000bQ\u00b3\u00cc@\u0097\u000f\u00df\u009a\u00adIv\u00aa.\u00d8\u00c9\u00ee\u009e`\u00bd$\u00af%\u00d0",
 "barburp", ["abcdefghijklmnopqrstuvwxyz", "!@#$%^&*()_+=-`~"])
  endfunc
  
+ func Test_uncrypt_blowfish2()
+   call Uncrypt_stable('blowfish2', 
"VimCrypt~03!\u001e\u00d1N\u00e3;\u00d3\u00c0\u00a0^C)\u0004\u00f7\u007f.\u00b6\u00abF\u000eS\u0019\u00e0\u008b6\u00d2[T\u00cb\u00a7\u0085\u00d8\u00be9\u000b\u00812\u000bQ\u00b3\u00cc@\u0097\u000f\u00df\u009a\u00adIv\u00aa.\u00d8\u00c9\u00ee\u009e`\u00bd$\u00af%\u00d0",
 "barburp", ["abcdefghijklmnopqrstuvwxyz", "!@#$%^&*()_+=-`~"])
+ endfunc
+ 
+ func Test_uncrypt_xchacha20()
+   CheckFeature sodium
+   let hex=['00000000: 5669 6d43 7279 7074 7e30 3421 6b7d e607  
vimCrypt~04!k}..',
+         \  '00000010: 4ea4 e99f 923e f67f 7b59 a80d 3bca 2f06  
N....>..{Y..;./.',
+         \  '00000020: fa11 b951 8d09 0dc9 470f e7cf 8b90 4310  
...Q....G.....C.',
+         \  '00000030: 653b b83b e493 378b 0390 0e38 f912 626b  
e;.;..7....8..bk',
+         \  '00000040: a02e 4697 0254 2625 2d8e 3a0b 784b e89c  
..F..T&%-.:.xK..',
+         \  '00000050: 0c67 a975 3c17 9319 8ffd 1463 7783 a1f3  
.g.u<......cw...',
+         \  '00000060: d917 dcb3 8b3e ecd7 c7d4 086b 6059 7ead  
.....>.....k`Y~.',
+         \  '00000070: 9b07 f96b 5c1b 4d08 cd91 f208 5221 7484  
...k\.M.....R!t.',
+         \  '00000080: 72be 0136 84a1 d3                        r..6...']
+   " the file should be in latin1 encoding, this makes sure that readfile()
+   " retries several times converting the multi-byte characters
+   call Uncrypt_stable_xxd('xchacha20', hex, "sodium_crypt", 
["abcdefghijklmnopqrstuvwxyzäöü", "ZZZ_äüöÄÜÖ_!@#$%^&*()_+=-`~"])
+ endfunc
+ 
+ func Test_uncrypt_xchacha20_invalid()
+   CheckFeature sodium
+   " load an invalid encrypted file and verify it can be decrypted with an
+   " error message
+   try
+     call feedkeys(":split samples/crypt_sodium_invalid.txt\<CR>sodium\<CR>", 
'xt')
+     call assert_false(1, 'should not happen')
+   catch
+     call assert_exception('pre-mature')
+   endtry
+   call assert_match("Note: Encryption of swapfile not supported, disabling 
swap- and undofile", execute(':5messages'))
+ 
+   call assert_equal(0, &swapfile)
+   call assert_equal("xchacha20", &cryptmethod)
+   call assert_equal('311111111111111111111111', getline('$'))
+   bw!
+ endfunc
+ 
+ func Test_uncrypt_xchacha20_2()
+   CheckFeature sodium
+   sp Xcrypt_sodium.txt
+   " Create a larger file, so that Vim will write in several blocks
+   call setline(1, range(1,4000))
+   call assert_equal(1, &swapfile)
+   set cryptmethod=xchacha20
+   call feedkeys(":X\<CR>sodium\<CR>sodium\<CR>", 'xt')
+   " swapfile disabled
+   call assert_equal(0, &swapfile)
+   call assert_match("Note: Encryption of swapfile not supported, disabling 
swap- and undofile", execute(':messages'))
+   w!
+   " encrypted using xchacha20
+   call assert_match("\[xchacha20\]", execute(':messages'))
+   bw!
+   call feedkeys(":sp Xcrypt_sodium.txt\<CR>sodium\<CR>", 'xt')
+   " successfully decrypted
+   call assert_equal(range(1, 4000)->map( {_, v -> string(v)}), getline(1,'$'))
+   set key=
+   w!
+   " enryption removed
+   call assert_match('"Xcrypt_sodium.txt" 4000L, 18893B written', 
execute(':message'))
+   bw!
+   call delete('Xcrypt_sodium.txt')
+   set cryptmethod&vim
+ endfunc
+ 
+ func Test_uncrypt_xchacha20_3_persistent_undo()
+   CheckFeature sodium
+   CheckFeature persistent_undo
+   sp Xcrypt_sodium_undo.txt
+   set cryptmethod=xchacha20 undofile
+   call feedkeys(":X\<CR>sodium\<CR>sodium\<CR>", 'xt')
+   call assert_equal(0, &undofile)
+   let ufile=undofile(@%)
+   call append(0, ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'])
+   call cursor(1, 1)
+ 
+   set undolevels=100
+   normal dd
+   set undolevels=100
+   normal dd
+   set undolevels=100
+   normal dd
+   set undolevels=100
+   w!
+   bw!
+   call feedkeys(":sp Xcrypt_sodium_undo.txt\<CR>sodium\<CR>", 'xt')
+   " should fail
+   norm! u
+   call assert_match('Already at oldest change', execute(':1mess'))
+   call assert_fails('verbose rundo' .. fnameescape(ufile), 'E822')
+   bw!
+   set undolevels& cryptmethod& undofile&
+   call delete('Xcrypt_sodium_undo.txt')
+ endfunc
+ 
+ func Test_encrypt_xchacha20_missing()
+   if has("sodium")
+     return
+   endif
+   sp Xcrypt_sodium_undo.txt
+   call assert_fails(':set cryptmethod=xchacha20', 'E474')
+   bw!
+   set cm&
+ endfunc
+ 
  func Test_uncrypt_unknown_method()
    split Xuncrypt_unknown.txt
    set bin noeol key= fenc=latin1
*** ../vim-8.2.3021/src/undo.c  2020-08-30 19:26:40.736556825 +0200
--- src/undo.c  2021-06-20 12:55:37.791731158 +0200
***************
*** 963,969 ****
  {
      if (bi->bi_buffer != NULL && bi->bi_state != NULL && bi->bi_used > 0)
      {
!       crypt_encode_inplace(bi->bi_state, bi->bi_buffer, bi->bi_used);
        if (fwrite(bi->bi_buffer, bi->bi_used, (size_t)1, bi->bi_fp) != 1)
            return FAIL;
        bi->bi_used = 0;
--- 963,971 ----
  {
      if (bi->bi_buffer != NULL && bi->bi_state != NULL && bi->bi_used > 0)
      {
!       // Last parameter is only used for sodium encryption and that
!       // explicitly disables encryption of undofiles.
!       crypt_encode_inplace(bi->bi_state, bi->bi_buffer, bi->bi_used, FALSE);
        if (fwrite(bi->bi_buffer, bi->bi_used, (size_t)1, bi->bi_fp) != 1)
            return FAIL;
        bi->bi_used = 0;
***************
*** 995,1001 ****
            if (copy == NULL)
                return 0;
        }
!       crypt_encode(bi->bi_state, ptr, len, copy);
        i = fwrite(copy, len, (size_t)1, bi->bi_fp);
        if (copy != small_buf)
            vim_free(copy);
--- 997,1005 ----
            if (copy == NULL)
                return 0;
        }
!       // Last parameter is only used for sodium encryption and that
!       // explicitly disables encryption of undofiles.
!       crypt_encode(bi->bi_state, ptr, len, copy, TRUE);
        i = fwrite(copy, len, (size_t)1, bi->bi_fp);
        if (copy != small_buf)
            vim_free(copy);
***************
*** 1129,1135 ****
                }
                bi->bi_avail = n;
                bi->bi_used = 0;
!               crypt_decode_inplace(bi->bi_state, bi->bi_buffer, bi->bi_avail);
            }
            n = size_todo;
            if (n > bi->bi_avail - bi->bi_used)
--- 1133,1139 ----
                }
                bi->bi_avail = n;
                bi->bi_used = 0;
!               crypt_decode_inplace(bi->bi_state, bi->bi_buffer, bi->bi_avail, 
FALSE);
            }
            n = size_todo;
            if (n > bi->bi_avail - bi->bi_used)
***************
*** 1176,1182 ****
        ptr[len] = NUL;
  #ifdef FEAT_CRYPT
        if (bi->bi_state != NULL && bi->bi_buffer == NULL)
!           crypt_decode_inplace(bi->bi_state, ptr, len);
  #endif
      }
      return ptr;
--- 1180,1186 ----
        ptr[len] = NUL;
  #ifdef FEAT_CRYPT
        if (bi->bi_state != NULL && bi->bi_buffer == NULL)
!           crypt_decode_inplace(bi->bi_state, ptr, len, FALSE);
  #endif
      }
      return ptr;
*** ../vim-8.2.3021/src/version.c       2021-06-20 12:40:05.342813034 +0200
--- src/version.c       2021-06-20 12:54:03.556035811 +0200
***************
*** 553,558 ****
--- 553,563 ----
  #else
        "-smartindent",
  #endif
+ #ifdef FEAT_SODIUM
+       "+sodium",
+ #else
+       "-sodium",
+ #endif
  #ifdef FEAT_SOUND
        "+sound",
  #else
*** ../vim-8.2.3021/src/version.c       2021-06-20 12:40:05.342813034 +0200
--- src/version.c       2021-06-20 12:54:03.556035811 +0200
***************
*** 752,753 ****
--- 757,760 ----
  {   /* Add new patch number below this line */
+ /**/
+     3022,
  /**/

-- 
Computers are useless. They can only give you answers.
                -- Pablo Picasso

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202106201203.15KC3BLr317168%40masaka.moolenaar.net.

Raspunde prin e-mail lui