git-annex/ encryption

git-annex mostly does not use encryption. Anyone with access to a git repository can see all the filenames in it, its history, and can access any annexed file contents.

Encryption is needed when using special remotes like Amazon S3, where file content is sent to an untrusted party who does not have access to the git repository.

Such an encrypted remote uses strong (symmetric or asymmetric) encryption on the contents of files, as well as HMAC hashing of the filenames. The size of the encrypted files, and access patterns of the data, should be the only clues to what is stored in such a remote.

You should decide whether to use encryption with a special remote before any data is stored in it. So, `git annex initremote` requires you to specify "encryption=none" when first setting up a remote in order to disable encryption. To use encryption, you run `git-annex initremote` in one of these ways:

- `git annex initremote newremote type=... encryption=hybrid keyid=KEYID`
- `git annex initremote newremote type=... encryption=shared`
- `git annex initremote newremote type=... encryption=pubkey keyid=KEYID`
- `git annex initremote newremote type=... encryption=sharedpubkey keyid=KEYID`

To see what encryption is used for a special remote, run `git annex info $remote` and look for a line like:

    encryption: hybrid (to gpg keys: AEC828149D85C538 C910D9122512E3C8)

## hybrid encryption keys (encryption=hybrid)

The hybrid key design allows additional encryption keys to be added on to a special remote later. Due to this flexibility, it is the default and recommended encryption scheme.

    git annex initremote newremote type=... [encryption=hybrid] keyid=KEYID

The KEYID is passed to `gpg` to find a gpg key. Typically, you will say "keyid=2512E3C7" to use a specific gpg key. Or, you might say "keyid=id@joeyh.name" to search for matching keys.

To add a new key and allow it to access all the content that is stored in the encrypted special remote, just run `git annex enableremote` specifying the keyid to add:

    git annex enableremote myremote keyid+=788A3F4C

You can repeat this process to add any number of gpg keys, including your own gpg keys and any public keys of others who you want to give access. Anyone with a corresponding secret key will be able to decrypt all content that is stored in the remote.

While a key can later be removed from the list, note that it will not prevent the owner of the key from accessing data on the remote (which is by design impossible to prevent, short of deleting the remote). In fact the only sound use of `keyid-=` is probably to replace a revoked key:

    git annex enableremote myremote keyid-=2512E3C7 keyid+=788A3F4C

See also encryption design for other security risks associated with encryption.

## shared encryption key (encryption=shared)

Alternatively, you can configure git-annex to use a shared cipher to encrypt data stored in a remote. This shared cipher is stored, unencrypted in the git repository. So it's shared among every clone of the git repository.

    git annex initremote newremote type=... encryption=shared

The advantage is you don't need to set up gpg keys. The disadvantage is that this is insecure unless you trust every clone of the git repository with access to the encrypted data stored in the special remote.

By default `gpg` is used for shared encryption, but it is also possible to use other programs that implement the Stateless OpenPGP command line interface. For example, to use Sequoia PGP's `sqop` command, configured to be backwards compatible with `gpg`:

    git config annex.shared-sop-command sqop
    git config annex.shared-sop-profile rfc4880

## regular public key encryption (encryption=pubkey)

This alternative simply encrypts the files in the special remotes to one or more public keys. The corresponding private key is needed to store anything in the remote, or access anything stored in it. It might be considered more secure due to its simplicity and since it's exactly the way everyone else uses gpg.

    git annex initremote newremote type=.... encryption=pubkey keyid=KEYID

A disadvantage is that it is not easy to later add additional public keys to the special remote. While the `enableremote` parameters `keyid+=` and `keyid-=` can be used, they have no effect on encrypted files that are already stored in the remote.

So if you need other public keys to also have access, it's best to add them immediately after initializing the remote:

    git-annex initremote newremote keyid+=788A3F4C

Another use for these parameters is to replace a revoked key:

    git annex enableremote myremote keyid-=2512E3C7 keyid+=788A3F4C

But even in this case, since the files are not re-encrypted, the revoked key has to be kept around to be able to decrypt those files. (Of course, if the reason for revocation is that the key has been compromised, it is insecure to leave files encrypted using that old key, and the user should re-encrypt everything.)

(A cipher still needs to be generated (and is encrypted to the given key IDs). It is only used for HMAC encryption of filenames.)

## regular public key encryption with shared filename encryption (encryption=sharedpubkey)

This is a variation on encryption=pubkey which lets anyone who has access to the gpg public keys store files in the special remote. But, only owners of the corresponding gpg private keys can retrieve the files from the special remote.

    git annex initremote newremote type=... encryption=sharedpubkey keyid=KEYID

This might be useful if you want to let others drop off files for you in a special remote, so that only you can access them.

The filenames used on the special remote are encrypted using HMAC, which prevents the special remote from seeing the filenames. But, anyone who can clone the git repository can access the HMAC cipher; it's stored unencrypted in the git repository.

