Vigenere Cipher

  • Thread starter Piotr Turkowski
  • Start date
P

Piotr Turkowski

Hi!

Here you can get some notes about Vigenere Cipher:
http://raphael.math.uic.edu/~jeremy/crypt/vignere.html

Here's whole code of my program, function stats() is in polish, so you
can omit it. The problem is that the encrypting function is not working
correctly, so I didn't write decryptying function. Plz, can you help me
with both issues?

#include <stdio.h>

#define IN 1 /* wewn¹trz s³owa */
#define OUT 0 /* poza s³owem */

/* Vigenere Cipher */


/* deklaracje fuknkcji uzytych w programie */
int wypelnij_male(char tab[][]);
int wypelnij_duze(char tab[][]);
char haslo(int ii, char pass[]);
void koduj_numer(char c);
void szyfruj();
void deszyfruj();
void stats();

main() {

/* menu programu */
int menu;
for(;;){
printf("\n");
printf("1. Szyfrowanie tekstu.\n");
printf("2. Deszyfrowanie tekstu.\n");
printf("3. Statystyka.\n");
printf("4. Zakonczenie programu.\n");
scanf("%d", &menu);


switch(menu) {

case 1: szyfruj(); break;
case 2: deszyfruj();
case 3: stats();
case 4: return;
default: return;
}
}
}


void szyfruj(){

int ii, c, i, s;
char pass[]={0};

char MALE[26][26]={0};
char DUZE[26][26]={0};

wypelnij_male(MALE);
wypelnij_duze(DUZE);

printf("Podaj haslo: ");
scanf("%s\0", &pass);
getchar();
printf("Podaj tekst do zaszyfrowania:\n");

for (ii = 0; (c = getchar()) != '\n'; ++ii) {
if (c >= 'a' && c <= 'z') {
putchar(MALE[c - 'a'][haslo(ii, pass) - 'a']);
}
else if (c >= 'A' && c <= 'Z') {
putchar(DUZE[c - 'A'][haslo(ii, pass) - 'A']);
}
else koduj_numer(c);

}

putchar('\n');
getchar();
system("cls");
/*
!!!!!!!!!!!!!!!!!!!!!
tu czyszczenie ekranu
!!!!!!!!!!!!!!!!!!!!!
*/
}
/* Funkcja wypelniajaca tablice dwuwymiarowa malymi literami alfabetu */

int wypelnij_male(char tab[26][26]) {
int xx, yy;

for (yy = 0; yy <= 25; yy++)
for (xx = 0; xx <= 25; xx++)
tab[yy][xx]=('a' + ((yy+xx) % 26));

}

/* Funckja wypelniajaca tablice dwuwymiarowa wiekimi literami alfabetu */

int wypelnij_duze(char tab[26][26]) {
int xx, yy;

for (yy = 0; yy <= 25; yy++)
for (xx = 0; xx <= 25; xx++)
tab[yy][xx]='A' + ((yy+xx) % 26);
}

/* Fukncja zwracajaca aktualna litere w hasle */

char haslo(int ii, char pass[]) {

int k;
k = ii % (sizeof(pass));

return pass[k];
}

void koduj_numer(char c){putchar(c);}


void deszyfruj(){}

void stats() {

int c, state, num_lines, num_words, num_chars, num_let, num_digit,
num_spec;

state = OUT;
num_lines = num_words = num_chars = num_let = num_digit = num_spec = 0;

while ((c = getchar()) != '\t') {
++num_chars;
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
c = 1;
num_let = num_let + c;
}
if (c >= '0' && c <= '9') {
c = 1;
num_digit = num_digit + c;
}
if (c == '\n')
++num_lines;
if (c == ' ' || c == '\n' || c == '\t')
state = OUT;
else if (state == OUT) {
state = IN;
++num_words;
}
}

num_spec = num_chars - (num_let + num_digit);

printf("Statystyki tekstu:\n\n");
printf("\tIlosc wszystkich znakow: %d\n", num_chars);
printf("\tIlosc wszyskich slow: %d\n", num_words);
printf("\tIlosc liter: %d", num_let);
printf("\tIlosc cyfr: %d", num_digit);
printf("\tIlosc znakow specjalnych: %d", num_spec);

