Giải mã bằng phân tích mẫu


11

Bạn được cung cấp một chuỗi được mã hóa, được mã hóa bằng mật mã thay thế rất đơn giản.

Vấn đề

Bạn không biết mật mã là gì nhưng bạn có biết mật mã là tiếng Anh và các chữ cái thường gặp nhất trong tiếng Anh là etaoinshrdlucmfwypvbgkqjxz theo thứ tự đó. Các ký tự được phép duy nhất là chữ in hoa và dấu cách. Bạn có thể thực hiện phân tích cơ bản - bắt đầu từ các chữ cái đơn lẻ, nhưng bạn có thể chuyển sang phân tích nhiều chữ cái phức tạp hơn - ví dụ, U hầu như luôn theo sau Q và chỉ một số chữ cái có thể đến hai lần liên tiếp.

Ví dụ

clear : SUBMARINE TO ATTACK THE DOVER WAREHOUSE AND PORT ON TUESDAY SUNRISE
cipher: ZOQ DUPAEYSRYDSSDXVYSHEYNRBEUYLDUEHROZEYDANYKRUSYRAYSOEZNDMYZOAUPZE

clear : THE QUICK BROWN FOX BEING QUITE FAST JUMPED OVER THE LAZY DOG QUITE NICELY
cipher: TNAEPDHIGEMZQJLEVQBEMAHL EPDHTAEVXWTEODYUASEQKAZETNAERXFCESQ EPDHTAELHIARC

clear : BUFFALO BUFFALO BUFFALO BUFFALO BUFFALO BUFFALO BUFFALO
cipher: HV  WRPDHV  WRPDHV  WRPDHV  WRPDHV  WRPDHV  WRPDHV  WRP

Thử thách

Xem bạn có thể giải mã văn bản trong mỗi mật mã này không:

  • SVNXIFCXYCFSXKVVZXIHXHERDXEIYRAKXZCOFSWHCZXHERDXBNRHCXZR RONQHXORWECFHCUH
  • SOFPTGFIFBOKJPHLBFPKHZUGLSOJPLIPKBPKHZUGLSOJPMOLEOPWFSFGJLBFIPMOLEOPXULBSIPLBP KBPBPWLIJFBILUBKHPGKISFG
  • TMBWFYAQFAZYCUOYJOBOHATMCYNIAOQW Q JAXOYCOCYCHAACOCYCAHGOVYLAOEGOTMBWFYAOBFF ACOBHOKBZYKOYCHAUWBHAXOQW XITHJOV WOXWYLYCU
  • FTRMKRGVRFMHSZVRWHRSFMFLMBNGKMGTHGBRSMKROKLSHSZMHKMMMMMRVVLVMPRKKOZRMFVDSGOFRW

Tôi có ma trận thay thế và văn bản rõ ràng cho từng loại, nhưng tôi sẽ chỉ tiết lộ chúng nếu nó trở nên quá khó khăn hoặc ai đó không tìm ra.

Giải pháp có thể giải mã được nhiều tin nhắn thành công nhất là người chiến thắng. Nếu hai giải pháp tốt như nhau, chúng sẽ được quyết định bằng số phiếu.


3
Điều gì định nghĩa »thanh lịch nhất«? Tôi nghĩ đó là điều tương tự mà Chris đã phản đối trong 99 chai. Đó là một tiêu chí chủ quan khá khó để đánh giá.
Joey

@Joey Hầu hết các upvote? Hãy để cộng đồng quyết định.
Thomas O

2
Re "most upvote": Tôi không vui khi thấy điều này trở thành một bài đăng cuộc thi phổ biến, không chỉ bởi vì bài viết là xuất sắc; xem meta.codegolf.stackexchange.com/questions/110/ Khăn để biết suy nghĩ của tôi về toàn bộ vấn đề.
Chris Jester-Young

2
"Elegant" nghĩa là gì ở đây? Hiệu suất big-O tốt nhất?
gnibbler

1
@ Bass5098, không. Nó chỉ là một bản mã khó được xử lý để làm cho nó trở nên linh hoạt hơn để phân tích tần số.
Thomas O

Câu trả lời:


9

Con trăn

Tôi đã tìm ra tất cả các cụm từ bí mật, nhưng tôi sẽ không đăng chúng ở đây. Chạy mã nếu bạn quan tâm.

Mã này hoạt động bằng cách chọn một ký tự khoảng trắng, liệt kê tất cả các thay thế có thể cho mỗi từ, sau đó tìm kiếm các thay thế tương thích. Nó cũng cho phép một số từ ngoài từ vựng xử lý lỗi chính tả trong văn bản rõ ràng :)

Tôi đã sử dụng một từ vựng lớn (~ 500K từ) từ http://wordlist.sourceforge.net/ .

import sys,re

# get input
message = sys.argv[1]

# read in lexicon of words
# download scowl version 7.1
# mk-list english 95 > wordlist
lexicon = set()
roman_only = re.compile('^[A-Z]*$')
for word in open('wordlist').read().upper().split():
  word=word.replace("'",'')
  if roman_only.match(word): lexicon.add(word)

histogram={}
for c in message: histogram[c]=0
for c in message: histogram[c]+=1
frequency_order = map(lambda x:x[1], sorted([(f,c) for c,f in histogram.items()])[::-1])

