diff options
Diffstat (limited to 'hgsshsign/keys.py')
-rw-r--r-- | hgsshsign/keys.py | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/hgsshsign/keys.py b/hgsshsign/keys.py new file mode 100644 index 0000000..d15af08 --- /dev/null +++ b/hgsshsign/keys.py | |||
@@ -0,0 +1,88 @@ | |||
1 | # vim: set filencoding=utf8 | ||
2 | """ | ||
3 | Key Loader Functions | ||
4 | |||
5 | @author: Mike Crute (mcrute@gmail.com) | ||
6 | @organization: SoftGroup Interactive, Inc. | ||
7 | @date: May 05, 2010 | ||
8 | """ | ||
9 | |||
10 | import os | ||
11 | from M2Crypto import RSA, DSA | ||
12 | from M2Crypto.EVP import MessageDigest | ||
13 | from M2Crypto.RSA import RSAError | ||
14 | from M2Crypto.DSA import DSAError | ||
15 | from structutils import unpack_string, get_packed_mp_ints, int_to_bytes | ||
16 | |||
17 | |||
18 | class PublicKey(object): | ||
19 | |||
20 | def __init__(self, hashed=None, instance=None, key_type=None): | ||
21 | self.instance = instance | ||
22 | self.hashed = hashed | ||
23 | self.key_type = key_type | ||
24 | |||
25 | @property | ||
26 | def blob(self): | ||
27 | return self.hashed.decode('base64') | ||
28 | |||
29 | def verify(self, data, signature): | ||
30 | try: | ||
31 | return bool(self.instance.verify(data, signature)) | ||
32 | except (RSAError, DSAError): | ||
33 | return False | ||
34 | |||
35 | def sign(self, data): | ||
36 | return self.instance.sign(data) | ||
37 | |||
38 | @classmethod | ||
39 | def from_string(cls, key): | ||
40 | """ | ||
41 | Loads an RFC 4716 formatted public key. | ||
42 | """ | ||
43 | pubkey = cls() | ||
44 | |||
45 | if key.startswith('ssh-'): | ||
46 | pubkey.hashed = key.split()[1] | ||
47 | else: | ||
48 | pubkey.hashed = key | ||
49 | |||
50 | pubkey.key_type, remainder = unpack_string(pubkey.blob) | ||
51 | |||
52 | if pubkey.key_type == 'ssh-rsa': | ||
53 | e, n = get_packed_mp_ints(remainder, 2) | ||
54 | pubkey.instance = RSA.new_pub_key((e, n)) | ||
55 | elif pubkey.key_type == 'ssh-dss': | ||
56 | p, q, g, y = get_packed_mp_ints(remainder, 4) | ||
57 | pubkey.instance = DSA.set_params(p, q, g) | ||
58 | |||
59 | return pubkey | ||
60 | |||
61 | @classmethod | ||
62 | def from_file(cls, filename): | ||
63 | fp = open(filename) | ||
64 | try: | ||
65 | return cls.from_string(fp.read()) | ||
66 | finally: | ||
67 | fp.close() | ||
68 | |||
69 | |||
70 | def load_private_key(filename): | ||
71 | fp = open(filename) | ||
72 | try: | ||
73 | first_line = fp.readline() | ||
74 | finally: | ||
75 | fp.close() | ||
76 | |||
77 | type = DSA if 'DSA' in first_line else RSA | ||
78 | return type.load_key(filename) | ||
79 | |||
80 | |||
81 | def sign_like_agent(data, key): | ||
82 | """ | ||
83 | Emulates the signing behavior of an ssh key agent. | ||
84 | """ | ||
85 | digest = MessageDigest('sha1') | ||
86 | digest.update(data) | ||
87 | my_data = digest.final() | ||
88 | return key.sign(data) | ||