【问题标题】:GnuPG - How to edit the file without decrypt and save to local disk first?GnuPG - 如何在不解密的情况下编辑文件并先保存到本地磁盘?
【发布时间】:2009-10-02 15:04:31
【问题描述】:

我正在使用 GNUPG 加密我的 ascii 文件。

我学会了生成密钥,以及如何使用它来加密和解密文件。

我使用了两种方式:

gpg -d foo.txt.gpg

gpg --output foo.txt --decrypt
foo.txt.gpg

我意识到第一种方法会在屏幕上显示解密后的文件,例如当我通过 SSH 执行命令时。

关于第二种方法,我担心它是否会在本地电脑上留下痕迹 - foo.txt 文件。

最重要的是,我不知道如何即时编辑 foo 文件的内容。 理想情况下,我想通过 SSH 使用 nano/pico 打开文件,输入我的密码来解密,然后编辑文件,保存并加密它。我非常希望避免将任何文件保存到本地磁盘。

欢迎任何cmets。

提前谢谢你。

【问题讨论】:

    标签: linux encryption gnupg


    【解决方案1】:

    一种方法是使用vim。见this page 和这个related question.

    如果您需要更大的灵活性或不想使用vim,编写一个简短的程序来读取来自 STDOUT 的解密文本,根据自己的喜好进行编辑,然后重新加密并不难。例如,您可以使用this minimal Python code(104 行!)为您提供最基本的编辑器,然后自己添加流读写功能。

    【讨论】:

      【解决方案2】:

      要记住的一件事是,将未加密的数据保存在内存中并不能保证它不会找到磁盘。如果有问题的系统负载过重,任何未加密的数据都可能被写入交换分区。同样,如果系统进入睡眠模式,任何挂起的进程的状态都将存储到磁盘中。如果你的程序运行在嵌入式系统上,可以想象你的内存和“磁盘”是一体的。

      mlock() 系统调用将保护分配的内存不被交换到磁盘。但是,这需要管理权限并将您限制为您直接负责内存管理的低级语言。

      也就是说,谨慎的做法是避免使用未加密的数据创建文件。只要知道,如果底层系统受到威胁,这并不能为您提供 100% 的安全。

      【讨论】:

      • 另一个(更好的?)将敏感数据交换到磁盘的解决方案是加密交换分区。完成后,您不再需要担心交换的内容。
      【解决方案3】:

      我编写了一个 python 脚本来解决这个问题(仅适用于 Linux)。它通过将文件解密到 /dev/shm 来确保未加密的数据永远不会写入磁盘(尽管任何使用数据的程序都可能交换到磁盘;这几乎总是一个问题)。

      与其他一些已发布的答案相比,这有一些好处:

      • 只需输入一次密码
      • 适用于任何编辑器

      代码如下:

      #!/usr/bin/python
      import os, sys, subprocess, getpass, stat, shutil
      
      editor = 'nano'
      dataFile = sys.argv[1]
      
      ## make a backup of the encrypted file
      bakFile = dataFile+'-gpgedit_backup'
      shutil.copy(dataFile, bakFile)
      dstat = os.stat(dataFile)
      
      ##  create temporary directory in tmpfs to work from
      tmpDir = '/dev/shm/gpgedit'
      n = 0
      while True:
          try:
              os.mkdir(tmpDir+str(n))
              break
          except OSError as err:
              if err.errno != 17:  ## file already exists
                  raise
          n += 1
      tmpDir += str(n)
      
      os.chmod(tmpDir, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
      
      
      try:
          ## Get password
          passwd = getpass.getpass()
      
          ## decrypt file
          tmpFile = os.path.join(tmpDir, 'data')
          cmd = "gpg -d --passphrase-fd 0 --output %s %s" % (tmpFile, dataFile)
          proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE)
          proc.stdin.write(passwd)
          proc.stdin.close()
          if proc.wait() != 0:
              raise Exception("Error decrypting file.")
      
          ## record stats of tmp file
          stat = os.stat(tmpFile)
      
          ## invoke editor
          os.system('%s %s' % (editor, tmpFile))
      
          ## see whether data has changed
          stat2 = os.stat(tmpFile)
          if stat.st_mtime == stat2.st_mtime and stat.st_size == stat2.st_size:
              raise Exception("Data unchanged; not writing encrypted file.")
      
          ## re-encrypt, write back to original file
          cmd = "gpg --yes --symmetric --passphrase-fd 0 --output %s %s" % (dataFile, tmpFile)
          proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE)
          proc.stdin.write(passwd)
          proc.stdin.close()
          if proc.wait() != 0:
              raise Exception("Error encrypting file.")
      except:
          ## If there was an error AND the data file was modified, restore the backup.
          dstat2 = os.stat(dataFile)
          if dstat.st_mtime != dstat2.st_mtime or dstat.st_size != dstat2.st_size:
              print "Error occurred, restored encrypted file from backup."
              shutil.copy(bakFile, dataFile)
          raise
      finally:
          shutil.rmtree(tmpDir)
          os.remove(bakFile)
      

      【讨论】:

      • 这并没有像以前那样加密它。
      【解决方案4】:

      gnupg plugin 在哪里 - 例如这一点

      【讨论】:

        【解决方案5】:

        受卢克回答的启发,我自己编写了一个 Python 脚本。希望有人会发现这很有用。以下是核心功能:

        • 使用 /dev/shm 下的临时文件使用安全方法生成临时文件
        • 在出现故障时创建备份文件
        • 两种加密模式(公钥/对称)
        • 即时创建新文件
        • 通过环境变量选择您的编辑器

        可以在脚本本身中找到更多信息。它目前无法在任何非 *nix 机器上运行。

        要安装脚本,只需将其放在路径上的任何目录中并使其可执行。

        Get it now!

        警告:备份您的数据!该脚本没有任何保证!

        【讨论】:

          【解决方案6】:

          另一种方法是使用tmp filesystem in ram using tmpfs,然后当您关闭电源时,它就永远消失了。

          【讨论】:

            【解决方案7】:

            如果您的编辑器可以从管道读取输入并保存到管道,那么您实际上可以使用解密到标准输出并从标准输入加密的 gpg 版本。不幸的是,对于 nano,从管道中读取的只是planned for 2.4。例如。对于gvim,你可以bind decryption and encryption (through pipes) to a key

            【讨论】:

            • 您好,我的浏览器提示最后一个链接是“该站点的安全证书不受信任!”
            • 所以请相信自己的网站。
            【解决方案8】:

            要打开 gpg 文件,编辑它们,然后再次加密/保存,请使用: 公斤 系统托盘中的图标有选项:编辑器... 按下它,然后打开 gpg 文件,然后在底部有一个用于解密它的按钮,瞧你的文件在编辑器中,在你进行任何更改后只需按 Encrypt 然后保存它。

            【讨论】:

              【解决方案9】:

              就在今天,我发现了一种在 vim 中执行所有这些操作的方法!

              这里是链接:full howto on setting up vim for gpg files

              就像一个魅力,就在那个教程中,插件的链接是一个页面的 url,所以不要获取它,而是转到该页面并选择您要下载的那个。

              【讨论】:

                【解决方案10】:

                我讨厌 vi,所以我不得不在 nano 周围补一些胶水。这就是我想出的。缺点是加密时必须再次输入密码。

                alias file_ed="gpg file.txt.gpg; nano file.txt; gpg -c --force-mdc -o file.txt.gpg_temp file.txt; mv file.txt.gpg_temp file.txt.gpg; rm file.txt"

                从文件系统的角度来看,它不是很安全,但我担心其他用户和我自己,而不是 root。

                【讨论】:

                  【解决方案11】:

                  viencrypt by Paul Tarjan 是一个用于即时编辑 GPG 加密文件的脚本。

                  【讨论】:

                    【解决方案12】:

                    在类似于

                    的命令中使用编辑器 joe(又名 Joe's Own Editor

                    gpg --decrypt foo.txt.gpg | joe - | gpg --armor --recipient name@example.com --encrypt > bar.txt.gpg

                    会做你想要的。

                    joe - 中的 - 告诉 joe 从标准输入获取输入,并在保存文件时将输出写入标准输出(按 ctrl+k然后 x 保存)。 Joe 最初会显示来自 gpg 的一些粗略的输出;这可以通过按 ctrl+r 刷新屏幕来清除。

                    我使用> bar.txt.gpg 来指定输出文件而不是--output bar.txt.gpg,因为--output 标志会导致gpg 在您覆盖输出文件时打开一个交互式对话框,这让joe 感到困惑。

                    【讨论】:

                      【解决方案13】:

                      我也在这个任务上花费了无数个小时:只需使用具有简单打开+读/写访问权限的密码来加密文本文件。我不想处理私钥/公钥,也不想处理绑定到操作系统登录的密钥环,等等,等等。仅使用密码的文件加密是如此简单、通用且非常适合用于保存密码的简单文本文件。 KeePass 等数据库驱动的解决方案既不臃肿也不复杂(这还需要将数据输入到多个 GUI 元素中,而不仅仅是在可搜索的文本文件中输入密码)。 Windows 上的黄金标准是 Steganos LockNote。如何在 Linux 上做到这一点?令人惊讶的是很难找到,但是......

                      我终于找到了我认为最好的推荐:奶油。 http://cream.sourceforge.net/ Cream 是 vim 的一个门面,使它对用户更加友好......对其他家庭成员有用(我是一个 Linux 极客,在工作中对 vi[m] 感到很舒服,但我需要一些对我的家人更容易使用的东西) .

                      只需输入:

                      "vim -x yourfile.txt"

                      它将被保存为使用密码加密的。

                      此时你可以使用 vim 或 cream:

                      “vim yourfile.txt”或“cream yourfile.txt”。

                      其中任何一个都将本机打开“yourfile.txt”并提示输入密码,并透明地允许编辑和重新保存为加密。终于任务完成了!!!!

                      【讨论】:

                        【解决方案14】:

                        这里对@Luke 的回答略有改进。它做了两个小的改进:

                        • 如果文件在编辑会话期间未修改,它会避免堆栈跟踪。

                        • 如果尝试重新加密回原始 gpg 文件,它会恢复原始 gpg 文件,这比检查编辑文件的修改日期更安全。

                        #!/usr/bin/python
                        
                        # Downloaded from https://stackoverflow.com/questions/1510105/gnupg-how-to-edit-the-file-without-decrypt-and-save-to-local-disk-first/12289967#12289967
                        # and then slightly improved.
                        
                        import os, sys, subprocess, getpass, stat, shutil
                        
                        editor = 'nano'
                        dataFile = sys.argv[1]
                        
                        ## make a backup of the encrypted file
                        bakFile = dataFile+'-gpgedit_backup'
                        shutil.copy(dataFile, bakFile)
                        dstat = os.stat(dataFile)
                        
                        ##  create temporary directory in tmpfs to work from
                        tmpDir = '/dev/shm/gpgedit'
                        n = 0
                        while True:
                            try:
                                os.mkdir(tmpDir+str(n))
                                break
                            except OSError as err:
                                if err.errno != 17:  ## file already exists
                                    raise
                            n += 1
                        tmpDir += str(n)
                        
                        os.chmod(tmpDir, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
                        
                        
                        reEncrypted = False
                        try:
                            ## Get password
                            passwd = getpass.getpass()
                        
                            ## decrypt file
                            tmpFile = os.path.join(tmpDir, 'data')
                            cmd = "gpg -d --cipher-algo AES256 --passphrase-fd 0 --output %s %s" % (tmpFile, dataFile)
                            proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE)
                            proc.stdin.write(passwd)
                            proc.stdin.close()
                            if proc.wait() != 0:
                                raise Exception("Error decrypting file.")
                        
                            ## record stats of tmp file
                            stat = os.stat(tmpFile)
                        
                            ## invoke editor
                            os.system('%s %s' % (editor, tmpFile))
                        
                            ## see whether data has changed
                            stat2 = os.stat(tmpFile)
                            if stat.st_mtime == stat2.st_mtime and stat.st_size == stat2.st_size:
                                print "Data unchanged; not re-writing encrypted file."
                            else:
                                ## re-encrypt, write back to original file
                            reEncrypted = True
                                cmd = "gpg --yes --symmetric --cipher-algo AES256 --passphrase-fd 0 --output %s %s" % (dataFile, tmpFile)
                                proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE)
                                proc.stdin.write(passwd)
                                proc.stdin.close()
                                if proc.wait() != 0:
                                    raise Exception("Error encrypting file.")
                        except:
                            ## If there was an error AND re-encryption was attempted, restore the backup.
                            if reEncrypted:
                                print "Error occurred; restoring encrypted file from backup."
                                shutil.copy(bakFile, dataFile)
                            raise
                        finally:
                            shutil.rmtree(tmpDir)
                            os.remove(bakFile)
                        

                        我会将这些建议的改进作为 cmets 发布到 @Luke 的回答中——我非常喜欢——但没有足够的声誉点来这样做。 :(

                        【讨论】:

                          【解决方案15】:

                          我编写了一个 shell 脚本来编辑使用 gpg 加密的文件。 将其称为./editgpg.sh path/to/.secrets.gpg,用 vim 编辑,然后用 ':q!' 关闭。 Vim 标志 '-n' 只在内存中打开文件。没有临时文件。

                          #!/usr/bin/env bash
                          
                          
                          # decrypt CRYPT_FILE, pipe to vim, and encrypt againg whent type ':q!'
                          edit_crypt_file() {
                                  echo "Enter your gpg encrypted file passphrase,
                          edit it with vim, then close the editor with ':q!'."
                          
                                  # first argument is a file encrypted with gpg
                                  CRYPT_FILE=$1
                                  # get password user input
                                  local pass
                                  read -sp "Password:" pass
                          
                                  gpg_flags='--batch --yes'
                                  vim_flags='- -n -u NONE --not-a-term'
                          
                                  # vim command to run before exit with ':q!'
                                  vim_autocmd=":autocmd VimLeave * :%! tee | gpg $gpg_flags --passphrase $pass -o $CRYPT_FILE -c"
                          
                                  gpg $gpg_flags --passphrase $pass -d $CRYPT_FILE | vim $vim_flags -c "$vim_autocmd"
                          
                                  # restart agent in order to lose kept password
                                  gpgconf --kill gpg-agent
                                  unset pass
                          }
                          
                          edit_crypt_file $1
                          
                          

                          【讨论】:

                            猜你喜欢
                            • 2014-02-04
                            • 2022-01-16
                            • 1970-01-01
                            • 1970-01-01
                            • 2022-06-29
                            • 1970-01-01
                            • 1970-01-01
                            • 2013-11-05
                            相关资源
                            最近更新 更多