summaryrefslogtreecommitdiffstats
path: root/challenge/c14.go
blob: 3b5b11c45d6c4621d1c520920f164b0f20102d2f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright © 2021 rsiddharth <s@ricketyspace.net>
// SPDX-License-Identifier: ISC

package challenge

import (
	"fmt"
	"ricketyspace.net/cryptopals/lib"
)

func C14() {
	blocksize := findBlockSizeForVarEncryptECB()
	rpl, nrpb, rpo := findRandPrefixLen(blocksize)
	nbl, us_sz := findUnknownStringNumBlocksLength(
		rpl, blocksize)
	in := append(freshSheepBytes(rpo), // random prefix offset
		freshSheepBytes(blocksize)...)
	ds := make([]byte, 0) // deciphered unknown string in bytes
	for i := 0; i < nbl; i++ {
		nby := blocksize
		if i == nbl-1 {
			nby = us_sz % blocksize
		}
		for j := 0; j < nby; j++ {
			in, ds = decipherOneByteUS(nrpb, rpo, blocksize,
				i+1, j+1, in, ds)
		}
		s := 16 * i
		e := s + 16
		in = append(freshSheepBytes(rpo), ds[s:e]...)
	}
	fmt.Printf("Unknown String:\n%v", lib.BytesToStr(ds))
}

func findBlockSizeForVarEncryptECB() int {
	in := make([]byte, 0)

	in = append(in, sheep)
	is := len(lib.OracleAESVarEncryptECB(in)) // initial size
	bs := 0
	for {
		in = append(in, sheep)
		bs = len(lib.OracleAESVarEncryptECB(in))
		if bs != is {
			return (bs - is)
		}
	}
}

func findRandPrefixLen(blocksize int) (int, int, int) {
	// Make two sheep blocks.
	tsb := append(freshSheepBytes(blocksize), freshSheepBytes(blocksize)...)

	v := []byte{}
	index := 0
	found := false
	for {
		in := append(v, tsb...)
		c := lib.OracleAESVarEncryptECB(in)
		index, found = lib.HasConsecutiveMatchingBlocks(c, blocksize)
		if found {
			break
		}
		// Add another sheep
		v = append(v, sheep)
	}
	l := index - len(v)
	nrpb := l / blocksize // number of randbox prefix blocks
	rpo := 0              // random prefix offset
	if l%blocksize != 0 {
		nrpb += 1
		rpo = blocksize - (l % blocksize)
	}
	return l, nrpb, rpo
}

// Finds the cipher block size and the length of the unknown string
// (target-bytes).
func findUnknownStringNumBlocksLength(rpl, blocksize int) (int, int) {
	padding := blocksize - (rpl % blocksize)
	in := make([]byte, padding)
	c_sz := len(lib.OracleAESVarEncryptECB(in)) // Cipher size

	nblocks := c_sz / blocksize            // total number of blocks
	rblocks := (rpl + padding) / blocksize // number of blocks of random prefix
	ublocks := nblocks - rblocks           // number of blocks of unknown string
	// Figure out size of unknown string.
	for {
		in = append(in, sheep)
		bs := len(lib.OracleAESVarEncryptECB(in))
		if bs != c_sz {
			return ublocks, (c_sz - len(in) - rpl)
		}
	}
}

// `nrpb` number of random prefix blocks
// `rpo` random prefix offset
// `blocksize` is the size of a block
// `block` is the nth block that is being deciphered
// `n` is the nth byte of the block `block` that is going to be deciphered.
// `in` (n-1)th block that is known
// `ds` deciphered unknown string
func decipherOneByteUS(nrpb, rpo, blocksize, block, n int, in, ds []byte) ([]byte, []byte) {
	oo := lib.OracleAESVarEncryptECB(in[0:(len(in) - n)])

	s := (nrpb * blocksize) + 16*(block-1)
	e := s + 16
	nbl := oo[s:e] // nth block of the cipher

	// Shift `in` to the left by one place.
	for i := rpo; i < len(in)-1; i++ {
		in[i] = in[i+1]
	}

	// Try all combinations.
	for i := 0; i < 256; i++ {
		in[len(in)-1] = byte(i)
		oo = lib.OracleAESVarEncryptECB(in)

		if lib.BlocksEqual(nbl,
			oo[(nrpb*blocksize):(nrpb*blocksize)+16]) {
			ds = append(ds, in[len(in)-1])
			return in, ds
		}
	}
	panic("not found!")
}

// Output:
// Unknown String:
// Rollin' in my 5.0
// With my rag-top down so my hair can blow
// The girlies on standby waving just to say hi
// Did you stop? No, I just drove by