summaryrefslogtreecommitdiff
path: root/break_fixed_nonce_s3.c
blob: eb37500be4ffcea3d71781e1c18b78df232c9898 (plain)
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
// https://cryptopals.com/sets/3/challenges/19
// https://cryptopals.com/sets/3/challenges/20
#include "util/aes.h"
#include "util/base64.h"
#include "util/random.h"
#include "util/score.h"

/* [challenge 20]
 * data/c20_s3.txt contains base64'd plaintext. solve by using repeating-key
 * XOR'd algorithm. CTR encryption appears different from repeated-key XOR, but
 * with a fixed nonce, they are effectively the same thing. to make use of this
 * "exploit", take collection of ciphertexts and trucate them to a common
 * length. solve resulting concatenation of ciphertexts as if for repeating-key
 * XOR, with a key size of the legnth of ciphertext.
 */

unsigned char key[16];
char *strings[] = {"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="};

int main() {
  init_with_random_bytes(key, 16);
  size_t arr_len = sizeof(strings) / sizeof(strings[0]);
  unsigned char *outs[arr_len];
  size_t lens[arr_len], max_len = 0;
  // encrypt with random key
  for (uint i = 0; i < arr_len; i++) {
    size_t in_len;
    uint8_t *in = base64_decode(strings[i], &in_len);
    outs[i] = malloc(in_len);
    lens[i] = in_len;
    if (in_len > max_len)
      max_len = in_len;
    if (!ctr_encrypt(in, (int)in_len, key, 0, outs[i])) {
      fprintf(stderr, "ctr_encrypt failed\n");
      exit(1);
    }
  }
  uint8_t buf[arr_len], key_stream[max_len];
  for (uint j = 0; j < max_len; j++) {
    size_t cnt = 0;
    for (uint i = 0; i < arr_len; i++)
      if (j < lens[i])
        buf[cnt++] = outs[i][j];
    key_stream[j] = best_key_step(buf, cnt, 0, 1);
  }
  // print decrypted result (last characters
  // of lines are too difficult to break)
  for (uint i = 0; i < arr_len; i++)
    for (uint j = 0; j < max_len; j++) {
      if (j < lens[i])
        printf("%c\n", outs[i][j] ^ key_stream[j]);
      else
        break;
    }
  return 0;
}