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;
}