aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Sokolovsky <paul.sokolovsky@linaro.org>2014-03-18 21:23:46 +0200
committerPaul Sokolovsky <paul.sokolovsky@linaro.org>2014-03-20 08:59:22 +0200
commit23a8ee2a833e752fd09309825743ce047d156b02 (patch)
tree37b1d5a4a4c830e0ea0d0ae30776807a4f609180
parent5e90312cff93c61e116e30db8cc06df143d1f9d1 (diff)
Initial version of git-gpgcrypt tool.
Portions are based on https://github.com/shadowhand/git-encrypt Change-Id: I16d33a95a69e4ab3f35c18a8e23e74ffbec46ffb
-rw-r--r--LICENSE20
-rw-r--r--README61
-rwxr-xr-xgit-gpgcrypt109
3 files changed, 190 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..b2e4c2c
--- /dev/null
+++ b/LICENSE
@@ -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.
diff --git a/README b/README
new file mode 100644
index 0000000..f42a08e
--- /dev/null
+++ b/README
@@ -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