如何在 C 中表示长位序列?
How to represent long sequence of bits in C?
我正在尝试将一串十六进制转换为一长串位。这是 Cryptopals 挑战中挑战 1 的一部分(将十六进制转换为 base64)。
我的想法是将字符串中的每两个字符转换为其数值的一个字符(同时将第一个字符乘以 16),因为 |hex| = 4, |char|=8.
然后,每次屏蔽前6位,转成base64
问题是在前 6 位之后我需要将所有数组左移 6 次 - 显然 - 我不知道该怎么做。
那么,首先,他们是否有更好的方法将十六进制字符串表示为位序列?
而且 - 我怎样才能将所有数组左移?我在这里看到了处理移动每个元素并复制它们的解决方案 - 这是最简单的方法吗?
这是我到目前为止所做的 - 我添加了一些额外的步骤来澄清:
int main(int argc, char * argv[]) {
int elm = strlen(argv[1]) / 2;
char *hashBits = malloc(sizeof(char) * elm);
char a,b,c;
for (int i = 0; i < elm; ++i) {
a = charToBinary(argv[1][i*2]); // Convert the char to its numeric value
b = charToBinary(argv[1][i*2+1]);
c = transformToChar(a,b); // multiply the first with 16 and adds the second one
hashBits[i] = c;
}
char base64Bits = 63 << 2;
int elm64 = elm * 2 * 4 / 6;
char *hashIn64Base = malloc(sizeof(char) * elm64);
for (int j = 0; j < elm64; ++j) {
hashIn64Base[j] = toBaseSixtyFour((hashBits[0] & base64Bits) >> 2);
hashBits = hashBits << 6; //***This is obviously wrong but - how to do it?***//
}
for (int k = 0; k < elm64; ++k) {
printf("%s", &hashIn64Base[k]);
}
}
如你所知,Base-64编码表示4个字符(每个代表6位)中的3个字节(24位)。
所以你想取这24位:
12345678 12345678 12345678
并将它们变成这四个块:
123456 781234 567812 345678
您可以使用 x & 0xfc
和 x & 0x03
等表达式 "mask off" 某些位。您可以使用 <<
和 >>
左右移动位。您可以使用 |
.
将两个不重叠的位序列放在一起
获得 6 位块后,将它们映射到 Base-64 字母表字符的常用方法是将它们用作数组的索引:
char base64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
您还需要做一些额外的工作来处理输入长度不是 3 字节的精确倍数的情况。
我不想破坏挑战的乐趣,剩下的就交给你了。
您阅读十六进制字符串的方式看起来应该可行。您没有显示 charToBinary
和 transformToChar
,但是根据函数调用旁边的注释,您应该以字符串将代表的字节数组结束,因此该方法(假设它已正确实现) 没问题。
至于创建 base64 字符串,为每个 base64 字符将整个数组移动 6 位是错误的方法。
利用8 * 3 == 6 * 4的优势,一次取3个字节,转换成4个base64字符。您可以通过循环获取当前元素以及接下来的两个元素来进行转换,并在每次迭代中将索引递增 3 来完成此操作。
您需要检查字节数是否是 3 的倍数。如果不是,则最后一次循环迭代将需要处理只有 1 或 2 个字节的情况。
发生这种情况时,任何与任何源字节无关的额外 base64 字符都将设置为 =
,并且字符中任何编码内容的额外位都将用 0 填充。
例如,给定以下两个字节:
00000000 11111111
你把它分成6个位组如下:
000000 001111 111100
请注意,最后一组的末尾有额外的 0。所以你最终会得到 3 个 base64 字符加上一个 =
.
给定一个字节:
11111111
分组为:
111111 110000
所以你将有 2 个 base64 字符加上 2 个 =
.
解码时,末尾有1个=
表示多出2个,有2个=
表示多出1个
我正在尝试将一串十六进制转换为一长串位。这是 Cryptopals 挑战中挑战 1 的一部分(将十六进制转换为 base64)。
我的想法是将字符串中的每两个字符转换为其数值的一个字符(同时将第一个字符乘以 16),因为 |hex| = 4, |char|=8.
然后,每次屏蔽前6位,转成base64
问题是在前 6 位之后我需要将所有数组左移 6 次 - 显然 - 我不知道该怎么做。
那么,首先,他们是否有更好的方法将十六进制字符串表示为位序列?
而且 - 我怎样才能将所有数组左移?我在这里看到了处理移动每个元素并复制它们的解决方案 - 这是最简单的方法吗?
这是我到目前为止所做的 - 我添加了一些额外的步骤来澄清:
int main(int argc, char * argv[]) {
int elm = strlen(argv[1]) / 2;
char *hashBits = malloc(sizeof(char) * elm);
char a,b,c;
for (int i = 0; i < elm; ++i) {
a = charToBinary(argv[1][i*2]); // Convert the char to its numeric value
b = charToBinary(argv[1][i*2+1]);
c = transformToChar(a,b); // multiply the first with 16 and adds the second one
hashBits[i] = c;
}
char base64Bits = 63 << 2;
int elm64 = elm * 2 * 4 / 6;
char *hashIn64Base = malloc(sizeof(char) * elm64);
for (int j = 0; j < elm64; ++j) {
hashIn64Base[j] = toBaseSixtyFour((hashBits[0] & base64Bits) >> 2);
hashBits = hashBits << 6; //***This is obviously wrong but - how to do it?***//
}
for (int k = 0; k < elm64; ++k) {
printf("%s", &hashIn64Base[k]);
}
}
如你所知,Base-64编码表示4个字符(每个代表6位)中的3个字节(24位)。
所以你想取这24位:
12345678 12345678 12345678
并将它们变成这四个块:
123456 781234 567812 345678
您可以使用 x & 0xfc
和 x & 0x03
等表达式 "mask off" 某些位。您可以使用 <<
和 >>
左右移动位。您可以使用 |
.
获得 6 位块后,将它们映射到 Base-64 字母表字符的常用方法是将它们用作数组的索引:
char base64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
您还需要做一些额外的工作来处理输入长度不是 3 字节的精确倍数的情况。
我不想破坏挑战的乐趣,剩下的就交给你了。
您阅读十六进制字符串的方式看起来应该可行。您没有显示 charToBinary
和 transformToChar
,但是根据函数调用旁边的注释,您应该以字符串将代表的字节数组结束,因此该方法(假设它已正确实现) 没问题。
至于创建 base64 字符串,为每个 base64 字符将整个数组移动 6 位是错误的方法。
利用8 * 3 == 6 * 4的优势,一次取3个字节,转换成4个base64字符。您可以通过循环获取当前元素以及接下来的两个元素来进行转换,并在每次迭代中将索引递增 3 来完成此操作。
您需要检查字节数是否是 3 的倍数。如果不是,则最后一次循环迭代将需要处理只有 1 或 2 个字节的情况。
发生这种情况时,任何与任何源字节无关的额外 base64 字符都将设置为 =
,并且字符中任何编码内容的额外位都将用 0 填充。
例如,给定以下两个字节:
00000000 11111111
你把它分成6个位组如下:
000000 001111 111100
请注意,最后一组的末尾有额外的 0。所以你最终会得到 3 个 base64 字符加上一个 =
.
给定一个字节:
11111111
分组为:
111111 110000
所以你将有 2 个 base64 字符加上 2 个 =
.
解码时,末尾有1个=
表示多出2个,有2个=
表示多出1个