Python/POpen/gpg:通过stdin或文件描述符提供密码短语和加密文本 [英] Python/POpen/gpg: Supply passphrase and encryption text both through stdin or file descriptor

查看:158
本文介绍了Python/POpen/gpg:通过stdin或文件描述符提供密码短语和加密文本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试通过POpen通过python程序远程控制gpg.
我有一个文件,其中包含要解密,修改并写回重新加密的磁盘的加密数据.
当前,我将解密后的信息存储在一个临时文件中(程序结束时,我将其保存为shred).然后,我对该文件进行修改,然后使用一个函数将其重新加密,该函数将密码短语通过stdin传递.
的代码如下:

I'm trying to remote control gpg through a python program via POpen.
I have a file that contains encrypted data which I want to decrypt, modify and write back to disk re-encrypted.
Currently I am storing the decrypted information in a temporary file (which I shred when the program ends). Then I perform my modifications to that file and then re-encrypt it using a function, which pipes the passphrase through stdin.
The code for this is as follows:

def encrypt(source, dest, passphrase, cipher=None):
  """Encrypts the source file.
  @param source Source file, that should be encrypted.
  @param dest Destination file.
  @param passphrase Passphrase to be used.
  @param cipher Cipher to use. If None or empty string gpg's default cipher is
  used.
  """
  phraseecho = Popen(("echo", passphrase), stdout=subprocess.PIPE)

  gpgargs = [
          "gpg",
          "-c",
          "--passphrase-fd", "0", # read passphrase from stdin
          "--output", dest,
          "--batch",
          "--force-mdc"]
  if not cipher is None and len(cipher) > 0:
      gpgargs.extend(("--cipher-algo", cipher))

  gpgargs.append(source)

  encrypter = Popen(
          gpgargs,
          stdin=phraseecho.stdout,
          stdout=subprocess.PIPE,
          stderr=subprocess.PIPE)
  stdout, stderr = encrypter.communicate()
  rc = encrypter.returncode
  if not rc == 0:
      raise RuntimeError(
              "Calling gpg failed with return code %d: %s" % (rc, stderr))

这非常好用,但是我可以肯定的是,在临时文件中存储潜在敏感的解密数据是一个很大的安全漏洞.
因此,我想以某种方式重写我的加密/解密功能,使它们能够完全在内存中工作,而无需在磁盘上存储敏感数据.
解密也可以通过stdin传递密码短语并捕获已解密数据的stdout来直接进行.

This works perfectly well, but I'm fairly sure that storing potentionally sensitive, decrypted data in a temporary file is a rather big security flaw.
So I want to rewrite my encryption/decryption functions in a way, that enables them to work completely in memory without storing sensitive data on disk.
Decryption works straight forward by also piping the passphrase via stdin and capturing stdout for the decrypted data.

另一方面,加密使我发疯,因为我不能仅将密码短语和消息传递给"stdin" ...至少

Encryption on the other hand drives me mad, since I can't just pipe the passphrase AND the message to `stdin'...at least

encrypter.stdin.write("%s\n%s" % (passphrase, message))

没有用.
我的下一个最佳猜测是提供某种内存中文件/管道/套接字或诸如--passphrase-fd参数之类的文件描述符.事实是:我不知道是否存在诸如内存中文件之类的东西,或者是否会套用套接字,因为我从未使用过它们.

didn't work.
My next best guess is to supply the file-descriptor of some kind of in-memory file/pipe/socket or whatever as --passphrase-fd argument. The thing is: I don't know if there even is a thing such as in-memory files or if sockets would apply, since I never used them.

有人可以帮我解决问题或为我提供更好的解决方案吗?
该解决方案不必具有可移植性-我对仅使用Linux的方法完全满意.

Can anybody help out or point me to a better solution for my problem?
The solution does not have to be portable - I'm totally fine with Linux only approaches.

预先感谢...


非常感谢您,Lars和ryran.两种解决方案都可以完美地工作!不幸的是我只能接受一个人


Thanks a lot to both of you, Lars and ryran. Both solutions work perfectly! Unfortunately I can only accept one

推荐答案

下面是我在 Obnam 运行gpg, 也许会对您有所帮助.

Below is the code I use in Obnam to run gpg, perhaps it can be of some assistance to you.

def _gpg_pipe(args, data, passphrase):
    '''Pipe things through gpg.

    With the right args, this can be either an encryption or a decryption
    operation.

    For safety, we give the passphrase to gpg via a file descriptor.
    The argument list is modified to include the relevant options for that.

    The data is fed to gpg via a temporary file, readable only by
    the owner, to avoid congested pipes.

    '''

    # Open pipe for passphrase, and write it there. If passphrase is
    # very long (more than 4 KiB by default), this might block. A better
    # implementation would be to have a loop around select(2) to do pipe
    # I/O when it can be done without blocking. Patches most welcome.

    keypipe = os.pipe()
    os.write(keypipe[1], passphrase + '\n')
    os.close(keypipe[1])

    # Actually run gpg.

    argv = ['gpg', '--passphrase-fd', str(keypipe[0]), '-q', '--batch'] + args
    tracing.trace('argv=%s', repr(argv))
    p = subprocess.Popen(argv, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    out, err = p.communicate(data)

    os.close(keypipe[0])

    # Return output data, or deal with errors.
    if p.returncode: # pragma: no cover
        raise obnamlib.Error(err)

    return out


def encrypt_symmetric(cleartext, key):
    '''Encrypt data with symmetric encryption.'''
    return _gpg_pipe(['-c'], cleartext, key)


def decrypt_symmetric(encrypted, key):
    '''Decrypt encrypted data with symmetric encryption.'''
    return _gpg_pipe(['-d'], encrypted, key)

这篇关于Python/POpen/gpg:通过stdin或文件描述符提供密码短语和加密文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