-
Notifications
You must be signed in to change notification settings - Fork 1
/
cbc.c
executable file
·171 lines (148 loc) · 5.25 KB
/
cbc.c
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include "tczero.h"
#include "cbc.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/random.h>
#define MASK ((HALF_BLOCK_SIZE == 64) ? ~0ull : (1ull << (HALF_BLOCK_SIZE)) - 1)
/* Copies the half block in array into the Least Significant Bits of x. */
void block_to_uint64(uint8_t *array, uint64_t *x) {
memcpy(x, array, BYTES_PER_HALF_BLOCK);
*x = (*x) & MASK;
}
/* Copies the HALF_BLOCK_SIZE Least Significant Bits of x into array. */
void uint64_to_block(uint64_t x, uint8_t *array) {
memcpy(array, &x, BYTES_PER_HALF_BLOCK);
}
/* Encrypts the given plaintext with a random IV.
*
* The returned value (ct) is the IV concataaated with the ciphertext.
*/
void cbc_enc(uint64_t key[2], uint8_t *pt, uint8_t *ct, size_t ptlen) {
/* Buffer block used to encrypt data */
uint64_t x[2];
/* Temporary variables used for local computations */
uint64_t y = 0;
uint64_t z = 0;
/* The current block being encrypted */
uint8_t *ptblock = pt;
/* The current resulting ciphertext block */
uint8_t *ctblock = ct + BYTES_PER_BLOCK;
/* The previous ciphertext block to be XORed with the plaintext block */
uint8_t *prev_ct = ct;
/* Number of blocks to be encrypted */
unsigned int numblocks = ptlen / BYTES_PER_BLOCK;
int i, j, k;
/* Generate IV inside the first ciphertext block */
if (getrandom(prev_ct, BYTES_PER_BLOCK, GRND_NONBLOCK) != BYTES_PER_BLOCK) {
printf("Error while trying to generate the IV\n");
exit(1);
}
for (i = 0; i < numblocks; i++) {
/* XOR the message block with the ciphertext block */
for (j = 0; j < 2; j++) {
block_to_uint64(ptblock, &y);
block_to_uint64(prev_ct, &z);
x[j] = y ^ z;
ptblock = ptblock + BYTES_PER_HALF_BLOCK;
prev_ct = prev_ct + BYTES_PER_HALF_BLOCK;
}
/* Encrypts the XORed block */
tc0_encrypt(x, key);
/* Copy the encrypted data into the ciphertext */
for (j = 0; j < 2; j++) {
uint64_to_block(x[j], ctblock);
ctblock = ctblock + BYTES_PER_HALF_BLOCK;
}
}
}
/* Decrypts the given ciphertext. */
void cbc_dec(uint64_t key[2], uint8_t *ct, uint8_t *pt, size_t ctlen) {
/* Buffer block used to decrypt data */
uint64_t x[2];
/* Temporary variables used for local computations */
uint64_t y = 0;
uint64_t z = 0;
/* The current block being decrypted */
uint8_t *ctblock = ct + BYTES_PER_BLOCK;
/* The current resulting plaintext block */
uint8_t *ptblock = pt;
/* The previous ciphertext block to be XORed with the decrypted block */
uint8_t *prev_ct = ct;
/* Number of blocks to be decrypted. It's the total number of block minus the IV. */
unsigned int numblocks = ctlen / BYTES_PER_BLOCK - 1;
int i, j, k;
for (i = 0; i < numblocks; i++) {
/* Copy the ciphertext block to x */
for (j = 0; j < 2; j++) {
block_to_uint64(ctblock, x + j);
ctblock = ctblock + BYTES_PER_HALF_BLOCK;
}
/* Decrypt the ciphertext block */
tc0_decrypt(x, key);
/* XOR the decrypted block with the previous ciphertext block */
for (j = 0; j < 2; j++) {
block_to_uint64(prev_ct, &y);
z = x[j] ^ y;
uint64_to_block(z, ptblock);
ptblock = ptblock + BYTES_PER_HALF_BLOCK;
prev_ct = prev_ct + BYTES_PER_HALF_BLOCK;
}
}
}
void allocate_ciphertext(size_t ptlen, uint8_t **ciphertext, size_t *ctlen) {
*ctlen = ptlen + BYTES_PER_BLOCK;
*ciphertext = (uint8_t *) malloc(*ctlen * sizeof(uint8_t));
}
void allocate_plaintext(size_t ctlen, uint8_t **plaintext, size_t *ptlen) {
*ptlen = ctlen - BYTES_PER_BLOCK;
*plaintext = (uint8_t *) malloc(*ptlen * sizeof(char));
}
void print_hex(uint8_t *hex_str, size_t length, char *sep, char *end) {
unsigned int i;
if (length > 0) {
printf("%02x", hex_str[0]);
}
for (i = 1; i < length; ++i) {
printf("%s%02x", sep, hex_str[i]);
}
printf("%s", end);
}
void read_key(char *filename, uint64_t key[2]) {
unsigned char *char_key = (unsigned char *) key;
unsigned int hex;
unsigned int i;
FILE *f = fopen(filename, "r");
if (f == NULL) {
printf("Error reading file \"%s\"\n", filename);
exit(1);
}
for (i = 0; i < 128 / 8; ++i) {
fscanf(f, "%02x", &hex);
char_key[i] = (unsigned char) hex;
}
fclose(f);
}
void read_text_file(char *filename, char **text, size_t *ptlen) {
char *buffer;
long length, adjusted_length, i;
FILE *f = fopen(filename, "r");
if (f == NULL) {
printf("Error reading file '%s'\n", filename);
exit(1);
}
fseek(f, 0, SEEK_END);
length = ftell(f);
adjusted_length = (((length + 1) + (BYTES_PER_BLOCK - 1)) / BYTES_PER_BLOCK) * BYTES_PER_BLOCK;
fseek(f, 0, SEEK_SET);
buffer = (char *) malloc(adjusted_length * sizeof(char));
fread(buffer, 1, length, f);
for (i = length; i < adjusted_length; ++i) {
buffer[i] = '\0';
}
printf("Read %ld chars from file '%s' into a buffer of size %ld\n", length, filename, adjusted_length);
*text = buffer;
*ptlen = adjusted_length;
fclose (f);
}