Alpine APK 包存储库,校验和是如何计算的?

Alpine APK Package Repositories, how are the checksums calculated?

我正在尝试了解如何在 Alpine APK 包存储库中计算包的拉取校验和。关于格式的 documentation 缺少任何细节。

当我 运行 apk index -o APKINDEX.unsigned.tar.gz *.apk 生成存储库时。当您从 gz 中提取 txt 文件时,它包含以下内容...

C:Q17KXT6xFVWz4EZDIbkcvXQ/uz9ys=
P:redis-server
V:3.2.3-0
A:noarch
S:2784844
I:102400
T:An advanced key-value store
U:http://redis.io/
L:
D:linux-headers

我对第一行的生成方式很感兴趣。我已经尝试阅读用于生成它的实际源代码,但我不是 C 程序员,所以我很难理解,因为它到处跳转。

文档中提到的两个文件是database.c and package.c.

如果这有点帮助,原始 APK 文件具有这些不同的哈希值...

CRC32 = ac17ea88
MD5 = a035ecf940a67a6572ff40afad4f396a
SHA1 = eca5d3eb11555b3e0464321b91cbd743fbb3f72b
SHA256 = 24bc1f03409b0856d84758d6d44b2f04737bbc260815c525581258a5b4bf6df4

所以...

/* Internal cointainer for MD5 or SHA1 */
struct apk_checksum {
    unsigned char data[20];
    unsigned char type;
};

基本上取C:值然后从前面砍掉Q然后base 64解码。砍掉最后一个值(默认为 SHA1 的类型),然后你就有了 sha1。这似乎是由包裹的内容组成的,但这需要进一步调查。

你需要看这里:https://git.alpinelinux.org/cgit/apk-tools/tree/src/blob.c#n492

是apk_blob_pull_csum

第一个'Q'代表编码 下一个 '1' 代表 SHA1

看起来这个校验和是 database.c 在 apk_db_unpack_pkg 中生成的:

    apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY_IDENTITY, &pkg->csum, db->keys_fd);
tar = apk_bstream_gunzip_mpart(bs, apk_sign_ctx_mpart_cb, &ctx.sctx);
r = apk_tar_parse(tar, apk_db_install_archive_entry, &ctx, TRUE, &db->id_cache);

但我不确定,因为我未能追踪到这段代码。

他们在做什么,真的不容易理解

pull checksum 是 apk 文件中第二个 tar.gz 文件的 sha1sum,包含 .PKGINFO 文件。

Alpine APK 包实际上是伪装的 3 个 tar.gz 文件的串联。

我们可以使用gunzip-split将下面的包拆分成3个.gz文件,然后重命名为.tar.gz

./gunzip-split -s -o ./out/ strace-5.14-r0.apk
mv ./out/file_1.gz ./out/file_1.tar.gz
mv ./out/file_2.gz ./out/file_2.tar.gz
mv ./out/file_3.gz ./out/file_3.tar.gz

sha1sum ./out/file_2.tar.gz
7a266425df7bfd7ce9a42c71a015ea2ae5715838  out/file_2.tar.gz

tar tvf out/file_2.tar.gz 
-rw-r--r-- root/root       702 2021-09-03 01:34 .PKGINFO

在 strace 包的情况下,校验和值可以按上述方式导出:

apk index strace-5.14-r0.apk -o APKINDEX.tar.gz
tar xvf APKINDEX.tar.gz
cat APKINDEX

echo eiZkJd97/XzppCxxoBXqKuVxWDg=|base64 -d|xxd
00000000: 7a26 6425 df7b fd7c e9a4 2c71 a015 ea2a  z&d%.{.|..,q...*
00000010: e571 5838                                .qX8

比较它们时,我们发现它们匹配。

参考资料

https://github.com/martencassel/apk-tools/blob/master/README.md

https://gitlab.com/cg909/gunzip-split/-/releases

https://lists.alpinelinux.org/~alpine/devel/%3C257B6969-21FD-4D51-A8EC-95CB95CEF365%40ferrisellis.com%3E#%3C20180309152107.472e4144@vostro.util.wtbts.net%3E