summaryrefslogblamecommitdiffstats
path: root/challenge/c19.go
blob: 5480dab16137f18e7fd73def90a22976ceca381e (plain) (tree)
1
                                                   




















































                                                                       

















                                                                            
                                                              
























                                                                          
                                                                    































































































                                                                                        
// Copyright © 2021 siddharth <s@ricketyspace.net>
// SPDX-License-Identifier: ISC

package challenge

import (
	"fmt"

	"ricketyspace.net/cryptopals/lib"
)

func C19() {
	texts := []string{
		"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=",
	}

	// Utility functions.
	cipherStreamByteGroups := func(ciphers [][]byte) map[int][]byte {
		kbg := make(map[int][]byte, 0)
		for i := 0; i < len(ciphers); i++ {
			for j := 0; j < len(ciphers[i]); j++ {
				if _, ok := kbg[j]; !ok {
					kbg[j] = make([]byte, 0)
				}
				kbg[j] = append(kbg[j], ciphers[i][j])
			}
		}
		return kbg
	}
	crackOutputBlockByteForGroup := func(pos int, g []byte) byte {
		po := make([][]byte, len(g)) // Potential Output block bytes
		for i, c := range g {
			po[i] = make([]byte, 0)
			for _, a := range lib.PrintableAscii {
				o := c ^ a
				po[i] = append(po[i], o)

				// Also try the uppercase version of ascii
				// character if it exists.
				au := lib.ByteToUpper(a)
				if a != au {
					o := c ^ au
					po[i] = append(po[i], o)
				}
			}
		}
		co := lib.BytesInCommon(po) // Common Output Block bytes.
		if len(co) < 1 {
			return 0 // NUL
		}
		if len(co) == 1 {
			return co[0]
		}
		tob := byte(0) // The Output Block byte.
		bscr := 0      // Best score.
		for _, o := range co {
			scr := 0
			for _, c := range g {
				p := c ^ o
				if s, ok := lib.AsciiScores[p]; ok {
					scr += s
				}
				if pos == 0 && lib.ByteIsUpper(p) {
					scr += 1
				}
			}
			if scr > bscr {
				bscr = scr
				tob = o
			}
		}
		return tob
	}

	// Make ciphers from plain text data.
	ciphers := make([][]byte, len(texts))
	key, err := lib.RandomBytes(16)
	if err != nil {
		fmt.Printf("Error generating key %v", err)
		return
	}
	nonce := uint64(lib.RandomInt(0, 10))
	for i, b64 := range texts {
		text := lib.Base64ToBytes(b64)
		ciphers[i], err = lib.AESEncryptCTR(text, key, lib.AESGenCTRFunc(nonce))
		if err != nil {
			fmt.Printf("Error encrypting text:%d: %v", i, err)
			return
		}
	}

	// Group the cipher streams into groups by position of the cipher
	// byte in the stream.
	cbg := cipherStreamByteGroups(ciphers)

	// Try get crack and get the output block stream.
	obs := make(map[int]byte, 0) // Output Block Stream map.
	for pos, cgrp := range cbg {
		obs[pos] = crackOutputBlockByteForGroup(pos, cgrp)
	}

	// Decipher cipher using the output block stream.
	for _, cipher := range ciphers {
		for i, c := range cipher {
			p := c ^ obs[i]
			fmt.Printf("%c", p)
		}
		fmt.Printf("\n")
	}
}

// Output:
// I have met them at close of day
// Coming with vivid faces
// From counter or desk among grey
// Eighteenth-century houses.
// I have passed with a nod of the heae
// Or polite meaningless words,
// Or have lingered awhile and said
// Polite meaningless words,
// And thought before I had done
// Of a mocking tale or a gibe
// To please a companion
// Around the fire at the club,
// Being certain that they and I
// But lived where motley is worn:
// All changed, changed utterly:
// A terrible beauty is born.
// That woman's days were spent
// In ignorant good will,
// Her nights in argument
// Until her voice grew shrill.
// What voice more sweet than hers
// When young and beautiful,
// She rode to harriers?
// This man had kept a school
// And rode our winged horse.
// This other his helper and friend
// Was coming into his force;
// He might have won fame in the end,
// So sensitive his nature seemed,
// So daring and sweet his thought.
// This other man I had dreamed
// A drunken, vain-glorious lout.
// He had done most bitter wrong
// To some who are near my heart,
// Yet I number him in the song;
// He, too, has resigned his part
// In the casual comedy;
// He, too, has been changed in his tus
// Transformed utterly:
// A terrible beauty is born.

// Stuff the program did not get correctly:
//  1. On the 5th line, 'heae' -> 'head'
//  2. On the 38th line, 'tus ' -> 'turn'