1
0
Fork 0
You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

431 lines
15 KiB
VimL

" openssl.vim version 3.3 2008 Noah Spurrier <noah@noah.org>
"
" == Changelog
"
" 3.3~fc1
"
" • simple password safe can be either .auth.aes or .auth.bfa
"
" 3.3
"
" • change simple password safe from .auth.bfa to .auth.aes
"
" == Edit OpenSSL encrypted files and turn Vim into a Password Safe! ==
"
" This plugin enables reading and writing of files encrypted using OpenSSL.
" The file must have the extension of one of the ciphers used by OpenSSL.
" For example:
"
" .des3 .aes .bf .bfa .idea .cast .rc2 .rc4 .rc5
"
" This will turn off the swap file and the .viminfo log. The `openssl` command
" line tool must be in the path.
"
" == Install ==
"
" Put this in your plugin directory and Vim will automatically load it:
"
" ~/.vim/plugin/openssl.vim
"
" You can start by editing an empty unencrypted file. Give it one of the
" extensions above. When you write the file you will be asked to give it a new
" password.
"
" == Simple Vim Password Safe ==
"
" If you edit any file named '.auth.aes' or '.auth.bfa' (that's the full name,
" not just the extension) then this plugin will add folding features and an
" automatic quit timeout.
"
" Vim will quit automatically after 5 minutes of no typing activity (unless
" the file has been changed).
"
" This plugin will fold on wiki-style headlines in the following format:
"
" == This is a headline ==
"
" Any notes under the headline will be inside the fold until the next headline
" is reached. The SPACE key will toggle a fold open and closed. The q key will
" quit Vim. Create the following example file named ~/.auth.aes:
"
" == Colo server ==
"
" username: maryjane password: esydpm
"
" == Office server ==
"
" username: peter password: 4m4z1ng
"
" Then create this bash alias:
"
" alias auth='view ~/.auth.aes'
"
" Now you can view your password safe by typing 'auth'. When Vim starts all
" the password information will be hidden under the headlines. To view the
" password information put the cursor on the headline and press SPACE. When
" you write an encrypted file a backup will automatically be made.
"
" This plugin can also make a backup of an encrypted file before writing
" changes. This helps guard against the situation where you may edit a file
" and write changes with the wrong password. You can still go back to the
" previous backup version. The backup file will have the same name as the
" original file with .bak before the original extension. For example:
"
" .auth.aes --> .auth.bak.aes
"
" Backups are NOT made by default. To turn on backups put the following global
" definition in your .vimrc file:
"
" let g:openssl_backup = 1
"
" Thanks to Tom Purl for the original des3 tip.
"
" I release all copyright claims. This code is in the public domain.
" Permission is granted to use, copy modify, distribute, and sell this
" software for any purpose. I make no guarantee about the suitability of this
" software for any purpose and I am not liable for any damages resulting from
" its use. Further, I am under no obligation to maintain or extend this
" software. It is provided on an 'as is' basis without any expressed or
" implied warranty.
"
augroup openssl_encrypted
if exists("openssl_encrypted_loaded")
finish
endif
let openssl_encrypted_loaded = 1
autocmd!
function! s:OpenSSLReadPre()
if has("filterpipe") != 1
echo "Your systems sucks."
exit 1
endif
set secure
set cmdheight=3
set viminfo=
set clipboard=
set noswapfile
set noshelltemp
set shell=/bin/sh
set bin
set shellredir=>
endfunction
function! s:OpenSSLReadPost()
" Most file extensions can be used as the cipher name, but
" a few need a little cosmetic cleanup.
let l:cipher = expand("%:e")
let l:opts = "-pbkdf2 -salt"
if l:cipher == "aes"
let l:cipher = "aes-256-cbc"
let l:opts = l:opts . " -a"
endif
if l:cipher == "bfa"
let l:cipher = "bf"
let l:opts = l:opts . " -a"
endif
let l:defaultopts = l:opts
let l:expr = "0,$!openssl " . l:cipher . " " . l:opts . " -d -pass stdin -in " . expand("%")
let l:defaultexpr = l:expr
set undolevels=-1
let l:success = v:false
while ! l:success
silent! execute "0,$d _"
redraw!
if exists("l:a")
echo " "
echohl ErrorMsg
echo "ERROR -- COULD NOT DECRYPT"
echo "You may have entered the wrong password or"
echo "your version of openssl may not have the given"
echo "cipher engine built-in. This may be true even if"
echo "the cipher is documented in the openssl man pages."
echo "DECRYPT EXPRESSION: " . l:defaultexpr
echohl WarningMsg
echo " "
echo "Try a different password or leave blank to cancel."
echo " "
echohl None
endif
let l:a = inputsecret("Password: ")
" Replace encrypted text with the password to be used for decryption.
execute "0,$d _"
execute "normal i". l:a
" Replace the password with the decrypted file.
silent! execute l:expr
let l:success = ! v:shell_error
let b:OpenSSLDecryptSuccessful = l:success
function! s:AttemptDecrypt(opts) closure
if ! l:success
execute "0,$d _"
execute "normal i". l:a
let l:expr = "0,$!openssl " . l:cipher . " " . a:opts . " -d -pass stdin -in " . expand("%")
" Replace the password with the decrypted file.
silent! execute l:expr
let l:success = ! v:shell_error
endif
endfunction
" Be explicit about the current OpenSSL default of sha256.
call s:AttemptDecrypt("-pbkdf2 -salt -a -md sha256")
call s:AttemptDecrypt("-pbkdf2 -salt -md sha256")
call s:AttemptDecrypt("-pbkdf2 -salt -a -md md5")
call s:AttemptDecrypt("-pbkdf2 -salt -md md5")
" The following is only ne
if ! l:success
" For the rest of these, might need to filter out the warning
" about not using -pbkdf2, which looks like
" *** WARNING : deprecated key derivation used.
" Using -iter or -pbkdf2 would be better.
let l:outputEncrypted = "2,$!cat " . expand("%")
execute "0,$d _"
silent! execute "head -1 " . expand("%") . " | grep '^*** WARNING : deprecated key derivation used.$'"
if ! v:shell_error
let l:outputEncrypted = l:outputEncrypted . " | tail +3"
endif
endif
function! s:AttemptDecryptWithFilter(opts) closure
if ! l:success
execute "0,$d _"
execute "normal i". l:a
execute "normal o"
silent! execute l:outputEncrypted
let l:expr = "0,$!openssl " . l:cipher . " " . a:opts . " -d -pass stdin"
" Replace the password and encrypted file with the decrypted file.
silent! execute l:expr
let l:success = ! v:shell_error
endif
endfunction
call s:AttemptDecryptWithFilter("-salt -a -md sha256")
call s:AttemptDecryptWithFilter("-salt -md sha256")
call s:AttemptDecryptWithFilter("-salt -a -md md5")
call s:AttemptDecryptWithFilter("-salt -md md5")
" Don't bother with -nosalt and -md sha256 because those defaults
" never existed together in OpenSSL.
call s:AttemptDecryptWithFilter("-nosalt -a -md md5")
call s:AttemptDecryptWithFilter("-nosalt -md md5")
" Don't check for empty password before attempting to decrypt in
" order to support decrypting with an empty password.
if l:a == "" && ! l:success
" Cleanup.
set nobin
set cmdheight&
set shellredir&
set shell&
execute "0,$d _"
set undolevels&
redraw!
throw "Empty password entered. Ending decryption attempts."
endif
let l:a="These are not the droids you're looking for."
endwhile
unlet l:a
" Cleanup.
set nobin
set cmdheight&
set shellredir&
set shell&
execute ":doautocmd BufReadPost ".expand("%:r")
set undolevels&
redraw!
endfunction
function! s:OpenSSLWritePre()
set cmdheight=3
set shell=/bin/sh
set bin
set shellredir=>
if !exists("g:openssl_backup")
let g:openssl_backup=0
endif
if (g:openssl_backup)
if filereadable(expand("%"))
silent! execute '!cp % %:r.bak.%:e'
endif
endif
" Most file extensions can be used as the cipher name, but
" a few need a little cosmetic cleanup. AES could be any flavor,
" but I assume aes-256-cbc format with base64 ASCII encoding.
let l:cipher = expand("<afile>:e")
if l:cipher == "aes"
let l:cipher = "aes-256-cbc -a"
endif
if l:cipher == "bfa"
let l:cipher = "bf -a"
endif
let l:exprBase = "!openssl " . l:cipher . " -pbkdf2 -salt -pass stdin"
let l:expr = "0,$" . l:exprBase . " -e"
let l:shouldCheckPassword = (exists("b:OpenSSLDecryptSuccessful") && b:OpenSSLDecryptSuccessful)
if ! l:shouldCheckPassword
let l:a = inputsecret(" New password: ")
else
let l:a = inputsecret(" Password: ")
endif
if l:a == ""
" Clean up because OpenSSLWritePost won't get called.
set nobin
set shellredir&
set shell&
set cmdheight&
throw "Empty password. This file has not been saved."
endif
if ! l:shouldCheckPassword
let l:ac = inputsecret("Retype new password: ")
else
" Attempt decrypting the existing file with the encryption
" password to check if it's the same password.
let l:decryptExpr = "1" . l:exprBase . " -d -in " . expand("%")
silent! execute "0goto"
silent! execute "normal i" . l:a . "\n"
silent! execute l:decryptExpr . " >/dev/null 2>/dev/null"
silent! undo
if v:shell_error
echohl WarningMsg
echo " "
echo "Warning: Password is different from decryption password."
echo "If intending to change the encryption password, retype the new password."
echo " "
echohl None
let l:ac = inputsecret("Retype new password: ")
else
let l:ac = l:a
endif
endif
if l:a != l:ac
let l:a ="These are not the droids you're looking for."
unlet l:a
let l:ac="These are not the droids you're looking for."
unlet l:ac
echohl ErrorMsg
echo "\n"
echo "ERROR -- COULD NOT ENCRYPT"
echo "The new password and the confirmation password did not match."
echo "This file has not been saved."
echo "ERROR -- COULD NOT ENCRYPT"
echohl None
" Clean up because OpenSSLWritePost won't get called.
set nobin
set shellredir&
set shell&
set cmdheight&
throw "Password mismatch. This file has not been saved."
endif
" Encrypt twice, first time take only the error output to capture it.
" Then do the actual encryption.
silent! execute "0goto"
silent! execute "normal i". l:a . "\n"
set shellredir=2>
silent! execute l:expr . " 2>&1 >/dev/null"
set shellredir=>
" Backup @" register and restore it afterward.
let l:register_tmp = getreg('"', 1, 1)
let l:register_tmp_mode = getregtype('"')
silent! 0,$y
let l:openssl_error = @"
call setreg('"', register_tmp, register_tmp_mode)
unlet l:register_tmp
unlet l:register_tmp_mode
silent! undo
silent! execute "0goto"
silent! execute "normal i". l:a . "\n"
silent! execute l:expr
" Cleanup.
let l:a ="These are not the droids you're looking for."
unlet l:a
let l:ac="These are not the droids you're looking for."
unlet l:ac
if v:shell_error
" Something for OpenSSLWritePost() to undo
silent! 0,$y _
" Undo the encryption.
call s:OpenSSLWritePost()
echohl ErrorMsg
echo "\n"
echo "ERROR -- COULD NOT ENCRYPT"
echo "Your version of openssl may not have the given"
echo "cipher engine built-in. This may be true even if"
echo "the cipher is documented in the openssl man pages."
echo "ENCRYPT EXPRESSION: " . expr
echo "ERROR FROM OPENSSL:"
echo "\n"
echo l:openssl_error
echo "\n"
echo "ERROR -- COULD NOT ENCRYPT"
echohl None
throw "OpenSSL error. This file has not been saved."
endif
if l:openssl_error !~ "^[\s\r\n]\*$"
redraw!
echohl WarningMsg
echo "OpenSSL output the following warning:"
echo " "
echo l:openssl_error
echo " "
echo "This usually means openssl.vim needs to be updated or modified."
echohl None
echo "Press any key to continue..."
let char = getchar()
redraw!
endif
endfunction
function! s:OpenSSLWritePost()
" Undo the encryption.
silent! undo
set nobin
set shellredir&
set shell&
set cmdheight&
redraw!
endfunction
autocmd BufReadPre,FileReadPre *.des3,*.des,*.bf,*.bfa,*.aes,*.idea,*.cast,*.rc2,*.rc4,*.rc5,*.desx call s:OpenSSLReadPre()
autocmd BufReadPost,FileReadPost *.des3,*.des,*.bf,*.bfa,*.aes,*.idea,*.cast,*.rc2,*.rc4,*.rc5,*.desx call s:OpenSSLReadPost()
autocmd BufWritePre,FileWritePre *.des3,*.des,*.bf,*.bfa,*.aes,*.idea,*.cast,*.rc2,*.rc4,*.rc5,*.desx call s:OpenSSLWritePre()
autocmd BufWritePost,FileWritePost *.des3,*.des,*.bf,*.bfa,*.aes,*.idea,*.cast,*.rc2,*.rc4,*.rc5,*.desx call s:OpenSSLWritePost()
"
" The following implements a simple password safe for any file named
" '.auth.aes' or '.auth.bfa'. The file is encrypted with AES and base64 ASCII
" encoded. Folding is supported for == headlines == style lines.
"
function! HeadlineDelimiterExpression(lnum)
if a:lnum == 1
return ">1"
endif
return (getline(a:lnum)=~"^\\s\\?\\*\\s.*$") || (getline(a:lnum)=~"^\\s*==.*==\\s*$") ? ">1" : "="
endfunction
autocmd BufReadPost,FileReadPost *.auth.*,logins.* set foldexpr=HeadlineDelimiterExpression(v:lnum)
autocmd BufReadPost,FileReadPost *.auth.*,logins.* set foldlevel=0
autocmd BufReadPost,FileReadPost *.auth.*,logins.* set foldcolumn=0
autocmd BufReadPost,FileReadPost *.auth.*,logins.* set foldmethod=expr
autocmd BufReadPost,FileReadPost *.auth.*,logins.* set foldtext=getline(v:foldstart)
autocmd BufReadPost,FileReadPost *.auth.*,logins.* nnoremap <silent><space> :exe 'silent! normal! za'.(foldlevel('.')?'':'l')<CR>
autocmd BufReadPost,FileReadPost *.auth.*,logins.* nnoremap <silent>q :q<CR>
autocmd BufReadPost,FileReadPost *.auth.*,logins.* highlight Folded ctermbg=red ctermfg=black
autocmd BufReadPost,FileReadPost *.auth.*,logins.* set updatetime=300000
autocmd CursorHold *.auth.*,logins.* quit
" End of openssl_encrypted
augroup END