GnuPG - 如何在不解密的情况下编辑文件并首先保存到本地磁盘?

时间:2009-10-02 15:04:32

标签: linux encryption gnupg

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

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

我使用的方法有两种:

gpg -d foo.txt.gpg

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

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

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

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

欢迎任何评论。

提前谢谢。

15 个答案:

答案 0 :(得分:5)

一种方法是使用vim。请参阅this page和此related question.

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

答案 1 :(得分:4)

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

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

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

以下是代码:

#!/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)

答案 2 :(得分:3)

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

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

尽管如此,谨慎的做法是避免使用未加密的数据创建文件。只要知道如果基础系统受到损害,这并不能为您提供100%的安全性。

答案 3 :(得分:2)

gnupg plugin在哪里 - 完全就这一点而言

答案 4 :(得分:1)

另一种方法是使用tmpfs在ram中创建一个tmp文件系统,然后在关闭它时它永远消失。

答案 5 :(得分:1)

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

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

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

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

Get it now!

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

答案 6 :(得分:0)

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

答案 7 :(得分:0)

要打开gpg文件,编辑它们然后再次保存/保存,请使用: KGpg将 系统托盘中的图标有选项:编辑器... 按下它,然后打开gpg文件,然后在底部有一个按钮来解密它,并且你在编辑器中有你的文件,在你做了任何更改之后只需按加密然后保存它。

答案 8 :(得分:0)

就在今天,我已经发现了一种在vim中完成所有这些工作的方法!

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

就像一个魅力,只是在那个教程中,插件的链接是一个页面的URL,所以不要忘记它,但是转到页面并选择你要下载的那个。

答案 9 :(得分:0)

我讨厌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。

答案 10 :(得分:0)

Paul Tarjan的

viencrypt是一个用于动态编辑GPG加密文件的脚本。

答案 11 :(得分:0)

在类似于

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

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

会做你想要的。

-中的joe -告诉joe从stdin获取输入并在保存文件时将其输出写入stdout(点击 ctrl + k 然后 x 保存)。 Joe最初将从gpg中显示一些狡猾的输出;这可以通过点击 ctrl + r 来刷新屏幕来清除。

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

答案 12 :(得分:0)

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

我终于收敛了我认为最好的建议:奶油。 http://cream.sourceforge.net/霜是vim的外观,使其更加用户友好...对其他家庭成员有用(我是一个熟悉vi [m]工作的Linux极客,但我需要更方便的东西家族)。

输入:

" vim -x yourfile.txt"

它将以密码保存为加密。

此时你可以使用vim或者奶油:

" vim yourfile.txt"或者"奶油yourfile.txt"。

任何一个都将本地打开" yourfile.txt"并提示输入密码并透明地允许编辑和重新保存为加密。最后任务已经完成!!!!

答案 13 :(得分:0)

@ 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)

我会将这些建议的改进作为对@Luke答案的评论发布 - 我非常喜欢 - 但没有足够的声誉点来这样做。 :(

答案 14 :(得分:0)

我写了一个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