Categories
Articles

Expectra – SalaireInGame

Expectra - SalaireInGame

This week was the occasion to (re)try last year's "SalaireInGame" challenge from Expectra. Back then, the first developper to solve all 5 enigmas had is salary doubled for the current month (yeah, better be a senior in this case 🙂 )

I chose python to go with, because it's my favourite scripting language, and the one for which I need the less reflexion and googeling to get something to work.

There is probably a lot of improvements that can be made to the scripts bellow, so don't hesitate to share your thoughts on the matter.

Before I start with solutions, you can check out the challenges yourself here : https://salaireingame.expectra.fr/. There really accessible, so try it out !

Enigma 1

First enigma consists in finding the first round number which's SHA512 hash started with 6 'a'.

import hashlib

i = 0
sha= ""

print("STARTING :")

while True:
    sha = hashlib.sha512(str(i).encode()).hexdigest() #encoding the number
    if (sha[:6] == "aaaaaa"): #if the hash starts with 'aaaaaa' exits the loop
        break
    i += 1

print("Hash : ", sha)
print("Number : ",i)

#answer is : 35318008

It might take some time, so don't worry if it's not printing anything at first. If you want to make sure it's running properly, you can add something like that in your main loop :

if i%1000000 = 0:
    print(i, " tries...")

But on programs with long loops and lots of calculations like that, never try to print the state at each loop. It might not seem like it, but printing does actually take some time. You can try it out, run it without any printing (except for the result of course), and by printing something at each loop. You will notice a great difference.

Enigma 2

For this one, you need to find an MD5 hash. The hash is basically a date in the following format :

YYMMDDHHmmss

The two things we know is that the date is between the 25 of July 2019 at 16h55min45s and the 6 of July 2019 at 18h26min50s, and that the 4 starting digits of the hash equal to the 4 last.

import hashlib

YY = "19"
MM = "07"
DD = 25
HH = 16
mm = 55
ss = 45

def convertDateString(DD,HH,mm,ss):
    """returns en encoded value corresponding to the formated date"""
    if (len(str(ss)) == 1):
        ss = "0"+str(ss)
    if (len(str(mm)) == 1):
        mm = "0"+str(mm)
    return (YY+MM+str(DD)+str(HH)+str(mm)+str(ss)).encode()


while (convertDateString(DD,HH,mm,ss) != b'190726182651'): # 190726182651-1 is the last possible date
    md5 = hashlib.md5(convertDateString(DD,HH,mm,ss)).hexdigest()
    if (md5[:4] == md5[-4:]): #comparing the 4 start and end digits
        print(md5)
        break
    ss += 1
    if (ss == 60): #incrementing if a full minute/hour/day was reached
        ss = 0
        mm += 1
    if (mm == 60):
        mm = 0
        HH += 1
    if (HH == 24):
        HH = 0
        DD += 1

#answer is : d5fc927dcdbb0a21e85e2759f6bbd5fc

Enigma 3

Here, you need to give the 100th element on the 200th line of Pascal's triangle. I remembered working on that triangle at school when I was younger, and that there are lot's of python scripts online for it. I took the first I found. The only thing to remember here when adding the printing restrictions is that the first element of a list actually has the index 0.

def trianglePascal(n):
    T = [[0] * (n+1) for p in range(n+1)]
    for n in range(n+1):
        if n == 0:
            T[n][0] = 1
        else:
            for k in range(n+1):
                if k == 0:
                    T[n][0] = 1
                else:
                    T[n][k] = T[n-1][k-1] + T[n-1][k]
    return T
print(trianglePascal(199)[199][99])

#anwser is : 45274257328051640582702088538742081937252294837706668420660

Enigma 4

