summaryrefslogtreecommitdiff
path: root/hgsshsign/keys.py
blob: c7238727f06a2c3ada27dbf3c73c0b1293e2d323 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# vim: set filencoding=utf8
"""
Key Loader Functions

@author: Mike Crute (mcrute@gmail.com)
@organization: SoftGroup Interactive, Inc.
@date: May 05, 2010
"""

import os

from M2Crypto import RSA, DSA
from M2Crypto.EVP import MessageDigest
from M2Crypto.RSA import RSAError
from M2Crypto.DSA import DSAError

from structutils import unpack_string, get_packed_mp_ints, int_to_bytes


class PublicKey(object):

    def __init__(self, hashed=None, instance=None, key_type=None):
        self.instance = instance
        self.hashed = hashed
        self.key_type = key_type

    @property
    def blob(self):
        return self.hashed.decode('base64')

    def verify(self, data, signature):
        try:
            return bool(self.instance.verify(data, signature))
        except (RSAError, DSAError):
            return False

    def sign(self, data):
        return self.instance.sign(data)

    @classmethod
    def from_string(cls, key):
        """
        Loads an RFC 4716 formatted public key.
        """
        pubkey = cls()

        if key.startswith('ssh-'):
            pubkey.hashed = key.split()[1]
        else:
            pubkey.hashed = key

        pubkey.key_type, remainder = unpack_string(pubkey.blob)

        if pubkey.key_type == 'ssh-rsa':
            e, n = get_packed_mp_ints(remainder, 2)
            pubkey.instance = RSA.new_pub_key((e, n))
        elif pubkey.key_type == 'ssh-dss':
            p, q, g, y = get_packed_mp_ints(remainder, 4)
            pubkey.instance = DSA.set_params(p, q, g)

        return pubkey

    @classmethod
    def from_file(cls, filename):
        fp = open(filename)
        try:
            return cls.from_string(fp.read())
        finally:
            fp.close()


class PrivateKey(object):

    def __init__(self, instance):
        self.instance = instance

    @classmethod
    def from_file(cls, filename):
        fp = open(filename)
        try:
            first_line = fp.readline()
        finally:
            fp.close()

        type_ = DSA if 'DSA' in first_line else RSA
        instance = type_.load_key(filename)

        return cls(instance)

    def sign(self, data):
        """
        Emulates the signing behavior of an ssh key agent.
        """
        digest = MessageDigest('sha1')
        digest.update(data)
        my_data = digest.final()
        return self.instance.sign(data)