def _hashed_order(names, origin=None, salt='', iterations=0): """ Hash the given names using SHA-1 algorithm, the given salt and the given number of iterations. Return list of tuples (name, hash) in hash order. Used for NSEC3 records generation. See RFC-5155 for details. """ # Add empty non terminals to the list, see RFC-5155, section 7.1 nameset = set(names) for name in names: n = name.relativize(origin) while len(n) > 1: n = n.parent() nameset.add(n.derelativize(origin)) names = list(nameset) ret = [] for name in names: h = name.to_digestable(origin) i = iterations while i >= 0: sha = Crypto.Hash.SHA.new() sha.update(h) sha.update(salt) h = sha.digest() i -= 1 ret.append((name, h)) # Check for hash collision if len(ret) != len(set(ret)): raise NSEC3Collision() ret = sorted(ret, key=lambda x: x[1]) return ret
def _compute_digest(self, hash_algorithm, scheme=DigestScheme.SIMPLE): hashinfo = _digest_hashers.get(hash_algorithm) if not hashinfo: raise UnsupportedDigestHashAlgorithm if scheme != DigestScheme.SIMPLE: raise UnsupportedDigestScheme if self.relativize: origin_name = dns.name.empty else: origin_name = self.origin hasher = hashinfo() for (name, node) in sorted(self.items()): rrnamebuf = name.to_digestable(self.origin) for rdataset in sorted(node, key=lambda rds: (rds.rdtype, rds.covers)): if name == origin_name and \ dns.rdatatype.ZONEMD in (rdataset.rdtype, rdataset.covers): continue rrfixed = struct.pack('!HHI', rdataset.rdtype, rdataset.rdclass, rdataset.ttl) for rr in sorted(rdataset): rrdata = rr.to_digestable(self.origin) rrlen = struct.pack('!H', len(rrdata)) hasher.update(rrnamebuf + rrfixed + rrlen + rrdata) return hasher.digest()
def nsec3hash(name, algnum, salt, iterations, binary_out=False): """ Compute NSEC3 hash for given domain name and parameters. name is of type dns.name.Name, salt is a binary bytestring, algnum and iterations are integers. """ if iterations < 0: raise ResError("NSEC3 hash iterations must be >= 0") if iterations > Prefs.N3_HASHLIMIT: raise ResError("NSEC3 hash iterations too high: {} {}".format( name, iterations)) hashfunc = nsec3_hashalg(algnum) digest = name.to_digestable() while iterations >= 0: d = hashes.Hash(hashfunc(), backend=default_backend()) d.update(digest + salt) digest = d.finalize() iterations -= 1 if binary_out: return digest output = base64.b32encode(digest) output = output.translate(b32_to_ext_hex).decode() return output