CTFlearn-Writeups/Cryptography/ALEXCTF CR2_ Many time secrets/cribdrag.py

105 lines
4.5 KiB
Python

#!/usr/bin/python
##########################
# cribdrag - An interactive crib dragging tool
# Daniel Crowley
# Copyright (C) 2013 Trustwave Holdings, Inc.
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
##########################
import sys
import re
import argparse
def sxor(ctext,crib):
# convert strings to a list of character pair tuples
# go through each tuple, converting them to ASCII code (ord)
# perform exclusive or on the ASCII code
# then convert the result back to ASCII (chr)
# merge the resulting array of characters as a string
results = []
single_result = ''
crib_len = len(crib)
positions = len(ctext)-crib_len+1
for index in xrange(positions):
single_result = ''
for a,b in zip(ctext[index:index+crib_len],crib):
single_result += chr(ord(a) ^ ord(b))
results.append(single_result)
return results
def print_linewrapped(text):
line_width = 40
text_len = len(text)
for chunk in xrange(0,text_len,line_width):
if chunk > text_len-line_width:
print str(chunk) + chr(9) + text[chunk:]
else:
print str(chunk) + chr(9) + text[chunk:chunk+line_width]
parser = argparse.ArgumentParser(description='cribdrag, the interactive crib dragging script, allows you to interactively decrypt ciphertext using a cryptanalytic technique known as "crib dragging". This technique involves applying a known or guessed part of the plaintext (a "crib") to every possible position of the ciphertext. By analyzing the result of each operation and the likelihood of the result being a successful decryption based on the expected format and language of the plaintext one can recover the plaintext by making educated guesses and adaptive application of the crib dragging technique.')
parser.add_argument('ciphertext', help='Ciphertext, encoded in an ASCII hex format (ie. ABC would be 414243)')
parser.add_argument('-c', '--charset', help='A regex-style character set to be used to identify best candidates for successful decryption (ex: for alphanumeric characters and spaces, use "a-zA-Z0-9 ")', default='a-zA-Z0-9.,?! :;\'"')
args = parser.parse_args()
ctext = args.ciphertext.decode('hex')
ctext_len = len(ctext)
display_ctext = "_" * ctext_len
display_key = "_" * ctext_len
charset = '^['+args.charset+']+$'
response = ''
while response != 'end':
print "Your message is currently:"
print_linewrapped(display_ctext)
print "Your key is currently:"
print_linewrapped(display_key)
crib = raw_input("Please enter your crib: ")
crib_len = len(crib)
results = sxor(ctext, crib)
results_len = len(results)
#Generate results
for result_index in xrange(results_len):
if (re.search(charset,results[result_index])):
print '*** ' + str(result_index) + ': "' + results[result_index] + '"'
else:
print str(result_index) + ': "' + results[result_index] + '"'
response = raw_input("Enter the correct position, 'none' for no match, or 'end' to quit: ")
#Replace part of the message or key
try:
response = int(response)
if (response < results_len):
message_or_key = ''
while (message_or_key != 'message' and message_or_key != 'key'):
message_or_key = raw_input("Is this crib part of the message or key? Please enter 'message' or 'key': ")
if(message_or_key == 'message'):
display_ctext = display_ctext[:response] + crib + display_ctext[response+crib_len:]
display_key = display_key[:response] + results[response] + display_key[response+crib_len:]
elif(message_or_key == 'key'):
display_key = display_key[:response] + crib + display_key[response+crib_len:]
display_ctext = display_ctext[:response] + results[response] + display_ctext[response+crib_len:]
else:
print 'Invalid response. Try again.'
except ValueError:
if (response == 'end'):
print "Your message is: " + display_ctext
print "Your key is: " + display_key
elif (response == 'none'):
print "No changes made."
else:
print "Invalid entry."