Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solved 0079 Passcode derivation #270

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions 0079_Passcode_derivation/0079_Passcode_derivation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# A common security method used for online banking is
# to ask the user for three random characters from a passcode.
# For example, if the passcode was 531278,
# they may ask for the 2nd, 3rd, and 5th characters
# the expected reply would be: 317.

# The text file, keylog.txt, contains fifty successful login attempts.

# Given that the three characters are always asked for in order,
# analyse the file so as to determine the shortest possible secret passcode of unknown length.


################################################
# TOO MUCH MEMORY FOR LONG KEY. TODO: OPTIMIZE #
################################################


from itertools import combinations, product

import numpy as np


def read_keylog(filename):
return np.loadtxt(filename, dtype=str, delimiter='\n')


def get_digits(n):
return [int(i) for i in str(n)]


def main():
keys_inserted_str = read_keylog("p079_keylog.txt")
# keys_inserted_str = ["317"]

length = 5
digits_str = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
digits_int = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
while True:
print("Searching for possible full keys with length:", length)

possible_indices_str_arr = list(combinations(digits_int[:length], 3))

possible_full_keys_set = set("".join(key_list) for key_list in product(digits_str, repeat=length))
found_at_least_one_before = False
for key_inserted in keys_inserted_str:
print("Checking inserted key", key_inserted, ". Length of found possible full keys:", len(possible_full_keys_set))
possible_full_keys_for_this_inserted_key = set()
found_at_least_one_before_for_this_inserted_key = False

for possible_full_key in possible_full_keys_set:
for possible_index in possible_indices_str_arr:

if possible_full_key[possible_index[0]] + \
possible_full_key[possible_index[1]] + \
possible_full_key[possible_index[2]] == key_inserted:
possible_full_keys_for_this_inserted_key.add(possible_full_key)
found_at_least_one_before_for_this_inserted_key = True

if found_at_least_one_before and len(possible_full_keys_set) == 0:
break
if found_at_least_one_before:
# intersect sets possible_full_keys_set and possible_full_keys_for_this_inserted_key
possible_full_keys_set = possible_full_keys_set.intersection(
possible_full_keys_for_this_inserted_key
)
else:
possible_full_keys_set = possible_full_keys_for_this_inserted_key
found_at_least_one_before = found_at_least_one_before_for_this_inserted_key

if found_at_least_one_before and len(possible_full_keys_set) == 0:
# full key with that length not possible, increase length
print("Full key with that length", length, "not possible, increase length to", length + 1)
length += 1
else:
# found something
print("\nFound something. List of all possible full keys:", sorted(list(possible_full_keys_set)))
break

main()
50 changes: 50 additions & 0 deletions 0079_Passcode_derivation/p079_keylog.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
319
680
180
690
129
620
762
689
762
318
368
710
720
710
629
168
160
689
716
731
736
729
316
729
729
710
769
290
719
680
318
389
162
289
162
718
729
319
790
680
890
362
319
760
316
729
380
319
728
716