from hashlib import sha384 from os import urandom import binascii import datetime def validatedate(date): try: return datetime.datetime.strptime(date, "%Y-%m-%d").strftime('%Y-%m-%d') == date except ValueError: return False def hhash(seed, name, surname, birthdate, idnumber): """Hashes the "hacker ID" from the seed, name, surname, birth date and id number provided""" if not validatedate(birthdate): raise ValueError("Birth date must be in format YYYY-MM-DD") name = name.encode("utf-8") surname = surname.encode("utf-8") birthdate = birthdate.encode("utf-8") idnumber = idnumber.encode("utf-8") return sha384(b"%s%d %d %d %d %s%s%s%s%s" % (seed, len(name), len(surname), len(birthdate), len(idnumber), name, surname, birthdate, idnumber, seed)).digest() def create(name, surname, birthdate, idnumber): """Creates a "hacker ID" based on the name, surname, birth date and id number provided""" seed = urandom(1024//8) try: return binascii.hexlify(seed+hhash(seed, name, surname, birthdate, idnumber)).decode("ascii") except (UnicodeEncodeError, ValueError): return None def verify(hid, name, surname, birthdate, idnumber): """Verifies the "hacker ID" hid based on the name, surname, birth date and id number provided""" try: hid = hid.encode("ascii") except UnicodeEncodeError: return False try: hid = binascii.unhexlify(hid) except binascii.Error: return False if len(hid) != (1024+384)//8: return False try: hhid = hhash(hid[0:1024//8], name, surname, birthdate, idnumber) except (UnicodeEncodeError, ValueError): return False return hhid == hid[1024//8:] """Here are some tests to ensure this works as intended""" assert(sha384(b"\x00"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest() == hhash(b"\x00"*128,"Test","Testertons","1967-01-02", "ESP12345678Z")) assert(sha384(b"\x01"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x01"*128).digest() != hhash(b"\x00"*128,"Test","Testertons","1967-01-02", "ESP12345678Z")) assert(sha384(b"\x00"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Y"+b"\x00"*128).digest() != hhash(b"\x00"*128,"Test","Testertons","1967-01-02", "ESP12345678Z")) assert(sha384(b"\x00"*128+b"4210 10 12 TestTestertons1967-01-02ESP12345678>"+b"\x00"*128).digest() != hhash(b"\x00"*128,"Test","Testertons","1967-01-02", "ESP12345678Z")) assert(sha384(b"\x00"*128+b"3 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest() != hhash(b"\x00"*128,"Test","Testertons","1967-01-02", "ESP12345678Z")) assert(create("Test","Testertons","1967-01-02", "ESP12345678Z") is not None) assert(create("Testa","Testertons","1967-01-02", "ESP12345678Z") != create("Test","Testertons","1967-01-02", "ESP12345678Z")) assert(create("Test","Testertons","1967-01-02", "ESP12345678Z") != create("Test","Testertons","1967-01-02", "ESP12345678Z")) assert(create("Test","Testertons","1967-02-31", "ESP12345678Z") is None) assert(create("Test","Testertons","1967-13-01", "ESP12345678Z") is None) assert(create("Test","Testertons","1967-1-1", "ESP12345678Z") is None) assert(verify(binascii.hexlify(b"\x00"*128+sha384(b"\x00"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest()).decode("ascii"),"Test","Testertons","1967-01-02", "ESP12345678Z")) assert(not verify(binascii.hexlify(b"\x00"*128+sha384(b"\x01"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x01"*128).digest()).decode("ascii"),"Test","Testertons","1967-01-02", "ESP12345678Z")) assert(not verify(binascii.hexlify(b"\x00"*128+sha384(b"\x00"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest()).decode("ascii"),"Test","Testertons","1967-01-02", "ESP12345678Y")) assert(not verify(binascii.hexlify(b"\x00"*128+sha384(b"\x00"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest()).decode("ascii"),"Test","Testertons","1967-1-2", "ESP12345678Z")) assert(not verify(binascii.hexlify(b"\x00"*128+sha384(b"\x00"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest()).decode("ascii"),"Test","Testertons","1967-13-02", "ESP12345678Z")) assert(not verify(binascii.hexlify(b"\x00"*128+sha384(b"\x00"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest()).decode("ascii"),"Test","Testertons","1967-02-31", "ESP12345678Z")) assert(not verify(binascii.hexlify(b"\x00"*128+sha384(b"\x00"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest()).decode("ascii"),"Tes","Testertons","1967-01-02", "ESP12345678Z")) assert(not verify(binascii.hexlify(b"\x00"*128+sha384(b"\x00"*128+b"4210 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest()).decode("ascii"),"Test","Testertons","1967-01-02", "ESP12345678Z")) assert(not verify(binascii.hexlify(b"\x00"*128+sha384(b"\x00"*128+b"3 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest()).decode("ascii"),"Test","Testertons","1967-01-02", "ESP12345678Z")) assert(verify(create("Test","Testertons","1967-01-02", "ESP12345678Z"),"Test","Testertons","1967-01-02", "ESP12345678Z")) assert(not verify(create("Test","Testertons","1967-01-02", "ESP12345678Z"),"Testa","Testertons","1967-01-02", "ESP12345678Z")) assert(not verify(create("Test","Testertons","1967-01-02", "ESP12345678Z"),"Test","Testerton","1967-01-02", "ESP12345678Z")) assert(not verify(create("Test","Testertons","1967-01-02", "ESP12345678Z"),"Test","Testertons","1967-01-12", "ESP12345678Z")) assert(not verify(create("Test","Testertons","1967-01-02", "ESP12345678Z"),"Test","Testertons","1967-01-02", "ESP12345679Z")) """ This is intended to provide a way to safely authenticate a hacker's personal data when proofing ownership of something bound to their personal data (for example on the entrance of an event before receiving a physical token proving purchase of a ticket). The event is supposed to bind the last 384-bits (48 bytes) of the hacker identifier to the ticket. The person is supposed to provide the first 1024-bits (128 bytes) along with their ID (card, passport, etc.) matching the data used to generate the personal data provided and ticket on the entrance for verification. Requirements: * Seed is kept private and only provided to the event organizers. * A hacker must be able to generate an ID without using event infrastructure. * An event is able to verify the generated ID on their own infrastructure. * Creation and verification should be possible offline to prevent attacks. * Changes on any of the input parameters will make ID verification fail (with a negligible probability). * An attacker with the event part of the ID but without the seed can't obtain a hacker's personal data with a probability that is not negligible for guess. * An attacker with the event part of the ID and seed can only verify if a set of inputs match the event part or not. I.e. can't extract any part of the input without knowing the others. * An attacker cannot calculate a seed so that another set of data will match with a probability that is not negligible for try. Assumptions: * SHA384 isn't vulnerable to preimage attacks with a non negligble probability * SHA384 isn't vulnerable to collision attacks with a non negligble probability * os.urandom isn't predictable by an external attacker Challenges: I'm willing to pay you 1000EUR if before 2020-01-01 00:00CET you find the data values used to create the event string below (without asking me or attacking my computer) 'bfa6dffdfb06b488cf9ccd310b464a2f6e45189c6df994df82291ebd0d965cc12a9007103fd6c65f9ef849a16c3a4451' I'm willing to pay you 1000EUR if before 2020-01-01 00:00CET you find a value for seed so that verify(seed+'a352573fc6477a1ee2a224c73c754ad632f20a24b12a8b2ee5e995880cb17665f9609e97afdd131b316039d86440bd1f',"Hacker","Rebuyer","1967-05-23","SWE123321867G") is True 'a352573fc6477a1ee2a224c73c754ad632f20a24b12a8b2ee5e995880cb17665f9609e97afdd131b316039d86440bd1f' is the result of create("Evil","Reseller","2001-03-12","FRA762345123H") with seed '9cbdf7ec7a7d8540feda0acf402ab28b1967f41ba5bccabfd0655049487b3892ffdcc4aab5be10e39be336d6c68e3e7a266ed390a4f35cdd0e7c717af0ec8299a4dffd43a0dfb9ff63aba617617d5eae0a9d626c017e911b310b2c689b91a4928cb2a478fd8825284bdb6045e826171c5f811ecd54a806cfb5dfe7ebb9c87787' Keep in mind that for verify to work seed must be 1024 bits long Alternatively I'm willing to pay you 1000EUR if before 2020-01-01 00:00CET you find a method to find a seed so that it matches one of any personal data values I provide after you give me a 384-bit value of event hash of your choice in less than 6-months in a core i7-4710HQ. I.e. if you can generate a 384-bit value that matches a set of name, surname, birthdate and idnumber that you can't know before actually generating said 384-bit value. This emulates "a resale attack" where the reseller can't know the personal data of any of the buyers before actually purchasing the ticket. Keep in mind that I will want a proof of your attack before actually providing you with some data for this challenge. I'm willing to pay you 100EUR if before 2020-01-01 00:00CET you find either of the name, surname, birthdate or idnumber for the string below (without asking me or attacking my computer) and 1000 if you can find a way to do this in less than 6-months for any arbitrary value in a core i7-4710HQ. '82ca48064ce274b4a4ebfc3f0f2263c214ee1311c0222fb75acc7a5b1c2edc71c0071ef441cbe302e2a4cec46e98d3d40cae3c7356723beb10e221b2cd8a46c0ed42685777441039ab778bdd0321aaff6356e88800baacaf0229b4deb3559b29ea735ae994d2fcf04c2a0d37fcc3554ca3ef44c12db4b60bd805da42ebdaface9e7b2934d000b1d913e04cd56c4740083009d42605e45ff66946b85a988ed15f9ca5b01798341f45eaf571c5d768000e' If my data survives until then I will post the values used in challenges 1 and 3 before 2020-02-01 00:00CET Dates are in YYYY-MM-DD format I reserve the right to fix eventual errors in this challenge description and rejecting solutions which are against the spirit (breaking the cryptography) of the challenge. """