Disclaimer: Whatever is below, it's related to Affine Cipher. For whomever doesn't know it, it's a encrypting method that uses a mathematical function Ax+B to shift each letter in a given plaintext according to the letter's index in the alphabet.
I've written a code that encrypts and decrypts a given plaintext or ciphered text using Affine Cipher. It consists of these three functions:
char *encryption(char Plaintext[MAXSIZE], int A, int B);
int modularinverse(int number, int modulo);
char *decryption(char Ciphered[MAXSIZE], int A, int B, int inverse);
The part that concerns me sites in the decryption function. Around three or four letters are miss-calculated.
Let's consider the following plaintext: "a b c d e"
Using the encryption function:
char *encryption(char Plaintext[MAXSIZE], int A, int B) {
static char Ciphered[MAXSIZE];
int i;
int y;
int index;
for (i = 0; i < strlen(Plaintext) - 1; i++) {
if (Plaintext[i] == ' ') {
Ciphered[i] = ' ';
} else {
index = (int)Plaintext[i] - 'a';
y = (A * index + B) % 26;
Ciphered[i] = (char)y + 97;
}
}
return Ciphered;
}
it turns the plaintext into: "f m t a h". Which is correct.
Decrypting the plaintext should obviously give: "a b c d e". But instead, it gives: "a b c J e".
char *decryption(char Ciphered[MAXSIZE], int A, int B, int inverse) {
static char NewPlaintext[MAXSIZE];
int i;
unsigned int x;
int y;
int index;
for (i = 0; i < strlen(Ciphered); i++) {
if (Ciphered[i] == ' ') {
NewPlaintext[i] = ' ';
} else {
index = (int)Ciphered[i] - 'a';
x = inverse * (index - B) % 26;
NewPlaintext[i] = (char)x + 97;
}
}
return NewPlaintext;
}
The letter d is miss-calculated for a reason I don't know. Printing the values of variables index, inverse, B and x for each one of the characters f m t a h will respectively return this:
5 15 5 0
12 15 5 1
19 15 5 2
0 15 5 -23
7 15 5 4
First column represents indexes of the letters f m t a h.
Second column represents the inverse of A=7, which is 15. (Totally harmful, you may ignore it).
Third column represents B which is a constant for now (You may ignore it).
Fourth column represents x which is the result of inverse*(index-B) % 26. Adding 97 (ASCII number of 'a') to each of number in this column will result to the ASCII number of each letter.
i.e 0+97 = 97 which is 'a'. By consequence Decryption(f)=a.
But if you can notice. the result of x for the letter 'a' is -23. -23+97=74 which is J in ASCII. It should rather be 100 as it's the ASCII number for d. Therefore the result of x should rather be 3, not -23.
The reason behind this miss-calculation is buzzing me and I haven't figured out what's causing it.
Your code has few issues which are causing this strange behavior;
Don't use int type if you are dealing with character. Use char
In decryption() handle if the value of x is negative.
you can modify your decryption() like this.
char *decryption(char Ciphered[MAXSIZE],int A, int B, int inverse)
{
static char NewPlaintext[MAXSIZE];
char x;
char index;
for(int i=0;i<strlen(Ciphered);i++)
{
if(Ciphered[i]==' ')
{
NewPlaintext[i]=' ';
}
else
{
index=(int)Ciphered[i] - 'a';
x=inverse*(index-B) % 26;
if(x < 0)
{
// add 26 to take care of negative values; since you are using %
x += 26;
}
NewPlaintext[i]=(char)x+97;
}
}
return NewPlaintext;
}
I tested it few entries and it works fine.
Hope this helps.
Your code has several problems:
you stop before the end of the string: i<strlen(Plaintext)-1
you do not null terminate the destination strings.
your return a pointer to static storage: only one string can be encrypted/decyphered at a time.
depending on the values, you may take the modulo of negative numbers, which will be negative too. Use this instead: x = ((inverse * (index - B) % 26) + 26) % 26;
Related
Is it possible to get the same results as this code using only a and b?
I'm trying to calculate c from a and b to avoid using a third variable, but I can't find a solution.
#include <stdio.h>
#include <stdlib.h>
const int LENGTH = 20;
int main()
{
char arr[LENGTH];
for (int a = 0, b = 1, c = 0; c < LENGTH; c++) {
if (a < b) {
arr[c] = '*';
a++;
} else {
arr[c] = ' ';
a = 0;
b++;
}
}
printf(arr);
return EXIT_SUCCESS;
}
Code result : * ** *** **** *****
In the event that checking if a number is triangular by linking or writing some sort of sqrt() function is not a solution that you find acceptable:
Each group of **... in the final string has a ' ' at the end, so the shortest segment in the string is "* ", which is 2 chars long.
The c in your loop is the index of the char array that this iteration should write to, the a is the index inside the current group of '*'s, and b is length of the current group of '*'s less one (since we want to count the spaces). Directly before the if clause in your for loop, it can be said that c is the sum from 2 to b plus a.
In other words, if a=0, and b=1, then c=0, because the sum from 2 to 0 is 0, plus 0 is 0.
If a=3, and b=4, then c= (2+3+4) + 3 = 12.
This means that you could write your code like this:
#include <stdio.h>
const int LENGTH = 20;
int sumFromTwo(int in){ //Recursive function to calculate sigma(2:in)
if(in < 2)
return 0;
else
return in + sumFromTwo(in - 1);
}
int main()
{
char arr[LENGTH + 1]; //Extra byte for null-terminator
for (int a = 0, b = 1; sumFromTwo(b) + a < LENGTH ; ) {
if (a < b) {
arr[sumFromTwo(b) + a] = '*';
a++;
} else {
arr[sumFromTwo(b) + a] = ' ';
a = 0;
b++;
}
}
arr[LENGTH] = '\0'; //Always null-terminate your strings
printf(arr);
return EXIT_SUCCESS;
}
But using recursion to avoid using a variable that is almost certainly going to be optimized into a register anyway is not going to save your computer any resources, least of all RAM, so it is definitely cleaner to do it the way you did in your question (but please null-terminate your string before passing it to your choice of printf or puts).
Trying to do a Caesar cipher.
enum alfabeto{
A=0,B,C,D,E,F,G,H,I,L,M,N,O,P,Q,R,S,T,U,V,Z // 21
};
void cifra(char *string, int k){
enum alfabeto letter; // initialize the enum letter
size_t i = 0; // initialize counter
while (*(string+i)!='\0'){ // while string is not ended
letter = *(string+i); // attempt to "link" the enum letter to the equivalent (already uppercased) char
printf("%d", letter);
letter = (letter+k) % 21; // then it increases of a factor k and if it goes out of 21, it should take the right value
printf(" %d\n", letter);
++i;
}
}
Output:
$ ./"cesare"
write the text:
>TEST
choose the factor k:
>2
84 8
69 14
83 7
84 8
The values are wrong... maybe because I can't "link" a enum value to a char... How could I do this?c
letter = *(string+i); // attempt to "link" the enum letter to the equivalent (already uppercased) char
Should be:
letter = *(string+i) - 'A'; // attempt to "link" the enum letter to the equivalent (already uppercased) char
That way, 'A' will map to zero, as required.
// A B C D E F G H I J K L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z
const int offsetTable[] = {0,1,2,3,4,5,6,7,8,-1,-1,9,10,11,12,13,14,15,16,17,18,19,-1,-1,-1,20};
const char charLookupTable[] = "ABCDEFGHILMNOPQRSTUVZ";
// Should probably use a struct for the above to prevent size mis-matches
const int offsetTableSize = 21;
void cifra(char *str, int k){
char letter;
int newLetterOffset;
printf("%s\n", str); // Show initial string.
while (letter = *str++){ // while string is not ended
const int oldLetterOffset = offsetTable[letter - 'A']; // Get the old letter's offset.
if(letter <= 'A' || letter >= 'Z' || oldLetterOffset == -1)
{
printf("\nBad character %c found - ending string processing\n", letter);
return;
}
newLetterOffset = (oldLetterOffset + k) % offsetTableSize; // Get the letter's position, add the global offset, and wrap to table size.
printf("%c", charLookupTable[newLetterOffset]); // Use that offset to read the character's value from the shortened alphabet.
}
printf("\n\n");
}
int main()
{
cifra("HELLO", 0);
cifra("HELLO", 1);
cifra("HELLo", 1);
cifra("YELLO", 1);
return 0;
}
Notice I needed 2 tables to do the work as we had to go into and out of your shortened character set. Typically, we would use a struct to hold those 2 arrays, but I kept it simple for this example. Also, the arrays do not need to be global, but I placed them there also to keep things simpler.
Notice I also changed your printf() values to use characters and strings to make it easier to read.
Finally, I added some error checking as you cannot trust a user to give you a good string. Many a security flaw or random crash has resulted from that.
I am forced to use memset and drand48() to set a random number (2 - 7) of random characters that are lower case letters ('a' to 'z'). My code returns non ASCII characters and I am not sure why.
struct Record {
int seqnum;
float threat;
unsigned int addrs[2];
unsigned short int ports[2];
char dns_name[NUMLTRS];
};
My code is in a for loop:
memset(rec_ptr[i].dns_name, (char)((122 * drand48()) + 97),
((sizeof(char) * 7) * drand48()) + (sizeof(char) * 2));
My code returns non ASCII characters and I am not sure why.
Wrong scale used to generate lower case letters.
(122 * drand48()) + 97 converted to an integer type can readily make 122 different values. [97...218]. This is outside the ASCII range of [0...127].
How do I set a random number of random lowercase character ...
drand48() provides a random value [0...1.0). Scale by 26 and truncate to get 26 different indexes.
int index = (int) (drand48()*26); // 0...25
Pedantic code would be concerned about the few random values that may round the product to 26.0
if (index >= 26) index = 26 - 1;
int az = index + 'a';
// or look up in a table if non-ASCII encoding might be used
// 12345678901234567890123456
int az = "abcdefghijklmnopqrstuvwxyz"[index];
Selecting a random length would use the same thing, but with NUMLTRS instead of 26.
int length = (int) (drand48()*NUMLTRS);
if (index >= NUMLTRS) index = NUMLTRS -1;
... to a Struct member using memset in C
It is unclear if dns_name[] should be all the same, or generally different letters.
struct Record foo;
if (all_same) [
memset(foo.dns_name, az, length);
} else {
for (int i = 0; i < length; i++) {
int index = (int) (drand48()*26); // 0...25
if (index >= 26) index = 26 -1;
int az = index + 'a';
foo.dns_name[i] = az; // Does not make sense to use memset() here
}
}
Lastly, if dns_name[] is meant to be a string for ease of later use, declare with a +1 size
dns_name[NUMLTRS + 1];
// above code
foo.dns_name[NUMLTRS] = '\0'; // append null character
printf("dna_name <%s>\n", foo.dns_name);
For class, I am required to create a function that converts an Integer into it's corresponding Binary number. However, I am forced to use the given main and parameters for the to_binary function. The whole problem requires me to print out the 32 bit binary number, but to break it up, I am just trying to print out the Char Array, that I thought I filled with Integers (perhaps the issue). When I do compile, I receive just a blank line (from the \n) and I am wondering how I can fix this. All I want to do is to be able to print the binary number for 5 ("101") yet I can't seem to do it with my professor's restrictions. Remember: I cannot change the arguments in to_binary or the main, only the body of to_binary. Any help would be greatly appreciated.
#include<stdio.h>
void to_binary(int x, char c[]) {
int j = 0;
while (x != 0) {
c[j] x = x % 2;
j++;
}
c[33] = '\0';
}
int main() {
int i = 5;
char b[33];
to_binary(i,b);
printf("%s\n", b);
}
This is the answer to your question.
void to_binary(int x, char c[]) {
int i =0;
int j;
while(x) {
/* The operation results binary in reverse order.
* so right-shift the entire array and add new value in left side*/
for(j = i; j > 0; j--) {
c[j] = c[j-1];
}
c[0] = (x%2) + '0';
x = x/2;
i++;
}
c[i]=0;
}
the problem is in the code below:
while (x != 0) {
c[j] = x % 2; // origin: c[j] x = x % 2; a typo?
j++;
}
the result of x % 2 is a integer, but you assigned it to a character c[j] —— integer 1 is not equal to character '1'.
If you want to convert a integer(0-9) to a character form, for example: integer 7 to character '7', you can do this:
int integer = 7;
char ch = '0' + integer;
One of the previous answers has already discussed the issue with c[j] x = x % 2; and the lack of proper character conversion. That being said, I'll instead be pointing out a different issue. Note that this isn't a specific solution to your problem, rather, consider it to be a recommendation.
Hard-coding the placement of the null-terminator is not a good idea. In fact, it can result in some undesired behavior. Imagine I create an automatic char array of length 5. In memory, it might look something like this:
Values = _ _ _ _ _
Index = 0 1 2 3 4
If I were to populate the first three indexes with '1', '0', and '1', the array might look like so:
Values = 1 0 1 _ _
Index = 0 1 2 3 4
Let's say I set index 4 to contain the null-terminator. The array now looks like so:
Values = 1 0 1 _ \0
Index = 0 1 2 3 4
Notice how index three is an open slot? This is bad. In C/C++ automatic arrays contain garbage values by default. Furthermore, strings are usually printed by iterating from character to character until a null-terminator is encountered.
If the array were to look like it does in the previous example, printing it would yield a weird result. It would print 1, 0, 1, followed by an odd garbage value.
The solution is to set the null-terminator directly after the string ends. In this case, you want your array to look like this:
Values = 1 0 1 \0 _
Index = 0 1 2 3 4
The value of index 4 is irrelevant, as the print function will terminate upon reading index 3.
Here's a code example for reference:
#include <stdio.h>
int main() {
const size_t length = 4;
char binary[length];
size_t i = 0;
while (i < length - 1) {
char c = getchar();
if (c == '0' || c == '1')
binary[i++] = c;
}
binary[i] = '\0';
puts(binary);
return 0;
}
#include<stdio.h>
int binary(int x)
{
int y,i,b,a[100];
if(x<16)
{
if(x%2==1)
a[3]=1;
if(x/2==1||x/2==3 || x/2==5 || x/2==7)
a[2]=1;
if(x>4 && x<8)
a[1]=1;
else if(x>12 && x<16)
a[1]=1;
if(x>=8)
a[0]=1;
}
for(i=0;i<4;i++)
printf("\t%d",a[i]);
printf("\n");
}
int main()
{
int c;
printf("Enter the decimal number (less than 16 ):\n");
scanf("%d",&c);
binary(c);
}
this code might help it will simply convert the decimal number less than 16 into the 4 digit binary number.if it contains any error than let me know
In this program convert.c, I am trying to convert a given number of any base to base 10. The command is given as convert .todecimal is supposed to do that. The code below has errors of course but I am not sure how to make it work. For eg,the number in argv[3]is 123 in base 9. The equation is supposed to work like this :(1 x 9^2) + (2 x 9^1) + (3 x 9^0) = (102)10.where the variables are (n x argv[3]^i) + (n+1 * argv[3]^i-1)....How do i get a char of 123 when 123 itself a char? Any help is appreciated.
#include<stdio.h>
#include<math.h>
int todecimal();
main(int argc, char *argv[])
{
int s = 0;
int i = 0;
int n = 1;
if (argc < 4) {
printf("Usage: convert <basefrom> <baseto> <number>\n");
}
printf("to decimal prints %d" todecimal());
}
int todecimal() {
if (argv[3] > 0) {
if ((getchar(argv[3]) != NULL)) {
i = i + 1;
}
while (i >= 0) {
s = s + (n * (pow(argv[3],i)));
n = n + 1;
i = i - 1;
}
return s;
}
}
There is a difference between char and char*. The latter is a pointer to char, also used as a string (a sequence of chars). So, wherever you can have more than one char, you use a pointer (to the first one) instead - this is your argv[3].
So, to get one char from a sequence of chars, you apply square brackets:
argv[3] - is the whole string, let's pretend it's "192" to reduce confusion
argv[3][0] - is the first char, '1'
argv[3][1] - is the second char, '9'
argv[3][2] - is the third char, '2'
In your case, you need argv[3][i]. But you have to fix your other bugs too (there are many, as other people noted).