The 4th was a little bit trickier (but nothing impossible don't worry). You get en encoded message, with the decoding protocol :

  • alphabetically sort the string
  • make a list of the number of occurences of each letter
  • decode knowing that 100 = 'a', 101 = 'b', 125 = 'z', 126 = ' '
m = "cnhhnhtanfreoeqitmptkaqcrjqhipabqhehanthitdposdgekjpqibceckmcmckfkcacdhggsdrdpinoedddofemdtrhjroepscdaskslgcclngaofmfprdnrodkftmgetiqrmlqimqreealabdibrmhfdqlidfltofhgrlospeemtdiholtmepcikatgprnhjlmpoglpcrktrbgdgtlkhiqssjdhtafsjffemikbjchkefgkeiarhoadgnteeeaomamnitlpfqalikbolbtrjitornkecitqsrblahlldgogceoeoeaeskmlqeshobkhckllnebsbetafesgcepsbdfkiahtjingpcjsoekkgncleesriqbcroidqorrtkhsnlikajdptptcinjpcglhsrlpnajpoctkhbikkcraaccsfrsjaeggmsbdorogdosmeofjamiqnsckgsaipjsfrasmlshcdgljcjqtpoelabkfkpjhjatigrfptbggknlpnnaojqrjodagaprahknentjarphosflnfklpeppfmtmooneracdjrjmpjcpjmknaootgscninqgoqedjffootcphihadosdefbkqhhoaotgkljknbflbjassaerfgnkaffjqgprbgntretnobsdrsbqmkseeqfbtadgopcqhpslrfoesimrhjpnhnbtidcrsqancnojmeoqphqqtbqhcregtsrlkedbqkjsgjbbpkhtjqsscfpkhtmkdaciirfgamabketrcsjdthackqfbijmgkpqnjanbesddtlfbmidbonnpsbiqbkmfhijptsphnshmlntgnskbqodngpiggqbcfcrcmkjincfdkotgcqgifialhhcjpqoocrnlebroiskplerloblhfrfajfnedfrcspcrpncchiqfqdfjsikmnhjffjlrnahdidllbnroqakpebeissgcbloqgdstnotlhknjscssqnheclkikehfbomioqfjtambhoadebcpsbsmbhhsjbkdtabbnsarghnbjgbfrrnlrmmnhitlojsondjinljfaforgdqhqpbhaongsismsdttbktlqkkfsefloooohalkmhpfdidjlssdhgeafkolncgknsmkkqgcmkdsmicmpjhmhfancllghbsmncdqpmhqdcenhtmtlafahhmdhnalgbbchlbigbnsomtqehteeodqhcngnrdfmjdlkbsinrarnciemhbljllqmnmnhrennfncljojfcrehbjgkesehghrdciebttbasdhqcsrlhplibscpatsjkjqagqreolechrfhsirjihsnchfdnaqmkpdplcnptjlflqmqtfcdcegfaeipdjqnorjtgdpjcfnlehmnqrpdlhobtchigkcdkgdmlkrbcdnirogdgmghpsihcftajoqroccacrremphrmmqgtrhfncntfjkdiitpmehgtqgehokoicqmjajfkfppklkkfdbrbimcqgkilsjjbfbnpkqglqkhllkcdobaacgjkmspldmlrgfkejribbesmmdljlbbaoftoenarodmaiasbolktbffidhfiecamdjehkqgoojanrsjohegpcnntebkbpjlorqglaqngrsqjmpgrpikgcrflkohhckqjctmhpapntmhrkipbnmrmoorglqraemdqkdhhbilpbdnjhgnnjblhctplsgtlqcenfrelmhgqdmrjjcsfljdkarnorppamnsichpeqshqjkroclegoameknrfbirodqstabbalirtnrlldopmmqdldoksrepsbpmkmtreqfpiffdekgqlkkgcjkappooolrldkmbbmnfqtrdsotjdsdqfhahdotlajgnsrmbkdsadoetpqiclqaaoqitrlijdasbbgimtqrhsgtneehgrcfbdmlofjpcqkaijtlqojstofpeltfsdantqngtajlsmebcokoeoiclfsqnkferebijamomccgklbhlbotksmlebdilliiqlnhdhkcnpmnmdsdshgaeckcpjitdsqqdktkfrsanorjnglqpgbhsospllegnkrsaimkhnccptfhbjlhpheqgcdbkgigltfanpmplaimrbqejbdlhlgeadsrbbmapccnjleknmjprktcdseipfifnddsnigdpkbobchrbgrbpfdrbqfnrlfcichsiieknhkjrhdmbqneicai"

sorted = "".join(sorted(m)) #sorting the string
c = "a" #initilizing a reference to the first letter value 
occurence = [0]
result = ""

for l in sorted:
    if l == c: #if the letter is still the same
        occurence[len(occurence)-1] += 1 #add one
    else: #if not, change to the new letter the reference
        c = l
        occurence.append(1) #create a new entry in our occurence list

#at this point we have this :
#[109, 114, 120, 117, 113, 104, 104, 126, 103, 104, 121, 126, 104, 123, 115, 104, 102, 119, 117, 100]

for n in occurence:
    if n == 126:
        result += " "
    else:
        result += chr(n-3) #matching the numbers to the corresponding letter
        
print(result)

#anwser is : journee dev expectra

I believe the comments are pretty clear here. On point I want to precise is the use of chr(n-3)

n is the value read in the occurrence list. I figured there was a gap of 3 between the Unicode value of a letter and it's value in the challenges cipher. (Example : unicode(a) = 97 | challenge(a) = 100)

chr() just transforms a Unicode integer representation into its character equivalent.

Enigma 5

And last (I would have said "and not least", but the last one is actually easier than the previous one in my opinion), you need to encode the String "expectra" by following the previous protocol (in reverse of course) without mixing the final String.

m = "expectra"
inNumber = []
result = ""

for l in m:
    inNumber.append(ord(l)+3) #converting the letters into numerical value
                              #by using the same trick then for enigma 4
l = 97

for n in inNumber:
    for i in range(n):
        result += chr(l)
    l += 1

print(result)

#answer is : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh

I don't think this script needs more explanations once you've understood the previous one.

In conclusion, nothing really hard about these challenges if you have any experience with any programming language. It was more of a speed contest really.

If you're interested in checking out last year's winner Mathis Hammel's solutions, you can do it here : https://blog.h25.io/Expectra-SalaireInGame/

This is it for this article, see you !

Leave a Reply

Your email address will not be published. Required fields are marked *