summaryrefslogtreecommitdiff
path: root/obnamlib/encryption.py
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2011-03-27 11:42:13 +0100
committerLars Wirzenius <liw@liw.fi>2011-03-27 11:42:13 +0100
commitb742bd1a3f2a82e6b93f9802d948720fe7926743 (patch)
tree9e1caaa4c6f961c8c662266bda2e14ff20e7e183 /obnamlib/encryption.py
parentae54d221b857ff86de6f9e544fbcbf060f574d78 (diff)
downloadobnam-b742bd1a3f2a82e6b93f9802d948720fe7926743.tar.gz
Implement symmetric encryption for real.
Diffstat (limited to 'obnamlib/encryption.py')
-rw-r--r--obnamlib/encryption.py63
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)
+