C 解析LUKS标头以正确读取整数值字段

C 解析LUKS标头以正确读取整数值字段,c,linux,binary,luks,C,Linux,Binary,Luks,我试图通过读取安装了luks卷的设备上的原始数据来解析luks头,遵循这里给出的规范:,特别是第6页,其中的表格显示了驻留在每个位置的数据、它是什么类型的数据以及单个值的这些数据类型的数量 例如,哈希规范字符串位于位置72,包含32个类型字符字节。将其收集到一个数组中并打印结果很简单,但是正如表中有关版本或密钥字节(假定为密钥长度)等数值的详细信息所示,这些值跨越多个整数。该版本有两个无符号短字符,键字节有四个无符号整数表示其值 我对此有些困惑,以及我应该如何解释它以检索正确的值。我编写了一个凌

我试图通过读取安装了luks卷的设备上的原始数据来解析luks头,遵循这里给出的规范:,特别是第6页,其中的表格显示了驻留在每个位置的数据、它是什么类型的数据以及单个值的这些数据类型的数量

例如,哈希规范字符串位于位置72,包含32个类型字符字节。将其收集到一个数组中并打印结果很简单,但是正如表中有关版本或密钥字节(假定为密钥长度)等数值的详细信息所示,这些值跨越多个整数。该版本有两个无符号短字符,键字节有四个无符号整数表示其值

我对此有些困惑,以及我应该如何解释它以检索正确的值。我编写了一个凌乱的测试脚本来扫描一个用luks加密的U盘,并显示从读取这些字段中检索到的内容

256
25953
hash spec:
sha256
key bytes (length):
1073741824
3303950314
1405855026
1284286704
这是非常令人困惑的,因为hash spec字段同样持有一个期望值,只是字符串本身,但是我应该如何解释version或key byte字段呢?这两个看起来都是完全随机的数字,从我可以看出,规范中没有任何东西可以解释这一点。我想这可能是我如何实际编写代码的问题,下面是用于显示这些值的脚本:

#include <stdio.h>

int main()  {

    unsigned short data[100];
    unsigned char data2[100];
    unsigned int data3[100];
    int i;

    FILE *fp;

    fp = fopen("/dev/sdd1", "rb");

    fseek(fp, 6, SEEK_SET);

    if (fp) {
        for (i=0; i < 2; i++)   {
            fread(&data[i], sizeof(short), 1, fp);
        }

        fseek(fp, 72, SEEK_SET);

        for (i=0; i < 32; i++)  {
            fread(&data2[i], sizeof(char), 1, fp);
        }

        fseek(fp, 108, SEEK_SET);

        for (i=0; i < 4; i++)   {
            fread(&data3[i], sizeof(int), 1, fp);
        }

        printf("version:\n");
        for (i=0; i < 2; i++)   {
            printf("%u\n", data[i]);
        }
        printf("hash spec:\n");
        for (i=0; i < 32; i++)  {
            printf("%c", data2[i]);
        }
        printf("\n");
        printf("key bytes (length):\n");
        for(i=0; i < 4; i++)    {
            printf("%u\n", data3[i]);
        }

        fclose(fp);
    }
    else {
        printf("error\n");
    }

    return 0;
}
#包括
int main(){
无符号短数据[100];
无符号字符数据2[100];
无符号整数数据3[100];
int i;
文件*fp;
fp=fopen(“/dev/sdd1”,“rb”);
fseek(fp,6,SEEK_SET);
if(fp){
对于(i=0;i<2;i++){
fread(和数据[i],sizeof(短),1,fp);
}
fseek(fp,72,SEEK_SET);
对于(i=0;i<32;i++){
fread(&data2[i],sizeof(char),1,fp);
}
fseek(fp,108,SEEK_SET);
对于(i=0;i<4;i++){
fread(&data3[i],sizeof(int),1,fp);
}
printf(“版本:\n”);
对于(i=0;i<2;i++){
printf(“%u\n”,数据[i]);
}
printf(“哈希规范:\n”);
对于(i=0;i<32;i++){
printf(“%c”,数据2[i]);
}
printf(“\n”);
printf(“密钥字节(长度):\n”);
对于(i=0;i<4;i++){
printf(“%u\n”,data3[i]);
}
fclose(fp);
}
否则{
printf(“错误\n”);
}
返回0;
}

任何帮助都将不胜感激,谢谢

问题是,您读取的数据是大端,但您运行的计算机是小端。例如,打印为1073741824的字节按顺序为0x00、0x00、0x00和0x40。作为一个大端数字,它是0x00000040,或64。作为一个小的endian数,通常在x86系统上使用,它是0x40000000,一个长得离谱的长度

幸运的是,有些函数可以为您转换这些值。要将32位big-endian(n网络字节顺序)转换为系统的(host字节顺序)格式,请使用
ntohl
,对于16位整数,请使用
ntohs

因此,当您读取16位整数的数据时,它将如下所示:

for (i=0; i < 2; i++)   {
    fread(&data[i], sizeof(short), 1, fp);
    data[i] = ntohs(data[i]);
}
(i=0;i<2;i++)的
{
fread(和数据[i],sizeof(短),1,fp);
数据[i]=NTOH(数据[i]);
}
作为旁注,如果您要使用固定大小的值,那么如果您使用
#包含
,然后使用类型
uint8\u t
uint16\u t
uint32\u t
,则更便于携带和理解。由于内置类型在不同平台之间可能有所不同,因此它们的大小总是合适的


如果您有兴趣阅读更多有关endianness的内容,.

啊,这很有效,谢谢。版本变为1,后跟24933,键字节变为256、25953、0、0。大概只有这些值中的第一个才是相关的-如果第一个值似乎很重要,你知道为什么仍然会有多个整数分配给这些值吗?如果第一个值工作正常,你应该得到1作为第一个值。但问题是我认为你没有正确阅读规范;当它说版本的长度是2时,这意味着2个字节(1
uint16\u t
),而不是2
uint16\u t
s。您正在读取密码名称作为下一个整数。