diff --git a/README.md b/README.md
index 210bc66..7271850 100644
--- a/README.md
+++ b/README.md
@@ -15,17 +15,20 @@ I've tested the output and input format with my own room keys and it has worked
 so far.
 
 ```
-usage: megolm_backup.py [-h] (--into | --from) [file]
+usage: megolm_backup.py [-h] [-o OUTPUT] (--into | --from) [file]
 
 Operate on megolm session backups.
 
 positional arguments:
-  file        Backup text file (- for stdin).
+  file                  Input text file (- for stdin).
 
 optional arguments:
-  -h, --help  show this help message and exit
-  --into      Encrypt and represent file as a megolm session backup.
-  --from      Decrypt the given megolm session and output the contents.
+  -h, --help            show this help message and exit
+  -o OUTPUT, --output OUTPUT
+                        Output text file (- for stdout).
+  --into                Encrypt and represent file as a megolm session backup.
+  --from                Decrypt the given megolm session and output the
+                        contents.
 ```
 
 Using the above example, let's say we want to only get session keys of the room
diff --git a/megolm_backup.py b/megolm_backup.py
index 3b0815d..07ebeb9 100755
--- a/megolm_backup.py
+++ b/megolm_backup.py
@@ -72,7 +72,8 @@ def enc_session_data(passphrase, json_data):
 	# Figure out our parameters.
 	version, S, IV, N = b"\x01", get_random_bytes(16), get_random_bytes(16), 500000
 
-	# Clear bit 63 of IV.
+	# Clear bit 63 of IV -- apparently this is required to work around a quirk
+	# of the Android AES-CTR's counter implementation.
 	IV = bytearray(IV)
 	IV[9] &= 0x7f
 
@@ -80,6 +81,7 @@ def enc_session_data(passphrase, json_data):
 	K, Kp = stretch_keys(passphrase, S, N)
 
 	# Encrypt the JSON.
+	# NOTE: The empty nonce is intentional -- all the bits are a counter.
 	cipher = AES.new(K, AES.MODE_CTR, nonce=b"", initial_value=IV)
 	plaintext = json_data
 	ciphertext = cipher.encrypt(plaintext)
@@ -125,13 +127,15 @@ def dec_session_data(passphrase, session_data):
 		bail("session data corrupted or bad passphrase: mac check failed")
 
 	# Okay, decrypt the JSON.
+	# NOTE: The empty nonce is intentional -- all the bits are a counter.
 	cipher = AES.new(K, AES.MODE_CTR, nonce=b"", initial_value=IV)
 	ciphertext = body[CryptoParams.size:-MAC_SIZE]
 	return cipher.decrypt(ciphertext)
 
 def main(args):
 	parser = argparse.ArgumentParser(description="Operate on megolm session backups.")
-	parser.add_argument("file", nargs="?", default="-", help="Backup text file (- for stdin).")
+	parser.add_argument("file", nargs="?", default="-", help="Input text file (- for stdin).")
+	parser.add_argument("-o", "--output", default="-", required=False, help="Output text file (- for stdout).")
 	mode_group = parser.add_mutually_exclusive_group(required=True)
 	mode_group.add_argument("--into", dest="mode", const="encrypt", action="store_const", help="Encrypt and represent file as a megolm session backup.")
 	mode_group.add_argument("--from", dest="mode", const="decrypt", action="store_const", help="Decrypt the given megolm session and output the contents.")
@@ -139,6 +143,8 @@ def main(args):
 
 	if args.file == "-":
 		args.file = "/dev/stdin"
+	if args.output == "-":
+		args.output = "/dev/stdout"
 
 	action = {
 		"encrypt": enc_session_data,
@@ -148,12 +154,15 @@ def main(args):
 	with open(args.file, "rb") as f:
 		data = f.read()
 
-	# Wait until after reading input to get the passphrase so pipelines work.
+	# Wait until after reading input to get the passphrase so pipelines work
+	# properly. This results in slightly strange behaviour for interactive
+	# uses, but most people will be using this in a pipeline.
 	passphrase = getpass.getpass("Backup passphrase [mode=%s]: " % (args.mode,))
 	output = action(passphrase, data)
 
-	sys.stdout.buffer.write(output + b"\n")
-	sys.stdout.buffer.flush()
+	with open(args.output, "wb") as f:
+		f.write(output + b"\n")
+		f.flush()
 
 if __name__ == "__main__":
 	main(sys.argv[1:])