It will force a lock even if working directory is unclean. Useful
for deconfiguring git-crypt if you've accidentally unlocked with the
wrong key or gotten into a similarly sticky situation.
This will let us run 'git lock' even if no filters are configured.
This logic is more complicated than I would like because running
'git config --remove-section' on a non-existent section results in
a noisy error (with text printed to stderr and an exit code of 128)
instead of a quiet error like the other 'git config' commands.
Starting with Git 2.2.2, `git checkout -f HEAD` no longer checks out
files if their mtimes haven't changed. This causes files to remain
encrypted in the work tree after running `git-crypt unlock`, and to
remain decrypted after running `git-crypt lock`'.
To fix this, git-crypt now figures out what files are encrypted (by
checking `git check-attr` on every file output by `git ls-files`),
touches those files, and then runs `git checkout` on them.
Previously, if you had a .gitattributes file in the root of your
repository that matched `*`, the files under .git-crypt would also be
encrypted, rendering the repository un-decryptable, unless you explicitly
excluded the .git-crypt directory, which was easy to overlook.
Now, `git-crypt add-gpg-user` automatically adds a .gitattributes file
to the .git-crypt directory to prevent its encryption.
IMPORTANT: If you are currently using GPG mode to encrypt an entire
repository, it is strongly advised that you upgrade git-crypt and then
do the following to ensure that the files inside .git-crypt are stored
properly:
1. Remove existing key files: `rm .git-crypt/keys/*/0/*`
2. Re-add GPG user(s): `git-crypt add-gpg-user GPG_USER_ID ...`
While writing the documention, I found that "GPG user" was less confusing
terminology than "GPG key," since you aren't really adding a "key"
to git-crypt, and git-crypt already uses "key" to refer to other concepts
(cf. the -k/--key-name options).
This does the reverse of what git-crypt unlock does:
- unconfigures the git filters
- forcibly checks out HEAD version
Usage:
git crypt lock locks repo using the "default" key
git crypt lock -k NAME locks the repo, using unlocked key named NAME
git crypt lock --key-name=NAME
git crypt lock -a locks the repo, removing ALL unlocked keys
git crypt lock --all
Result is that you can now decrypt and then revert back to encrypted
form of files and vice versa.
Modified-by: Andrew Ayer <agwa@andrewayer.name>
* Make argv argument to lock() const.
* Minor whitespace/style fixes to conform to project conventions.
Signed-off-by: Andrew Ayer <agwa@andrewayer.name>
Since Git consults the checked-out .gitattributes instead of the
.gitattributes in effect at the time the file was committed, Git
may invoke the smudge filter on old versions of a file that were
committed without encryption.
Git-crypt's position has always been that authentication is best left
to Git, since 1) Git provides immutable history based on SHA-1 hashes
as well as GPG-signed commits and tags, and 2) git-crypt can't be used
safely anyways unless the overall integrity of your repository is assured.
But, since git-crypt already has easy access to a (truncated) HMAC of the
file when decrypting, there's really no reason why git-crypt shouldn't
just verify it and provide an additional layer of protection.
Storing the key name in the key file makes it unnecessary to pass the
--key-name option to git-crypt unlock.
This breaks compatibility with post-revamp keys. On the plus side,
keys are now extensible so in the future it will be easier to make
changes to the format without breaking compatibility.
This will help distinguish keys encrypted with GPG from keys encrypted by
other means. (For example, a future version of git-crypt might support
passphrase-encrypted keys.)
The init, export-key, add-collab, and unlock commands now
take an optional -k (equivalently, --key-name) option to
specify an alternative key. Files can be encrypted with
the alternative key by specifying the git-crypt-KEYNAME filter
in .gitattributes. Alternative key support makes it possible
to encrypt different files with different keys.
Note that the -k option to unlock is temporary. Unlock
will eventually auto-detect the name of the key you're
unlocking, either by looking in the symmetric key file,
or by scanning the .git-crypt/keys directory.
Note that the layout of the .git/git-crypt and .git-crypt
directories has changed as follows:
* .git/git-crypt/key is now .git/git-crypt/keys/default
* .git-crypt/keys is now .git-crypt/keys/default
'git-crypt status' tells you which files are and aren't encrypted and
detects other problems with your git-crypt setup.
'git-crypt status -f' can be used to re-stage files that were incorrectly
staged unencrypted.
The UI needs work, and it needs to also output the overall repository
status (such as, is git-crypt even configured yet?), but this is a
good start.
Don't bother checking for !in because the gcount() check is quite
sufficient and having both checks was confusing.
Make some variables const because they can be.
This abstracts away the details of argument quoting, which differs
between Unix and Windows.
Also replace all uses of the system() library call with exec_command().
Although system() exists on Windows, it executes the command via cmd.exe,
which has ridiculous escaping rules.
Move Unix-specific code to util-unix.cpp, and place Windows equivalents
in util-win32.cpp. Most of the Windows functions are just stubs at
the moment, and we need a build system that works on Windows.
Run 'git-crypt add-collab KEYID' to authorize the holder of the given
GPG secret key to access the encrypted files. The secret git-crypt key
will be encrypted with the corresponding GPG public key and stored in the
root of the Git repository under .git-crypt/keys.
After cloning a repo with encrypted files, run 'git-crypt unlock'
(with no arguments) to use a secret key in your GPG keyring to unlock
the repository.
Multiple collaborators are supported, however commands to list the
collaborators ('git-crypt ls-collabs') and to remove a collaborator
('git-crypt rm-collab') are not yet supported.
The active key is now stored in .git/git-crypt/key instead of being
stored outside the repo. This will facilitate GPG support, where the
user may never interact directly with a key file. It's also more
convenient, because it means you don't have to keep the key file
around in a fixed location (which can't be moved without breaking
git-crypt).
'git-crypt init' now takes no arguments and is used only when initializing
git-crypt for the very first time. It generates a brand-new key, so
there's no longer a separate keygen step.
To export the key (for conveyance to another system or to a collaborator),
run 'git-crypt export-key FILENAME'.
To decrypt an existing repo using an exported key, run 'git-crypt unlock
KEYFILE'. After running unlock, you can delete the key file you passed
to unlock.
Key files now use a new format that supports key versioning (which will
facilitate secure revocation in the future).
I've made these changes as backwards-compatible as possible. Repos
already configured with git-crypt will continue to work without changes.
However, 'git-crypt unlock' expects a new format key. You can use
the 'git-crypt migrate-key KEYFILE' command to migrate old keys to the
new format.
Note that old repos won't be able to use the new commands, like
export-key, or the future GPG support. To migrate an old repo, migrate
its key file and then unlock the repo using the unlock command, as
described above.
While making these changes, I cleaned up the code significantly, adding
better error handling and improving robustness.
Next up: GPG support.
Rationale:
* /dev/random blocks unpredictably on Linux, leading to slow
key generation.
* OpenSSL's RNG is more cross-platform than /dev/(u)random.
Some platforms might not have a (u)random device, or worse,
have a /dev/(u)random that produces insecure random numbers
(like Cygwin, apparently).