/*****************************************************//**
* @brief Sample Vigenere cipher, with flexible alphabet.
*
* @file vigenere.c
* @version 0.2
* @date 16 Feb, 2012
* @author migf1 <mig_f1@hotmail.com>
* @par Language:
* ANSI C (C89)
*
* @note http://e...content-available-to-author-only...a.org/wiki/Vigen%C3%A8re_cipher.
*********************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define SHUFFLE 1 /* set it to 0 to disable alphabet shuffling */
#define MAXINPUT (1024+1)
#define pressENTER() \
do{ \
char mYcHAr; \
printf( "press ENTER..." ); \
while ( (mYcHAr=getchar()) != '\n' && mYcHAr != EOF ) \
; \
}while(0)
/*
* Typedefs for passing arrays of strings as arrays of constant strings to functions.
* (this makes sure that those functions will not alter any of the array contents).
*/
typedef const char *const ConstString;
typedef const char *const * ArrayOfConstString;
/*********************************************************//**
* @brief Read a c-string from stdin.
* @param[in,out] s (char *) The c-string to be read.
* @return The c-string (it remains unchanged on error)
*************************************************************
*/
char *s_read( char *s )
{
int lenstr = 0;
if ( !s
|| !fgets(s
, MAXINPUT
, stdin
) ) return s;
if ( s[ lenstr - 1 ] == '\n' )
s[ lenstr -1 ] = '\0';
return s;
}
/*********************************************************//**
* @brief Get the index of a given char c in a given c-string s.
* @param[in] s (const char *) The c-string to be searched.
* @param[in] c (const char ) The character to be looked for.
* @return The zero-based index of c in s, or -1 on error.
*************************************************************
*/
int s_cindex( const char *s, const char c )
{
char *cp = NULL;
if ( !s || !*s )
return -1;
return (cp
= strchr(s
,c
)) ? (int)(cp
- s
) : -1; }
/*********************************************************//**
* @brief Shuffle the contents of a given c-string s.
* @param[in,out] s (char *) The c-string to be shuffled.
* @return The shuffled c-string (it remains unchanged on error).
* @note It requires the constant SHUFFLE to contain an non-zero value.
*************************************************************
*/
char *s_shuffle( char *s )
{
#if SHUFFLE
char *cp = NULL, c = '\0';
int len = 0;
int i = 0;
/* sanity check */
if ( !s
|| !*s
|| (len
= strlen(s
)) < 2 ) return s;
for (cp=s; *cp; cp++)
{
c = *cp;
*cp = s[i];
s[i] = c;
}
#endif
return s;
}
/*********************************************************//**
* @brief Roatate to the left a given c-string s of length len,
* by rotby characters.
* @param[in,out] s (char *) The c-string to be rotated.
* @param[in] rotby (int) The amount of characters the c-string will be rotated by.
* @param[in] len (const int) The length of the c-string in characters,
* excluding the nil terminator.
* @return The rotated c-string (remains unchanged on error).
*************************************************************
*/
char *s_rotate_left( char *s, int rotby, const int len )
{
char *temp = NULL;
if ( !s || rotby < 1 || len < 2 || (rotby %= len) == 0 )
return s;
if ( NULL
== (temp
= malloc( rotby
* sizeof(char) )) ) return s;
memcpy( temp
, s
, rotby
* sizeof(char) );
memmove( s
, &s
[ rotby
], (len
-rotby
) * sizeof(char) ); memcpy( &s
[ len
-rotby
], temp
, rotby
* sizeof(char) );
return s;
}
/*********************************************************//**
* @brief Print to stdout the contents of a NULL terminated
* array of c-strings.
* @param[in] sarr (ConstString *) The NULL terminated array of c-strings.
*************************************************************
*/
void sarr_print( ConstString sarr[] )
{
int i = 0;
if ( !sarr )
return;
for (i=0; sarr[i]; i++ )
printf("%2d: %s\n", i
, sarr
[i
] );
return;
}
/*********************************************************//**
* @brief Free memory reserved for a NULL terminated array of c-strings.
* @param[in,out] sarr (char ***) Pointer to the NULL terminated array of c-strings.
* @remark The array pointer \a *sarr is reset to NULL (that's why it
* passed <em>by reference</em> to the function).
*************************************************************
*/
void sarr_free( char ***sarr )
{
int i = 0;
if ( !sarr || !*sarr )
return;
while ( (*sarr)[i] )
*sarr = NULL;
}
/*********************************************************//**
* @brief Reserve memory for a NULL terminated array of c-strings.
* @param[in] nstrings (const int) The number of c-strings to be allocated,
* not counting the terminating NULL string.
* @param[in] lenstr (const int) The number of character to be allocated for
* each c-string, excluding the nil-terminator character.
* @return A pointer to the newly allocated memory, or NULL on error.
*************************************************************
*/
char **sarr_new( const int nstrings, const int lenstr )
{
char **sarr = NULL;
int i=0;
if ( nstrings < 1 || lenstr < 1 )
return NULL;
if ( NULL
== (sarr
= calloc( nstrings
+1, sizeof(char *) )) ) return NULL;
for (i=0; i < nstrings; i++)
{
if ( NULL
== (sarr
[i
] = calloc( lenstr
+1, sizeof(char) )) ) {
int j;
for (j=i-1; j > -1; j--)
return NULL;
}
}
return sarr;
}
/*********************************************************//**
* @brief Encrypt a character according to its corresponding Vigenere
* key-character.
* @param[in] c (const char) The character to be encrypted.
* @param[in] kc (const char) The corresponding Vigenere key-character.
* @param[in] tabrecta (ConstString *) The Vigenere tabula recta, holding all the
* alphabets.
* @return The encrypted character, or '\0' on error (if either c or kc
* is not part of the basic alphabet it is considered an error).
* @remark http://e...content-available-to-author-only...a.org/wiki/Vigen%C3%A8re_cipher
************************************************************/
char c_encrypt_vigenere( const char c, const char kc, ConstString tabrecta[] )
{
int ci = -1; /* index of c in the basic alphabet */
int kci = -1; /* index of kc in the basic alphabet */
/* sanity checks */
if ( !tabrecta || !tabrecta[0]
|| -1 == (ci=s_cindex( tabrecta[0], c ))
|| -1 == (kci=s_cindex(tabrecta[0], kc)) )
return '\0';
return tabrecta[kci][ci];
}
/*********************************************************//**
* @brief Decrypt a character according to its corresponding Vigenere
* key-character.
* @param[in] c (const char) The character to be decrypted.
* @param[in] kc (const char) The corresponding Vigenere key-character.
* @param[in] tabrecta (ConstString *) The Vigenere tabula recta, holding all the
* alphabets.
* @return The decrypted character, or '\0' on error (if either c or kc
* is not part of the basic alphabet it is considered an error).
* @remark http://e...content-available-to-author-only...a.org/wiki/Vigen%C3%A8re_cipher
************************************************************/
char c_decrypt_vigenere( const char c, const char kc, ConstString tabrecta[] )
{
int ci = -1; /* index of c */
int kci = -1; /* index of kc */
/* sanity checks (including both c & kc being valid chars of basic alphabet) */
if ( !tabrecta || !tabrecta[0]
|| -1 == (ci=s_cindex(tabrecta[0], c))
|| -1 == (kci=s_cindex(tabrecta[0], kc)) )
return '\0';
ci = s_cindex(tabrecta[kci], c); /* index of c in the kci'th alphabet */
return tabrecta[0][ci]; /* ci'th char in the basic alphabet */
}
/*********************************************************//**
* @brief Encrypt a c-string according to a Vigenere key c-string.
* @param[in,out] s (char *) The c-string to be encrypted.
* @param[in] skey (const char *) The Vigenere key c-string.
* @param[in] tabrecta (ConstString *) The Vigenere tabula recta, holding all the
* alphabets.
* @return The encrypted c-stsring, or NULL on error.
* @sa c_encrypt_vigenere()
************************************************************/
char *s_encrypt_vigenere(char *s, const char *skey, ConstString tabrecta[])
{
int i = 0; /* to parse s & skey */
/* sanity checks */
if ( !s
|| !*s
|| !skey
|| !*skey
|| !tabrecta
|| strlen(s
) != strlen(skey
) ) return NULL;
for (i=0; s[i]; i++)
{
s[i] = c_encrypt_vigenere(s[i], skey[i], (ArrayOfConstString)tabrecta);
if ( '\0' == s[i] )
return NULL;
}
return s;
}
/*********************************************************//**
* @brief Decrypt a c-string according to a Vigenere key c-string.
* @param[in,out] s (char *) The c-string to be decrypted.
* @param[in] skey (const char *) The Vigenere key c-string.
* @param[in] tabrecta (ConstString *) The Vigenere tabula recta, holding all the
* alphabets.
* @return The decrypted c-stsring, or NULL on error.
* @sa c_decrypt_vigenere()
************************************************************/
char *s_decrypt_vigenere( char *s, const char *skey, ConstString tabrecta[] )
{
int i = 0; /* to parse s & skey */
/* sanity checks */
if ( !s
|| !*s
|| !skey
|| !*skey
|| !tabrecta
|| strlen(s
) != strlen(skey
) ) return NULL;
for (i=0; s[i]; i++)
if ( '\0' == (s[i] = c_decrypt_vigenere(s[i], skey[i], tabrecta)) )
return NULL;
return s;
}
/*********************************************************//**
* @brief Create & fill the Vigenere tabula recta (table of alphabets).
*
* @param[in,out] tabrecta (char ***) Pointer to an array of c-strings (tabula
* recta) to be created & filled-in. If the array is
* created successfully, its last c-string will be a
* NULL string (NULL terminated array of c-strings).
* @param[in] ab (const char *) A c-string to be used as basic
* alphabet (see notes).
* @param[in] cstart (const char) The 1st character in the basic alphabet
* (see notes).
* @param[in] ablen (cont int) The basic alphabet length, in characters
* (see notes).
*
* @return The length of the newly created basic alphabet in
* characters, excluding the nil-terminator, or 0 on
* error. Since tabula recta is a square table, the
* return value of the function equals also to the
* number of c-string alphabets created, excluding the
* final NULL string.
*
* @note You may use this function differently depending on
* the arguments you pass to it. If you specify a valid,
* non-empty, c-string as the 2nd argument, then it is
* used as the basic alphabet and the rest of the
* arguments are ignored.
* However, if you pass the 2nd argument as NULL or as
* an empty c-string, then the basic alphabet is
* constructed from consecutive characters in the
* current ASCII table, starting from character \a
* cstart up to character <em>(cstart + ablen-1)</em>.
* Please note that in this case, the zero character
* '\0' is not allowed (the function returns error).
* In general, you should never include the zero
* character in your basic alphabet.
*************************************************************
*/
int tabrecta_make(
char ***tabrecta, const char *ab, const char cstart, const int ablen )
{
int i, len = 0;
/* sanity check */
if ( !tabrecta )
return 0;
/* when ab exists and it is not an empty c-string */
if ( ab && *ab )
{
/* reserve memory for the tablula recta */
if ( NULL == (*tabrecta = sarr_new(len, len)) )
return 0;
/* copy the basic alphabet ab to the 1st string of the tabula recta */
s_shuffle( (*tabrecta)[0] );
/* remaining strings have basic alphabet rotated by 1 char at a time */
for (i=1; (*tabrecta)[i]; i++) {
strcpy( (*tabrecta
)[i
], (*tabrecta
)[0] ); s_rotate_left( (*tabrecta)[i], i, len );
}
}
/* when ab is NULL or empty, make alphabet from cstart to (cstart+ablen-1) */
else if (cstart > '\0' && ablen > 0 && cstart + ablen - 1 < 257)
{
/* reserve memory for the tablula recta */
len = ablen;
if (NULL == (*tabrecta = sarr_new(len, len)) )
return 0;
/* construct the basic alphabet into the 1st string of tabula recta */
for (i=0; i < len; i++)
(*tabrecta)[0][i] = cstart + i;
s_shuffle( (*tabrecta)[0] ); /* shuffle the alphabet */
/* remaining strings have basic alphabet rotated by 1 char at a time */
for (i=1; (*tabrecta)[i]; i++) {
strcpy( (*tabrecta
)[i
], (*tabrecta
)[0] ); s_rotate_left( (*tabrecta)[i], i, len );
}
}
/* error */
else
return 0;
return len;
}
/*********************************************************//**
*
*************************************************************
*/
int main( void )
{
char **tabrecta = NULL; /* Vigenere tabula recta */
int ablen = 0; /* length of basic alphabet */
char text[ MAXINPUT ] = {'\0'}; /* text to be encrypted */
char vigkey[ MAXINPUT ] = {'\0'}; /* Vigenere key */
/* create the Vigenere tabula recta, with alphabet from '\t' to ASCII(254) */
if ( 0 == (ablen=tabrecta_make( &tabrecta, NULL, '\t', 246 )) ) {
puts("\nTabula recta initialization failed!"); goto exit_failure;
}
printf("Alphabet (%d chars):\n%s\n\n", ablen
, tabrecta
[0] );
/* get the text to be encrypted */
printf("Text to be encrypted: "); if ( *s_read(text) == '\0' ) {
puts("\nempty text was given, nothing to do!"); goto exit_failure;
}
/* get a valid Vigenere key string */
do {
printf("Enter the key-string: "); s_read(vigkey);
/* encrypt given text with the given Vigenere key */
if ( NULL == s_encrypt_vigenere(text, vigkey, (ArrayOfConstString)tabrecta) ) {
puts("\tencryption error (perhaps an invalid char was found in text)"); goto exit_failure;
}
printf("\nEncrypted text: %s\n", text
);
/* decrypt given text using given Vigenere key */
if ( NULL == s_decrypt_vigenere(text, vigkey, (ArrayOfConstString)tabrecta) ) {
puts("\tdecryption error (perhaps an invalid char was found in text)"); goto exit_failure;
}
printf("Decrypted text: %s\n\n", text
);
sarr_free( &tabrecta );
pressENTER();
exit_failure:
sarr_free( &tabrecta );
pressENTER();
}