def parse(self): self.pubkey_version = self.data[0] offset = 1 if self.pubkey_version in (2, 3): self.raw_creation_time = get_int4(self.data, offset) self.creation_time = datetime.utcfromtimestamp( self.raw_creation_time) offset += 4 self.raw_days_valid = get_int2(self.data, offset) offset += 2 if self.raw_days_valid > 0: self.expiration_time = self.creation_time + timedelta( days=self.raw_days_valid) self.raw_pub_algorithm = self.data[offset] offset += 1 offset = self.parse_key_material(offset) md5 = hashlib.md5() # Key type must be RSA for v2 and v3 public keys if self.pub_algorithm_type == "rsa": key_id = format_keyid(self.modulus) self.key_id = key_id.encode('ascii') md5.update(get_int_bytes(self.modulus)) md5.update(get_int_bytes(self.exponent)) elif self.pub_algorithm_type == "elg": # Of course, there are ELG keys in the wild too. This formula # for calculating key_id and fingerprint is derived from an old # key and there is a test case based on it. key_id = format_keyid(self.prime) self.key_id = key_id.encode('ascii') md5.update(get_int_bytes(self.prime)) md5.update(get_int_bytes(self.group_gen)) else: raise PgpdumpException("Invalid non-RSA v{} public key" .format(self.pubkey_version)) self.fingerprint = md5.hexdigest().lower().encode('ascii') elif self.pubkey_version == 4: sha1 = hashlib.sha1() seed_bytes = (0x99, (self.length >> 8) & 0xff, self.length & 0xff) sha1.update(bytearray(seed_bytes)) sha1.update(self.data) self.fingerprint = sha1.hexdigest().lower().encode('ascii') self.key_id = self.fingerprint[24:] self.raw_creation_time = get_int4(self.data, offset) self.creation_time = datetime.utcfromtimestamp( self.raw_creation_time) offset += 4 self.raw_pub_algorithm = self.data[offset] offset += 1 offset = self.parse_key_material(offset) else: raise PgpdumpException("Unsupported public key packet, " "version {}".format(self.pubkey_version)) return offset
def patchkey(key, i, rsakey, fp): # find signature packet offset=0 # must be secret/public key packet type if ((key[0] & 0x3f) >> 2) not in [5, 6]: print "data does not start with a key packet" sys.exit(1) o2, l = old_tag_length(key,offset) datestart=offset+2+o2 offset+=1 + o2 + l # next must be keyid packet type if ((key[offset] & 0x3f) >> 2) !=13: print "packet is not a keyid" sys.exit(1) # nothing to see here - skip to next o2, l = old_tag_length(key,offset) offset+=1 + o2 + l # next packet must be signature packet type if ((key[offset] & 0x3f) >> 2)!=2: print "packet is not a signature" sys.exit(1) # skip to end of hashed data o2, l = old_tag_length(key,offset) offset+=struct.unpack('!H', str(key[offset+5+o2:offset+7+o2]))[0]+7+o2 #print "end of hashed data:", offset #print ' '.join(["%02x" % x for x in key[offset:offset+32]]) if not key[offset+2:offset+4]==bytearray([9,0x10]): print "issuer not found" sys.exit(1) # calculate hash of data to be signed hash=hashlib.sha1(str(key[:offset])).digest() # find out offset to store the keys hstart=offset+struct.unpack('!H', str(key[offset:offset+2]))[0]+2 # patch date key[datestart:datestart+4]=struct.pack('!i',i) # patch issuer id key[offset+4:offset+12]=fp[-8:] # sign and patch the key sig = rsakey.sign(hash, Random.get_random_bytes(20)) sig=utils.get_int_bytes(sig) siglen=len(sig)*8 patch=''.join([hash[-2:], struct.pack('!H',siglen), str(sig)]) key[hstart:hstart+len(patch)]=patch
def test_int_bytes(self): self.assertEqual(b"\x11", get_int_bytes(17)) self.assertEqual(b"\x01\x00\x01", get_int_bytes(65537))