# returns true if the two maps are compatible.
# they are compatible if the mappings agree wherever they are defined,
# and no two different args map to the same value.
def mergeable_maps(map1, map2):
  agreements = 0
  for c in map1:
    if c in map2:
      if map1[c] != map2[c]: return False
      agreements += 1
  return len(set(map1.values() + map2.values())) == len(map1) + len(map2) - agreements

def merge_maps(map1, map2):
  m = {}
  for (c,d) in map1.items(): m[c]=d
  for (c,d) in map2.items(): m[c]=d
  return m

def search(map, word_maps, outside_lexicon_allowance, words_outside_lexicon):
  cleartext = ''.join(map[x] if x in map else '?' for x in message)
  #print 'trying', cleartext

  # pick a word to try next
  best_word = None
  best_score = 1e9
  for (word,subs) in word_maps.items():
    if word in words_outside_lexicon: continue
    compatible_subs=0
    for sub in subs:
      if mergeable_maps(map, sub): compatible_subs += 1
    unassigned_chars = 0
    for c in word:
      if c not in map: unassigned_chars += 1  #TODO: duplicates?
    if compatible_subs == 0: score = 0
    elif unassigned_chars == 0: score = 1e9
    else: score = 1.0 * compatible_subs / unassigned_chars   # TODO: tweak?
    if score < best_score:
      best_score = score
      best_word = word
  if not best_word:  # no words with unset characters, except possibly the outside lexicon ones
    print cleartext,[''.join(map[x] if x in map else '?' for x in word) for word in words_outside_lexicon]
    return True

  # use all compatible maps for the chosen word
  r = False
  for sub in word_maps[best_word]:
    if not mergeable_maps(map, sub): continue
    r |= search(merge_maps(map, sub), word_maps, outside_lexicon_allowance, words_outside_lexicon)

  # maybe this word is outside our lexicon
  if outside_lexicon_allowance > 0:
    r |= search(map, word_maps, outside_lexicon_allowance - 1, words_outside_lexicon + [best_word])
  return r

for outside_lexicon_allowance in xrange(3):
  # assign the space character first
  for space in frequency_order:
    words = [w for w in message.split(space) if w != '']
    if reduce(lambda x,y:x|y, [len(w)>20 for w in words]): continue  # obviously bad spaces

    # find all valid substitution maps for each word
    word_maps={}
    for word in words:
      n = len(word)
      maps = []
      for c in lexicon:
        if len(c) != n: continue
        m = {}
        ok = 1
        for i in xrange(n):
          if word[i] in m:                      # repeat letter
            if m[word[i]] != c[i]: ok=0; break  # repeat letters map to same thing
          elif c[i] in m.values(): ok=0; break  # different letters map to different things
          else: m[word[i]]=c[i]
        if ok: maps.append(m);
      word_maps[word]=maps

    # look for a solution
    if search({space:' '}, word_maps, outside_lexicon_allowance, []): sys.exit(0)

print 'I give up.'

1

PHP (Chưa hoàn thành)

Đây là một giải pháp PHP chưa hoàn chỉnh, hoạt động bằng cách sử dụng thông tin tần số chữ cái trong câu hỏi cộng với một từ điển các từ khớp với các biểu thức thông thường dựa trên các chữ cái đáng tin cậy nhất trong từ đã cho.

Hiện tại từ điển khá nhỏ nhưng với sự mở rộng phù hợp tôi dự đoán rằng kết quả sẽ được cải thiện. Tôi đã xem xét khả năng khớp một phần nhưng với từ điển hiện tại, điều này dẫn đến sự xuống cấp thay vì cải thiện kết quả.

Ngay cả với từ điển nhỏ, hiện tại tôi nghĩ rằng tôi hoàn toàn có thể nói những gì thông điệp thứ tư mã hóa.

#!/usr/bin/php
<?php

    if($argv[1]) {

        $cipher = $argv[1];

        // Dictionary
        $words = explode("/", "the/to/on/and/in/is/secret/message");
        $guess = explode("/", "..e/t./o./a../i./.s/.e..et/.ess..e");

        $az = str_split("_etaoinshrdlucmfwypvbgkqjxz");

        // Build table
        for($i=0; $i<strlen($cipher); $i++) {
            $table[$cipher{$i}]++;
        }
        arsort($table);

        // Do default guesses
        $result = str_replace("_", " ", str_replace(array_keys($table), $az, $cipher));

        // Apply dictionary
        $cw = count($words);
        for($i=0; $i<$cw*2; $i++) {
            $tokens = explode(" ", $result);
            foreach($tokens as $t) {
                if(preg_match("/^" . $guess[$i%$cw] . "$/", $t)) {
                    $result = deenc($words[$i%$cw], $t, $result);
                    echo $t . ' -> ' . $words[$i%$cw] . "\n";
                    break;
                }
            }
        }

        // Show best guess
        echo $result . "\n";

    } else {

        echo "Usage: " . $argv[0] . " [cipher text]\n";

    }

    // Quick (non-destructive) replace tool
    function deenc($word, $enc, $string) {
        $string = str_replace(str_split($enc), str_split(strtoupper($word)), $string);
        $string = str_replace(str_split($word), str_split($enc), $string);
        return strtolower($string);
    }

?>

Hãy thử sử dụng / usr / share / dict / words nếu bạn đang sử dụng hệ thống có nó.
Keith Randall
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.