-
Notifications
You must be signed in to change notification settings - Fork 96
/
caesarCipher.c
147 lines (122 loc) · 3.53 KB
/
caesarCipher.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
#include <stddef.h>
#ifndef NB_ALPHABETS
#define NB_ALPHABETS 2
#endif //NB_ALPHABETS
#ifndef ALPHAS
#define ALPHAS {'A', 'a'}
#endif //ALPHAS
#ifndef OMEGAS
#define OMEGAS {'Z', 'z'}
#endif //OMEGAS
#ifndef ALPHABET_SIZES
#define ALPHABET_SIZES {26, 26}
#endif //ALPHABET_SIZES
#ifndef APPLY_ROTATION
#define APPLY_ROTATION(Char, Alpha, Rot, AlphabetSize) (mathMod(((Char) - (Alpha) + (Rot)), (AlphabetSize)) + (Alpha))
#endif //APPLY_ROTATION
static unsigned int mathMod(int x, unsigned int y){
const int out = x % y;
return out + (out < 0) * y;
}
/*
> Description:
The caesarCipher() function applies a rotationon each byte of string toBeEncrypted, which
has to be of size len. The rotation, which is of size rot, is only applied if the byte is
recognized as a character of given-at-compile-time alphabets.
The result of the cypher is stored in dst.
> Warnings:
The dst memspace has to have (len + 1) bytes allocated as it will be null-terminated.
> Return values:
If len is invalid, returns NULL.
Otherwise, returns dst.
*/
char *caesarCipher(char *dst, const char *toBeEncrypted, const size_t len, const int rot)
{
static const char alphas[NB_ALPHABETS] = ALPHAS;
static const char omegas[NB_ALPHABETS] = OMEGAS;
static const size_t alphabetSizes[NB_ALPHABETS] = ALPHABET_SIZES;
if (len < 1)
{
return NULL;
}
unsigned int adjustedRotations[NB_ALPHABETS];
for (size_t i = 0; i < NB_ALPHABETS; ++i)
{
adjustedRotations[i] = mathMod(rot, alphabetSizes[i]);
}
for (size_t i = 0; i < len; ++i)
{
const char current = *(toBeEncrypted + i);
int wasSet = 0;
for (size_t j = 0; j < NB_ALPHABETS; ++j)
{
if (alphas[j] <= current && current <= omegas[j])
{
*(dst + i) = APPLY_ROTATION(current, alphas[j], adjustedRotations[j], alphabetSizes[j]);
wasSet = 1;
break;
}
}
if(!wasSet)
{
*(dst + i) = current;
}
}
*(dst + len) = '\0';
return dst;
}
#ifdef TESTING
#include <assert.h>
#include <string.h>
#ifdef NB_ALPHABETS
#undef NB_ALPHABETS
#define NB_ALPHABETS 2
#endif //NB_ALPHABETS
#ifdef ALPHAS
#undef ALPHAS
#define ALPHAS {'A', 'a'}
#endif //ALPHAS
#ifdef OMEGAS
#undef OMEGAS
#define OMEGAS {'Z', 'z'}
#endif //OMEGAS
int main()
{
//failure test
char buff[65535];
assert(caesarCipher(buff, buff, 0, 0) == NULL);
//simple success test
char *res = caesarCipher(buff, "Et tu, Brute?", 13, 13);
char *expected = "Rg gh, Oehgr?";
assert(res == buff && strcmp(res, expected) == 0);
//rather more exhaustive test
char garbageData[301] = "Why, man, he doth bestride the narrow world\nLike a Colossus, and we petty men\nWalk under his huge legs and peep about\nTo find ourselves dishonorable graves.\nMen at some time are masters of their fates.\nThe fault, dear Brutus, is not in our stars,\nBut in ourselves, that we are underlings.";
for (short int i = -128; i < 127; ++i)
{
res = caesarCipher(buff, garbageData, 301, i);
res = caesarCipher(buff, res, 301, 26 - mathMod(i, 26));
assert(res == buff && strcmp(res, garbageData) == 0);
}
}
#else
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
if(argc < 3)
{
fprintf(
stderr,
"Expected 2 arguments (input string & rotation length).\nOnly received %d arguments.\n",
argc
);
return 1;
}
size_t length = strlen(argv[1]);
unsigned short int rot = atoi(argv[2]);
char *encrypted = (char *)calloc(sizeof(*encrypted), length);
printf("%s\n", caesarCipher(encrypted, argv[1], length, rot));
return 0;
}
#endif //TESTING