title: Break Repeated Key XOR
body: <p>I'm working on the matasano crypto challenges <a href="http://cryptopals.com/sets/1/" rel="nofollow"><strong>here</strong></a></p>
  
  <p>But I'm having a hard time with challenge 6, which does a nice job of outlining the steps needed. I have to try finding the key size, break the cipher text into key size length blocks, transpose the blocks to get block corresponding to each byte of the key size and then solve the transposed blocks as if they were a single character XOR cipher. Conceptually, it all makes sense. But being pretty new to python, my program isn't working as desired. I've gone through and it looks like the hamming distance function below works as its supposed to, and breaking up the hex encoded text works as well. But when it comes time to call <code>get_max_single_char_xor</code>, I get a bunch of unreadable text back. Maybe a second pair of eyes can help me figure out what I'm doing wrong or why it's failing to give me readable output.</p>
  
  <p>check out the code below:</p>
  
  <pre><code>def calc_hamming_dist(str1, str2):
    diff = 0
    val = int(str1, 16) ^ int(str2, 16)
    while(val != 0):
      diff += 1
      val &amp;= val-1
    return diff
  
  def break_repeating_key_XOR(hex_text):
    keysize = 2
    key_hamming_val = []
    hex_len = len(hex_text)
    print 'hex_len: ' + str(hex_len)
  
    for b in xrange(2, 40):
      hamming_vals = 0
      pos = 0
      counter = 0
      while(pos + 2*keysize &lt;= hex_len):
          key1 = hex_text[pos:pos+keysize]
          pos += keysize
          key2 = hex_text[pos:pos+keysize]
          pos += keysize
          hamming_vals += calc_hamming_dist(key1, key2)
          counter += 1
      hamming_vals = float(hamming_vals/float(counter))
      key_hamming_val.append((float(hamming_vals/float(keysize)), keysize))
      keysize += 1
  
    print 'hamming_val length: ' + str(len(key_hamming_val))
    key_hamming_val.sort()
    for a in xrange(2, 38):
      blocks1 = []
      blocks2 = []
      count = 0
      key = ''
  
      min_hamming, keysize_guess = key_hamming_val[a]
      #for x in range(keysize_guess):
          #blocks2.append('')
      while count &lt;= hex_len:
          blocks1.append(hex_text[count:count+keysize_guess])
          count += keysize_guess
      print str(min_hamming) + ', ' + str(keysize_guess)
      zzz = 0
      for x in blocks1:
          zzz += len(x)
      #print blocks1
  
      for x in range(keysize_guess):
          count = 0
          in_str = ''
          while count &lt; len(blocks1):
              try:
                  in_str += (blocks1[count])[x]
              except IndexError:
                  break
              count += 1
          #print in_str
          blocks2.insert(x, in_str)
      zzz = 0
      for x in blocks2:
          zzz += len(x)
      #print blocks2
  
      for y in blocks2:
          if (len(y) % 2) != 0:
              y = '0' + y
          (score, words, key_guess) = get_max_single_char_xor(y)
          #print ' ' + str(key_guess)
          key += chr(key_guess)
  
      print key + ' (' + str(len(key)) + ')'
  </code></pre>
  
  <p>A few notes: hex_text being passed in is a string of hex values that have been encoded. Here are some of the functions being called in another module:</p>
  
  <pre><code>def score_plaintext(s, val):
    letters = filter(lambda val: 'a'&lt;=val&lt;='z' or 'A'&lt;=val&lt;='Z', s)
    #letters = filter(lambda  val: ' '&lt;=val&lt;='~', s)
    return float(len(letters)) / len(s)
  
  def get_max_single_char_xor(val):
    res = []
    for i in range(256):
      chrs = [chr(ord(s) ^ i) for s in val.decode('hex')]
      res.append([score_plaintext(chrs, val), ''.join(chrs), i])
  
  ret = sorted(res, key=lambda res: res[0], reverse=True)
    for i in ret:
      (score, words, key) = i
      if all(c in string.printable for c in words):
          return i
    return max(res, key=lambda s: s[0])
  </code></pre>
  
  <p>Based on some of the other challenges, the two functions above should be working fine. But I can't be sure.</p>
  
  <p>Anyone see any problems with this code?</p>