summaryrefslogtreecommitdiff
path: root/hgsshsign/keys.py
blob: aa291eba562707238b6428fb3a1d4299363a0fb0 (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
# 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()


def load_private_key(filename):
    fp = open(filename)
    try:
        first_line = fp.readline()
    finally:
        fp.close()

    type = DSA if 'DSA' in first_line else RSA
    return type.load_key(filename)


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