def sign_hash(pub_algorithm_type, secret_key, hash_, k=None): if pub_algorithm_type in (1, 3): # RSA sig_string = PKCS1_v1_5.new(secret_key).sign(hash_) return (bytes_to_long(sig_string), ) elif pub_algorithm_type == 20: # ELG # TODO: Should only be allowed for test purposes if k is None: while 1: # This can be pretty darn slow k = random.StrongRandom().randint(1, secret_key.p - 1) if GCD(k, secret_key.p - 1) == 1: break print(k) # TODO: Remove dependence on undocumented method sig_string = PKCS1_v1_5.EMSA_PKCS1_V1_5_ENCODE(hash_, secret_key.size()) return secret_key.sign(sig_string, k) elif pub_algorithm_type == 17: q = secret_key.q qbits = int(math.floor(float(math.log(q, 2)))) + 1 qbytes = int(math.ceil(qbits / 8.0)) if k is None: k = random.StrongRandom().randint(1, q - 1) digest = hash_.digest()[:qbytes] return secret_key.sign(bytes_to_long(digest), k) else: # TODO: complete raise ValueError
def verify_hash(pub_algorithm_type, public_key, hash_, values): if pub_algorithm_type in (1, 3): # RSA s = long_to_bytes(values[0]) return PKCS1_v1_5.new(public_key).verify(hash_, s) elif pub_algorithm_type == 20: # ELG # TODO: Remove dependence on undocumented method sig_string = PKCS1_v1_5.EMSA_PKCS1_V1_5_ENCODE(hash_, public_key.size()) return public_key.verify(sig_string, values) elif pub_algorithm_type == 17: # DSA q = public_key.q qbits = int(math.floor(float(math.log(q, 2)))) + 1 qbytes = int(math.ceil(qbits / 8.0)) digest = hash_.digest() # Discard empty leading bytes start = 0 while digest[start] == b'\x00': start += 1 digest = digest[start:start + qbytes] return public_key.verify(bytes_to_long(digest), values) else: # TODO: complete this raise ValueError
jwt0 = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJsb2dpbiI6InRlc3QifQ.qMW0MsNUqx0c5AgprBkDWFEWLSAp2tw4FnhoR0afqbhQ4BtLopSOEf-MKTQybuzhuI0iwZ_326WkhG3BE3E5z26TbtJaK0gUWEnmje1vE5L3giE2BoTRsyzqzYY93VrRAxOG9sDiKj1cu1b1t9-XKdyH2vhdl1eZfhuQouQEvzmo1PTfXbbfzv6ZRSCJ4FA99jBnPHdHJxdn4fU4t1W9-unuCJSHNmdut7s5LQjzqPkz-s1Wp8MLq5CKeJTNIFR2QOTENga9FaqfEi5IkBqdRPNWH4riHOB2XicsUW8-ctVWhnkXRjSzojcXURkhG6YHP8TJEqCNZZfDy2qLND1LVA' jwt1 = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJsb2dpbiI6Im1vIn0.gobkqhpwWF74HfKRYzoV2yORJ9iFHR2Bi2R2_Gh4h2ftP1TaafcXgc8Lec2VG2k4H5KyRjaSoS1qSvJXlrpG3ZMu-_zjy8Nx_oGCWAygGIk7oV__HBS8eTiqY9bVypJ934GP_GowWB2KWSy89Hb8xKtLkxdaW8NCcL4xOtsA1FLuVxeo3sjNGBOei4_q2-zp72-kCmFUABHuqr_jyrsYT-hRrJn3-kx82ASGFn3RZDLAHzOGpH1pwFw0_mzKI_y1ZhB1Ifajn9BZPbOAMrZNcAFZ7xvLsDdxQY2ZWdQCheHYMltdRzu4aMZnwVOWoCBuoF1bUJLlHRSq7tL3gwGFAA' jwt0_sig_bytes = b64urldecode(jwt0.split('.')[2]) jwt1_sig_bytes = b64urldecode(jwt1.split('.')[2]) if len(jwt0_sig_bytes) != len(jwt1_sig_bytes): raise Exception( "Signature length mismatch" ) # Based on the mod exp operation alone, there may be some differences! jwt0_sig = bytes2mpz(jwt0_sig_bytes) jwt1_sig = bytes2mpz(jwt1_sig_bytes) jks0_input = ".".join(jwt0.split('.')[0:2]) sha256_0 = SHA256.new(jks0_input.encode('ascii')) padded0 = PKCS1_v1_5.EMSA_PKCS1_V1_5_ENCODE(sha256_0, len(jwt0_sig_bytes)) jks1_input = ".".join(jwt1.split('.')[0:2]) sha256_1 = SHA256.new(jks1_input.encode('ascii')) padded1 = PKCS1_v1_5.EMSA_PKCS1_V1_5_ENCODE(sha256_1, len(jwt0_sig_bytes)) m0 = bytes2mpz(padded0) m1 = bytes2mpz(padded1) pkcs1 = asn1tools.compile_files('data/pkcs1.asn', codec='der') x509 = asn1tools.compile_files('data/x509.asn', codec='der') for e in [mpz(3), mpz(65537)]: gcd_res = gcd(pow(jwt0_sig, e) - m0, pow(jwt1_sig, e) - m1) #To speed things up switch comments on prev/next lines! #gcd_res = mpz(0x143f02c15c5c79368cb9d1a5acac4c66c5724fb7c53c3e048eff82c4b9921426dc717b2692f8b6dd4c7baee23ccf8e853f2ad61f7151e1135b896d3127982667ea7dba03370ef084a5fd9229fc90aeed2b297d48501a6581eab7ec5289e26072d78dd37bedd7ba57b46cf1dd9418cd1ee03671b7ff671906859c5fcda4ff5bc94b490e92f3ba9739f35bd898eb60b0a58581ebdf14b82ea0725f289d1dac982218d6c8ec13548f075d738d935aeaa6260a0c71706ccb8dedef505472ce0543ec83705a7d7e4724432923f6d0d0e58ae2dea15f06b1b35173a2f8680e51eff0fb13431b1f956cf5b08b2185d9eeb26726c780e069adec0df3c43c0a8ad95cbd342)
n_bytes = b64urldecode(jks["n"]) p_bytes = b64urldecode(jks["p"]) q_bytes = b64urldecode(jks["q"]) d_bytes = b64urldecode(jks["d"]) e_bytes = b64urldecode(jks["e"]) n = bytes2mpz(n_bytes) p = bytes2mpz(p_bytes) q = bytes2mpz(q_bytes) d = bytes2mpz(d_bytes) e = bytes2mpz(e_bytes) jks_input = ".".join(encoded.decode('utf8').split('.')[0:2]) sha256_0 = SHA256.new(jks_input.encode('ascii')) padded = PKCS1_v1_5.EMSA_PKCS1_V1_5_ENCODE(sha256_0, 256) jks2_input = ".".join(encoded2.decode('utf8').split('.')[0:2]) sha256_2 = SHA256.new(jks2_input.encode('ascii')) padded2 = PKCS1_v1_5.EMSA_PKCS1_V1_5_ENCODE(sha256_2, 256) m = bytes2mpz(padded) m2 = bytes2mpz(padded2) s0 = pow(m, d, n) s2 = pow(m2, d, n) print("Generated and calculated signatures should match:\n") print("First signature:") print(hex(s0)) print(hex(encoded_sig))
def encode(digest_info, total_len): digest_info = digest_info.encode() padding_len = total_len - 3 - len(digest_info) return bytes([0x00, 0x01] + [0xFF] * padding_len + [0x00]) + digest_info def sha256_digest_info(digest): """See https://tools.ietf.org/html/rfc3447#section-9.2""" # http://oid-info.com/get/2.16.840.1.101.3.4.2.1 return make_digest_info("2.16.840.1.101.3.4.2.1", digest) assert (encode(sha256_digest_info(hashlib.sha256(b"hello").digest()), 1024) == PKCS1_v1_5.EMSA_PKCS1_V1_5_ENCODE( SHA256.new(b"hello"), 1024)) def sha1_digest_info(digest): # http://oid-info.com/get/1.3.14.3.2.26 return make_digest_info("1.3.14.3.2.26", digest) def get_digest(digest_asn1, ensure_full_parse=False): """Call this on an extracted ASN.1-encoded digest.""" digest_info, leftover = asn1.partial_decode(digest_asn1) if ensure_full_parse and len(leftover) > 0: return None return digest_info.types[1].str
# Reading the public key file key = RSA.importKey(open("public.key", 'r').read()) n = key.n e = key.e # Finding the signature suffix # string = "hi mom" # Step-1: Finding the target string ie. the output which we want string = "challenge" h = MD5.new(string) num = int(h.hexdigest(), 16) assert num % 2 == 1 padded = PKCS1_v1_5.EMSA_PKCS1_V1_5_ENCODE(h, size(key.n) / 8)[2:] padded = padded.encode("hex") print padded index = padded.find("00") padded = padded[index:].decode("hex") res = find_target(padded, 3) print long_to_bytes(bytes_to_long(res)**3).encode("hex")[-70:] while True: prefix = bytes_to_long("\x00\x01" + os.urandom(1024 / 8 - 2)) sig_prefix = long_to_bytes(true_cbrt(prefix))[:-35] sig = sig_prefix + res if "\x00" not in long_to_bytes(bytes_to_long(sig)**3)[:-35]: break