getchar();
getchar();
system("cls");
}
 
P

Peter Pichler

Piotr Turkowski said:
Hi!

Here you can get some notes about Vigenere Cipher:
http://raphael.math.uic.edu/~jeremy/crypt/vignere.html

Here's whole code of my program, function stats() is in polish, so you
can omit it. The problem is that the encrypting function is not working
correctly, so I didn't write decryptying function. Plz, can you help me
with both issues?

Which "both" issues? The fact that stats() is in Polish and that you haven't
written the decrypting function? No, I cannot help with the two ;-)

Now seriously. Your program seems a bit overcomplicated for such a simple
cipher. It also heavily relies on ASCII coding. In general, it is not
guaranteed that 'a'..'z' or 'A'..'Z' are contiguous. If you don't believe
me, Google for "EBCDIC".

I have added some comments interspersed with your code, but do not expect
that they are complete.
#include <stdio.h>

#define IN 1 /* wewn¹trz s³owa */
#define OUT 0 /* poza s³owem */

/* Vigenere Cipher */

/* deklaracje fuknkcji uzytych w programie */
int wypelnij_male(char tab[][]);
int wypelnij_duze(char tab[][]);

This declaration as good as nothing. I am surprised it even compiles. Only
the first index range may be left unspecified, e.g.

int wypelnij_male(char tab[][42]);

Besides, a few lines below you actually define the functions as

int wypelnij_male(char tab[26][26]) {...}

Doesn't your compiler complain about definition not matching the prototype?
If not, turn up your warning level.
char haslo(int ii, char pass[]);
void koduj_numer(char c);
void szyfruj();
void deszyfruj();
void stats();

main() {

This form is deprecated. Better spell it out: int main (void).
/* menu programu */
int menu;
for(;;){
printf("\n");
printf("1. Szyfrowanie tekstu.\n");
printf("2. Deszyfrowanie tekstu.\n");
printf("3. Statystyka.\n");
printf("4. Zakonczenie programu.\n");
scanf("%d", &menu);

scanf() is not an ideal function, although it seems that every beginner's
class starts with scanf(). I don't know why.

Do you know what happens if you enter "Ham and eggs 4 me, please", followed
by Enter? Your scanf() will try to read a decimal integer as dictated by %d
and stop on the space after 4. Any standard input function will read the
space (and whatever follows, up to the end of the line). If that's what you
want, OK.
switch(menu) {

case 1: szyfruj(); break;
case 2: deszyfruj();
case 3: stats();
case 4: return;
default: return;

return what? Your main in (correctly, though implicitly) int, so give it
one. I bet you turned your warning level *down*, didn't you?
}
}
}


void szyfruj(){

This function takes no arguments and returns nothing. So what does it do?
int ii, c, i, s;
char pass[]={0};

What do you think this declaration does? I'll tell you: it declares an array
pass of type char. The size of the array is unspeified, so the compiler has
to look right at the initializer list. Which contains how many
initializaerz? Correct, only one! So your declaration is equivalent to char
pass[1] = {0};
char MALE[26][26]={0};
char DUZE[26][26]={0};

wypelnij_male(MALE);
wypelnij_duze(DUZE);

See my comments on these two functions above.
printf("Podaj haslo: ");
scanf("%s\0", &pass);
getchar();

Why do you need the \0 in scanf? And why do you need getchar? Isn't it
because of using scanf to read the menu item in main?
printf("Podaj tekst do zaszyfrowania:\n");

for (ii = 0; (c = getchar()) != '\n'; ++ii) {
if (c >= 'a' && c <= 'z') {
putchar(MALE[c - 'a'][haslo(ii, pass) - 'a']);
}
else if (c >= 'A' && c <= 'Z') {
putchar(DUZE[c - 'A'][haslo(ii, pass) - 'A']);
}
else koduj_numer(c);


Have you heard about isalpha and tolower? They are defined in ctype.h and
would make your life much easier. And your code much more portable (your
only works on ASCII systems). Compare your code with:

if (isalpha(c))
putchar(MALE[tolower(c) - 'a'][haslo(ii, pass) - 'a']);
else
koduj_numer(c);

Admittedly, it *still* relies on ASCII coding (the -'a' bit). Resolving that
would require a bit more work, but not *that* much.
}

putchar('\n');
getchar();
system("cls");

Is this really necessary?
/*
!!!!!!!!!!!!!!!!!!!!!
tu czyszczenie ekranu
!!!!!!!!!!!!!!!!!!!!!
*/
}
/* Funkcja wypelniajaca tablice dwuwymiarowa malymi literami alfabetu */

