Solve challenge 19 in Python because my Rust still sucks.
parent
e70c6c470c
commit
467c3bdbef
|
@ -0,0 +1,40 @@
|
|||
SSBoYXZlIG1ldCB0aGVtIGF0IGNsb3NlIG9mIGRheQ==
|
||||
Q29taW5nIHdpdGggdml2aWQgZmFjZXM=
|
||||
RnJvbSBjb3VudGVyIG9yIGRlc2sgYW1vbmcgZ3JleQ==
|
||||
RWlnaHRlZW50aC1jZW50dXJ5IGhvdXNlcy4=
|
||||
SSBoYXZlIHBhc3NlZCB3aXRoIGEgbm9kIG9mIHRoZSBoZWFk
|
||||
T3IgcG9saXRlIG1lYW5pbmdsZXNzIHdvcmRzLA==
|
||||
T3IgaGF2ZSBsaW5nZXJlZCBhd2hpbGUgYW5kIHNhaWQ=
|
||||
UG9saXRlIG1lYW5pbmdsZXNzIHdvcmRzLA==
|
||||
QW5kIHRob3VnaHQgYmVmb3JlIEkgaGFkIGRvbmU=
|
||||
T2YgYSBtb2NraW5nIHRhbGUgb3IgYSBnaWJl
|
||||
VG8gcGxlYXNlIGEgY29tcGFuaW9u
|
||||
QXJvdW5kIHRoZSBmaXJlIGF0IHRoZSBjbHViLA==
|
||||
QmVpbmcgY2VydGFpbiB0aGF0IHRoZXkgYW5kIEk=
|
||||
QnV0IGxpdmVkIHdoZXJlIG1vdGxleSBpcyB3b3JuOg==
|
||||
QWxsIGNoYW5nZWQsIGNoYW5nZWQgdXR0ZXJseTo=
|
||||
QSB0ZXJyaWJsZSBiZWF1dHkgaXMgYm9ybi4=
|
||||
VGhhdCB3b21hbidzIGRheXMgd2VyZSBzcGVudA==
|
||||
SW4gaWdub3JhbnQgZ29vZCB3aWxsLA==
|
||||
SGVyIG5pZ2h0cyBpbiBhcmd1bWVudA==
|
||||
VW50aWwgaGVyIHZvaWNlIGdyZXcgc2hyaWxsLg==
|
||||
V2hhdCB2b2ljZSBtb3JlIHN3ZWV0IHRoYW4gaGVycw==
|
||||
V2hlbiB5b3VuZyBhbmQgYmVhdXRpZnVsLA==
|
||||
U2hlIHJvZGUgdG8gaGFycmllcnM/
|
||||
VGhpcyBtYW4gaGFkIGtlcHQgYSBzY2hvb2w=
|
||||
QW5kIHJvZGUgb3VyIHdpbmdlZCBob3JzZS4=
|
||||
VGhpcyBvdGhlciBoaXMgaGVscGVyIGFuZCBmcmllbmQ=
|
||||
V2FzIGNvbWluZyBpbnRvIGhpcyBmb3JjZTs=
|
||||
SGUgbWlnaHQgaGF2ZSB3b24gZmFtZSBpbiB0aGUgZW5kLA==
|
||||
U28gc2Vuc2l0aXZlIGhpcyBuYXR1cmUgc2VlbWVkLA==
|
||||
U28gZGFyaW5nIGFuZCBzd2VldCBoaXMgdGhvdWdodC4=
|
||||
VGhpcyBvdGhlciBtYW4gSSBoYWQgZHJlYW1lZA==
|
||||
QSBkcnVua2VuLCB2YWluLWdsb3Jpb3VzIGxvdXQu
|
||||
SGUgaGFkIGRvbmUgbW9zdCBiaXR0ZXIgd3Jvbmc=
|
||||
VG8gc29tZSB3aG8gYXJlIG5lYXIgbXkgaGVhcnQs
|
||||
WWV0IEkgbnVtYmVyIGhpbSBpbiB0aGUgc29uZzs=
|
||||
SGUsIHRvbywgaGFzIHJlc2lnbmVkIGhpcyBwYXJ0
|
||||
SW4gdGhlIGNhc3VhbCBjb21lZHk7
|
||||
SGUsIHRvbywgaGFzIGJlZW4gY2hhbmdlZCBpbiBoaXMgdHVybiw=
|
||||
VHJhbnNmb3JtZWQgdXR0ZXJseTo=
|
||||
QSB0ZXJyaWJsZSBiZWF1dHkgaXMgYm9ybi4=
|
|
@ -0,0 +1,40 @@
|
|||
P/GjKtnHZo+G2yMpBHauUrOYTL/0AmG777V5s8uPCg==
|
||||
Nb6mIsHFZpWK22t9Gnq1G7bMCr37CGE=
|
||||
MKOkJo/BKZeN22YvTHyxUraJH7e4DH+xob0/9N2LCg==
|
||||
M7isI9vHI4yXxy4+CX23B6CVTLT3GGG7vPQ=
|
||||
P/GjKtnHZpKC3HA4CDO0G6aETL24A32677V5s9uGFjhFxe+v
|
||||
OaPrO8DOL5aGj244DX2qHLWACa/rTWWxvb5svw==
|
||||
OaPrI87UI8KPxm06CWGmFvKNG7TxAXf+rrR7s9yPGnw=
|
||||
Jr6nItvHZo+Gzm00AnSvF6GfTKv3H3at4w==
|
||||
N7+va9vKKZeEx3d9DnalHaCJTJW4BXO6775w/co=
|
||||
ObfrKo/PKYGIxm06TGeiHrfMA664DDK5prh6
|
||||
Ir7rO8PHJ5GGj2J9D3yuArOCBbP2
|
||||
N6OkPsHGZpaLyiM7BWGmUrOYTKjwCDK9o699vw==
|
||||
NLSiJciCJYeR22I0AjO3GrOYTKjwCGv+rrR7s+Y=
|
||||
NKS/a8PLMIeHj3Q1CWGmUr+DGLD9FDK3vPpo/N2ASQ==
|
||||
N72na8zKJ4yEymdxTHCrE7yLCbi4GGaqqqhz6pU=
|
||||
N/G/Lt3QL4CPyiM/CXK2BqvMBa+4D32sofQ=
|
||||
IrmqP4/VKY+CwSQuTHeiC6HMG7nqCDKtv79x5w==
|
||||
P7/rIsjMKZCCwXd9C3ysFvKbBbD0QQ==
|
||||
PrS5a8HLIYqX3CM0AjOiALWZAbn2GQ==
|
||||
I7+/IsOCLoeRj3UyBXCmUrWeCau4HnqsprZzvQ==
|
||||
IbmqP4/UKYuAyiMwA2GmUqGbCbnsTWa2rrQ/+8qcAA==
|
||||
IbmuJY/bKZeNyCM8AnfjELeNGajxC2ey4w==
|
||||
Jbmua93NIofD22x9BHKxALuJHq+n
|
||||
IrmiOI/PJ4zDx2I5THimAqbMDfzrDnqxoLY=
|
||||
N7+va93NIofDwHYvTGSqHLWJCPzwAmCtqvQ=
|
||||
IrmiOI/NMoqG3SM1BWDjGreAHLnqTXOwq/p54caLHXw=
|
||||
IbC4a8zNK4uNyCM0AmesUrqFH/z+AmC9quE=
|
||||
PrTrJsbFLpbDx2IrCTO0HbzMCr31CDK3ofpr+8rOFnZJjA==
|
||||
Jb7rOMrMNYuXxnU4THuqAfKCDajtH3f+vL96/sqKXw==
|
||||
Jb7rL87QL4yEj2IzCDOwBbeJGPzwBGH+u7Jw5siGBzY=
|
||||
IrmiOI/NMoqG3SMwDX3jO/KEDbi4CWC7rrd69w==
|
||||
N/GvOdrMLYeNgyMrDXqtX7WAA67xAmet77Zw5tvA
|
||||
PrTrI87GZoaMwWZ9AXywBvKOBajsCGD+uKhw/cg=
|
||||
Ir7rOMDPI8KUx2x9DWGmUryJDa64AGv+p79+4dvC
|
||||
L7S/a+aCKJeOzWYvTHuqH/KFAvzsBXf+vLVx9JQ=
|
||||
PrTna9vNKc7Dx2IuTGGmAbuLArn8TXq3vPpv8t2a
|
||||
P7/rP8fHZoGC3HY8ADOgHb+JCKWj
|
||||
PrTna9vNKc7Dx2IuTHGmF7zMD7T5A3W7q/p2/Y+GGmsN1Pu5f1c=
|
||||
IqOqJdzEKZCOymd9GWe3F6CAFeY=
|
||||
N/G/Lt3QL4CPyiM/CXK2BqvMBa+4D32sofQ=
|
44
src/main.rs
44
src/main.rs
|
@ -9,23 +9,29 @@ mod set2;
|
|||
mod set3;
|
||||
|
||||
fn main() {
|
||||
set1::challenge1();
|
||||
set1::challenge2();
|
||||
set1::challenge3();
|
||||
set1::challenge4();
|
||||
set1::challenge5();
|
||||
set1::challenge6();
|
||||
set1::challenge7();
|
||||
set1::challenge8();
|
||||
set2::challenge9();
|
||||
set2::challenge10();
|
||||
set2::challenge11();
|
||||
set2::challenge12();
|
||||
set2::challenge13();
|
||||
set2::challenge14();
|
||||
set2::challenge15();
|
||||
set2::challenge16();
|
||||
set3::challenge17();
|
||||
set3::challenge18();
|
||||
set3::challenge19();
|
||||
const RUN_ALL: bool = true;
|
||||
if RUN_ALL {
|
||||
set1::challenge1();
|
||||
set1::challenge2();
|
||||
set1::challenge3();
|
||||
set1::challenge4();
|
||||
set1::challenge5();
|
||||
set1::challenge6();
|
||||
set1::challenge7();
|
||||
set1::challenge8();
|
||||
set2::challenge9();
|
||||
set2::challenge10();
|
||||
set2::challenge11();
|
||||
set2::challenge12();
|
||||
set2::challenge13();
|
||||
set2::challenge14();
|
||||
set2::challenge15();
|
||||
set2::challenge16();
|
||||
set3::challenge17();
|
||||
set3::challenge18();
|
||||
set3::challenge19();
|
||||
set3::challenge20();
|
||||
} else {
|
||||
set3::challenge20();
|
||||
}
|
||||
}
|
||||
|
|
30
src/set3.rs
30
src/set3.rs
|
@ -3,6 +3,7 @@ use crate::bytes_base64::BytesBase64;
|
|||
use crate::cbc;
|
||||
use crate::ctr;
|
||||
use rand::Rng;
|
||||
use std::fs;
|
||||
use std::io::{BufRead, BufReader};
|
||||
|
||||
pub fn challenge17() {
|
||||
|
@ -100,7 +101,7 @@ pub fn challenge18() {
|
|||
|
||||
let cleartext = Bytes::from_utf8("Let's see if we can get the party started hard my friends.");
|
||||
let cipher = ctr::encrypt(&key, 42351234, &cleartext);
|
||||
let roundtrip = ctr::encrypt(&key, 42351234, &cipher);
|
||||
let roundtrip = ctr::decrypt(&key, 42351234, &cipher);
|
||||
assert_eq!(cleartext, roundtrip);
|
||||
|
||||
let cipher = BytesBase64::from_base64(
|
||||
|
@ -112,5 +113,30 @@ pub fn challenge18() {
|
|||
}
|
||||
|
||||
pub fn challenge19() {
|
||||
println!("[xxxx] Challenge 19: TBD");
|
||||
fn read(path: &str) -> Vec<Bytes> {
|
||||
let file = std::fs::File::open(path).unwrap();
|
||||
let br = BufReader::new(file);
|
||||
br.lines()
|
||||
.map(|line| BytesBase64::from_base64(&line.unwrap()).to_bytes())
|
||||
.collect()
|
||||
}
|
||||
|
||||
let plaintexts = read("data/19.txt");
|
||||
let key = Bytes::from_utf8("YELLOW SUBMARINE");
|
||||
let encrypt = |plaintext: &Bytes| -> Bytes { ctr::encrypt(&key, 0, plaintext) };
|
||||
let ciphers: Vec<Bytes> = plaintexts.iter().map(|ct| encrypt(&ct)).collect();
|
||||
let mut data = String::new();
|
||||
for cipher in ciphers.iter() {
|
||||
let copy_cipher = Bytes(cipher.0.to_vec());
|
||||
let cipher_base64 = BytesBase64::from_bytes(copy_cipher);
|
||||
data.push_str(&cipher_base64.to_string());
|
||||
data.push_str("\n");
|
||||
}
|
||||
|
||||
fs::write("data/19_enc.txt", data).expect("Unable to write file");
|
||||
println!("[okay] Challenge 19: encrypted to data/19_enc.txt, attack in set3c19.py.");
|
||||
}
|
||||
|
||||
pub fn challenge20() {
|
||||
println!("[xxxx] Challenge 20: TBD");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
import binascii
|
||||
import string
|
||||
from typing import List, Dict, Set
|
||||
|
||||
|
||||
def load_ciphers() -> List[bytes]:
|
||||
with open("data/19_enc.txt", "r") as f:
|
||||
r = [binascii.a2b_base64(line) for line in f]
|
||||
return r
|
||||
|
||||
|
||||
def xor_lookup_set(letters: str) -> Dict[int, Set[str]]:
|
||||
d = {i: set() for i in range(256)}
|
||||
for c1 in letters:
|
||||
for c2 in letters:
|
||||
xored = ord(c1) ^ ord(c2)
|
||||
d[xored].add(c1)
|
||||
d[xored].add(c2)
|
||||
return d
|
||||
|
||||
|
||||
def attack(ciphers: List[bytes]) -> List[List[str]]:
|
||||
""" Find out possible characters for each cipher pair and hope that there
|
||||
is only one possible character. If no character was found add '?' and
|
||||
if more than one was found add '^'. """
|
||||
|
||||
ciphers_len = len(ciphers)
|
||||
deciphered = [[] for _ in range(ciphers_len)]
|
||||
max_cipher_len = max(map(len, ciphers))
|
||||
for byte_index in range(0, max_cipher_len):
|
||||
# Certain bytes only work with certain letters (found empirically).
|
||||
if byte_index == 10:
|
||||
LETTERS = string.ascii_letters + " _-.,;:'"
|
||||
elif byte_index == 20:
|
||||
LETTERS = string.ascii_letters + " _-.,;:?"
|
||||
else:
|
||||
LETTERS = string.ascii_letters + " _-.,;:"
|
||||
lookup = xor_lookup_set(LETTERS)
|
||||
ciphers_len = len(ciphers)
|
||||
target_bytes = [cipher[byte_index]
|
||||
if len(cipher) > byte_index
|
||||
else None
|
||||
for cipher in ciphers]
|
||||
possible_chars = [set(LETTERS) for _ in range(ciphers_len)]
|
||||
for i in range(ciphers_len):
|
||||
for j in range(i, ciphers_len):
|
||||
if target_bytes[i] is None or target_bytes[j] is None:
|
||||
continue
|
||||
xored = target_bytes[i] ^ target_bytes[j]
|
||||
chars = lookup[xored]
|
||||
possible_chars[i] &= chars
|
||||
possible_chars[j] &= chars
|
||||
for cipher_index in range(ciphers_len):
|
||||
if len(ciphers[cipher_index]) <= byte_index:
|
||||
continue
|
||||
chars = list(possible_chars[cipher_index])
|
||||
match len(chars):
|
||||
case 0:
|
||||
# print(f"No chars for {cipher_index=} {byte_index=}")
|
||||
deciphered[cipher_index].append('?')
|
||||
case 1:
|
||||
deciphered[cipher_index].append(chars[0].lower())
|
||||
case 2:
|
||||
if chars[0].lower() == chars[1].lower():
|
||||
deciphered[cipher_index].append(chars[0].lower())
|
||||
else:
|
||||
# print(f"Two {chars=} {cipher_index=} {byte_index=}")
|
||||
deciphered[cipher_index].append('^')
|
||||
case _:
|
||||
# print(f"Too many {chars=} {cipher_index=} {byte_index=}")
|
||||
deciphered[cipher_index].append('^')
|
||||
return deciphered
|
||||
|
||||
|
||||
def manual(decrypts: List[List[str]]) -> List[bytes]:
|
||||
""" Manually add guessed letters. """
|
||||
decrypts[0][30] = 'y'
|
||||
decrypts[2][30] = 'y'
|
||||
decrypts[4][30] = 'e'
|
||||
decrypts[4][32] = 'h'
|
||||
decrypts[4][33] = 'e'
|
||||
decrypts[4][34] = 'a'
|
||||
decrypts[4][35] = 'd'
|
||||
decrypts[6][30] = 'i'
|
||||
decrypts[13][30] = ' '
|
||||
decrypts[20][30] = ' '
|
||||
decrypts[25][30] = 'n'
|
||||
decrypts[28][30] = ' '
|
||||
decrypts[29][30] = 't'
|
||||
decrypts[37][30] = 'i'
|
||||
decrypts = list(map(lambda l: "".join(l), decrypts))
|
||||
return decrypts
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
ciphers = load_ciphers()
|
||||
decrypts = manual(attack(ciphers))
|
||||
for d in decrypts:
|
||||
print(d)
|
Loading…
Reference in New Issue