Skip to content

Commit a55f30c

Browse files
committed
Set up C project for working on Cryptopals challenges
1 parent aaeded0 commit a55f30c

File tree

10 files changed

+452
-0
lines changed

10 files changed

+452
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
*.pyc
22
*~
33
*node_modules*
4+
*.dSYM
5+
*.out
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# For OSX, Install openssl with `brew install openssl`
2+
3+
DEBUG=false
4+
CC=gcc
5+
6+
LIBS= -lssl -lcrypto
7+
INCLUDES= -I/usr/local/opt/openssl/include
8+
LDFLAGS= -L/usr/local/opt/openssl/lib
9+
10+
11+
ifeq ($(DEBUG),true)
12+
CFLAGS="-g -O0"
13+
else
14+
CFLAGS=""
15+
endif
16+
17+
main:
18+
$(CC) $(CFLAGS) src/try.c src/utils.c -o try.out -I./src/ $(LIBS) $(LDFLAGS) $(INCLUDES)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
TODO
2+
====
3+
4+
- [ ] Handle ecb mode with partial plaintext blocks gracefully

Cryptopal-Challenges/brice/api.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#include "common.h"
2+
3+
/*
4+
* Block cipher modes of operation
5+
*/
6+
Mode MODE_ECB(void);
7+
Mode MODE_CBC(void);
8+
9+
/*
10+
* Available ciphers
11+
*/
12+
Cipher AES_128_128(void);
13+
14+
/*
15+
* Available padding modes
16+
*/
17+
Padding PKCS7(void);
18+
19+
20+
typedef ERROR (ENCRYPT_FN)(
21+
const unsigned char* plaintext,
22+
const int plaintext_length,
23+
OUT unsigned char* ciphertext,
24+
const int ciphertext_limit,
25+
OUT int* encrypted_bytes
26+
);
27+
28+
typedef ERROR (DECRYPT_FN)(
29+
const unsigned char* ciphertext,
30+
const int ciphertext_length,
31+
OUT unsigned char* plaintext,
32+
const int plaintext_limit,
33+
OUT int* decrypted_bytes
34+
);
35+
36+
typedef struct {
37+
unsigned char* key;
38+
unsigned char* iv;
39+
ENCRYPT_FN* encrypt;
40+
DECRYPT_FN* decrypt;
41+
} Cipher;
42+
43+
Cipher CipherInit(
44+
Mode mode,
45+
Primitive cipher,
46+
Padding padding_mode,
47+
const unsigned char* key,
48+
const unsigned char* iv
49+
);
50+
51+
const unsigned char* error_string(ERROR);
52+
53+
void log_error(ERROR);
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
2+
#define OUT /**/
3+
4+
typedef enum {
5+
OK,
6+
IV_PROVIDED_IN_ERROR,
7+
LIMIT_TOO_SMALL,
8+
UNKNOWN_FATAL
9+
} ERROR;
10+
11+
typedef ERROR (ENCRYPT_BLOCK)(
12+
const unsigned char* key,
13+
const unsigned char* plainblock,
14+
OUT unsigned char* cipherblock
15+
);
16+
17+
typedef ERROR (DECRYPT_BLOCK)(
18+
const unsigned char* key,
19+
const unsigned char* cipherblock,
20+
OUT unsigned char* plainblock
21+
);
22+
23+
typedef ERROR (PAD_FN)(
24+
const int block_size,
25+
const int text_length, /*The length of the text to be padded*/
26+
unsigned char* text, /* Pointer to the text buffer, which should be allocated as a multiple of block_size */
27+
const int text_limit
28+
);
29+
30+
typedef ERROR (DEPAD_FN)(
31+
const int block_size,
32+
unsigned char* text, /* Pointer to the text buffer, We're going to 'depad' by overwriting the padding with '\0' */
33+
const int text_limit
34+
);
35+
36+
typedef struct {
37+
int block_size;
38+
int key_size;
39+
ENCRYPT_BLOCK* encrypt;
40+
DECRYPT_BLOCK* decrypt;
41+
} Primitive;
42+
43+
typedef struct {
44+
PAD_FN* pad;
45+
DEPAD_FN* depad;
46+
} Padding;
47+
48+
typedef ERROR (MODE_ENCRYPT)(
49+
const Primitive* cipher,
50+
const Padding* padding,
51+
const unsigned char* key,
52+
const unsigned char* iv,
53+
const unsigned char* plaintext,
54+
const int plaintext_length,
55+
OUT unsigned char* ciphertext,
56+
const int ciphertext_limit
57+
);
58+
59+
typedef ERROR (MODE_DECRYPT)(
60+
const Primitive* cipher,
61+
const Padding* padding,
62+
const unsigned char* key,
63+
const unsigned char* iv,
64+
const unsigned char* ciphertext,
65+
const int ciphertext_length,
66+
OUT unsigned char* plaintext,
67+
const int plaintext_limit
68+
);
69+
70+
typedef struct {
71+
MODE_ENCRYPT* encrypt;
72+
MODE_DECRYPT* decrypt;
73+
} Mode;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include <stdlib.h>
2+
3+
#include "common.h"
4+
5+
int main(){
6+
ERROR status = OK;
7+
8+
/* For example: */
9+
Cipher AES_ECB = CipherInit(
10+
MODE_ECB(),
11+
RIJNDAEL_128_128(),
12+
PKCS7(),
13+
"YELLOW SUBMARINE",
14+
"I AM AN INIT VEC"
15+
);
16+
17+
18+
unsigned char original[] = "My big secret";
19+
int original_length = strlen(original);
20+
21+
int ciphertext_limit = 64;
22+
unsigned char ciphertext[ciphertext_limit];
23+
int encrypted_bytes = 0;
24+
25+
if(OK != (status = AES_ECB.encrypt(original, original_length, ciphertext, ciphertext_limit, &encrypted_bytes))){
26+
log_error(status);
27+
exit(1);
28+
};
29+
30+
int plaintext_limit = 64;
31+
unsigned char plaintext[plaintext_limit];
32+
int decrypted_bytes = 0;
33+
34+
if(OK != (status = AES_ECB.decrypt(ciphertext, encrypted_bytes, plaintext, plaintext_limit, &decrypted_bytes))){
35+
log_error(status);
36+
exit(1);
37+
};
38+
39+
printf("ORIGINAL: ");print_hex(original);printf("\n");
40+
printf("CIPHERTEXT: ");print_hex(ciphertext);printf("\n");
41+
printf("PLAINTEXT: ");print_hex(plaintext);printf("\n");
42+
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* Implement CBC mode
3+
*
4+
* CBC mode is a block cipher mode that allows us to encrypt
5+
* irregularly-sized messages, despite the fact that a block
6+
* cipher natively only transforms individual blocks.
7+
*
8+
* In CBC mode, each ciphertext block is added to the next
9+
* plaintext block before the next call to the cipher core.
10+
*
11+
* The first plaintext block, which has no associated previous
12+
* ciphertext block, is added to a "fake 0th ciphertext block"
13+
* called the initialization vector, or IV.
14+
*
15+
* Implement CBC mode by hand by taking the ECB function you
16+
* wrote earlier, making it encrypt instead of decrypt (verify
17+
* this by decrypting whatever you encrypt to test), and using
18+
* your XOR function from the previous exercise to combine them.
19+
*
20+
* The file here is intelligible (somewhat) when CBC decrypted
21+
* against "YELLOW SUBMARINE" with an IV of all ASCII 0
22+
* (\x00\x00\x00 &c)
23+
*/
24+
25+
#include <stdio.h>
26+
#include <string.h>
27+
#include <stdlib.h>
28+
29+
#include <openssl/conf.h>
30+
#include <openssl/evp.h>
31+
#include <openssl/err.h>
32+
33+
#include "utils.h"
34+
#include "common.h"
35+
36+
37+
static const int NO_PADDING = 0;
38+
static const int BLOCK_SIZE = 16;
39+
40+
void handleErrors(void){
41+
ERR_print_errors_fp(stderr);
42+
abort();
43+
}
44+
45+
void aes_encrypt_block(const unsigned char* plaintext, const unsigned char* key, unsigned char* ciphertext){
46+
EVP_CIPHER_CTX *ctx;
47+
int outlen, tmplen;
48+
49+
// Create and initialise the context
50+
if(!(ctx = EVP_CIPHER_CTX_new())){
51+
handleErrors();
52+
}
53+
54+
// Initialises context with cipher
55+
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, NULL)){
56+
handleErrors();
57+
}
58+
59+
// Don't PCKS5 pad
60+
EVP_CIPHER_CTX_set_padding(ctx, NO_PADDING);
61+
62+
// Encrypt plaintext
63+
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &outlen , plaintext, BLOCK_SIZE)){
64+
handleErrors();
65+
}
66+
67+
// Finalise the encryption.
68+
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + outlen, &tmplen)){
69+
handleErrors();
70+
}
71+
72+
// Clean up
73+
EVP_CIPHER_CTX_free(ctx);
74+
}
75+
76+
void aes_decrypt_block(const unsigned char* ciphertext, const unsigned char* key, unsigned char* plaintext){
77+
EVP_CIPHER_CTX *ctx;
78+
int outlen, tmplen;
79+
80+
// Create and initialise the context
81+
if(!(ctx = EVP_CIPHER_CTX_new())){
82+
handleErrors();
83+
}
84+
85+
// Initialises context with cipher
86+
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, NULL)){
87+
handleErrors();
88+
}
89+
90+
// Don't PCKS5 pad
91+
EVP_CIPHER_CTX_set_padding(ctx, NO_PADDING);
92+
93+
// Encrypt plaintext
94+
if(1 != EVP_DecryptUpdate(ctx, plaintext, &outlen , ciphertext, BLOCK_SIZE)){
95+
handleErrors();
96+
}
97+
98+
// Finalise the encryption.
99+
if(1 != EVP_DecryptFinal_ex(ctx, plaintext + outlen, &tmplen)){
100+
handleErrors();
101+
}
102+
103+
// Clean up
104+
EVP_CIPHER_CTX_free(ctx);
105+
106+
}
107+
108+
109+
void test_basic_block_encryption(){
110+
unsigned char original[] = "TO BE OR NOT TO ";
111+
unsigned char key[] = "YELLOW SUBMARINE";
112+
113+
unsigned char ciphertext[64];
114+
unsigned char plaintext[64];
115+
memset(ciphertext, 0, 64);
116+
memset(plaintext, 0, 64);
117+
118+
printf("ORIGINAL: >%s<\n", original);
119+
printf("ORIGINAL: ");print_hex(original);printf("\n");
120+
aes_encrypt_block(original, key, ciphertext);
121+
aes_decrypt_block(ciphertext, key, plaintext);
122+
printf("CIPHERTEXT: ");print_hex(ciphertext);printf("\n");
123+
printf("PLAINTEXT: ");print_hex(plaintext);printf("\n");
124+
printf("PLAINTEXT: >%s<\n", plaintext);
125+
}
126+
127+
128+
void decrypt_ecb(
129+
const unsigned char* ciphertext,
130+
const unsigned char* key,
131+
const int len,
132+
unsigned char* plaintext
133+
){
134+
for( int offset = 0; offset < len; offset+=BLOCK_SIZE){
135+
aes_decrypt_block(ciphertext+offset, key, plaintext+offset);
136+
}
137+
}
138+
139+
140+
int main (int argc, char** agrv){
141+
// test_basic_block_encryption();
142+
unsigned char * ciphertext = NULL;
143+
long length = read_to_buffer("aes-test.dat", &ciphertext);
144+
145+
if (!ciphertext){
146+
printf("No ciphertext found!\n");
147+
return 1;
148+
}
149+
150+
unsigned char* plaintext = calloc(length, sizeof(unsigned char)+BLOCK_SIZE+BLOCK_SIZE);
151+
152+
if(!plaintext){
153+
printf("Calloc returned null for some reason o_O?\n");
154+
free(ciphertext);
155+
return 1;
156+
}
157+
158+
decrypt_ecb(ciphertext, (unsigned char *)"YELLOW SUBMARINE", length, plaintext);
159+
printf(">>%s\n", plaintext);
160+
161+
free(plaintext);
162+
free(ciphertext);
163+
return 0;
164+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
4+
#include "utils.h"
5+
6+
void print_hex(const unsigned char *s){
7+
while(*s)
8+
printf("%02x ", (unsigned int) *s++);
9+
}
10+
11+
long read_to_buffer(const char* filename, unsigned char** buffer){
12+
long length = 0;
13+
FILE * f = fopen (filename, "rb");
14+
15+
if (f){
16+
fseek (f, 0, SEEK_END);
17+
length = ftell (f);
18+
fseek (f, 0, SEEK_SET);
19+
*buffer = malloc (length);
20+
if (*buffer)
21+
{
22+
fread (*buffer, 1, length, f);
23+
}
24+
fclose (f);
25+
}
26+
return length;
27+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
3+
4+
void print_hex(const unsigned char *s);
5+
long read_to_buffer(const char* filename, unsigned char** buffer);

0 commit comments

Comments
 (0)