int wypelnij_male(char tab[26][26]) {
int xx, yy;

for (yy = 0; yy <= 25; yy++)
for (xx = 0; xx <= 25; xx++)
tab[yy][xx]=('a' + ((yy+xx) % 26));

}

As mentined aforehand, the definition does not match the prototype. Plus, it
relies on ASCII coding. Also, I stylistically prefer for (yy = 0; yy < 26;
yy++).
/* Funckja wypelniajaca tablice dwuwymiarowa wiekimi literami alfabetu */

int wypelnij_duze(char tab[26][26]) {
int xx, yy;

for (yy = 0; yy <= 25; yy++)
for (xx = 0; xx <= 25; xx++)
tab[yy][xx]='A' + ((yy+xx) % 26);
}

What is a difference between this function and the one above? The only one
that I can see is using 'A' instead of 'a'. Why don't you make it one
function and pass the constant as a parameter?
/* Fukncja zwracajaca aktualna litere w hasle */

char haslo(int ii, char pass[]) {

int k;
k = ii % (sizeof(pass));

Ha! What's sizeof(pass) here? Hint: it is not 1, as one would expect given
the declaration of pass in your main().
Answer: in function calls, arrays decay to pointers, so your char pass[] is
equivalent to char * pass. Therefore, sizeof(pass) is a size of a pointer on
your system. Given your DOS system() call, I take an educated guess that
sizeof(pass) is either 2 or 4, depending on how you compile your program.
return pass[k];

Undefined behaviour. Your pass is passed (no pun intended) from main, where
it is declared as having one element. For any k other than 0, the program
may do pretty much whatever it pleases.
}

void koduj_numer(char c){putchar(c);}


void deszyfruj(){}

void stats() {

I am ignoring this function, as you suggested at the beginning ;-)
 
P

Piotr Turkowski

U¿ytkownik Peter Pichler napisa³:
Which "both" issues? The fact that stats() is in Polish and that you haven't
written the decrypting function? No, I cannot help with the two ;-)

badly decrypting, and no encrypting :)
Now seriously. Your program seems a bit overcomplicated for such a simple
cipher. It also heavily relies on ASCII coding. In general, it is not
guaranteed that 'a'..'z' or 'A'..'Z' are contiguous. If you don't believe
me, Google for "EBCDIC".

I'll check.
/* deklaracje fuknkcji uzytych w programie */
int wypelnij_male(char tab[][]);
int wypelnij_duze(char tab[][]);


This declaration as good as nothing. I am surprised it even compiles. Only
the first index range may be left unspecified, e.g.

int wypelnij_male(char tab[][42]);

Besides, a few lines below you actually define the functions as

int wypelnij_male(char tab[26][26]) {...}

Doesn't your compiler complain about definition not matching the prototype?
If not, turn up your warning level.

Declaration will be corrected.
I use Dev-C++ 4980 and it didn't warn me about problem in here.
This form is deprecated. Better spell it out: int main (void).
OK.

scanf() is not an ideal function, although it seems that every beginner's
class starts with scanf(). I don't know why.

Do you know what happens if you enter "Ham and eggs 4 me, please", followed
by Enter? Your scanf() will try to read a decimal integer as dictated by %d
and stop on the space after 4. Any standard input function will read the
space (and whatever follows, up to the end of the line). If that's what you
want, OK.

Yeah, I know, I tried :) This is version 0.0001 alpha beta pre relaease
1 :))
return what? Your main in (correctly, though implicitly) int, so give it
one. I bet you turned your warning level *down*, didn't you?

