<commit_before>#!/usr/bin/python3

"""
 The hex encoded string:

<KEY>

... has been XOR'd against a single character. Find the key, decrypt 
    the message.

You can do this by hand. But don't: write code to do it for you.

How? Devise some method for "scoring" a piece of English plaintext. 
    Character frequency is a good metric. Evaluate each output and 
    choose the one with the best score. 
"""

import argparse
import string
import binascii
import sys

def find_key(hexstr):
    keys = ('', '', '')
    score = 0
    msg = binascii.unhexlify(hexstr.encode('utf-8'))

    def get_score(s):
        sscore = 0
        for c in s:
            if c in string.ascii_letters or c == ' ' or c == '\n':
                sscore += 1
            elif c in string.punctuation or c in string.digits:
                sscore -= 5
            else:
                sscore -= 100
        return sscore

    def xor_key(msg, key, msglen):
        testmsg = ''.join(chr(x ^ key) for x in msg)
        sscore = get_score(testmsg)
        if sscore > 0:
            return (testmsg, sscore)
        return ('', -1)

    for x in range(1,255):
        (test,testscore) = xor_key(msg,x,len(hexstr)/2)
        if score < testscore:
            score = testscore
            keys = (chr(x), test, score)
    return keys

def main():
    ret = find_key(
        '1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736'
        )
    if ret:
        print(ret[0] + ": " + ret[1])
        return 0
    return -1

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description='Tests finding a single char key by XOR\'ing a fixed hex \
        value representing encrypted data.')
    args = parser.parse_args()
    sys.exit(main())
<commit_msg>validate input by checking hex string length<commit_after>#!/usr/bin/python3

"""
 The hex encoded string:

1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736

... has been XOR'd against a single character. Find the key, decrypt 
    the message.

You can do this by hand. But don't: write code to do it for you.

How? Devise some method for "scoring" a piece of English plaintext. 
    Character frequency is a good metric. Evaluate each output and 
    choose the one with the best score. 
"""

import argparse
import string
import binascii
import sys

def find_key(hexstr):
    keys = ('', '', '')
    score = 0
    try:
        msg = binascii.unhexlify(hexstr.encode('utf-8'))
    except binascii.Error:
        print('Hexadecimal strings must be even length')
        return ''

    def get_score(s):
        sscore = 0
        for c in s:
            if c in string.ascii_letters or c == ' ' or c == '\n':
                sscore += 1
            elif c in string.punctuation or c in string.digits:
                sscore -= 5
            else:
                sscore -= 100
        return sscore

    def xor_key(msg, key, msglen):
        testmsg = ''.join(chr(x ^ key) for x in msg)
        sscore = get_score(testmsg)
        if sscore > 0:
            return (testmsg, sscore)
        return ('', -1)

    for x in range(1,255):
        (test,testscore) = xor_key(msg,x,len(hexstr)/2)
        if score < testscore:
            score = testscore
            keys = (chr(x), test, score)
    return keys

def main():
    ret = find_key(
        '<KEY>'
        )
    if ret:
        print(ret[0] + ": " + ret[1])
        return 0
    return -1

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description='Tests finding a single char key by XOR\'ing a fixed hex \
        value representing encrypted data.')
    args = parser.parse_args()
    sys.exit(main())

{'fraction_non_alphanumeric': 0.10250135943447526, 'fraction_numerical': 0.04187058183795541, 'mean_word_length': 2.078661087866109, 'pattern_counts': {'":': 2, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '782354', 'n_tokens_mistral': 1284, 'n_tokens_neox': 1165, 'n_words': 386}