b836926d70ebbed403f710e8ecdc36dacdefc202
[gpg-migrate.git] / gpg-migrate.py
1 #!/usr/bin/python
2
3 import subprocess as _subprocess
4 import struct as _struct
5
6
7 def _get_stdout(args, stdin=None):
8     stdin_pipe = None
9     if stdin is not None:
10         stdin_pipe = _subprocess.PIPE
11     p = _subprocess.Popen(args, stdin=stdin_pipe, stdout=_subprocess.PIPE)
12     stdout, stderr = p.communicate(stdin)
13     status = p.wait()
14     if status != 0:
15         raise RuntimeError(status)
16     return stdout
17
18
19 class PGPPacket (dict):
20     # http://tools.ietf.org/search/rfc4880
21     _old_format_packet_length_type = {  # type: (bytes, struct type)
22         0: (1, 'B'),  # 1-byte unsigned integer
23         1: (2, 'H'),  # 2-byte unsigned integer
24         2: (4, 'I'),  # 4-byte unsigned integer
25         3: (None, None),
26         }
27
28     def from_bytes(self, data):
29         packet_tag = data[0]
30         always_one = packet_tag & 1 << 7
31         if not always_one:
32             raise ValueError('most significant packet tag bit not set')
33         self['new-format'] = packet_tag & 1 << 6
34         if self['new-format']:
35             self['packet-tag'] = packet_tag & 0b111111
36             raise NotImplementedError('new-format packet length')
37         else:
38             self['packet-tag'] = packet_tag >> 2 & 0b1111
39             self['length-type'] = packet_tag & 0b11
40             length_bytes, length_type = self._old_format_packet_length_type[
41                 self['length-type']]
42             if not length_bytes:
43                 raise NotImplementedError(
44                     'old-format packet of indeterminate length')
45
46     def to_bytes(self):
47         pass
48
49
50 def migrate(old_key, new_key):
51     """Add the old key and sub-keys to the new key
52
53     For example, to upgrade your master key, while preserving old
54     signatures you'd made.  You will lose signature *on* your old key
55     though, since sub-keys can't be signed (I don't think).
56     """
57     old_key_export = _get_stdout(
58         ['gpg', '--export', old_key])
59     old_key_packet = PGPPacket()
60     old_key_packet.from_bytes(data=old_key_export)
61     old_key_secret_export = _get_stdout(
62         ['gpg', '--export-secret-keys', old_key])
63     old_key_secret_packet = PGPPacket()
64     old_key_secret_packet.from_bytes(data=old_key_secret_export)
65
66     import pprint
67     pprint.pprint(old_key_packet)
68     pprint.pprint(old_key_secret_packet)
69
70
71 if __name__ == '__main__':
72     import sys as _sys
73
74     old_key, new_key = _sys.argv[1:3]
75     migrate(old_key=old_key, new_key=new_key)