No, I didn't :). And return nothing :) just shutdown the program.
This function takes no arguments and returns nothing. So what does it do?

It's decrypting, it don't have to return anything, it just have to write
decrypted text, and that's all.
int ii, c, i, s;
char pass[]={0};

What do you think this declaration does? I'll tell you: it declares an array
pass of type char. The size of the array is unspeified, so the compiler has
to look right at the initializer list. Which contains how many
initializaerz? Correct, only one! So your declaration is equivalent to char
pass[1] = {0};

Hmm, i don't know how long the password will be. So how should it look like?
Why do you need the \0 in scanf? And why do you need getchar? Isn't it
because of using scanf to read the menu item in main?

I don't think so. I was thinking, that without \n or \0 it would read
one char too much, and without getchar(); program run too fast.
printf("Podaj tekst do zaszyfrowania:\n");

for (ii = 0; (c = getchar()) != '\n'; ++ii) {
if (c >= 'a' && c <= 'z') {
putchar(MALE[c - 'a'][haslo(ii, pass) - 'a']);
}
else if (c >= 'A' && c <= 'Z') {
putchar(DUZE[c - 'A'][haslo(ii, pass) - 'A']);
}
else koduj_numer(c);
Have you heard about isalpha and tolower? They are defined in ctype.h and
would make your life much easier. And your code much more portable (your
only works on ASCII systems). Compare your code with:

if (isalpha(c))
putchar(MALE[tolower(c) - 'a'][haslo(ii, pass) - 'a']);
else
koduj_numer(c);


Hmm, actualy, after encrypting I want to have same text as it was before
decrypting, so I need two alphabets. I'll try you function, but i think
that i would return all text BIG ot small.
Is this really necessary?

Should I use: printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\"); instead of
system("cls"); ?? Version for linux will have system("clear"); ;-)
As mentined aforehand, the definition does not match the prototype. Plus, it
relies on ASCII coding. Also, I stylistically prefer for (yy = 0; yy < 26;
yy++).

I giva up. What would be your solution?
/* Funckja wypelniajaca tablice dwuwymiarowa wiekimi literami alfabetu */

int wypelnij_duze(char tab[26][26]) {
int xx, yy;

for (yy = 0; yy <= 25; yy++)
for (xx = 0; xx <= 25; xx++)
tab[yy][xx]='A' + ((yy+xx) % 26);
}


What is a difference between this function and the one above? The only one
that I can see is using 'A' instead of 'a'. Why don't you make it one
function and pass the constant as a parameter?

Beacause I'm not that skilled.
/* Fukncja zwracajaca aktualna litere w hasle */

char haslo(int ii, char pass[]) {

int k;
k = ii % (sizeof(pass));


Ha! What's sizeof(pass) here? Hint: it is not 1, as one would expect given
the declaration of pass in your main().
Answer: in function calls, arrays decay to pointers, so your char pass[] is
equivalent to char * pass. Therefore, sizeof(pass) is a size of a pointer on
your system. Given your DOS system() call, I take an educated guess that
sizeof(pass) is either 2 or 4, depending on how you compile your program.

And this is the problem called: 'incorrect decrypting' (in 90%).
 
P

Peter Pichler

Piotr Turkowski said:
U¿ytkownik Peter Pichler napisa³:

Declaration will be corrected.
I use Dev-C++ 4980 and it didn't warn me about problem in here.

The default warning level must be set low in your compiler. This is
unfortunately quite a common practise.
No, I didn't :). And return nothing :) just shutdown the program.

mani() is a function like any other. If it is declared int (and it is, in
your case, although implicitly), it must return an int. Use 'return 0;' and
you'll be fine.
char pass[]={0};

What do you think this declaration does? I'll tell you: it declares an array
pass of type char. The size of the array is unspeified, so the compiler has
to look right at the initializer list. Which contains how many
initializaerz? Correct, only one! So your declaration is equivalent to char
pass[1] = {0};

Hmm, i don't know how long the password will be. So how should it look
like?

So leave the decision for later. Declare a pointer and allocate memory
dynamically once you know how much you need. If that is too advanced for you
yet, think of a number that is "big enough" and declare pass accordingly.

I forgot to mention two things here:
1. Standard output is usually line-buffered. It means that nothing is
guaranteed to be printed before the next \n or before you force flush the
buffer by fflush(stdout).
2. Since your pass is only 1 character long and that is taken up by the
terminating zero, the scanf() above is most likely going to do something
nasty.
I don't think so. I was thinking, that without \n or \0 it would read
one char too much, and without getchar(); program run too fast.

It *does* read too much already, see my comments on the size of pass ;-)
As for the program "going too fast", I assume you mean it prints the
following text without waiting for your password. If that's the case, try
experimenting with your scanf()s. You have two, one in main() and one above,
both working with the same input buffer. The second one continues where the
first one finished, which may not be where you *think* it finished.
printf("Podaj tekst do zaszyfrowania:\n");