## MAC algorithm

The default MAC algorithm to be applied on the filenames is HMACSHA1. A stronger one, for instance HMACSHA512, can be chosen upon creation of the special remote with the option `mac=HMACSHA512`. The available MAC algorithms are HMACSHA1, HMACSHA224, HMACSHA256, HMACSHA384, and HMACSHA512. Note that it is not possible to change algorithm for a non-empty remote.

## credentials storage

Special remotes that need some form of credentials, such as a password, may support embedding the credentials in the git repository, using embedcreds=yes. See individual special remotes' documentation for details.

When credentials are embedded in the repository, they're also encrypted using whatever encryption setting has been selected for the repository.

Such credentials are also cached locally in a file only you can read, in `.git/annex/creds/`. If you prefer to not expose the credentials on disk in unencrypted form, you can disable this cache, by setting the `annex.cachecreds` config to `false`.

To only encrypt the credentials, without encrypting any data stored in the special remote, use onlyencryptcreds=yes.

Encrypt to different subkeys?

Is it possible to encrypt with subkeys. I have a few subkeys distributed to different computers and I'd like to be able to sync to a special remote with all of them. Right now, if the master key is stripped, I get an error from gpg.

I do this exact thing with password-store. Appending "!" to the subkey id should force gpg to use that specific key: https://lists.zx2c4.com/pipermail/password-store/2014-September/001131.html.

Comment by Yurt — Wed Oct 29 14:05:27 2025
comment 8

@joern.mankiewicz, I see you found a bug and filed it, so will answer in the but report.

Barring bugs, adding another gpg key to a hybrid encryption special remote is as simple as `git annex enableremote $theremote keyid+=$newkey`

Comment by joey — Wed Oct 29 14:05:27 2025
Workflow for adding a keyid in hybrid-enc lateron and re-encrypting?

Hi folks!

We are considering introducing git-annex with gcrypt in hybrid mode as secure storage for common data in our company and I'd rather not delete and reinit the repo everytime when somebody new is granted access. A little testing with current git-annex showed, that GCRYPT_FULL_REPACK with a forced git-push of all branches makes the git-repo accessible (I get the files) to the newcomer but not the annexed data (gpg error "No secret key" in git annex get, git annex info secretRepo just lists my first key).

Has anybody sucessfully tested adding keyids in hybrid-encryption later on? Which further steps where needed to make it work?

Thanks for any input! :)

Cheers

Jörn

Comment by joern.mankiewicz — Wed Oct 29 14:05:27 2025
comment 6

@gavinwahl, it's a single shared key that any clone of the repository provides access to.

If you use the tahoe special remote, storing files in tahoe-lafs does result in a new capability (a kind of key) being stored in the git repo. So someone with an old clone can't access the files from tahoe-lafs. Tahoe is unique in providing that ability.

Comment by joey — Wed Oct 29 14:05:27 2025
Shared key - how many keys?

In shared mode, is a single key used to encrypt every file in the repository? Or is a new key created for each file?

Shared mode has the properties I need - getting access to the git repo should give you access to all the content. BUT, if one loses access to updates to the git repo, they should not have access to files added after they lost access.

Comment by gavinwahl — Wed Oct 29 14:05:27 2025
listing gpg keys

Run "git annex info specialremote" and it will describe the encryption settings of the remote, including gpg keys where applicable.

Needs a fairly recent git-annex. `git show git-annex:remote.log` can also be used.

Comment by joey — Wed Oct 29 14:05:27 2025
Listing GPG keys enabled for a remote with hybrid encryption
Is there a straight-forward way to list which GPG keys are enabled for a particular remote?
Comment by whlabratz — Wed Oct 29 14:05:27 2025
comment 2

@Giovanni, git is complaining that there is already a remote named "myremote" enabled in the current repository. Perhaps you have reused this name for a different remote.

(This seems to have nothing to do with the page the comment was posted to, which is a bit annoying. Please post questions in the forum and not attached to random other pages.)

Comment by joey — Wed Oct 29 14:05:27 2025
Re: Why is the default HMACSHA1 for shared encryption?

This is a HMACSHA1 of the git-annex key, so for a collision to be a problem you would need two files whose keys collide to be stored in the repository. And then the result would be that retrieving one of the files from the remote would fail when it verifies the downloaded file matches the hash. Which is not worth the bother of generating the collision.

The point of using HMAC here is not cryptographic collision resistance, but to prevent an attacker who does not have access to the git repository (and so lacks access to the HMAC secret key) from making guesses about what files are stored in an encrypted special remote that they do have access to. And HMACSHA1 accomplishes that as securely as HMACSHA256, I think.

Comment by joey — Wed Oct 29 14:05:27 2025
Why is the default HMACSHA1 for shared encryption?

