How would I go about circle left shifting every character in a string by the corresponding character in a 'password' string.
char *shift_encrypt(char *plaintext, char *password) {
for (int i = 0; plaintext[i] != '\0'; i++) {
plaintext[i] = (plaintext[i] << password[i]) | (plaintext[i] >> (8 - password[i]));
}
return plaintext;
}
EDIT:
To clarify what I am asking, if I wanted to circle shift for example the character 'A' by the character 'p', I mean something along the lines of:
0100 0001 ('A') << 0x70 ('p')
shown bit-shifted left bit by bit
1. 1000 0010
2. 0000 0101
.
.
.
110. 0101 0000
111. 1010 0000
112. 0100 0001
So basically shifting by 1, 126 times?
To circular shift an 8-bit object with large values like 112 ('p'), mod the shift by 8u. % with a negative char and 8 is not mod so use unsigned math.
Access plaintext[i] as an unsigned char [] to avoid sign extension on right shifts.
Use size_t to index string to handle even very long strings.
Sample fix:
char *shift_encrypt2(char *plaintext, const char *password) {
unsigned char *uplaintext = (unsigned char *) plaintext;
for (size_t i = 0; uplaintext[i]; i++) {
unsigned shift = password[i] % 8u;
uplaintext[i] = (uplaintext[i] << shift) | (uplaintext[i] >> (8u - shift));
}
return plaintext;
}
Note: if the password string is shorter than than plaintext string, we have trouble. A possible fix would re-cycle through the password[].
Advanced: use restrict to allow the compiler to assume plaintext[] and password[] do not overlap and emit potentially faster code.
char *shift_encrypt2(char * restrict plaintext, const char * restrict password) {
Advanced: Code really should access password[] as an unsigned char array too, yet with common and ubiquitous 2's compliment, password[i] % 8u makes no difference.
char *shift_encrypt3(char * restrict plaintext, const char * restrict password) {
if (password[0]) {
unsigned char *uplaintext = (unsigned char *) plaintext;
const unsigned char *upassword = (const unsigned char *) password;
for (size_t i = 0; uplaintext[i]; i++) {
if (*upassword == 0) {
upassword = (const unsigned char *) password;
}
unsigned shift = *upassword++ % 8u;
uplaintext[i] = (uplaintext[i] << shift) | (uplaintext[i] >> (8u - shift));
}
}
return plaintext;
}
Disclaimer: as pointed out in the comments and explained here the C standard does not guarantee that letters are contiguous. However the idea behind this answer still holds.
Characters are defined as linear entries in an ASCII table. This means that each character is represented by a number. Adding 1 to a character brings you to the next one and so on.
You should also be familiar with modular arithmetic. What is "Z"
+1? It goes back to "a".
Putting together these information you can see how the first representable character in a string in an ASCII table is represented by the number 33 decimal and the last one is represented by 126.
You can then make a shift function to shift a letter by n:
shift_letter(L,n)
ret 33 + (((L-33)+n)%(126-33))
The L-33 is done to start from 0.
Then we add n.
We cycle back in case the result is grater than the number of possible letters. %(126-33)
We add offset again
PS:
As I said in the comments, your are shifting in the mathematical sense which not only makes no sense for the operation you want to do, but it also throws an error because shifting by 112 means multiplying by 2^112 which is just a bit too much.
Related
I am trying to convert a string representation of a 32 bit binary number to a string representative of the hex value of that number in a function called hexConversion(). To do this, I am required to use only basic C programming (for loops, basic arrays) and bit shifting/masking. In this assignment, the binary representation used is one that is returned as an array from another function binaryConversion().
I do have an idea of how to convert the 4 bit values into their hex values, but I am confused on how to actually break up the 32 bit value into smaller and more workable 4 bit values.
For example, I might want to change 11111111111111111111111111111111 to 1111 1111 1111 1111 1111 1111 1111 1111 so that I might be able to work with each 1111 separately to convert each to F
"Basic C" but maybe not what you are looking for...
binaryConversion(const char *bits, char *buf, int len) {
snprintf(buf, len, "%lx", strtol(bits, NULL, 2));
}
A more complex solution specifically using bitmasks and shifts may be something like this...
binaryConversion(const char *bits, char *buf, int len) {
const char *xdig = "0123456789ABCDEF";
long val = strtol(bits, NULL, 2);
int i;
for (i = 0; i < 8; ++i) {
int nib = val & 0xf;
if (len > i) buf[i] = xdig[nib];
val = val << 4;
}
}
This is what I've tried, my logic is that my tmp shifting left 31 times will get compared to the user input integer I and a value of 1 or 0 will be inserted to index str[0] -> str[31] and the I null terminate str[32] with the \0.
However, I'm getting a segmentation fault.
P.S. I'm not allowed to change the parameters of this function and my professor set the size of str to be 33 in the main, which, I'm not allow to change either.
void int2bitstr(int I, char *str) {
int tmp = 1 << 31;
do{
*str++ = !!(tmp & I) + '0';
} while(tmp >>= 1);
*str = '\0';
}
Try making tmp an unsigned int. The behaviour of right-shifting a negative (signed) integer is implementation-defined, and in your case is likely shifting in 1s (the original MSB) thus causing the loop to exceed the length of str.
I am new to C and having a hard time understanding why the code below prints out ffffffff when binary 1111111 should equal hex ff.
int i;
char num[8] = "11111111";
unsigned char result = 0;
for ( i = 0; i < 8; ++i )
result |= (num[i] == '1') << (7 - i);
}
printf("%X", bytedata);
You print bytedata which may be uninitialized.
Replace
printf("%X", bytedata);
with
printf("%X", result);
Your code then run's fine. code
Although it is legal in C, for good practice you should make
char num[8] = "11111111";
to
char num[9] = "11111111";
because in C the null character ('\0') always appended to the string literal. And also it would not compile as a C++ file with g++.
EDIT
To answer your question
If I use char the result is FFFFFFFF but if I use unsigned char the result is FF.
Answer:
Case 1:
In C size of char is 1byte(Most implementation). If it is unsigned we can
use 8bit and hold maximum 11111111 in binary and FF in hex(decimal 255). When you print it with printf("%X", result);, this value implicitly converted to unsigned int which becomes FF in hex.
Case 2: But when you use char(signed), then MSB bit use as sign bit, so you can use at most 7 bit for your number whose range -128 to 127 in decimal. When you assign it with FF(255 in decimal) then Integer Overflow occur which leads to Undefined behavior.
I would like to know how the string is represented in integer, so I wrote the following program.
#include <stdio.h>
int main(int argc, char *argv[]){
char name[4] = {"#"};
printf("integer name %d\n", *(int*)name);
return 0;
}
The output is:
integer name 64
This is understandable because # is 64 in integer, i.e., 0x40 in hex.
Now I change the program into:
#include <stdio.h>
int main(int argc, char *argv[]){
char name[4] = {"##"};
printf("integer name %d\n", *(int*)name);
return 0;
}
The output is:
integer name 16448
I dont understand this. Since ## is 0x4040 in hex. So it should be 2^12+2^6 = 4160
If I count the '\0' at the end of the string, then it should be 2^16+2^10 = 66560
Could someone explain where 16448 comes from?
Your math is wrong: 0x4040 == 16448. The two fours are the 6th and 14th bits respectively.
Your code actually invokes undefined behavior because you must not alias a char * with an int *. This is known as the strict aliasing rule. To see just one reason why this should be disallowed, consider what would otherwise have to happen if the code is run on a little and a big endian machine.
If you want to see the hex pattern of the string, you should simply loop over its bytes and print out each byte.
void
print_string(const char * strp)
{
printf("0x");
do
printf("%02X", (unsigned char) *strp);
while (*strp++);
printf("\n");
}
Of course, instead of printing the bytes, you can shift them into an integer (that will very soon overflow) and only finally output that integer. While doing this, you'll be forced to take a stand on “your” endianness.
/* Interpreting as big endian. */
unsigned long
int_string(const char * strp)
{
unsigned long value = 0UL;
do
value = (value << 8) | (unsigned char) *strp;
while (*strp++);
return value;
}
This is how 16448 comes :
0x4040 can be written like this in binary :
4 0 4 0 -> Hex
0100 0000 0100 0000 -> Binary
2^14 2^6 = 16448
Because here 6th and 14th bit are set.
Hope you got it :)
Say I have the following:
int32 a = ...; // value of variable irrelevant; can be negative
unsigned char *buf = malloc(4); /* assuming octet bytes, this is just big
enough to hold an int32 */
Is there an efficient and portable algorithm to write the two's complement big-endian representation of a to the 4-byte buffer buf in a portable way? That is, regardless of how the machine we're running represents integers internally, how can I efficiently write the two's complement representation of a to the buffer?
This is a C question so you can rely on the C standard to determine if your answer meets the portability requirement.
Yes, you can certainly do it portably:
int32_t a = ...;
uint32_t b = a;
unsigned char *buf = malloc(sizeof a);
uint32_t mask = (1U << CHAR_BIT) - 1; // one-byte mask
for (int i = 0; i < sizeof a; i++)
{
int shift = CHAR_BIT * (sizeof a - i - 1); // downshift amount to put next
// byte in low bits
buf[i] = (b >> shift) & mask; // save current byte to buffer
}
At least, I think that's right. I'll make a quick test.
unsigned long tmp = a; // Converts to "twos complement"
unsigned char *buf = malloc(4);
buf[0] = tmp>>24 & 255;
buf[1] = tmp>>16 & 255;
buf[2] = tmp>>8 & 255;
buf[3] = tmp & 255;
You can drop the & 255 parts if you're assuming CHAR_BIT == 8.
If I understand correctly, you want to store 4 bytes of an int32 inside a char buffer, in a specific order(e.g. lower byte first), regardless of how int32 is represented.
Let's first make clear about those assumptions: sizeof(char)=8, two's compliment, and sizeof(int32)=4.
No, there is NO portable way in your code because you are trying to convert it to char instead of unsigned char. Storing a byte in char is implementation defined.
But if you store it in an unsigned char array, there are portable ways. You can right shift the value each time by 8 bit, to form a byte in the resulting array, or with the bitwise and operator &:
// a is unsigned
1st byte = a & 0xFF
2nd byte = a>>8 & 0xFF
3rd byte = a>>16 & 0xFF
4th byte = a>>24 & 0xFF