for (ii = 0; (c = getchar()) != '\n'; ++ii) {
if (c >= 'a' && c <= 'z') {
putchar(MALE[c - 'a'][haslo(ii, pass) - 'a']);
}
else if (c >= 'A' && c <= 'Z') {
putchar(DUZE[c - 'A'][haslo(ii, pass) - 'A']);
}
else koduj_numer(c);
Have you heard about isalpha and tolower? They are defined in ctype.h and
would make your life much easier. And your code much more portable (your
only works on ASCII systems). Compare your code with:

if (isalpha(c))
putchar(MALE[tolower(c) - 'a'][haslo(ii, pass) - 'a']);
else
koduj_numer(c);

Hmm, actualy, after encrypting I want to have same text as it was before
decrypting, so I need two alphabets. I'll try you function, but i think
that i would return all text BIG ot small.

You are right, I made a mistake. (It is not unusual, unfortunately.) I
didn't notice the difference between MALE a DUZE in your code.
Should I use: printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\"); instead of
system("cls"); ?? Version for linux will have system("clear"); ;-)

Do you need to clear the screen at all? Many users (including me) find it
annoying.
I giva up. What would be your solution?

See below.
/* Funckja wypelniajaca tablice dwuwymiarowa wiekimi literami alfabetu */

int wypelnij_duze(char tab[26][26]) {
int xx, yy;

for (yy = 0; yy <= 25; yy++)
for (xx = 0; xx <= 25; xx++)
tab[yy][xx]='A' + ((yy+xx) % 26);
}

What is a difference between this function and the one above? The only one
that I can see is using 'A' instead of 'a'. Why don't you make it one
function and pass the constant as a parameter?

Beacause I'm not that skilled.

