]> Nutra Git (v2) - gamesguru/git-remote-gcrypt.git/commitdiff
Use a separate symmetric key per packfile (REPO FORMAT CHANGE)
authorroot <root@localhost>
Thu, 14 Feb 2013 00:00:00 +0000 (00:00 +0000)
committerroot <root@localhost>
Thu, 14 Feb 2013 00:00:00 +0000 (00:00 +0000)
A separate key per pack is simpler and costs us very little; with
repack changes later it will be possible to change keys regularly.

README.rst
git-remote-gcrypt

index 90da3dd6fb2e36a4ed749dac40eeef59b1ac0d16..b1530266a003abdec5ae6104af07ea974ec841fe 100644 (file)
@@ -24,7 +24,7 @@ Example use::
     git push cryptremote master
     > gcrypt: Setting up new repository at ssh://example.com:repo
     > gcrypt: Repository ID  is KNBr0wKzct52
-    > gcrypt: Repository URL is gcrypt::ssh://example.com:repo/G/KNBr0wKzct52
+    > gcrypt: Repository URL is gcrypt::ssh://example.com:repo/G.KNBr0wKzct52
     > gcrypt: (configuration for cryptremote updated)
     > [ more lines .. ]
     > To gcrypt::[...]
@@ -70,37 +70,35 @@ Repository Format
     Encrypt(K,X) is symmetric encryption
     Hash(X)      is SHA-224
 
-    K: master key, generated once, 128 bytes
     B: branch list
-    L: list of packfile hashes
+    L: list of the hash (Hi) and key (Ki) for each packfile
     R: Hash(Repository ID)
     
