For posterity, that patch is now on HEAD.  There are really two problems here: 1 that I note in the commit, and another that [sync] doesn't do any encryption or decryption, only [put] and [get].  Seems odd.

commit 6d13879bb6c8cc885b47a424427334c79dce86ab
Author: Matt Domsch <>
Date:   Tue Apr 22 19:37:26 2014 -0500

    don't use attrs md5 when file was gpg-encrypted by us
    Since 5fc2bbcc (2013-05-20 23:31:50 -0500), the value we stored into
    the s3cmd-attrs header for md5 contains the value for the plaintext,
    not the encrypted, instance of the file.  But after download we're
    (incorrectly) checking the md5 of the encrypted file. This patch fixes
    We started storing the md5 value in s3cmd-attrs header in 1703df7009
    (Fri Jun 15 23:43:00 2012).  So it's likely been broken for a couple
    years, and we'll have to deal with it (check both before and after
    decryption I suppose, in case it matches either).  That'll be another patch.
    With the new Content-MD5 branch too, calculating md5 before encrypting
    is a really really bad idea - that's just broken design.  Encryption
    should be done before we calculate the MD5 of the thing being
    uploaded.  It was the filename swizzle that caught me off guard.

On Tue, Apr 22, 2014 at 3:05 PM, Matt Domsch <> wrote:
Try this patch.  With the new Content-MD5 branch too, calculating md5 before encrypting is a really really bad idea - that's just broken design.  Encryption should be done long we calculate the MD5 of the thing being uploaded.
 Ugh.  Once we fix this, we need to somehow indicate (I'd propose using a new metadata value to denote encryption) whether encryption was done before or after MD5 was calculated. :-(

diff --git a/S3/ b/S3/
index 46068b8..121dee1 100644
--- a/S3/
+++ b/S3/
@@ -1148,10 +1148,14 @@ class S3(object):
                 response["md5"] = response["headers"]["etag"]
         md5_hash = response["headers"]["etag"]
-        try:
-            md5_hash = response["s3cmd-attrs"]["md5"]
-        except KeyError:
-            pass
+        if not 'x-amz-meta-s3tools-gpgenc' in response["headers"]:
+            # we can't trust our stored md5 because we
+            # encrypted the file after calculating it but before
+            # uploading it.
+            try:
+                md5_hash = response["s3cmd-attrs"]["md5"]
+            except KeyError:
+                pass
         response["md5match"] = md5_hash.find(response["md5"]) >= 0
         response["elapsed"] = timestamp_end - timestamp_start

On Tue, Apr 22, 2014 at 11:41 AM, Abrao Grynglas <> wrote:
Using the s3cmd version 1.5.0-beta1,  I receive a "MD5 signatures do not match" when downloading a file (no multipart involved) that was previously uploaded with GPG encryption.

It seems that the problem is caused by line 1026 in replacing the etag md5 value with the md5 value from s3cmd-attrs, which is the md5  before file encryption.

Could somebody please take a look at it?

Start Your Social Network Today - Download eXo Platform
Build your Enterprise Intranet with eXo Platform Software
Java Based Open Source Intranet - Social, Extensible, Cloud Ready
Get Started Now And Turn Your Intranet Into A Collaboration Platform
S3tools-general mailing list