I'm rather new to C and have recently been working on making a simple encryption/decryption program. I managed to get the encryption fine, but I've hit a road block with the decryption.
The relevant code is as follows:
Encryption (where asciinum is the ascii value for the letter, and k is the "vigenere" key to be shifted by).
//shifts lowercase letters by key
if (asciinum >= 97 && asciinum <= 123)
{
f = p % keylen;
k = key[f];
asciinum = (asciinum - 97) + k;
asciinum = (asciinum % 26) + 97;
letterc = (char) asciinum;
//printf("%c\n", letterc);
cipher[j] = letterc;
p++;
}
//shifts uppercase letters by key
if (asciinum >= 65 && asciinum <= 91)
{
f = p % keylen;
k = key[f];
asciinum = (asciinum - 65) + k;
asciinum = (asciinum % 26) + 65;
letterc = (char) asciinum;
cipher[j] = letterc;
p++;
}
I want to use a similar model to decrypt (using the same key), but the modulo method I used to wrap around the 26 characters doesn't work when asciinum is negative, as would be the case in subtracting a k of 5 from a (i.e. 0).
Decryption attempt...
//shifts uppercase letters by key
if (asciinum >= 65 && asciinum <= 91)
{
f = p % keylen;
k = key[f];
asciinum = (asciinum - 65) - k;
asciinum = (asciinum % 26) + 65;
letterc = (char) asciinum;
cipher[j] = letterc;
p++;
}
Any help would be greatly appreciated. Thanks!
In pre-C99 C, the behaviour of % for negative numbers is implementation-defined. In C99 onwards, it's defined, but doesn't do what you want.
The easiest way out is to do:
((asciinum + 26) % 26)
Assuming asciinum can never get lower than -26.
Instead of using asciinum % 26, use (asciinum + 26) % 26, this will have you using modulus on positive numbers, at the cost of an extra addition each time through the cycle.
Related
I have a given exercise that wants me to find the uppercase letter that is K places from the letter in this case char variable that is named C. The range is uppercase letters from A to Z.
For example if the input is B 3 the output should be E. For this specific input its simple you just sum the values and you get your answer but for example what if we go out of the range. Here is one example F 100 the program should output B because if the value is > than Z the program starts from A.
If there are some confusions I will try to explain it more here are some test cases and my code that only work if we don't cross the range.
Input Output
B 3 E
X 12345 S
F 100 B
T 0 T
#include <stdio.h>
int main(){
int K;
char C,rez;
scanf("%c %d",&C,&K);
int ch;
for(ch = 'A';ch <= 'Z';ch++){
if(C>='A' && C<='Z'){
rez = C+K;
}
}
printf("%c",rez);
return 0;
}
Think of the letters [A-Z] as base 26 where zero is A, one is B and 25 is Z.
As we sum of the letter (in base 26) and the offset, it is only the least significant base 26 digit we have interest, so use % to find the least significant base 26 digit much like one uses % 10 to find the least significant decimal digit.
scanf(" %c %d",&C,&K);
// ^ space added to consume any white-space
if (C >= 'A' && C <= 'Z') {
int base26 = C - 'A';
base26 = base26 + K;
base26 %= 26;
int output = base26 + 'A';
printf("%c %-8d %c\n", C, K, output);
}
For negative offsets we need to do a little more work as % in not the mod operator, but the remainder. This differs with some negative operands.
base26 %= 26;
if (base < 0) base26 += 26; // add
int output = base26 + 'A';
Pedantically, C + K may overflow with extreme K values. To account for that, reduce K before adding.
// base26 = C + K;
base26 = C + K%26;
We could be a little sneaky and add 26 to insure the sum is not negative.
if (C >= 'A' && C <= 'Z') {
int base26 = C - 'A';
base26 = base26 + K%26 + 26; // base26 >= 0, even when K < 0
base26 %= 26; // base26 >= 0 and < 26
int output = base26 + 'A';
printf("%c %-8d %c\n", C, K, output);
}
... or make a complex one-line
printf("%c %-8d %c\n", C, K, (C - 'A' + K%26 + 26)%26 + 'A');
This can be accomplished by using 2 concepts.
ASCII value
Modulus operator (%)
In C every character has an ASCII value. Basically it goes from 0-127.
The character 'A' has the value of 65
The character 'B' has the value of 66 (65 + 1)
and so on...
Until Z which is 65 + 25 = 90
And the 2nd concept I want to highlight in math is modulo arithmetic where if you always want to map a number to certain range, you can use a modulus operator.
Modulus is the reminder that you get after dividing a number by another number.
In our case, we have 26 alphabets so we can always get a number between 0 to 25
For the example you took
100 % 26 = 22
But you have to consider the starting point too.
So, we always subtract the initial alphabet by the value of 'A', i.e. 65 so that 'A' maps to 0 and 'Z' maps to 25
So, if we start with 'F' and need to go 100 places..
Subtract 'A' value from 'F' value. Characters behave like numbers so you can actually store 'F' - 'A' in an integer
In this case 'F' - 'A' = 5
Next we add the offset to this.
5 + 100 = 105
Then we perform modulus with 26
105 % 26 = 1
Finally add the value of 'A' back to the result
'A' + 1 = 'B'
And you are done
Get the remainder of input number with 26 using modulo operator. If sum of input character and remainder is less than or equal to Z then its the answer otherwise again find the remainder of sum with 26 and that will be answer (take care of offset because the ASCII decimal value of letter A is 65).
Roughly the implementation will be:
#include <stdio.h>
int main(){
int K;
char C, rez;
scanf("%c %d",&C,&K);
// Validate the user input
int ch;
int rem = K % 26;
if ((rem + C) - 'A' < 26) {
rez = rem + C;
} else {
rez = ((rem + C - 'A') % 26) + 'A';
}
printf("%c\n",rez);
return 0;
}
Note that, I know there is scope of improvement in the implementation. But this is just to give an idea to OP about how it can be done.
Output:
# ./a.out
B 3
E
# ./a.out
X 12345
S
# ./a.out
F 100
B
# ./a.out
T 0
T
I'm trying to re-index my ASCII decimal characters of the alphabet so that they start at 0 with 'A' rather than 65 so I can use a certain formula.
My initial thoughts were to create a string of the alphabet and iterate over it taking away minus 65 at each iteration, I then realised this is only having an effect on the string (which gives a segfault anyway) and does not have any effect on the decimal value of the actual character:
string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
for (int k = 0, length_ = strlen(alphabet); k < length_ ; k ++)
{
alphabet[k] = alphabet[k] - 65;
printf("Alphabet no.%i is equal to %c", k, alphabet[k]);
}
Any ideas?
void printAlpha(int i){
if(i < 26)
printf("%c", 'A' + i);
else if(i < 52)
printf("%c", i - 26 + 'a');
}
I am trying to perform a Caesar cipher from text from user using modulo operation with the ascii characters. But, my code simply prints the entered test. For example, when the text entered is HELLO the program returns "HELLO". The goal is for a key of 13 it should print URYYB. Thank you.
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int key = atoi(argv[1]);
string plaintext = get_string("Enter plaintext: ");
for (int i = 0; i < strlen(plaintext); i++)
{
if (isalpha(plaintext[i]))
{
if (isupper(plaintext[i]))
{
printf("%c", ((plaintext[i] + key) % 26) + 65);
}
else if (islower(plaintext[i]))
{
printf("%c", ((plaintext[i] + key) % 26) + 97);
}
else
{
printf("%c", plaintext[i]);
}
}
}
printf("\n");
Preliminary analysis
Character code of 'H' is 72.
(72 + 13) % 26 + 65 = 85 % 26 + 65 = 7 + 65 ~ 'H'
Let's see if we subtract 65 first:
(72 - 65 + 13) % 26 + 65 = (7 + 13) % 26 + 65 = 20 % 26 + 65 = 20 + 65 = 85 ~ 'U'
Solution
printf("%c", ((plaintext[i] + key - 65) % 26) + 65);
and
printf("%c", ((plaintext[i] + key - 97) % 26) + 97);
respectively.
Proof
If you have a character code, C, where S <= C < S + 26, then the formula you used is:
((C + key) % 26) + S
however, the actual letter is L and we know that
C = S + L,
so the formula is
((S + L + key) % 26) + S
and, since
(A + B) % C = ((A % C) + (B % C)) % C,
replacing A with (S), B with (L + key) and C with 26, we get:
((S % 26) + ((L + key) % 26)) % 26, we see that the result is distorted by (S % 26), which, in the case of 65 is exactly 13. Since a distortion of 13 + the key of 13 you used in the modulo class of 26 will yield the initial letter!
So, the proposed new formula of
((C + key - S) % 26) + S = (((S + L) + key - S) % 26) + S = ((L + key) % 26) + S
is exactly what you need.
You are adding key to the value of each plaintext character, when it is meant to apply to the corresponding letter's index in the alphabet. For example, in case of the 'H' in ASCII, your formula is: (72 + 13) % 26 which gives 7 (which is also the index of H in the alphabet, when starting from zero).
You need to convert the (ASCII) value of the character to its index before applying key, e.g., ((plaintext[i] - 'A' + key) % (1 + 'Z' - 'A')) + 'A'.
The solution for 'H' would then become (72 - 65 + 13) % 26, which gives 20 (the correct answer, 7 + 13, the index of U).
Your cipher function just does nothing if the key is 13:
run a bit amended one and see the result :D
int main()
{
int key = 13;
char plaintext[] = "HELLO";
for (int i = 0; i < strlen(plaintext); i++)
{
if (isalpha(plaintext[i]))
{
if (isupper(plaintext[i]))
{
printf("%d, %d\n", (int)plaintext[i], (int)(((plaintext[i] + key) % 26) + 65));
}
else
{
if (islower(plaintext[i]))
{
//printf("%c", ((plaintext[i] + key) % 26) + 97);
}
else
{
//printf("%c", plaintext[i]);
}
}
}
}
printf("\n");
return 0;
}
I am making a program that decrypts the vigenere cipher. User can only give alphabetical key.
for (int i = 0, counter = strlen(text); i < counter; i++)
{
// prints non-alphabetical characters straight away
if (!isalpha(text[i]))
{
printf("%c", text[i]);
}
else
{
// for index of key
index = meta % strlen(key);
if (islower(text[i]))
{
// separate cases depending upon case of key
if (islower(key[index]))
{
printf("%c", (((text[i] - 97) - (key[index] - 97)) % 26) + 97);
}
else
{
printf("%c", (((text[i] - 97) - (key[index] - 65)) % 26) + 97);
}
}
else
{
if (islower(key[index]))
{
printf("%d", (((text[i] - 65) - (key[index] - 97)) % 26) + 65);
}
else
{
printf("%c", (((text[i] - 65) - (key[index] - 65)) % 26) + 65);
}
}
// incrementing for next key alphabet
meta++;
}
Vigenere:
Input: MyName
key: qwerty
output: CuRrfc
De Vigenere:
Input: CuRrfc
key:qwerty
expected output: MyName
given output: 3_NaSK
How can I fix it?
The problem is the way the modulus operator deals with negative numbers.
For some characters you get negative values and the modulus operation then returns a negative value. You want a value in the range [0, 25].
You can fix it by adding 26 before taking the modulus.
printf("%c", (((text[i] - 97) - (key[index] - 97)) % 26) + 97);
would become
printf("%c", (((text[i] - 97) - (key[index] - 97) + 26) % 26) + 97);
Change all four rows the same way.
This program is supposed to crypt a certain message with the vigenere cypher. The program is supposed to be 'case sensitive' both the message and the keyword. If the program encounters any special characters or numbers, is also supposed to print them untouched.
The last part seems to be working, and the rest, even though the math seems to be right, it doesn't print as it's supposed to. I'm also converting the ASCII values to A-Z/0-26, doing the cypher formula, and them converting them back to ASCII.
// key validation
string kw = argv[1];
int kwl = strlen(kw);
for (int i = 0; i < kwl; i++)
{
if (!isalpha(kw[i]))
{
printf("Usage: ./vigenere keyword\n");
return 1;
}
}
// get message and length
string mssg;
mssg = GetString();
int lngth = strlen(mssg);
// cryptography
int k = 0;
for (int j = 0; j < lngth; j++)
{
if (isalpha(mssg[j]))
{
if (islower(mssg[j]))
{
if (islower(kw[k % kwl]))
printf("%c", (((mssg[j] - 97) + (kw[k % kwl] - 97)) & 26) + 97);
else
printf("%c", (((mssg[j] - 97) + (kw[k % kwl] - 65)) & 26) + 97);
k++;
}
else if (isupper(mssg[j]))
{
if (isupper(kw[k % kwl]))
printf("%c", (((mssg[j] - 65) + (kw[k % kwl] - 65)) & 26) + 65);
else
printf("%c", (((mssg[j] - 65) + (kw[k % kwl] - 97)) & 26) + 65);
k++;
}
}
else
printf("%c", mssg[j]);
}
printf("\n");
return 0;
}
I'm still getting an error somewhere on the math
The error is that you have & 26 instead of % 26.