I see that the shared encryption seems to use HMACSHA1 as the default. The https://git-annex.branchable.com/backends/ page indicates that SHA256E is the default backend used for the unencrypted key value store.

Is there a reason why the default for shared encryption is not HMACSHA256 to match the default used by unencrypted repos?

Does using HMACSHA1 present any caveats? I imagine something like collisions more likely with the older hashing algorithm. However, I don't know enough about how it works to make a good judgement on that.

Any insight is appreciated.

Thanks

Comment by liam — Wed Oct 29 14:05:27 2025
comment 17
It’s on the git-annex branch. See internals.
Comment by Ilya_Shlyakhter — Wed Oct 29 14:05:27 2025
reply

> Try getting the encrypted symmetric key from remote.log

Sorry, but where is that file? `find ./ -type f -name *.log` doesn't show me anything in this repository.

Comment by datamanager — Wed Oct 29 14:05:27 2025
hybrid encryption
With hybrid encryption, your gpg key encrypts a symmetric key which then encrypts file content. Try getting the encrypted symmetric key from `remote.log`, decrypting it with your gpg key, then using that to decrypt file content.
Comment by Ilya_Shlyakhter — Wed Oct 29 14:05:27 2025
comment 1

See https://git-annex.branchable.com/tips/Decrypting_files_in_special_remotes_without_git-annex/ for a small shell script that can do it.

Comment by joey — Wed Oct 29 14:05:27 2025
Can I manually decrypt my files?

I have a dropbox remote configured, and `git annex copy/move/get/etc` all seem to work just fine. I have hybrid encryption enabled on the remote, using my gpg key. So I thought, what if I were to download the encrypted file, and attempt to decrypt it locally. Would that work? It didn't work. Maybe I'm doing something wrong? I simply download the file through rclone, or the dropbox interface, and run `gpg --decrypt filename....` pinentry does ask for my password, but I don't think it's asking for the password to my gpg key. Maybe the file is encrypted twice? Once with my key, and again using a generic password that git-annex knows? I am not sure. Any help would be appreciated!

Comment by datamanager — Wed Oct 29 14:05:27 2025
Option to disable filename encyprtion
Are there plans to have a mac=PLAIN/NONE option?
Comment by johannes — Wed Oct 29 14:05:27 2025
headless configs

is there some combination of this and the gcrypt special remote that would give me the following properties:

1. password-less operation (ie. allow uploading content without the private key)
2. easy revocation and key rotation (ie. not encrypt directly with GnuPG but instead encrypt a keyfile with the public keys)

It seems to me this would be technically possible, no? A mix of "hybrid" and "sharedpubkey", basically...?

Hybrid works great, except I can't use it in my scenario because I am trying to automate backups and it will prompt me for the private key password. I guess the solution here is to have a special unencrypted private key for the batch job? Thanks! -- [[anarcat]

Comment by anarcat — Wed Oct 29 14:05:27 2025
comment 10

@Yurt, git-annex will let you specify the gpg key id using anything that gpg accepts, including a keyid with a appended '!'. However, when I tried that, gpg seemed to still pick the master key instead of the subkey. That happens because git-annex runs the input through `gpg --list-public-keys` (in order to convert eg, email addresses to key ids) which always lists the master key even when given a subkey.

I made a small change to git-annex to special case this '!' suffix behavior. Seems to work in my very limited testing.

Please file bug reports about this kind of thing!

Comment by joey — Wed Oct 29 14:05:27 2025
comment 1

I have a gcrypt special remote encrypted in hybrid mode, when I try to add a keyid using:

     git annex enableremote myremote keyid+=XXXXXXXX

I get this error:

     enableremote myremote (encryption update) (hybrid cipher with gpg keys XXXXXXXX XXXXXXX) fatal: remote myremote already exists.
     git-annex: git [Params "remote add",Param "myremote",Param "gcrypt::XXXXXXXXXXX:gcrypt-tests"] failed

this is my git-annex version info:

     git-annex version: 5.20141125
     build flags: Assistant Webapp Webapp-secure Pairing Testsuite S3 WebDAV Inotify DBus DesktopNotify XMPP DNS Feeds Quvi TDFA CryptoHash
     key/value backends: SHA256E SHA1E SHA512E SHA224E SHA384E SKEIN256E SKEIN512E SHA256 SHA1 SHA512 SHA224 SHA384 SKEIN256 SKEIN512 WORM URL
     remote types: git gcrypt S3 bup directory rsync web webdav tahoe glacier ddar hook external
     local repository version: 5
     supported repository version: 5
     upgrade supported from repository versions: 0 1 2 4

am I doing something wrong? thank you Giovanni

Comment by https://www.google.com/accounts/o8/id?id=AItOawlZ-6dtxJY4cP7shhvV8E6YyuV0Rak8it4 — Wed Oct 29 14:05:27 2025
Comments on this page are closed.