# Copyright (c) 2001-2004 Twisted Matrix Laboratories. # See LICENSE for details. # """A basic ASN.1 parser to parse private SSH keys. This module is unstable. Maintainer: U{Paul Swartz} """ from Crypto.Util import number def parse(data): things = [] while data: t = ord(data[0]) assert (t & 0xc0) == 0, 'not a universal value: 0x%02x' % t #assert t & 0x20, 'not a constructed value: 0x%02x' % t l = ord(data[1]) assert data != 0x80, "shouldn't be an indefinite length" if l & 0x80: # long form ll = l & 0x7f l = number.bytes_to_long(data[2:2+ll]) s = 2 + ll else: s = 2 body, data = data[s:s+l], data[s+l:] t = t&(~0x20) assert t in (SEQUENCE, INTEGER), 'bad type: 0x%02x' % t if t == SEQUENCE: things.append(parse(body)) elif t == INTEGER: #assert (ord(body[0])&0x80) == 0, "shouldn't have negative number" things.append(number.bytes_to_long(body)) if len(things) == 1: return things[0] return things def pack(data): ret = '' for part in data: if type(part) in (type(()), type([])): partData = pack(part) partType = SEQUENCE|0x20 elif type(part) in (type(1), type(1L)): partData = number.long_to_bytes(part) if ord(partData[0])&(0x80): partData = '\x00' + partData partType = INTEGER else: raise 'unknown type %s' % type(part) ret += chr(partType) if len(partData) > 127: l = number.long_to_bytes(len(partData)) ret += chr(len(l)|0x80) + l else: ret += chr(len(partData)) ret += partData return ret INTEGER = 0x02 SEQUENCE = 0x10