paramiko/paramiko/dsskey.py

111 lines
3.4 KiB
Python

#!/usr/bin/python
"""
L{DSSKey}
"""
from ssh_exception import SSHException
from message import Message
from util import inflate_long, deflate_long
from Crypto.PublicKey import DSA
from Crypto.Hash import SHA
from ber import BER, BERException
from pkey import PKey
from ssh_exception import SSHException
class DSSKey (PKey):
"""
Representation of a DSS key which can be used to sign an verify SSH2
data.
"""
def __init__(self, msg=None, data=None):
self.valid = 0
if (msg is None) and (data is not None):
msg = Message(data)
if (msg is None) or (msg.get_string() != 'ssh-dss'):
return
self.p = msg.get_mpint()
self.q = msg.get_mpint()
self.g = msg.get_mpint()
self.y = msg.get_mpint()
self.size = len(deflate_long(self.p, 0))
self.valid = 1
def __str__(self):
if not self.valid:
return ''
m = Message()
m.add_string('ssh-dss')
m.add_mpint(self.p)
m.add_mpint(self.q)
m.add_mpint(self.g)
m.add_mpint(self.y)
return str(m)
def __hash__(self):
h = hash(self.get_name())
h = h * 37 + hash(self.p)
h = h * 37 + hash(self.q)
h = h * 37 + hash(self.g)
h = h * 37 + hash(self.y)
# h might be a long by now...
return hash(h)
def get_name(self):
return 'ssh-dss'
def sign_ssh_data(self, randpool, data):
hash = SHA.new(data).digest()
dss = DSA.construct((long(self.y), long(self.g), long(self.p), long(self.q), long(self.x)))
# generate a suitable k
qsize = len(deflate_long(self.q, 0))
while 1:
k = inflate_long(randpool.get_bytes(qsize), 1)
if (k > 2) and (k < self.q):
break
r, s = dss.sign(inflate_long(hash, 1), k)
m = Message()
m.add_string('ssh-dss')
m.add_string(deflate_long(r, 0) + deflate_long(s, 0))
return m
def verify_ssh_sig(self, data, msg):
if not self.valid:
return 0
if len(str(msg)) == 40:
# spies.com bug: signature has no header
sig = str(msg)
else:
kind = msg.get_string()
if kind != 'ssh-dss':
return 0
sig = msg.get_string()
# pull out (r, s) which are NOT encoded as mpints
sigR = inflate_long(sig[:20], 1)
sigS = inflate_long(sig[20:], 1)
sigM = inflate_long(SHA.new(data).digest(), 1)
dss = DSA.construct((long(self.y), long(self.g), long(self.p), long(self.q)))
return dss.verify(sigM, (sigR, sigS))
def read_private_key_file(self, filename, password=None):
# private key file contains:
# DSAPrivateKey = { version = 0, p, q, g, y, x }
self.valid = 0
data = self._read_private_key_file('DSA', filename, password)
try:
keylist = BER(data).decode()
except BERException:
raise SSHException('Unable to parse key file')
if (type(keylist) != type([])) or (len(keylist) < 6) or (keylist[0] != 0):
raise SSHException('not a valid DSA private key file (bad ber encoding)')
self.p = keylist[1]
self.q = keylist[2]
self.g = keylist[3]
self.y = keylist[4]
self.x = keylist[5]
self.size = len(deflate_long(self.p, 0))
self.valid = 1