-    Store Manifest as EncSign(K || B || L || R) in filename R
-    Each packfile P is stored as P' = Encrypt(K,P) in filename Hash(P')
-    L is the list of Hash(P').
+    Store Manifest as EncSign(B || L || R) in filename R
+    Store each packfile P as P' = Encrypt(Ki, P) in filename Hi
+        where Hi = Hash(P') and Ki is a random string
 
     To read the repository
 
-    decrypt+verify Manifest using private key -> (K, B, L, R)
+    decrypt+verify Manifest using private key -> (B, L, R)
     verify R matches Hash(Requested Repository ID)
-    for each entry in L:
-        get the entry from the server -> P'
-        verify  Hash(P') matches the entry in L
-        decrypt P' using K -> P -> open P with git
+    for Hi, Ki in L:
+        download file Hi from the server -> P'
+        verify Hash(P') matches Hi
+        decrypt P' using Ki -> P then open P with git
 
     Only packs mentioned in L are downloaded.
 
 + The manifest looks like this::
 
-    $ gpg -d < 9f42017de5cb482e509ff147d54ceeb0413d6379717f3f0db770f00a
-    T+pCUr/1FxbBC93ABIiIgG36EgqaxvgdNYjdmRSueGkgGETc4Qs7di+/yIsq2R5GysiqFaR0 \
-    bGSWf9omsoAH84hmED/kR/ZQiOGT/vg2Pg7CGI0xzdlW9GQjeFBAo4vsDDDBxrn5L7F9E532 \
-    LOnnPLSIZD7BpmyY/oZiXoP5Vlw=
-    b4a4a39365d19282810c19d0f3f24d04dd2d179f refs/tags/something
+    $ gpg -d < 5a191cea8c1021a95d813c4007c14f2cc987a40880c2f669430f1916
+    b4a4a39365d19282810c19d0f3f24d04dd2d179f refs/tags/version1
     1d323ddadf4cf1d80fced447e637ab3766b168b7 refs/heads/master
-    pack :SHA224:00ef27cc2c5b76365e1a46479ed7429e16572c543cdff0a8bf745c7c
-    pack :SHA224:b934d8d6c0f48e71b9d7a4d5ea56f024a9bed4f6f2c6f8e688695bee
-    repo 9f42017de5cb482e509ff147d54ceeb0413d6379717f3f0db770f00a
+    pack :SHA224:cfdf36515e0d0820554fe5fd9f00a4bee17bcf88ec8a752d851c46ee Rc+j8\
+    Nv6GOW3mBhWOx6W6jjz3BTX7B6XIJ6RYI+P4TEyy+X6p2PB/fsBL9la0Tuc
+    pack :SHA224:a43ccd208d3bd2ea582dbd5407cb8ed6e18b150b1da25c806115eaa5 UXR3/\
+    R7awFCUJWYdzXzrlkk7E2Acxq/Y4EfEcd62AwGGe0o0QxL+s5CwWI/NvMhb
+    repo :SHA224:5a191cea8c1021a95d813c4007c14f2cc987a40880c2f669430f1916 1
 
 
 Pieces yet to be Implemented
index b13b5b3286685bbc67db4062073ef6318f4a0a9c..4666e60cc06bf532e9b20ef557f0ed61f6cadfd2 100755 (executable)
@@ -15,7 +15,10 @@ export GITCEPTION="$GITCEPTION+" # Reuse $Gref except when stacked
 Gref="refs/gcrypt/gitception$GITCEPTION"
 Gref_rbranch="refs/heads/master"
 Repoid=
-Packpfx="pack :SHA224:"
+Hashpfx=":SHA224:"
+UrlTag="G."
+Packpfx="pack $Hashpfx"
+Packkey_len=48  # bytes of pack key
 
 # compat/utility functions
 xecho()
@@ -53,6 +56,7 @@ splitcolon()
        prefix_=${1%%:*}
        suffix_=${1#*:}
 }
+repoidstr() { xecho "repo $Hashpfx$Repoid 1"; }
 
 ## gitception part
 # Fetch giturl $1, file $2
@@ -182,18 +186,16 @@ CLEAN_FINAL()
 
 ENCRYPT()
 {
-       gpg --batch --force-mdc --compress-algo none \
-               --passphrase-fd 3 -c  3<<EOF
-$Masterkey
+       gpg --batch --force-mdc --compress-algo none --passphrase-fd 3 -c 3<<EOF
+$1
 EOF
 }
 
 DECRYPT()
 {
        gpg -q --batch --no-default-keyring --secret-keyring /dev/null \
-               --keyring /dev/null \
-               --passphrase-fd 3 -d  3<<EOF
-$Masterkey
+               --keyring /dev/null --passphrase-fd 3 -d  3<<EOF
+$1
 EOF
 }
 
@@ -260,7 +262,6 @@ make_new_repo()
        local urlid_= fix_config=
        echo_info "Setting up new repository at $URL"
        PUTREPO "$URL"
-       Masterkey="$(genkey 128)"
 
        # We need a relatively short ID for URL+REPO
        # The manifest will be stored at SHA224(urlid_)
@@ -269,12 +270,12 @@ make_new_repo()
        urlid_=$(genkey 9 | tr '/+' 'Zz')
        Repoid=$(xecho_n "$urlid_" | pack_hash)
        echo_info "Repository ID  is" "$urlid_"
-       isnoteq "${NAME#gcrypt::}" "$URL" && {
-               git config "remote.$NAME.url" "gcrypt::$URL/G/$urlid_"
+       iseq "${NAME#gcrypt::}" "$URL" || {
+               git config "remote.$NAME.url" "gcrypt::$URL/$UrlTag$urlid_"
                fix_config=1
-       } || :
-       echo_info "Repository URL is" "gcrypt::$URL/G/$urlid_"
-       isnonnull "$fix_config" && echo_info "(configuration for $NAME updated)"||:
+       }
+       echo_info "Repository URL is" "gcrypt::$URL/$UrlTag$urlid_"
+       isnull "$fix_config" || echo_info "(configuration for $NAME updated)"
 }
 
 
@@ -295,10 +296,10 @@ ensure_connected()
        read_config
 
        # split out Repoid from URL
-       url_id=${URL##*/G/}
-       iseq "$url_id" "$URL" && url_id= && return 0 || :
+       url_id=${URL##*/"$UrlTag"}
+       isnoteq "$url_id" "$URL" || return 0
 
-       URL=${URL%/G/"$url_id"}
+       URL=${URL%/"$UrlTag$url_id"}
        Repoid=$(xecho_n "$url_id" | pack_hash)
 
        TmpManifest_Enc="$Localdir/manifest.$$"
@@ -321,12 +322,10 @@ ensure_connected()
        rm -f "$TmpManifest_Enc"
        trap - EXIT
 
-       Masterkey=$(xecho "$manifest_" | head -n 1)
        Branchlist=$(xecho "$manifest_" | xgrep -E '^[0-9a-f]{40} ')
        Packlist=$(xecho "$manifest_" | xgrep "^$Packpfx")
        rcv_repoid=$(xecho "$manifest_" | xgrep "^repo ")
-       iseq "repo $Repoid" "$rcv_repoid" ||
-               echo_die "Repository id mismatch!"
+       iseq "$(repoidstr)" "$rcv_repoid" || echo_die "Repository id mismatch!"
 }
 
 do_capabilities()
@@ -343,7 +342,7 @@ do_list()
 
        xecho "$Branchlist" | while read line_
        do
-               isnull "$line_" && break || :
+               isnonnull "$line_" || break
                obj_id=${line_%% *}
                ref_name=${line_##* }
                echo_git "$obj_id" "$ref_name"
@@ -363,7 +362,7 @@ do_fetch()
        # The PACK id is the hash of the encrypted git packfile.
        # We only download packs mentioned in the encrypted manifest,
        # and check their digest when received.
-       local pack_= rcv_id= packline_= pneed_= pboth_= phave_=
+       local pack_= rcv_id= packline_= pneed_= pboth_= phave_= premote_= key_=
 
        ensure_connected
 
@@ -376,15 +375,16 @@ do_fetch()
        TmpPack_Encrypted="$Localdir/tmp_pack_ENCRYPTED_.$$"
        trap 'rm -f "$TmpPack_Encrypted"' EXIT
 
+       premote_=$(xecho "$Packlist" | cut -f 1-2 -d ' ')
        # Needed packs is  Packlist - (phave & Packlist)
        # The `+` for $GITCEPTION is pointless but we will be safe for stacking
        phave_="$(cat "$Localdir/have_packs+" 2>/dev/null || :)"
-       pboth_="$( (xecho "$Packlist"; xecho "$phave_") | sort_C | uniq -d)"
-       pneed_="$( (xecho "$Packlist"; xecho "$pboth_") | sort_C | uniq -u)"
+       pboth_="$( (xecho "$premote_"; xecho "$phave_") | sort_C | uniq -d)"
+       pneed_="$( (xecho "$premote_"; xecho "$pboth_") | sort_C | uniq -u)"
 
        xecho "$pneed_" | while read packline_
        do
-               isnull "$packline_" && continue || :
+               isnonnull "$packline_" || continue
                pack_=${packline_#"$Packpfx"}
                rcv_id="$(GET "$URL" "$pack_" | \
                        tee "$TmpPack_Encrypted" | pack_hash)"
@@ -392,7 +392,8 @@ do_fetch()
                then
                        echo_die "Packfile $pack_ does not match digest!"
                fi
-               DECRYPT < "$TmpPack_Encrypted" |
+               key_=$(xecho "$Packlist" | grep "$pack_" | cut -f 3 -d ' ')
+               DECRYPT "$key_" < "$TmpPack_Encrypted" |
                        git index-pack -v --stdin >/dev/null
                # add to local pack list
                xecho "$Packpfx$pack_" >> "$Localdir/have_packs$GITCEPTION"
@@ -410,7 +411,7 @@ do_push()
        # Each git packfile is encrypted and then named for the encrypted
        # file's hash. The manifest is updated with the pack id.
        # The manifest is encrypted.
-       local remote_has= remote_want= prefix_= suffix_= line_= pack_id=
+       local remote_has= remote_want= prefix_= suffix_= line_= pack_id= key_=
 
        ensure_connected
        check_recipients
@@ -447,16 +448,17 @@ EOF
 
        TmpPack_Encrypted="$Localdir/tmp_pack_ENCRYPTED_.$$"
        TmpObjlist="$Localdir/tmp_packrevlist.$$"
+       key_=$(genkey "$Packkey_len")
 
        append "$remote_has" "$remote_want" |
                git rev-list --objects --stdin -- |
                tee "$TmpObjlist" |
-               git pack-objects --stdout | ENCRYPT "$TmpPack_Encrypted"
+               git pack-objects --stdout | ENCRYPT "$key_">"$TmpPack_Encrypted"
        # Only send pack if we have any objects to send
        if [ -s "$TmpObjlist" ]
        then
                pack_id=$(pack_hash < "$TmpPack_Encrypted")
-               Packlist=$(append "$Packlist" "$Packpfx$pack_id")
+               Packlist=$(append "$Packlist" "$Packpfx$pack_id $key_")
                PUT "$URL" "$pack_id" < "$TmpPack_Encrypted"
        fi
 
@@ -466,15 +468,12 @@ EOF
 
        # Update manifest
        echo_info "Encrypting manifest to \"$Recipients\""
-       echo_info "Requesting manifest key signature"
+       echo_info "Requesting manifest signature"
 
        TmpManifest_Enc="$Localdir/manifest.$$"
        trap 'rm -f "$TmpManifest_Enc"' EXIT
 
-       (xecho "$Masterkey"
-       xecho "$Branchlist"
-       xecho "$Packlist"
-       xecho "repo $Repoid") |
+       (xecho "$Branchlist"; xecho "$Packlist"; repoidstr) |
                PRIVENCRYPT "$Recipients" > "$TmpManifest_Enc"
 
        PUT "$URL" "$Repoid" < "$TmpManifest_Enc"