Open nhantrn opened 5 years ago
Are you really using a text editor with built-in encryption?
Why not use some other program that allows working with encrypted file containers? It's much more reliable and flexible and doesn't involve temporary files (temporary files are the weak spot of archive-based encryption like 7-zip, that's true).
I'm using it as secondary protection and for non critical info. Just something quick and dirty for around the office use.
I see what you mean. It's possible we may implement it but much simpler (incompatible with that mod). I see no reason to use any libraries for software encryption and/or hashing, Windows CryptoAPI is more than enough for such use case.
Anyway, we have to close some other tasks first.
@cshnik
There are 3 flavours of the same format.
Format 1 is OpenSSL's verbatim format: magic string = Salted__
, 8-byte salt, encrypted data.
Format 2 is format 1 without the magic string (so there's no identification and the data looks like random noise).
Format 3 is format 1 prepended with key slot(s). Each slot is a format 2 data - a master passphrase (mpassphrase) encrypted with different user-supplied passphrases. Each slot is 40 bytes long (8 for salt, 32 for AES block size). Data of format 1 (which follows the key slots) is encrypted with mpassphrase.
Number of slots may be different but never more than MaxKeySlots. This number is calculated by dividing offset of Salted__
(format 1 start) by 40.
The main data is encrypted with a common mpassphrase and master salt (msalt). See openssl enc
examples in the File command
section.
_______________ format 3 ______________
/ \
[slot 1] [slot 2] ... Salted__ msalt data
40 B 40 B 8 B 8 B *
format 2 format 2 \____ format 1 ___/
Format detection:
Salted__
- format 1Salted__
within the first MaxKeySlots 40 bytes + 1 (5 40 + 1 = 201) and Salted__
0-based offset is even to 40 - format 3Therefore Notepad 2e must have 2 internal fundamental encryption functions: one for format 2 encryption, another - for format 2 decryption, both using CryptoAPI. Other 2 formats' functions are based on these 2 functions.
You can use this openssl enc
command to generate encrypted data in format 1 (result is 32-byte long, note that each time it's different because of the random salt):
echo -n hello | openssl aes-256-cbc -md md5 -pass pass:sEcReT | xxd
To decrypt, use the -d
switch:
openssl aes-256-cbc -md md5 -pass pass:sEcReT -d -in encrypted.file
With regular encryption, AES needs an IV and a key. openssl enc
derives both from the salt and the password - see EVP_BytesToKey()
in OpenSSL's sources.
AES-256's key length is 32 bytes, IV length is 16 bytes.
Encrypte&d
Create &Desktop Link
to ...Lin&k
&Encrypt
&Decrypt
5
There is a single new dialog - prompt for the password(s). It's shown on secure desktop.
Besides OK/Cancel buttons it contains N inputs (N = MaxKeySlots): Passphrase &N:
(e.g. Passphrase &2:
).
Both work on the selection or, if it's blank, on the entire buffer. If the operation was successful, the selection (buffer) is replaced by the new content, and re-selected (if there was no selection, entire buffer is replaced and selected). If failed, selection is unchanged and user sees an error message.
Encrypt displays the prompt and produces a data stream (cipher-text) in format 1 (because it's binary, user should enable Binary-Safe Save #170).
Decrypt displays the prompt and produces another data stream (plain-text), or possibly junk if the passphrase specified were incorrect (there's no verification except padding).
Works on the entire buffer ignoring current selection, and resets selection to the start of the buffer when called.
EncryptedFileIO indicates if the buffer should be silently encrypted when saving (FileIO).
When File > Encrypted is called and EncryptedFileIO is true - just set EncryptedFileIO to false. (Reload/F5 would reset EncryptedFileIO and display the garbled encrypted data.)
When File > Encrypted is called and EncryptedFileIO is false - check if the buffer is in format 1 or 3 (not 2).
If it is format 1, display the prompt, decrypt the entire buffer (replace window text), set CachedKeySlots to null and set EncryptedFileIO to true.
If it is format 3, display the prompt, iterate over all key slots (each in format 2), decrypt a slot (mpassphrase), decrypt the main data (format 1), replace the window's text with decrypted buffer, set CachedKeySlots (part before format 3, Salted__
) and set EncryptedFileIO to true.
if neither 1 nor 3, display the prompt and set EncryptedFileIO to true. Do not actually encrypt/change the buffer's contents/window text.
Passphrase
inputs are enabledPassphrase &1
Passphrase &1
, 2nd with junk (unusable), 3rd with Passphrase &3
Passphrase 1
is not blank, set it to CachedPassphrase and set CachedKeySlots to nullIntended usage scenario: user starts with cipher-text or plain-text, calls File > Encrypt to mark it as "encrypt-on-save" and possibly decrypt it; then continues to edit the same plain-text and when he saves it, it gets encrypted internally thanks to the FileIO change (below).
Note: if Encrypt/Decrypt prompts are cancelled or if a encryption/decryption error occurs, this is treated as command failure and global variables' and window's state is unchanged.
On writing to a file (FileIO), if EncryptedFileIO is true the buffer is silently encrypted as format 1 or 3 and then written (window's text and global variables are left as is).
Salted__
(because mpassphrase remains the same and user's CachedPassphrase is able to decrypt one of the key slots)Notes:
In the end, when using File > Encrypted, it should be possible to decrypt openssl enc
streams as well as produce streams recognized by openssl enc -d
.
Example of producing a format 3 data using standard tools:
dd if=/dev/urandom of=mpassphrase bs=20 count=1
echo -n hello | openssl aes-256-cbc -md md5 -pass fd:3 3<mpassphrase -out format-1
openssl aes-256-cbc -md md5 -pass pass:sEcReT -in mpassphrase | xxd -p -seek 8 | xxd -r -p >key-slot-1
openssl aes-256-cbc -md md5 -pass pass:pRiNcEsS -in mpassphrase | xxd -p -seek 8 | xxd -r -p >key-slot-2
cat key-slot-* format-1 >format-3
To decode a format-3 given any one of the key slots' passphrases (no mpassphrase):
xxd -p -seek 0 -len 40 format-3 | xxd -r -p >key-slot-1
xxd -p -seek 40 -len 40 format-3 | xxd -r -p >key-slot-2
xxd -p -seek 80 format-3 | xxd -r -p >format-1
echo -n Salted__ | cat - key-slot-2 | openssl aes-256-cbc -d -md md5 -pass pass:pRiNcEsS -out mpassphrase
openssl aes-256-cbc -d -md md5 -pass fd:3 3<mpassphrase -in format-1
As part of this task, write unit tests relying on openssl
to validate encryption/decryption results. Let's assume some environment variable like NP2E_OPENSSL
pointing to openssl.exe
is set on the test system.
echo -n hello | openssl aes-256-cbc -md md5 -pass pass:sEcReT | xxd
I suspect if you try this today you will get warnings (along the lines of https://unix.stackexchange.com/questions/507131/openssl-1-1-1b-warning-using-iter-or-pbkdf2-would-be-better-while-decrypting) with suggestions to use the "new" KDF.
However using the new KDF will result in a number of iterations significantly lower than is recommended.
Encryption support would be great, but not this implementation. Doe you have support (or plans) for buffer/filters where the editor reads stdout from a subprocess (e.g. popen())? Vim and emacs make use of this to shell out to an external exe to handle this. This does require the editor NOT perform file up and instead read/write pipes to the subprocess.
The ccrypt section in https://vim.fandom.com/wiki/Encryption has a good example (along with gpg)
Do you have support (or plans) for buffer/filters where the editor reads stdout from a subprocess (e.g. popen())? Vim and emacs make use of this to shell out to an external exe to handle this.
I suppose we can buffer the entire pipe or stdin in memory, that's what Notepad2 already does when reading regular files. We don't need input or output to be seekable. But the saving operation (if it's directed to a pipe or stdout) will be essentially one-off, after which Notepad 2e will quit, right?
This will require some work on UI (disable Revert, etc.) as well as a new option for specifying the output (disabling Save As, etc.):
openssl enc -d ... | Notepad2e.exe - - | openssl enc ...
@ProgerXP I've not seen any editor support that construct. As you said, it would really be limited to a single read and write and be very limiting. Usually piping into stdin of an editor is considered a one time read only operation.
I was suggesting support in the editor to internally call an OS routine like popen() https://man7.org/linux/man-pages/man3/popen.3.html
Take a look at the vim example link above for usage. Any read or write goes through custom config.
https://github.com/clach04/puren_tonbo/blob/main/integrations/scite/pt_scite.lua includes lua code that works with Scite (another scintilla based editor that uses lua for user config/scripting) when opening files with specific file extensions instead of regular fopen() calls.
I see your idea. I'll note it but I can't promise any implementation date. It's not a priority at the moment.
Can you add the encryption module from https://github.com/RaiKoHoff/notepad2-mod-crypto ? It's based on XhmikosR's build, but it's been archived.