diff options
author | Lars Wirzenius <liw@liw.fi> | 2011-03-27 11:42:13 +0100 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2011-03-27 11:42:13 +0100 |
commit | b742bd1a3f2a82e6b93f9802d948720fe7926743 (patch) | |
tree | 9e1caaa4c6f961c8c662266bda2e14ff20e7e183 /obnamlib/encryption.py | |
parent | ae54d221b857ff86de6f9e544fbcbf060f574d78 (diff) | |
download | obnam-b742bd1a3f2a82e6b93f9802d948720fe7926743.tar.gz |
Implement symmetric encryption for real.
Diffstat (limited to 'obnamlib/encryption.py')
-rw-r--r-- | obnamlib/encryption.py | 63 |
1 files changed, 62 insertions, 1 deletions
diff --git a/obnamlib/encryption.py b/obnamlib/encryption.py index 08bb58a9..4ec718d7 100644 --- a/obnamlib/encryption.py +++ b/obnamlib/encryption.py @@ -14,6 +14,11 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. +import os +import subprocess +import tempfile + + def generate_symmetric_key(numbits): '''Generate a random key of at least numbits for symmetric encryption.''' @@ -22,9 +27,65 @@ def generate_symmetric_key(numbits): key = f.read(bytes) f.close() + # Passphrase should not contain newlines. Hex encode? + return key +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]) + + # Write the data to temporary file. Remove its name at once, so that + # if we crash, it gets removed automatically by the kernel. + + datafd, dataname = tempfile.mkstemp() + os.remove(dataname) + os.write(datafd, data) + os.lseek(datafd, 0, 0) + + # Actually run gpg. + + argv = ['gpg', '--passphrase-fd', str(keypipe[0]), '-q', '--batch'] + args + p = subprocess.Popen(argv, stdin=datafd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + out, err = p.communicate() + + os.close(keypipe[0]) + os.close(datafd) + + # Return output data, or deal with errors. + if p.returncode: # pragma: no cover + raise Exception(err) + + return out + + def encrypt_with_symmetric_key(cleartext, key): '''Encrypt data with symmetric encryption.''' - return '' + return _gpg_pipe(['-c'], cleartext, key) + + +def decrypt_with_symmetric_key(encrypted, key): + '''Decrypt encrypted data with symmetric encryption.''' + return _gpg_pipe(['-d'], encrypted, key) + |