static const char male[] = "abcdefghijklmnopqrstuvwxyz";
static const char duze[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

static int wypelnij (char tab[26][26], const char alphabet[])
{
int xx, yy;

for (yy = 0; yy < 26; yy++)
for (xx = 0; xx < 26; xx++)
tab[yy][xx] = alphabet[(yy+xx) % 26];
}

int wypelnij_duze (char tab[26][26]) { return wypelnij(tab, duze); }
int wyplenij_male (char tab[26][26]) { return wypelnij(tab, male); }

No dependency on the character encoding, only one function to update should
you need to... The '26' could be replaced with a symbolic constant, to make
it more flexible.
/* Fukncja zwracajaca aktualna litere w hasle */

char haslo(int ii, char pass[]) {

int k;
k = ii % (sizeof(pass));

Ha! What's sizeof(pass) here? Hint: it is not 1, as one would expect given
the declaration of pass in your main().
Answer: in function calls, arrays decay to pointers, so your char pass[] is
equivalent to char * pass. Therefore, sizeof(pass) is a size of a pointer on
your system. Given your DOS system() call, I take an educated guess that
sizeof(pass) is either 2 or 4, depending on how you compile your
program.

And this is the problem called: 'incorrect decrypting' (in 90%).

Solution: pass the size of the array as another parameter and use that
parameter instead of sizeof(pass) inside your function.

Peter
 
R

Randy Howard

Declaration will be corrected.
I use Dev-C++ 4980 and it didn't warn me about problem in here.

Dev-C++ is just a front end to gcc. You can change the invocation to
gcc in the project options, for such things as -Wall -O2 -ansi, etc.
It'll make the detection of a whole host of common errors much more
automagic. :)
 
D

Dave Thompson

/* deklaracje fuknkcji uzytych w programie */
int wypelnij_male(char tab[][]);
int wypelnij_duze(char tab[][]);

This declaration as good as nothing. I am surprised it even compiles. Only
the first index range may be left unspecified, e.g.

int wypelnij_male(char tab[][42]);
In C99 yes; this is (now) a constraint on the array declarator, that
the element type must be complete and hence not (sub)array with
unknown bound. In C89, questionable; that constraint did not exist,
and the only applicable requirement was on actual array types or maybe
objects in 6.1.2.5, and the actual object here is a (rewritten)
pointer not an array -- char (*)[], which is a legal type *if* the
rewriting happens before the element type is checked, which was not
specified -- and the requirement was not a constraint anyway.
Besides, a few lines below you actually define the functions as

int wypelnij_male(char tab[26][26]) {...}

Doesn't your compiler complain about definition not matching the prototype?
If not, turn up your warning level.
And rewritten char (*)[] is compatible with char (*)[26] according to
the type rules, which rely only on information available at (separate)
compile time, hence no required diagnostic. This usage is rather
dangerous -- for precisely the reasons you imply -- and could
reasonably be warned about, but that isn't required.

<many other good points snipped>

- David.Thompson1 at worldnet.att.net
 
P

Peter Pichler

Dave Thompson said:
/* deklaracje fuknkcji uzytych w programie */
int wypelnij_male(char tab[][]);
int wypelnij_duze(char tab[][]);

This declaration as good as nothing. I am surprised it even compiles. Only
the first index range may be left unspecified, e.g.

int wypelnij_male(char tab[][42]);
In C99 yes; this is (now) a constraint on the array declarator, that
the element type must be complete and hence not (sub)array with
unknown bound. In C89, questionable; that constraint did not exist,
and the only applicable requirement was on actual array types or maybe
objects in 6.1.2.5, and the actual object here is a (rewritten)
pointer not an array -- char (*)[], which is a legal type *if* the
rewriting happens before the element type is checked, which was not
specified -- and the requirement was not a constraint anyway.

But these are not the same types! tab[12][34] has a different semantics when
tab is char[][42] than when it is char (*)[]. What is tab[12][34] in the
latter case anyway? Even if no constraints were broken, I would expect my
compiler to complain (as it does). A QoI issue...?

Peter
 
D

Dave Thompson

Dave Thompson said:
(re function declaration using char x[][] vs char x[][known])
In C99 yes; this is (now) a constraint on the array declarator, that
the element type must be complete and hence not (sub)array with
unknown bound. In C89, questionable; that constraint did not exist,
and the only applicable requirement was on actual array types or maybe
objects in 6.1.2.5, and the actual object here is a (rewritten)
pointer not an array -- char (*)[], which is a legal type *if* the
rewriting happens before the element type is checked, which was not
specified -- and the requirement was not a constraint anyway.

But these are not the same types! tab[12][34] has a different semantics when
tab is char[][42] than when it is char (*)[]. What is tab[12][34] in the
latter case anyway? Even if no constraints were broken, I would expect my
compiler to complain (as it does). A QoI issue...?
Right. Precisely, if the actual object is char[any][34] and the
prototype is char[][] rewritten to char(*)[], what is passed is really
the decayed char(*)[34]. Within the body, the only fully correct
access is if you cast/convert back to char(*)[34] and use that; or go
down to the first row and use *x as char[] decayed to char* for 0..33.
If you wrongly convert to and use e.g. char(*)[42] it's undefined --
although in practice you will always get the corresponding element for
row-major layout, if it exists; there's no other reasonable way to
implement C "multidim" arrays. That's what I meant when I went on to
describe the usage as "rather dangerous". And thus yes a warning is
good QoI but not required. All in C89, of course.

- David.Thompson1 at worldnet.att.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top