diff options
author | Paul Sokolovsky <paul.sokolovsky@linaro.org> | 2014-03-18 21:23:46 +0200 |
---|---|---|
committer | Paul Sokolovsky <paul.sokolovsky@linaro.org> | 2014-03-20 08:59:22 +0200 |
commit | 23a8ee2a833e752fd09309825743ce047d156b02 (patch) | |
tree | 37b1d5a4a4c830e0ea0d0ae30776807a4f609180 | |
parent | 5e90312cff93c61e116e30db8cc06df143d1f9d1 (diff) |
Initial version of git-gpgcrypt tool.
Portions are based on https://github.com/shadowhand/git-encrypt
Change-Id: I16d33a95a69e4ab3f35c18a8e23e74ffbec46ffb
-rw-r--r-- | LICENSE | 20 | ||||
-rw-r--r-- | README | 61 | ||||
-rwxr-xr-x | git-gpgcrypt | 109 |
3 files changed, 190 insertions, 0 deletions
@@ -0,0 +1,20 @@ +Copyright (c) 2011 Woody Gilk <woody.gilk@gmail.com> +Copyright (c) 2014 Linaro Ltd. http://linaro.org + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. @@ -0,0 +1,61 @@ +Transparent git encryption using GPG public key infrastructure +============================================================== + +This script allows to encrypt some (or all) files in a git repository using +existing GPG public key infrastructure. It allows to set access list of +key IDs which can access files, and then all decryption and encryption +is handled transparently, while performing usual git operations (assuming +current user is in existing access list, and has public keys of other +recipients). + +git-gpgcrypt is inspired by (and based on) https://github.com/shadowhand/git-encrypt +project, which uses symmetric encryption scheme and +http://thread.gmane.org/gmane.comp.version-control.git/113124/focus=113189 +thread which initially explored using GPG for git encryption. + +Usage: + +Installation +------------ +1. git clone https://git.linaro.org/infrastructure/git-gpgcrypt.git +2. Put git-gpgcrypt/git-gpgcrypt somewhere on PATH + + +New repository +-------------- +1. git init +2. Create ".recipients" file listing key names of persons who may access +encrypted files in the repository. These may be either key IDs or +substrings of user IDs (e.g., emails). Note that corresponding keys must +be already present in your keyring (TODO: add convenience command to import +keys from keyserver). +3. git gpgcrypt init +4. Review .gitattributes file for file encryption settings (it's not required +to encrypt all files; in particular, default .gitattributes makes README and +some other files plain-text). +5. Add files and use repository as usual. + +Cloned repository +----------------- +1. git clone +2. git gpgcrypt init + +Update list of recipients +------------------------- +1. Update list in .recipients +2. git gpgcrypt update +3. TODO: Set up git hook for automatic update. + + +Implementation details +---------------------- +GPG encryption is non-deterministic (meaning that encrypting same cleartext +2 times produces different ciphertexts). So, if GPG encryption is used +directly, it can lead to spurious empty commits (specifically it was found +that after cloning and initializing existing repository, freshly decrypted +files are marked as changed, even though cleartext matches one in HEAD). +To work that around, some of GPG message encryption process was reimplemented: +files are encrypted using deterministic symmetric cipher, while cipher key +is encrypted using GPG for each of repository recipients. That roughly +corresponds to how GPG handles message encryptions itself (but it applies +additional padding and randomization). diff --git a/git-gpgcrypt b/git-gpgcrypt new file mode 100755 index 0000000..082acbd --- /dev/null +++ b/git-gpgcrypt @@ -0,0 +1,109 @@ +#!/bin/bash + +if [ -z "$GIT_DIR" ]; then + GIT_DIR=".git" +fi + +CIPHER=aes-256-ecb +SALT="123456789abcdef" + +init() { + # From git 1.7.8+, the .git in submodule folder is a file containing the actual path of gitdir. + if [ -f "$GIT_DIR" ]; then + GIT_DIR=`cat $GIT_DIR | sed 's/^gitdir: //'` + fi + + if [ ! -d "$GIT_DIR" ]; then + echo "Not a git repository. Did you run 'git init'?" + exit 1 + fi + + if [ ! -f .recipients ]; then + echo "Before running 'init' create .recipients file, and add to it target key IDs" + echo "(one per line). IDs can be either key fingerprints, substrings of user IDs" + echo "(e.g., emails) or whatever else gpg accepts for --recipient option (man gpg)." + exit 1 + fi + + if [ -f .key ]; then + git diff-index --quiet HEAD + clean=$? + if [ $clean -eq 1 ]; then + echo "Intended to initialize gpgcrypt in fresh clone, but your working copy/index" + echo "is not clean. Not doing anything. If you intended to initialize a fresh" + echo "clone either, something went wrong, you may need to clone again (or deal with" + echo "pending changes, then run '$0 init' again, then" + echo "'git checkout HEAD^; git checkout master', or remove everything but .git" + echo "directory and run 'git checkout .', or )" + else + setup_filters + git checkout -f . + echo "Initialized a clone" + fi + return + fi + + echo "* filter=encrypt diff=encrypt" >>.gitattributes + echo "# You probably want to describe in README why one can't see anything useful in other files" >>.gitattributes + echo "README !filter !diff" >>.gitattributes + echo "# Don't encrypt recipient list, you can comment this to encrypt it" >>.gitattributes + echo ".recipients !filter !diff" >>.gitattributes + echo "# Never encrypt .gitattributes and .key files" >>.gitattributes + echo ".gitattributes !filter !diff" >>.gitattributes + echo ".key !filter !diff" >>.gitattributes + echo "[merge]" >>.gitattributes + echo " renormalize=true" >>.gitattributes + touch .recipients + + KEY=$(cat /dev/urandom | LC_ALL="C" tr -dc '!@#$%^&*()_A-Z-a-z-0-9' | head -c32) + + encrypt_key "$KEY" + + setup_filters + + echo "git gpgcrypt initialized." + echo + + git add .gitattributes .recipients .key + git commit .gitattributes .recipients .key -m "Initialized git gpgcrypt state." +} + +setup_filters() { + git config filter.encrypt.smudge "git-gpgcrypt smudge" + git config filter.encrypt.clean "git-gpgcrypt clean" + git config diff.encrypt.textconv "git-gpgcrypt diff" +} + +get_key() { + gpg -d -q --batch --no-tty .key +} + +encrypt_key() { + echo "$1" | gpg -ea --group gr="$(cat .recipients|tr '\n' ' ')" -r gr >.key +} + +case "$1" in + init) + init + ;; + update) + encrypt_key "$(get_key)" + ;; + clean) + #gpg -ea --group gr="$(cat .recipients|tr '\n' ' ')" -r gr + openssl enc -base64 -$CIPHER -S $SALT -k "$(get_key)" + ;; + smudge) + #gpg -d -q --batch --no-tty || cat + openssl enc -d -base64 -$CIPHER -k "$(get_key)" 2> /dev/null || cat + ;; + diff) + #gpg -d -q --batch --no-tty "$2" 2>/dev/null || cat "$2" + openssl enc -d -base64 -$CIPHER -k "$(get_key)" -in "$2" 2> /dev/null || cat "$2" + ;; + *) + echo "$0 - Set up transparent GPG encryption for files in git repository" + echo "usage: $0 init" + exit 1 + ;; +esac |