C 中的 Xor 加密?
Xor encryption in C?
我尝试学习 C 中的 XOR,我在 github 上找到了 this example。
#include <stdio.h>
#include <string.h>
void encryptDecrypt(char *input, char *output) {
char key[] = {'K', 'C', 'Q'}; //Can be any chars, and any size array
int i;
for(i = 0; i < strlen(input); i++) {
output[i] = input[i] ^ key[i % (sizeof(key)/sizeof(char))];
}
}
int main (int argc, char *argv[]) {
char baseStr[] = "kylewbanks.com";
char encrypted[strlen(baseStr)];
encryptDecrypt(baseStr, encrypted);
printf("Encrypted:%s\n", encrypted);
char decrypted[strlen(baseStr)];
encryptDecrypt(encrypted, decrypted);
printf("Decrypted:%s\n", decrypted);
}
你能解释一下这个说法吗?
output[i] = input[i] ^ key[i % (sizeof(key)/sizeof(char))];
PS:如果我更改char baseStr[]中的语句输出是错误的,为什么?例如,如果 baseStr 的值为 Test,则输出将为:
Encrypted: *?�
Decrypted:Test�&
编辑
如果有人想要这个程序的工作版本,这里是:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void encryptDecrypt(char*, char*, char*);
int main()
{
char message[500];
char key[50];
printf("Enter the message: ");
fgets(message, 500, stdin);
message[strcspn(message, "\n")] = 0;
printf("Enter the key: ");
fgets(key, 50, stdin);
key[strcspn(key, "\n")] = 0;
for(size_t i = 0; i < strlen(key); ++i)
key[i] = toupper (key[i]);
putchar('\n');
char encryptedMessage[strlen(message) + 1];
memset(encryptedMessage, '[=13=]', sizeof(encryptedMessage));
encryptDecrypt(message, encryptedMessage, key);
printf("Encrypted message: %s\n", encryptedMessage);
char decryptedMessage[strlen(message) + 1];
memset(decryptedMessage, '[=13=]', sizeof(decryptedMessage));
encryptDecrypt(encryptedMessage, decryptedMessage, key);
printf("Decrypted message: %s\n", decryptedMessage);
return 0;
}
void encryptDecrypt(char *input, char *output, char *key)
{
for (int i = 0; i < strlen(input); ++i)
output[i] = input [i] ^ key [i % strlen(key)];
}
%s
格式说明符用于 C 风格的字符串。您不能将它用于任意字符数组。如您所见,它无法知道要打印多少个字符。
那个代码很糟糕。它在其输入上调用 strlen
。所以它的输入必须是一个C风格的字符串。但它的输出不是 C 风格的字符串,它只是一个字符数组。缺乏对称性使得代码难以使用和理解。
一块一块地分解:
(sizeof(key)/sizeof(char))
这是key
数组的长度。在你的例子中是 3
。注意,sizeof(char)
是多余的,可以省略。
key[i % 3]
这将 key
的索引绑定到 0
、1
或 2
,因此不会访问 [=13= 之外的内存]数组。
output[i] = input[i] ^ key[i % 3]
;您将 input
中的每个 char
角色与 key
进行异或并将其分配给 output
.
注意,如果你想打印 encrypted
和 decrypted
你应该这样定义它们:
char encrypted[strlen(baseStr) + 1] = {'[=10=]'};
char decrypted[strlen(baseStr) + 1] = {'[=10=]'};
编辑
根据 user3386109,声明 VLA 时不允许提供初始值设定项。因此,您应该执行(例如)以下操作:
memset(encrypted, '[=11=]', sizeof(encrypted));
memset(decrypted, '[=11=]', sizeof(decrypted));
对于:
output[i] = input[i] ^ key[i % (sizeof(key)/sizeof(char))];
sizeof(key)/sizeof(char)
真正得到的是列表中的元素个数:3/1
I % numelemement
得到 I/numelements 的余数 - 所以在这种情况下,当你上升到 I 位置时,将是 0,1,2,0,1,2(在这种情况下)
所以
output_value = input_value 异或密钥[余数]
您不是以空值终止输入字符串,因此 strlen 调用与原始字符串不同。
PS: If I change the statement in char baseStr[] the output is wrong, why? For example if the value of baseStr is Test the output will be:
Encrypted: *?�
Decrypted:Test�&
这是因为 encryptDecrypt
正在使用 strlen
来确定“字符串”的结尾。 strlen
依靠读取空字节来确定字符串的结尾。加密时,您有一个以空字符结尾的字符串。但是加密不会产生以空值结尾的字符串,它会产生一个不以空值结尾的字节流。
我们可以解决这个问题。
void encryptDecrypt(char *input, char *output) {
char key[] = {'K', 'C', 'Q'}; //Can be any chars, and any size array
size_t len = strlen(input);
for(size_t i = 0; i < len; i++) {
printf("%zu\n", i);
output[i] = input[i] ^ key[i % (sizeof(key)/sizeof(char))];
}
output[len] = '[=11=]';
}
我不知道这是否是一个很好的修复。 strlen
可能对解密不安全,因为加密字符串的一个字节可能包含空字节。函数取输入的长度可能更聪明。
void encryptDecrypt(char *input, char *output, size_t *strlen)
// We know baseStr is a string and can use strlen.
char encrypted[strlen(baseStr)];
encryptDecrypt(baseStr, encrypted, strlen(baseStr));
// The encrypted string is the same length as `baseStr`.
char decrypted[strlen(baseStr)];
encryptDecrypt(encrypted, decrypted, strlen(baseStr));
output[i] = input[i] ^ key[i % (sizeof(key)/sizeof(char))];
(sizeof(key)/sizeof(char))
正在获取 key
中的元素数。 sizeof
产生字节数。因此 (sizeof(key)/sizeof(char))
通过将数组的大小除以每个元素的大小来得出元素的数量。
char
总是 1 个字节,我们可以去掉 sizeof(char)
让事情变得更简单。
output[i] = input[i] ^ key[i % sizeof(key)];
这是对 input
的每个字符与 key
的每个字符进行异或运算。因为key
和input
可能是不同的长度,而key
可能更短, it must wrap around and reuse the
keyagain.
%`是取模运算符,所以会除以余数
- 0 % 3 = 0
- 1 % 3 = 1
- 2%3=2
- 3 % 3 = 0
- 4 % 3 = 1
这也称为“时钟数学”。
这样,input
的第一个字符与 key
的第一个字符进行异或运算,第二个字符与第二个字符进行异或运算,第三个字符与第三个字符进行异或运算,但 [=4] 的第四个字符进行异或运算。 =26=] 与 key
.
的第一个字符异或
您可以通过打印 i
和密钥索引来查看实际效果。
for(size_t i = 0; i < len; i++) {
printf("%zu\n", i);
size_t ki = i % sizeof(key);
printf("i = %zu, ki = %zu\n", i, ki);
output[i] = input[i] ^ key[ki];
}
我尝试学习 C 中的 XOR,我在 github 上找到了 this example。
#include <stdio.h>
#include <string.h>
void encryptDecrypt(char *input, char *output) {
char key[] = {'K', 'C', 'Q'}; //Can be any chars, and any size array
int i;
for(i = 0; i < strlen(input); i++) {
output[i] = input[i] ^ key[i % (sizeof(key)/sizeof(char))];
}
}
int main (int argc, char *argv[]) {
char baseStr[] = "kylewbanks.com";
char encrypted[strlen(baseStr)];
encryptDecrypt(baseStr, encrypted);
printf("Encrypted:%s\n", encrypted);
char decrypted[strlen(baseStr)];
encryptDecrypt(encrypted, decrypted);
printf("Decrypted:%s\n", decrypted);
}
你能解释一下这个说法吗?
output[i] = input[i] ^ key[i % (sizeof(key)/sizeof(char))];
PS:如果我更改char baseStr[]中的语句输出是错误的,为什么?例如,如果 baseStr 的值为 Test,则输出将为:
Encrypted: *?�
Decrypted:Test�&
编辑
如果有人想要这个程序的工作版本,这里是:#include <stdio.h>
#include <string.h>
#include <ctype.h>
void encryptDecrypt(char*, char*, char*);
int main()
{
char message[500];
char key[50];
printf("Enter the message: ");
fgets(message, 500, stdin);
message[strcspn(message, "\n")] = 0;
printf("Enter the key: ");
fgets(key, 50, stdin);
key[strcspn(key, "\n")] = 0;
for(size_t i = 0; i < strlen(key); ++i)
key[i] = toupper (key[i]);
putchar('\n');
char encryptedMessage[strlen(message) + 1];
memset(encryptedMessage, '[=13=]', sizeof(encryptedMessage));
encryptDecrypt(message, encryptedMessage, key);
printf("Encrypted message: %s\n", encryptedMessage);
char decryptedMessage[strlen(message) + 1];
memset(decryptedMessage, '[=13=]', sizeof(decryptedMessage));
encryptDecrypt(encryptedMessage, decryptedMessage, key);
printf("Decrypted message: %s\n", decryptedMessage);
return 0;
}
void encryptDecrypt(char *input, char *output, char *key)
{
for (int i = 0; i < strlen(input); ++i)
output[i] = input [i] ^ key [i % strlen(key)];
}
%s
格式说明符用于 C 风格的字符串。您不能将它用于任意字符数组。如您所见,它无法知道要打印多少个字符。
那个代码很糟糕。它在其输入上调用 strlen
。所以它的输入必须是一个C风格的字符串。但它的输出不是 C 风格的字符串,它只是一个字符数组。缺乏对称性使得代码难以使用和理解。
一块一块地分解:
(sizeof(key)/sizeof(char))
这是key
数组的长度。在你的例子中是3
。注意,sizeof(char)
是多余的,可以省略。key[i % 3]
这将key
的索引绑定到0
、1
或2
,因此不会访问 [=13= 之外的内存]数组。output[i] = input[i] ^ key[i % 3]
;您将input
中的每个char
角色与key
进行异或并将其分配给output
.
注意,如果你想打印 encrypted
和 decrypted
你应该这样定义它们:
char encrypted[strlen(baseStr) + 1] = {'[=10=]'};
char decrypted[strlen(baseStr) + 1] = {'[=10=]'};
编辑
根据 user3386109,声明 VLA 时不允许提供初始值设定项。因此,您应该执行(例如)以下操作:
memset(encrypted, '[=11=]', sizeof(encrypted));
memset(decrypted, '[=11=]', sizeof(decrypted));
对于:
output[i] = input[i] ^ key[i % (sizeof(key)/sizeof(char))];
sizeof(key)/sizeof(char)
真正得到的是列表中的元素个数:3/1
I % numelemement
得到 I/numelements 的余数 - 所以在这种情况下,当你上升到 I 位置时,将是 0,1,2,0,1,2(在这种情况下)
所以
output_value = input_value 异或密钥[余数]
您不是以空值终止输入字符串,因此 strlen 调用与原始字符串不同。
PS: If I change the statement in char baseStr[] the output is wrong, why? For example if the value of baseStr is Test the output will be:
Encrypted: *?� Decrypted:Test�&
这是因为 encryptDecrypt
正在使用 strlen
来确定“字符串”的结尾。 strlen
依靠读取空字节来确定字符串的结尾。加密时,您有一个以空字符结尾的字符串。但是加密不会产生以空值结尾的字符串,它会产生一个不以空值结尾的字节流。
我们可以解决这个问题。
void encryptDecrypt(char *input, char *output) {
char key[] = {'K', 'C', 'Q'}; //Can be any chars, and any size array
size_t len = strlen(input);
for(size_t i = 0; i < len; i++) {
printf("%zu\n", i);
output[i] = input[i] ^ key[i % (sizeof(key)/sizeof(char))];
}
output[len] = '[=11=]';
}
我不知道这是否是一个很好的修复。 strlen
可能对解密不安全,因为加密字符串的一个字节可能包含空字节。函数取输入的长度可能更聪明。
void encryptDecrypt(char *input, char *output, size_t *strlen)
// We know baseStr is a string and can use strlen.
char encrypted[strlen(baseStr)];
encryptDecrypt(baseStr, encrypted, strlen(baseStr));
// The encrypted string is the same length as `baseStr`.
char decrypted[strlen(baseStr)];
encryptDecrypt(encrypted, decrypted, strlen(baseStr));
output[i] = input[i] ^ key[i % (sizeof(key)/sizeof(char))];
(sizeof(key)/sizeof(char))
正在获取 key
中的元素数。 sizeof
产生字节数。因此 (sizeof(key)/sizeof(char))
通过将数组的大小除以每个元素的大小来得出元素的数量。
char
总是 1 个字节,我们可以去掉 sizeof(char)
让事情变得更简单。
output[i] = input[i] ^ key[i % sizeof(key)];
这是对 input
的每个字符与 key
的每个字符进行异或运算。因为key
和input
可能是不同的长度,而key
可能更短, it must wrap around and reuse the
keyagain.
%`是取模运算符,所以会除以余数
- 0 % 3 = 0
- 1 % 3 = 1
- 2%3=2
- 3 % 3 = 0
- 4 % 3 = 1
这也称为“时钟数学”。
这样,input
的第一个字符与 key
的第一个字符进行异或运算,第二个字符与第二个字符进行异或运算,第三个字符与第三个字符进行异或运算,但 [=4] 的第四个字符进行异或运算。 =26=] 与 key
.
您可以通过打印 i
和密钥索引来查看实际效果。
for(size_t i = 0; i < len; i++) {
printf("%zu\n", i);
size_t ki = i % sizeof(key);
printf("i = %zu, ki = %zu\n", i, ki);
output[i] = input[i] ^ key[ki];
}