Skip to content

Instantly share code, notes, and snippets.

@Grezzo
Last active August 29, 2015 14:22
Show Gist options
  • Save Grezzo/6c4abb17287389b0e92d to your computer and use it in GitHub Desktop.
Save Grezzo/6c4abb17287389b0e92d to your computer and use it in GitHub Desktop.
Pocket RC4 Decode for challenge 1 of MWR's HackFu 2015 Challenge
#Orders document for challenge 1 of MWR's HackFu 2015 mentions "Pocket RC4"
#Decrypt Pocket RC4 using algorythm from http://aarontoponce.org/wiki/card-ciphers/pocket-rc4
#Twitter account for clues is mentioned in earlier document
#Suit order from a tweet clue by MWRLabs (https://twitter.com/mwrlabs)
#"He Shall Conquer Dragons" (https://twitter.com/mwrlabs/status/579991389410357248)
def letter_to_number(letter):
return ord(letter.upper()) - 64 #64 is the number chars before "A"
def number_to_letter(number):
return chr(number + 64) #64 is the number chars before "A"
def value_to_card(number, color):
if number <= 13:
if color == 'black':
return [number, 'S']
else:
return [number, 'H']
else: #Clubs and diamonds are high
if color == 'black':
return [number - 13, 'C']
else:
return [number - 13, 'D']
def card_to_value(card): #If card is diamond or club (high suits), value is plus 13
if card[1] == 'D' or card[1] == 'C':
return card[0] + 13
else:
return card[0]
def load_deck(deck):
deck = deck.split()
for i in range(len(deck)):
number = deck[i][:-1]
if number == 'A':
number = 1
elif number == 'J':
number = 11
elif number == 'Q':
number = 12
elif number == 'K':
number = 13
else:
number = int(number)
suit = deck[i][-1:]
deck[i] = [number, suit]
return deck
def key_deck(deck, iv):
for letter in iv:
card = value_to_card(letter_to_number(letter), 'black')#Find black card that corresponds to letter
deck_location = deck.index(card) #Find place of black card in deck
deck[0], deck[deck_location - 1] = deck[deck_location - 1], deck[0] #Exchange the red card immediately above this black card with the top card (also red).
deck = deck + [deck.pop(deck_location - 1)] #Move the black IV card and the next red card immediately above this black card (red) to the bottom of the deck.
deck = deck + [deck.pop(deck_location - 1)]
deck = deck + [deck.pop(0)] #Move the top two cards on the deck (one red and one black) to the bottom of the deck.
deck = deck + [deck.pop(0)]
return deck
def decode_cypher(deck, cypher):
plaintext = ""
for letter in cypher:
j = card_to_value(deck[-2]) #Set the value of the bottom red card to 'j'.
j = (j + card_to_value(deck[0])) % 26 #Add the value of the top red card to j, modulo 26 (or 27 if using the jokers).
if j == 0: #26 % 26 is 0, but that's not a valid number, and should be 26 ("Z")
j = 26
deck_location = deck.index(value_to_card(j, 'black')) #Find the black card corresponding to 'j'.
k = (card_to_value(deck[deck_location - 1]) + card_to_value(deck[0])) % 26 #Add the red card immediately above the 'j' black card to the top red card modulo 26 (or 27 if using the jokers). Call this value 'k'.
if k == 0: #26 % 26 is 0, but that's not a valid number, and should be 26 ("Z")
k = 26
plaintext_number = (letter_to_number(letter) - k) % 26 #Subtract the value of 'k' from the ciphertext letter, modulo 26 (or 27 if using the jokers).
if plaintext_number == 0: #26 % 26 is 0, but that's not a valid number, and should be 26 ("Z")
plaintext_number = 26
plaintext_letter = number_to_letter(plaintext_number) #Write down this value as your ciphertext number, and convert to an alphabetic character.
deck[0], deck[deck_location - 1] = deck[deck_location - 1], deck[0] #Exchange the two red cards.
deck = deck + [deck.pop(0)] #Move the top two cards on the deck (one red and one black) to the bottom of the deck.
deck = deck + [deck.pop(0)]
plaintext += plaintext_letter
return plaintext
cyphertext = input('Input cyphertext or hit enter for default of\n\'WEMUSTFOLLOWTHEWHITERABBITANHXJRAAZEBYYOMNWPBKGZOGY\'\n') or 'WEMUSTFOLLOWTHEWHITERABBITANHXJRAAZEBYYOMNWPBKGZOGY'
deck = input('Input deck order or hit enter for default of\n\'AD AC 2D 2C 3D 3C 4D 4C 5D 5C 6D 6C 7D 7C 8D 8C 9D 9C 10D 10C JD JC QD QC KD KC AH AS 2H 2S 3H 3S 4H 4S 5H 5S 6H 6S 7H 7S 8H 8S 9H 9S 10H 10S JH JS QH QS KH KS\'\n') or 'AD AC 2D 2C 3D 3C 4D 4C 5D 5C 6D 6C 7D 7C 8D 8C 9D 9C 10D 10C JD JC QD QC KD KC AH AS 2H 2S 3H 3S 4H 4S 5H 5S 6H 6S 7H 7S 8H 8S 9H 9S 10H 10S JH JS QH QS KH KS'
iv = cyphertext[:26] #Extract initialisation vector from start of cyphertext
cypher = cyphertext[26:] #Extract actual encrypted characters from cyphertext
deck = load_deck(deck)
deck = key_deck(deck, iv)
plaintext = decode_cypher(deck, cypher)
plaintext = plaintext.lower() #Earlier doc says "All proceeding passphrases (excluding the epilogue) are all in lower case."
print('Plaintext is:', plaintext)
input('\nPress any key to close...')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment