/*****************************************************//**
* @brief Vigenere cipher of texts or text-files, with flexible alphabet.
* @file vigenere.c
* @version 0.3
* @date 19 Feb, 2012
* @author migf1 <mig_f1@hotmail.com>
* @par Language:
* ANSI C (C89)
* @remark Source code tab-size: 8
* @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>
#include <limits.h>
const short int DEBUGMODE = 1; /* set it to 0 to disable own error messages */
const short int ABSHUFFLE = 1; /* set it to 0 to disable alphabet shuffling */
#define MAXINPUT (1024+1) /* limit in chars for reading the stdin line */
/* Macro for outputting our own error-messages */
#define MSG_ERROR( msg ) \
do { \
extern const short int DEBUGMODE; \
if ( DEBUGMODE ) { \
fprintf(stderr, "\n*** ERR [%s()|ln:%d]: %s\n", \
__func__, __LINE__, msg ); \
fputc('\n', stderr); \
} \
} while(0)
/* Portable alternative to Windows system("pause"); */
#define pressENTER() \
do{ \
char mYcHAr; \
printf( "press ENTER..." ); \
while ( (mYcHAr=getchar()) != '\n' && mYcHAr != EOF ) \
; \
}while(0)
/* Typedefs for passing arrays of unsigned strings as arrays of constant unsigned
strings to functions (this makes sure that those functions will not alter any
of the array contents).
*/
typedef const unsigned char *const ConstUString;
typedef const unsigned char *const * ArrayOfConstUString;
/*********************************************************//**
* @par Prototype:
* int fname_exists( const char *fname );
*
* @brief Check whether a file exits or not.
* @param[in] fname (const char *) A c-string holding the name of the file
* to be chacked.
* @return 1 (TRUE) if the file exists, 0 (FALSE) otherwise.
*************************************************************
*/
int fname_exists( const char *fname )
{
FILE *fp = NULL;
if ( !fname
|| !*fname
|| !(fp
=fopen(fname
,"r")) ) return 0; /* FALSE */
if ( fp )
return 1; /* TRUE */
}
/*********************************************************//**
* @par Prototype:
* int int_read( int *intvar );
*
* @brief Read an integer from stdin.
* @param[in,out] intvar (int *) A pointer to the integer variable to be read.
* @return The integer value read, or INT_MAX on error.
*************************************************************
*/
int int_read( int *intvar )
{
int try = 0;
char input[ MAXINPUT ] = {'\0'};
if ( !fgets(input
, MAXINPUT
, stdin
) ) return INT_MAX;
if ( EOF
== (try
=sscanf(input
, "%d", intvar
)) || try
< 1 ) return INT_MAX;
return *intvar;
}
/*********************************************************//**
* @par Prototype:
* char *s_read( char *s );
*
* @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;
}
/*********************************************************//**
* @par Prototype:
* int s_cindex( const char *s, const char c );
*
* @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;
char *str = (char *)s;
if ( !s || !*s )
return -1;
return (cp
= strchr(str
,c
)) ? (int)(cp
- str
) : -1; }
/*********************************************************//**
* @par Prototype:
* char *s_shuffle( char *s );
*
* @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 )
{
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;
}
return s;
}
/*********************************************************//**
* @par Prototype:
* char *s_rotate_left( char *s, int rotby, const size_t len );
*
* @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 size_t 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;
}
/*********************************************************//**
* @par Prototype:
* void sarr_print( ConstUString sarr[] );
*
* @brief Print to stdout the contents of a NULL terminated
* array of unsigned c-strings.
* @param[in] sarr (ConstUString *) The NULL terminated array of c-strings.
*************************************************************
*/
void sarr_print( ConstUString sarr[] )
{
int i = 0;
if ( !sarr )
return;
for (i=0; sarr[i]; i++ )
printf("%2d: %s\n", i
, sarr
[i
] );
return;
}
/*********************************************************//**
* @par Prototype:
* void sarr_free( char ***sarr );
*
* @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 )
{
size_t i = 0;
if ( !sarr || !*sarr )
return;
while ( (*sarr)[i] )
*sarr = NULL;
}
/*********************************************************//**
* @par Prototype:
* char **sarr_new( const int nstrings, const int lenstr );
*
* @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;
}
/*********************************************************//**
* @par Prototype:
* unsigned char c_encrypt_vigenere(
* const unsigned char c, const unsigned char kc, ConstUString tabrecta[] );
*
* @brief Encrypt an unsigned character according to its corresponding
* Vigenere key-character.
* @param[in] c (const unsigned char) The character to be encrypted.
* @param[in] kc (const unsigned char) The corresponding Vigenere key-character.
* @param[in] tabrecta (ConstUString *) The Vigenere tabula recta, holding all the
* alphabets.
* @return The encrypted character, or '\0' on error (if either c or kc
* is out of the basic alphabet, c is returned unchanged).
* @remark http://e...content-available-to-author-only...a.org/wiki/Vigen%C3%A8re_cipher
* @sa s_encrypt_vigenere(), f_encrypt_vigenere().
************************************************************/
unsigned char c_encrypt_vigenere(
const unsigned char c, const unsigned char kc, ConstUString 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] || c == '\0' )
return '\0';
/* characters out of alphabet are returned unchanged */
if ( -1 == (ci=s_cindex( (const char *)tabrecta[0], (const char)c ))
|| -1 == (kci=s_cindex( (const char *)tabrecta[0], (const char)kc)) )
return c;
return tabrecta[kci][ci];
}
/*********************************************************//**
* @par Prototype:
* unsigned char c_decrypt_vigenere(
* const unsigned char c, const unsigned char kc, ConstUString tabrecta[] );
*
* @brief Decrypt an unsigned character according to its corresponding
* Vigenere key-character.
* @param[in] c (const unsigned char) The enrypted character.
* @param[in] kc (const unsigned char) The corresponding Vigenere key-character.
* @param[in] tabrecta (ConstUString *) The Vigenere tabula recta, holding all the
* alphabets.
* @return The decrypted character, or '\0' on error (if either c or kc
* is out of the basic alphabet, c is returned unchanged).
* @remark http://e...content-available-to-author-only...a.org/wiki/Vigen%C3%A8re_cipher
* @sa s_decrypt_vigenere(), f_decrypt_vigenere().
************************************************************/
unsigned char c_decrypt_vigenere(
const unsigned char c, const unsigned char kc, ConstUString 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] || c == '\0' )
return '\0';
/* characters out of alphabet are returned unchanged */
if ( -1 == (ci=s_cindex((const char *)tabrecta[0], (const char)c))
|| -1 == (kci=s_cindex((const char *)tabrecta[0], (const char)kc)) )
return c;
/* index of c in the kci'th alphabet */
ci = s_cindex((const char *)tabrecta[kci], (const char)c);
return tabrecta[0][ci]; /* ci'th char in the basic alphabet */
}
/*********************************************************//**
* @par Prototype:
* int vigkey_repeat( unsigned char *skey, const size_t txtlen );
*
* @brief Repeat or truncate a Vigenere base key-string
* so that its length matches a given length.
* @param[in,out] skey (unsigned char *) The Vigenere base key-string
* to be modified.
* @param[in] txtlen (const int) The length to be matched.
* @return 1 (TRUE) or 0 (FALSE) on error.
* @remark The length to be matched should be equal to
* the length of the encrypted/decrypted text.
*************************************************************
*/
int vigkey_repeat( unsigned char *skey, const size_t txtlen )
{
size_t i=0, len=0;
/* sanity checks */
if ( !skey || !*skey || txtlen > MAXINPUT-1)
return 0; /* FALSE */
/* when base key is longer than plain text, truncate it */
if (len > txtlen) {
skey[ txtlen ] = '\0';
}
/* when base key is shorter than plain text, repeat it */
else {
for (i=len; i+len < txtlen; i += len)
memmove( &skey
[i
], skey
, len
* sizeof(char) ); memmove( &skey
[i
], skey
, (txtlen
-i
) * sizeof(char) ); }
return 1; /* TRUE */
}
/*********************************************************//**
* @par Prototype:
* unsigned char *s_encrypt_vigenere(
* unsigned char *s, const unsigned char *repkey, ConstUString tabrecta[]
* );
*
* @brief Encrypt an unsigned c-string according to a Vigenere
* repetitive key c-string.
* @param[in,out] s (unsigned char *) The unsigned c-string to be encrypted.
* @param[in] repkey (const unsigned char *) The Vigenere repetitive key c-string.
* @param[in] tabrecta (ConstUString *) The Vigenere tabula recta, holding all the
* alphabets.
* @return The encrypted unsigned c-string, or NULL on error.
* @note Contrary to the function f_encrypt_vigenere() which expects the
* base key-string, this one expects the repetitive key-string.
* @sa c_encrypt_vigenere(), f_encrypt_vigenere().
************************************************************/
unsigned char *s_encrypt_vigenere(
unsigned char *s, const unsigned char *repkey, ConstUString tabrecta[] )
{
size_t i = 0; /* to parse s & repkey */
/* sanity checks */
if ( !s || !*s || !repkey || !*repkey || !tabrecta ) {
MSG_ERROR("Sanity check failed!");
return NULL;
}
MSG_ERROR("Key length does not match text length!");
return NULL;
}
for (i=0; s[i]; i++)
{
s[i] = c_encrypt_vigenere(s[i], repkey[i], (ArrayOfConstUString)tabrecta);
if ( '\0' == s[i] ) {
MSG_ERROR("Invalid character found during encryption!");
return NULL;
}
}
return s;
}
/*********************************************************//**
* @par Prototype:
* unsigned char *s_decrypt_vigenere(
* unsigned char *s, const unsigned char *repkey, ConstUString tabrecta[]
* );
*
* @brief Decrypt an unsigned c-string according to a Vigenere
* repetitive key c-string.
* @param[in,out] s (unsigned char *) The unsigned c-string to be decrypted.
* @param[in] repkey (const unsigned char *) The repetitive Vigenere key c-string.
* @param[in] tabrecta (ConstUString *) The Vigenere tabula recta, holding all the
* alphabets.
* @return The decrypted unsigned c-string, or NULL on error.
* @note Contrary to the function f_decrypt_vigenere() which expects the
* base key-string, this one expects the repetitive key-string.
* @sa c_decrypt_vigenere(), f_decrypt_vigenere().
************************************************************/
unsigned char *s_decrypt_vigenere(
unsigned char *s, const unsigned char *repkey, ConstUString tabrecta[] )
{
int i = 0; /* to parse s & repkey */
/* sanity checks */
if ( !s || !*s || !repkey || !*repkey || !tabrecta
MSG_ERROR("Sanity check failed!");
return NULL;
}
for (i=0; s[i]; i++)
{
if ( '\0' == (s[i] = c_decrypt_vigenere(s[i], repkey[i], tabrecta)) ) {
MSG_ERROR("Invalid character found during decryption!");
return NULL;
}
}
return s;
}
/*********************************************************//**
* @par Prototype:
* int f_encrypt_vigenere(
* const char *, const unsigned char *, ConstUString *, const char *
* );
*
* @brief Encrypt the contents of a text-file, and save them to another
* text-file.
* @param[in] fname (const char *fname) A c-string holding the name of the file
* whose contents are about to get encrypted.
* @param[in] skey (const unsigned char *) An unsigned c-string holding the
* Vigenere base key (that is, without being repititive).
* @param[in] tabrecta (ConstUString *) The Vigenere tabula recta, holding all the
* alphabets.
* @param[in] decfname (const char *fname) A c-string holding the name of the file
* to be created with the encrypted contents.
* @return 1 (TRUE) or 0 (FALSE) on error.
* @note Contrary to the function s_encrypt_vigenere() which expects the
* repetitive key-string, this one expects the base key-string.
* @sa c_encrypt_vigenere(), s_encrypt_vigenere().
*************************************************************
*/
int f_encrypt_vigenere(
const char *fname,
const unsigned char *skey,
ConstUString tabrecta[],
const char *encfname )
{
FILE *fp = NULL, *encfp = NULL;
int cin = '\0', cout = '\0';
size_t i = 0;
if ( !fname
|| !*fname
|| NULL
== (fp
= fopen(fname
, "r")) ) goto ret_failure;
if ( !encfname
|| !*encfname
|| NULL
== (encfp
= fopen(encfname
, "w")) ) goto ret_failure;
while ( EOF
!= (cin
= fgetc(fp
)) ) {
if ( '\0' == skey[i] )
i = 0;
cout = (int)c_encrypt_vigenere((unsigned char)cin, skey[i], tabrecta);
if ( 0 == cout )
goto ret_failure;
if ( EOF
== fputc(cout
, encfp
) ) goto ret_failure;
i++;
}
fputs("\nf_encrypt_vigenere() failed!\n", stderr
);
return 1; /* TRUE */
ret_failure:
if ( encfp ) {
}
if ( fp )
return 0; /* FALSE */
}
/*********************************************************//**
*
*************************************************************
*/
#if 0
int _f_encrypt_vigenere(
const char *fname,
char *skey,
ConstUString tabrecta[],
const char *encfname )
{
FILE *fp = NULL, *encfp = NULL;
char line[ MAXINPUT ] = {'\0'};
char repkey[ MAXINPUT ] = {'\0'};
size_t lenskey = 0;
if ( !fname
|| !*fname
|| NULL
== (fp
= fopen(fname
, "r")) ) goto ret_failure;
if ( !encfname
|| !*encfname
|| NULL
== (encfp
= fopen(encfname
, "w")) ) goto ret_failure;
while ( fgets(line
, MAXINPUT
, fp
) ) {
strncpy( repkey
, skey
, MAXINPUT
-1 ); if ( !vigkey_repeat
(repkey
, strlen(line
)) ) goto ret_failure;
if ( !s_encrypt_vigenere(line, repkey, tabrecta ) )
goto ret_failure;
if ( EOF
== fputs(line
, encfp
) ) goto ret_failure;
}
goto ret_failure;
return 1; /* TRUE */
ret_failure:
if ( encfp )
if ( fp )
return 0; /* FALSE */
}
#endif
/*********************************************************//**
* @par Prototype:
* int f_decrypt_vigenere(
* const char *, const unsigned char *, ConstUString *, const char *
* );
*
* @brief Decrypt the contents of a text-file, and save them to another
* text-file.
* @param[in] fname (const char *fname) A c-string holding the name of the file
* whose contents are about to get decrypted.
* @param[in] skey (const unsigned char *) An unsigned c-string holding the
* Vigenere base key (that is, without being repititive).
* @param[in] tabrecta (ConstUString *) The Vigenere tabula recta, holding all the
* alphabets.
* @param[in] decfname (const char *fname) A c-string holding the name of the file
* to be created with the decrypted contents.
* @return 1 (TRUE) or 0 (FALSE) on error.
* @note Contrary to the function s_decrypt_vigenere() which expects the
* repetitive key-string, this one expects the base key-string.
* @sa c_decrypt_vigenere(), s_decrypt_vigenere().
*************************************************************
*/
int f_decrypt_vigenere(
const char *fname,
const unsigned char *skey,
ConstUString tabrecta[],
const char *decfname )
{
FILE *fp = NULL, *decfp = NULL;
int cin = 0, cout = 0;
size_t i = 0;
if ( !skey
|| !fname
|| !*fname
|| !(fp
= fopen(fname
, "r")) ) goto ret_failure;
if ( !decfname
|| !*decfname
|| !(decfp
= fopen(decfname
, "w")) ) goto ret_failure;
i = 0;
while ( EOF
!= (cin
= fgetc(fp
)) ) {
if ( '\0' == skey[i] )
i = 0;
cout = (int)c_decrypt_vigenere((unsigned char)cin, skey[i], tabrecta);
if ( 0 == cout )
goto ret_failure;
if ( EOF
== fputc(cout
, decfp
) ) goto ret_failure;
i++;
}
goto ret_failure;
return 1; /* TRUE */
ret_failure:
if ( decfp ) {
}
if ( fp )
return 0; /* FALSE */
}
/*********************************************************//**
* @par Prototype:
* int do_file_vigenere( ConstUString tabrecta[] );
*
* @brief Handle menu-selection "input from file".
* @param[in] tabrecta (ConstUString *) The Vigenere tabula recta, holding all the
* alphabets.
* @return 1 (TRUE) or 0 (FALSE) on error.
*************************************************************
*/
int do_file_vigenere( ConstUString tabrecta[] )
{
char fname[ MAXINPUT ] = {'\0'};
char *encfname = "enc.txt";
char *decfname = "dec.txt";
unsigned char vigkey[ MAXINPUT ] = {'\0'};
/* get the name of the text file to be encrypted */
do
printf("Enter the name of the file: "); while ( '\0' == *s_read(fname) );
if ( !fname_exists(fname)) {
MSG_ERROR("No such file, try again...");
return 0; /* FALSE */
}
/* get a Vigenere base key-string */
do
printf("Enter a base key-string: "); while ( '\0' == *s_read((char *)vigkey) );
/* encrypt the file fname */
if ( !f_encrypt_vigenere( fname, vigkey, (ArrayOfConstUString)tabrecta, encfname ) ) {
MSG_ERROR("f_encrypt_vigenere() failed!");
return 0; /* FALSE */
}
printf( "\nfile %s encrypted successfully, the resulting file is %s\n", fname, encfname);
/* decrypt the file out.txt */
if ( !f_decrypt_vigenere( encfname, vigkey, (ArrayOfConstUString)tabrecta, decfname ) ) {
MSG_ERROR("f_decrypt_vigenere() failed!");
return 0; /* FALSE */
}
printf( "file %s decrypted successfully, the resulting file is %s\n", encfname, decfname);
return 1; /* TRUE */
}
/*********************************************************//**
* @par Prototype:
* int do_stdin_vigenere( ConstUString tabrecta[] );
*
* @brief Handle menu-selection "input from keyboard".
* @param[in] tabrecta (ConstUString *) The Vigenere tabula recta, holding all the
* alphabets.
* @return 1 (TRUE) or 0 (FALSE) on error.
*************************************************************
*/
int do_stdin_vigenere( ConstUString tabrecta[] )
{
unsigned char text[ MAXINPUT ] = {'\0'}; /* plain text to en(de)crypt */
unsigned char vigkey[ MAXINPUT ] = {'\0'};
/* get the text to be encrypted */
do
printf("Text to be encrypted : "); while ( *s_read((char *)text) == '\0' );
/* get a Vigenere base key-string */
do
printf("Enter base key-string: "); while ( *s_read((char *)vigkey) == '\0' );
/* convert the base key-string to a repetitive key-string */
if ( !vigkey_repeat
(vigkey
, strlen((char *)text
)) ) { MSG_ERROR("Key repetition failed, nothing more to do!");
return 0; /* FALSE */
}
printf("\nRepetitive key-string: %s\n", vigkey
);
/* encrypt given text with the given Vigenere key */
if ( NULL == s_encrypt_vigenere(text, vigkey, (ArrayOfConstUString)tabrecta) ) {
MSG_ERROR("encryption error (perhaps invalid char in text)!");
return 0; /* FALSE */
}
printf("\nEncrypted text: %s\n", text
);
/* decrypt given text using given Vigenere key */
if ( NULL == s_decrypt_vigenere(text, vigkey, (ArrayOfConstUString)tabrecta) ) {
MSG_ERROR("\tdecryption error (perhaps invalid char in text)");
return 0; /* FALSE */
}
printf("Decrypted text: %s\n\n", text
);
return 1; /* TRUE */
}
/*********************************************************//**
* @par Prototype:
* char menu_selection( void );
*
* @brief Display the commands menu and the get user selection.
* @return (char) The menu selection, as a character.
*************************************************************
*/
char menu_selection( void )
{
char input[ MAXINPUT ] = {'\0'};
puts("\n-----------------------"); puts("migf1 @ Vigenere Cipher"); puts("-----------------------"); puts("1. display the alphabet"); puts("2. input from keyboard"); puts("3. input form text file"); puts("-----------------------");
s_read( input );
return *input;
}
/*********************************************************//**
* @par Prototype:
* short int tabrecta_make(
* unsigned char ***, const unsigned char *, const unsigned char,const int
* );
*
* @brief Create & fill the Vigenere tabula recta (table of
* unsigned alphabets).
* @param[in,out] tabrecta (unsigned char ***) Pointer to an array of unsigned
* c-strings (tabula recta) to be created & filled-in.
* If the array is created successfully, its last
* c-string will be a NULL pointer (NULL terminated
* array of unsigned c-strings).
* @param[in] ab (const unsigned char *) An unsigned c-string to be
* used as basic alphabet (see notes).
* @param[in] cstart (const unsigned char) The 1st character in the basic
* alphabet (see notes).
* @param[in] ablen (const 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.
* @sa tabrecta_extend().
*************************************************************
*/
short int tabrecta_make(
unsigned char ***tabrecta,
const unsigned char *ab,
const unsigned char cstart,
const int ablen )
{
short int i, len = 0;
/* sanity check */
if ( !tabrecta )
return 0;
/* when tabrecta already exists, just return its alphabet length */
if ( *tabrecta && (*tabrecta)[0] ) {
MSG_ERROR("TabulaRecta already existed (stayed unchanged)");
return strlen( (char *)(*tabrecta
)[0] ); }
/* when argument ab exists and it is not an empty c-string */
if ( ab && *ab )
{
/* reserve memory for the tablula recta */
if ( NULL == (*tabrecta = (unsigned char **)sarr_new(len, len)) )
return 0;
/* copy the basic alphabet ab to the 1st string of the tabula recta */
strcpy( (char *)(*tabrecta
)[0], (char *)ab
); s_shuffle( (char *)(*tabrecta)[0] );
/* remaining strings have basic alphabet rotated by 1 char at a time */
for (i=1; (*tabrecta)[i]; i++) {
strcpy( (char *)(*tabrecta
)[i
], (char *)(*tabrecta
)[0] ); s_rotate_left( (char *)(*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 = (unsigned char **) 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;
if ( ABSHUFFLE )
s_shuffle( (char *)(*tabrecta)[0] ); /* shuffle alphabet */
/* remaining strings have basic alphabet rotated by 1 char at a time */
for (i=1; (*tabrecta)[i]; i++) {
strcpy( (char *)(*tabrecta
)[i
], (char *)(*tabrecta
)[0] ); s_rotate_left( (char *)(*tabrecta)[i], i, len );
}
}
/* error */
else
return 0;
return len;
}
/*********************************************************//**
* @par Prototype:
* short int tabrecta_extend( unsigned char ***, const unsigned char *extension );
*
* @brief Extend the alphabet of an existing tabula recta.
* @param[in,out] tabrecta (unsigned char ***) Pointer to a NULL terminated array
* of unsigned c-strings, holding the tabula recta to be
* modified.
* @param[in] extension (char **) An unsigned c-string holding the characters
* to be added to the existing tabula recta.
* @return The length of the extended 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
* extended number of c-string alphabets, excluding
* the final NULL string.
* @note After the needed houskeeping and error-checking is done,
* the function comoletely destroys the old tabula recta
* and re-builds it from scratch. Thus, it is crucial to
* always check if it succeeded, before attempting to
* move on with the rest of the proggram.
*************************************************************
*/
short int tabrecta_extend( unsigned char ***tabrecta, const unsigned char *extension )
{
short int ablen = 0, newlen = 0;
unsigned char *abnew = NULL; /* temp c-str for extended alphabet */
/* sanity checks */
if ( !tabrecta || !*tabrecta )
return 0;
/* when tabula recta exists, get its alphabet length */
if ( (*tabrecta)[0] )
ablen
= strlen( (char *)(*tabrecta
)[0] );
/* more sanity checks */
if ( !extension || !*extension )
return ablen;
/* allocate memory for the extended alphabet */
newlen
= ablen
+ strlen( (char *)extension
); if ( NULL
== (abnew
= calloc( newlen
+1, sizeof(unsigned char) )) ) return 0;
/* construct the extended alphabet */
strcpy( (char *)abnew
, (char *)(*tabrecta
)[0] ); strcat( (char *)abnew
, (char *)extension
);
/* destroy old tabula recta and re-build it with the extended alphabet */
sarr_free( (char ***)tabrecta );
newlen = tabrecta_make( tabrecta, abnew, 0, 0 );
/* free memory temporarily reserved for the c-string of the extended alphabet */
return newlen;
}
/*********************************************************//**
*
*************************************************************
*/
int main( void )
{
char msel = '0'; /* menu selection */
unsigned char **tabrecta = NULL; /* Vigenere tabula recta */
short int ablen = 0; /* length of basic alphabet */
/* create the Vigenere tabula recta, with alphabet from ' ' to ASCII(254) */
if ( 0 == (ablen=tabrecta_make( &tabrecta, NULL, ' ', 223 )) ) {
MSG_ERROR("Tabula recta initialization failed!");
goto exit_failure;
}
/* extend the alphabet of the created Vigenere tabula recta with 5 more chars*/
if ( 0 == (ablen=tabrecta_extend( &tabrecta, (unsigned char *)"\t\v\n\r\f")) )
{
MSG_ERROR("Tabula recta extension failed!");
goto exit_failure;
}
/* display the commands menu and apply user selection */
for (;;)
{
if ( '\0' == (msel=menu_selection()) ) /* just an ENTER was pressed */
continue;
if ( '0' == msel ) /* exit was selected */
break;
if ( '1' == msel ) /* display the alphabet */
printf("\nAlphabet (%d chars):\n%s\n", ablen
, tabrecta
[0] );
else if ( '2' == msel ) { /* use stdin for input */
do_stdin_vigenere( (ArrayOfConstUString)tabrecta );
pressENTER();
}
else if ( '3' == msel ) { /* use a file for input */
do_file_vigenere( (ArrayOfConstUString)tabrecta );
pressENTER();
}
else
puts("\ninvalid option, try again...");
}
sarr_free( (char ***)&tabrecta );
exit_failure:
sarr_free( (char ***)&tabrecta );
pressENTER();
}