def asn1_build(node): """ Builds an asn.1 data structure based on pairs of (type, data), this function may be used as a generator of a buffer. :type node: Tuple :param node: The root node of the structure that is going to be used as reference for the generation of the asn.1 buffer. """ tag, value = node if tag == BIT_STRING: yield netius.legacy.chr(BIT_STRING) + asn1_length(len(value)) + value elif tag == OCTET_STRING: yield netius.legacy.chr(OCTET_STRING) + asn1_length(len(value)) + value elif tag == INTEGER: value = util.integer_to_bytes(value) yield netius.legacy.chr(INTEGER) + asn1_length(len(value)) + value elif tag == NULL: assert value is None yield netius.legacy.chr(NULL) + asn1_length(0) elif tag == OBJECT_IDENTIFIER: yield netius.legacy.chr(OBJECT_IDENTIFIER) + asn1_length( len(value)) + value elif tag == SEQUENCE: buffer = [] for item in value: generator = asn1_build(item) data = b"".join(generator) buffer.append(data) result = b"".join(buffer) yield netius.legacy.chr(SEQUENCE) + asn1_length(len(result)) + result else: raise netius.GeneratorError("Unexpected tag in template 0x%02x" % tag)
def dkim_sign(message, selector, domain, private_key, identity=None, separator=":"): separator = netius.legacy.bytes(separator) identity = identity or "@" + domain headers, body = mime.rfc822_parse(message, strip=False) if not identity.endswith(domain): raise netius.GeneratorError("Identity must end with domain") headers = dkim_headers(headers) body = dkim_body(body) include_headers = [name.lower() for name, _value in headers] sign_headers = [ header for header in headers if header[0].lower() in include_headers ] sign_names = [name for name, _value in sign_headers] hash = hashlib.sha256() hash.update(body) body_digest = hash.digest() body_hash = base64.b64encode(body_digest) body_hash = netius.legacy.str(body_hash) creation = time.time() creation = int(creation) creation_s = str(creation) names = separator.join(sign_names) names = netius.legacy.str(names) sign_fields = [ ("v", "1"), ("a", "rsa-sha256"), ("c", "simple/simple"), ("d", domain), ("i", identity), ("l", len(body)), ("q", "dns/txt"), ("s", selector), ("t", creation_s), ("h", names), ("bh", body_hash), ("b", ""), ] signature = "DKIM-Signature: " + "; ".join("%s=%s" % field for field in sign_fields) if type(signature) == netius.legacy.UNICODE: signature = signature.encode("utf-8") signature = dkim_fold(signature) hash = hashlib.sha256() for name, value in sign_headers: hash.update(name) hash.update(b":") hash.update(value + b"\r\n") hash.update(signature) digest = hash.digest() digest_info = asn.asn1_gen((asn.SEQUENCE, [ (asn.SEQUENCE, [ (asn.OBJECT_IDENTIFIER, asn.HASHID_SHA256), (asn.NULL, None), ]), (asn.OCTET_STRING, digest), ])) modulus = private_key["modulus"] exponent = private_key["private_exponent"] modulus_s = util.integer_to_bytes(modulus) modulus_l = len(modulus_s) digest_l = len(digest_info) delta_l = modulus_l - digest_l - 3 delta_l = 0 if delta_l < 0 else delta_l if digest_l + 3 > modulus_l: raise netius.GeneratorError("Hash too large for modulus") base = b"\x00\x01" + b"\xff" * delta_l + b"\x00" + digest_info base_i = util.bytes_to_integer(base) signature_i = rsa.rsa_crypt(base_i, exponent, modulus) signature_s = util.integer_to_bytes(signature_i, length=modulus_l) signature += base64.b64encode(signature_s) + b"\r\n" return signature
def rsa_exponents(prime_1, prime_2, number_bits, basic=True): """ Generates both the public and the private exponents for the rsa cryptography system taking as base the provided prime numbers and the amount of bits for the values. :type prime_1: int :param prime_1: The first prime number use for rsa. :type prime_2: int :param prime_2: The second prime number use for rsa. :type number_bits: int :param number_bits: The number of bits that are going to be used for the generation of the values. :type basic: bool :param basic: If the basic approach to the generation of the public exponent should be taken into account. :rtype: Tuple :return: The tuple containing the generated public and private keys (properly tested). """ # calculates the modulus and the phi value for the # modulus, as the y are going to be used for calculus modulus = prime_1 * prime_2 phi_modulus = (prime_1 - 1) * (prime_2 - 1) # starts by setting the is first flag so that the first iteration # of the public exponent generation cycle is taking into account # the possible basic flag value for the public exponent is_first = True # iterates continuously to find a valid public exponent, one # that satisfies the relative prime while True: # make sure e has enough bits so we ensure "wrapping" through # modulus (n value) note that if the this is the first attempt # to create a public exponent and the basic mode is active the # number chosen is the "magic" number (compatibility) public_exponent = calc.prime(max(8, number_bits // 2)) if is_first and basic: public_exponent = 65537 is_first = False # checks if the exponent and the modulus are relative primes # and also checks if the exponent and the phi modulus are relative # primes, for that situation a valid public exponent has been fond # and the cycle may be broken is_relative = calc.relatively_prime(public_exponent, modulus) is_relative_phi = calc.relatively_prime(public_exponent, phi_modulus) if is_relative and is_relative_phi: break # retrieves the result of the extended euclid greatest common divisor, # this value is going to be used as the basis for the calculus of the # private exponent for the current operation d, l, _e = calc.egcd(public_exponent, phi_modulus) private_exponent = l # in case the greatest common divisor between both is not one, the values # are not relative primes and an exception must be raised if not d == 1: raise netius.GeneratorError( "The public exponent '%d' and the phi modulus '%d' are not relative primes" % (public_exponent, phi_modulus)) # calculates the inverse modulus for both exponent and in case it's not one # an exception is raised about the problem inverse_modulus = (public_exponent * private_exponent) % phi_modulus if not inverse_modulus == 1: netius.GeneratorError( "The public exponent '%d' and private exponent '%d' are not multiplicative inverse modulus of phi modulus '%d'" % (public_exponent, private_exponent, phi_modulus)) # creates the tuple that contains both the public and the private # exponent values that may be used for rsa based cryptography return (public_exponent, private_exponent)