""" Generate a DNSSEC DS record based on the incoming DNSKEY record The DNSKEY can be found using for example 'dig': $ dig DNSKEY secure.widodh.nl The output can then be parsed with the following code to generate a DS record for in the parent DNS zone Author: Wido den Hollander <wido@widodh.nl> Many thanks to this blogpost: https://www.v13.gr/blog/?p=239 """ import struct import base64 import hashlib DOMAIN = 'secure.widodh.nl' DNSKEY = '257 3 8 AwEAAckZ+lfb0j6aHBW5AanV5A0V0IfF99vAKFZd6+fJfEChpZtjnItWDnJLPa3/LAFec/tUhLZ4jgmzaoEuX3EQQgI1V4kp9SYf8HMlFPP014eO+AnjkYFGLE2uqHPx/Tu7/pO3EyKwTXi5fMadROKuo/mfat5AEIhGjteGGO93DhnOa6kcqj5RHYJBh5OZ/GoZfbeYHK6Muur1T16hHiI12rYGoqJ6ZW5+njYprG6qwp6TZXxJyE7wF1JdD+Zhbjhf0Md4zMEysP22wBLghBaX6eDIBh/7jU7dw1Ob+I42YWk+X4NSiU3sRYPaq1R13JEK4zVqQtL++UVtgRPEbfj5RQ8=' def _calc_keyid(flags, protocol, algorithm, dnskey): st = struct.pack('!HBB', int(flags), int(protocol), int(algorithm)) st += base64.b64decode(dnskey) cnt = 0 for idx in range(len(st)): s = struct.unpack('B', st[idx:idx+1])[0] if (idx % 2) == 0: cnt += s << 8 else: cnt += s return ((cnt & 0xFFFF) + (cnt >> 16)) & 0xFFFF def _calc_ds(domain, flags, protocol, algorithm, dnskey): if domain.endswith('.') is False: domain += '.' signature = bytes() for i in domain.split('.'): signature += struct.pack('B', len(i)) + i.encode() signature += struct.pack('!HBB', int(flags), int(protocol), int(algorithm)) signature += base64.b64decode(dnskey) return { 'sha1': hashlib.sha1(signature).hexdigest().upper(), 'sha256': hashlib.sha256(signature).hexdigest().upper(), } def dnskey_to_ds(domain, dnskey): dnskeylist = dnskey.split(' ', 3) flags = dnskeylist[0] protocol = dnskeylist[1] algorithm = dnskeylist[2] key = dnskeylist[3].replace(' ', '') keyid = _calc_keyid(flags, protocol, algorithm, key) ds = _calc_ds(domain, flags, protocol, algorithm, key) ret = list() ret.append(str(keyid) + ' ' + str(algorithm) + ' ' + str(1) + ' ' + ds['sha1'].lower()) ret.append(str(keyid) + ' ' + str(algorithm) + ' ' + str(2) + ' ' + ds['sha256'].lower()) return ret print(dnskey_to_ds(DOMAIN, DNSKEY))