【问题标题】:How do I do symmetric encryption with the python gnupg module vers. 1.2.5?如何使用 python gnupg 模块 vers 进行对称加密。 1.2.5?
【发布时间】:2014-05-04 17:32:49
【问题描述】:

我正在尝试使用 python 和 gnupg 进行对称加密。

这段代码 sn-p 在我的 windows vista 机器上运行,python gnupg 模块的版本是 0.3.2:

import gnupg
gpg = gnupg.GPG()
data = 'the quick brown fow jumps over the laxy dog.'
passphrase='12345'
crypt = gpg.encrypt(data, recipients=None,
                     symmetric='AES256',
                     passphrase=passphrase,
                     armor=False)

当我尝试使用版本 1.2.5 python gnupg 模块在我的 linux 机器上运行它时,我收到此错误:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
  File "/usr/local/lib/python2.7/dist-packages/gnupg/gnupg.py", line 961, in encrypt
    result = self._encrypt(stream, recipients, **kwargs)
TypeError: _encrypt() got multiple values for keyword argument 'recipients'

我已经进行了多次搜索,但找不到任何内容。

【问题讨论】:

    标签: python encryption gnupg


    【解决方案1】:

    这是一个老问题,但我在 Google 搜索中发现了这个问题,并且对提供的答案不满意。我在 python-gnupg 的 GitHub 问题中找到了真正的答案:

    gpg.encrypt(data, symmetric='AES256', passphrase=passphrase, armor=False, encrypt=False)

    所以,删除recipients=None 并添加encrypt=False。然后,您的 crypt.data 将包含加密数据。不直观,但它有效。

    (src:https://github.com/isislovecruft/python-gnupg/issues/110)

    【讨论】:

    • 加密似乎有效,关于如何解密的任何想法? gpg.decrypt(crypt.data, passphrase=passphrase) 似乎不起作用...
    • gpg.encrypt(data, recipients=None, symmetric='AES256', passphrase=passphrase, armour=False) 适用于最后一个版本
    【解决方案2】:

    我认为它只是坏了(如果我错了,请纠正我)。对于 Python 3.x,它似乎已在 gnupg 0.3.6-1 中修复。您可能最好使用它或尝试一种解决方法,例如类似于我将要描述的方法。

    此解决方法在 Python 中使用命令行 gpg 而不是 gnupg 模块。当然,您可以使用 gpg.encrypt_file 做类似的解决方法(它没有我在下一段中谈到的临时存储的密码;这很可能是一个更好的选择)。

    如果您担心任务管理器中显示的密码短语,我会通过将密码放入临时文件并使用 cat 将其通过管道传输到 gpg 来解决这个问题。但是,您可能不得不担心恶意软件会从临时文件中窃取密码,如果它能够及时做到的话。

    请注意,此代码在 Python 3.x 中,因为这是我最常使用的(要在 2.x 中重新创建它,您必须了解临时文件在其中的工作方式,也许还有其他一些东西)。

    import subprocess, tempfile, os, shutil
    
    def gpg_encrypt(data, passphrase, alg="AES256", hash="SHA512", compress_alg="BZIP2", compress_lvl="9", iterations="1000000"):
        #This is for symmetric encryption.
        with tempfile.TemporaryDirectory() as directory:
            filepath=os.path.join(directory, "tmp")
            with open(filepath, "w") as FILE:
                FILE.write(data)
            iterations=str(iterations)
            compress_level="--compress-level "+compress_lvl
            if compress_alg.upper()=="BZIP2":
                compress_level="--bzip2-compress-level "+compress_lvl
            tmp_filename="tmp"
            with tempfile.TemporaryDirectory() as DIR:
                tmpfilepath=os.path.join(DIR, tmp_filename)
                with open(tmpfilepath, "w") as FILE:
                    FILE.write(passphrase)
                subprocess.Popen("cat "+tmpfilepath+"|gpg --batch --yes --passphrase-fd 0 --force-mdc --s2k-mode 3 --s2k-count "+iterations+" --s2k-cipher-algo "+alg+" --s2k-digest-algo "+hash+" --compress-algo='"+compress_alg+"' --compress-level "+compress_lvl+" -ac '"+filepath+"'", stdin=subprocess.PIPE, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, shell=True).communicate()[0]
            result=None
            with open(filepath+".asc", "r") as FILE:
                result=FILE.read()
            return result
    
    def gpg_decrypt(data, passphrase):
        #This is for decryption.
        with tempfile.TemporaryDirectory() as directory:
            filepath=os.path.join(directory, "tmp")
            with open(filepath, "w") as FILE:
                FILE.write(data)
            decrypted=None
            tmp_filename="tmp"
            with tempfile.TemporaryDirectory() as DIR:
                tmpfilepath=os.path.join(DIR, tmp_filename)
                with open(tmpfilepath, "w") as FILE:
                    FILE.write(passphrase)
                decrypted=subprocess.Popen("cat "+tmpfilepath+"|gpg --batch --yes --passphrase-fd 0 --output='"+filepath+".gpg"+"' '"+filepath+"'", stdin=subprocess.PIPE, shell=True, stderr=subprocess.STDOUT, stdout=subprocess.PIPE).communicate()[0]
            result=None
            decrypted=not "decryption failed:" in str(decrypted)
            if decrypted==True:
                with open(filepath+".gpg", "r") as FILE:
                    result=FILE.read()
        return decrypted, result #If it worked, return True. If not, return False. (And, return the decrypted data.)
    
    test=gpg_encrypt(data="This is a test!", passphrase="enter")
    print("Here is the encrypted message:\n"+test)
    decrypted, data=gpg_decrypt(data=test, passphrase="enter")
    if decrypted:
        print("Here is the decrypted message:\n"+data)
    else:
        print("Incorrect passphrase to decrypt the message.")
    

    这是加密/解密对称加密文件的代码(只是为了更好的衡量):

    import subprocess, tempfile, os, shutil
    
    def gpg_encrypt_file(filepath, passphrase, output=None, alg="AES256", hash="SHA512", compress_alg="BZIP2", compress_lvl="9", iterations="1000000"):
        #This is for symmetric encryption.
        filepath=filepath.replace("'", "'\\''") #This makes it so you can have apostrophes within single quotes.
        iterations=str(iterations)
        compress_level="--compress-level "+compress_lvl
        if compress_alg.upper()=="BZIP2":
            compress_level="--bzip2-compress-level "+compress_lvl
        result=None
        tmp_filename="tmp"
        with tempfile.TemporaryDirectory() as DIR:
            tmpfilepath=os.path.join(DIR, tmp_filename)
            with open(tmpfilepath, "w") as FILE:
                FILE.write(passphrase)
            if output:
                if output[0]!=os.sep and filepath[0]==os.sep:
                    output=os.path.join(os.path.dirname(filepath), output)
                result=subprocess.Popen("cat "+tmpfilepath+"|gpg --batch --yes --passphrase-fd 0 --force-mdc --s2k-mode 3 --s2k-count "+iterations+" --s2k-cipher-algo "+alg+" --s2k-digest-algo "+hash+" --compress-algo='"+compress_alg+"' "+compress_level+" --output='"+output+"' -ac '"+filepath+"'", stdin=subprocess.PIPE, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, shell=True).communicate()[0]
            else:
                result=subprocess.Popen("cat "+tmpfilepath+"|gpg --batch --yes --passphrase-fd 0 --force-mdc --s2k-mode 3 --s2k-count "+iterations+" --s2k-cipher-algo "+alg+" --s2k-digest-algo "+hash+" --compress-algo='"+compress_alg+"' --compress-level "+compress_lvl+" -ac '"+filepath+"'", stdin=subprocess.PIPE, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, shell=True).communicate()[0]
        return result.strip()
    
    def gpg_decrypt_file(filepath, passphrase, output=None):
        #This is for decryption.
        filepath=filepath.replace("'", "'\\''")
        result=None
        tmp_filename="tmp"
        with tempfile.TemporaryDirectory() as DIR:
            tmpfilepath=os.path.join(DIR, tmp_filename)
            with open(tmpfilepath, "w") as FILE:
                FILE.write(passphrase)
            if output:
                if output[0]!=os.sep and filepath[0]==os.sep:
                    output=os.path.join(os.path.dirname(filepath), output)
                result=subprocess.Popen("cat "+tmpfilepath+"|gpg --batch --yes --passphrase-fd 0 --output='"+output+"' '"+filepath+"'", stdin=subprocess.PIPE, shell=True, stderr=subprocess.STDOUT, stdout=subprocess.PIPE).communicate()[0]
            else:
                result=subprocess.Popen("cat "+tmpfilepath+"|gpg --batch --yes --passphrase-fd 0 '"+filepath+"'", stdin=subprocess.PIPE, shell=True, stderr=subprocess.STDOUT, stdout=subprocess.PIPE).communicate()[0]
        return not "decryption failed:" in str(result) #If it worked, return True. If not, return False.
    
    gpg_encrypt_file(filepath="test.txt", passphrase="myPassphrase", output="test.asc")
    if gpg_decrypt_file(filepath="test.asc", passphrase="myPassphrase", output="output.txt"):
        print("Successfully decrypted!")
    else:
        print("Incorrect passphrase.")
    

    【讨论】:

      【解决方案3】:

      仔细检查the documentation,参数不是recipient,是recipients(注意复数)

      文档(强调我的):

      对称(默认为 False)如果指定,对称加密是 用过的。在这种情况下,请将 recipients 指定为 None。如果指定了 True, 然后使用默认密码算法 (CAST5)。从...开始 0.3.5 版,您还可以指定要使用的密码算法(例如 例如,“AES256”)。检查你的 gpg 命令行帮助,看看有什么 支持对称密码算法。注意默认 (CAST5) 可能不是最好的。

      【讨论】:

      • 使用gpg.encrypt(data, recipients=None, symmetric='AES256', passphrase=passphrase, armor=False) 我得到TypeError: _encrypt() got multiple values for keyword argument 'recipients'
      • 在我的完整代码中是recipients,但是当我拿出代码 sn-p 来提问时,s 不知何故丢失了。
      【解决方案4】:

      这应该适用于 python-gnupg 0.3.5 及更高版本(根据需要进行调整):

      import gnupg
      
      gpg_home = "~/.gnupg"
      gpg = gnupg.GPG(gnupghome=gpg_home)
      
      data = raw_input("Enter full path of file to encrypt: ")
      phrase = raw_input("Enter the passphrase to decrypt the file: ")
      cipher = raw_input("Enter symmetric encryption algorithm to use: ")
      savefile = data+".asc"
      
      afile = open(data, "rb")
      encrypted_ascii_data = gpg.encrypt_file(afile, None, passphrase=phrase, symmetric=cipher.upper(), output=savefile)
      afile.close()
      

      不确定 0.3.5 之前的版本。

      当调用 gpg.encrypt_file() 时,收件人的“无”(对于当前版本的模块)不需要“收件人=无”。

      【讨论】:

      • 我没有使用gpg.encrypt_file。我正在使用gpg.encrypt,因为我的数据来自 python 代码作为字符串,而不是来自文件。将它传递给String.IO并使用gpg.encrypt_file会更好吗?
      • 使用 'gpg.encrypt(data, None, symmetric='AES256', passphrase=passphrase, armour=False)' 我得到ValueError: Unknown status message: u'NO_RECP'
      猜你喜欢
      • 2021-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 1970-01-01
      • 1970-01-01
      • 2019-08-10
      相关资源
      最近更新 更多