crypto: streaming blake2b for validation
exposes the internals of the streaming blake2b checksum and integrates the cryptography code with the standard fake-vtable mechanism for file i/o in Limine, allowing for validation of the checksum without reading the whole file into memory in one shot and caching it until closed.
diff --git a/common/crypt/blake2b.c b/common/crypt/blake2b.c
index b62183f3..40a40ede 100644
--- a/common/crypt/blake2b.c
+++ b/common/crypt/blake2b.c
@@ -5,6 +5,7 @@
#include <stdint.h>
#include <stddef.h>
#include <crypt/blake2b.h>
+#include <fs/file.h>
#include <lib/libc.h>
#define BLAKE2B_BLOCK_BYTES 128
@@ -218,3 +219,25 @@ void blake2b(void *out, const void *in, size_t in_len) {
blake2b_update(&state, in, in_len);
blake2b_final(&state, out);
}
+
+bool blake2b_verify_file(struct file_handle *fd, const uint8_t expected[BLAKE2B_OUT_BYTES]) {
+ uint8_t out_buf[BLAKE2B_OUT_BYTES];
+
+ if (fd->is_memfile) {
+ blake2b(out_buf, fd->fd, fd->size);
+ return memcmp(out_buf, expected, BLAKE2B_OUT_BYTES) == 0;
+ }
+
+ struct blake2b_state state;
+ blake2b_init(&state);
+ char chunk_buf[4096];
+
+ for (uint64_t r = fd->size, off = 0, sz; r > 0; off += sz, r -= sz) {
+ fd->read(fd, chunk_buf, off, sz = r < 4096 ? r : 4096);
+ blake2b_update(&state, chunk_buf, sz);
+ }
+
+ blake2b_final(&state, out_buf);
+
+ return memcmp(out_buf, expected, BLAKE2B_OUT_BYTES) == 0;
+}
diff --git a/common/crypt/blake2b.h b/common/crypt/blake2b.h
index 313a7c63..7967d57f 100644
--- a/common/crypt/blake2b.h
+++ b/common/crypt/blake2b.h
@@ -7,4 +7,7 @@
void blake2b(void *out, const void *in, size_t in_len);
+struct file_handle;
+bool blake2b_verify_file(struct file_handle *fd, const uint8_t expected[BLAKE2B_OUT_BYTES]);
+
#endif
diff --git a/common/lib/uri.c b/common/lib/uri.c
index 7f868791..d04e3917 100644
--- a/common/lib/uri.c
+++ b/common/lib/uri.c
@@ -257,20 +257,13 @@ struct file_handle *uri_open(char *uri) {
}
if (hash != NULL && ret != NULL) {
- uint8_t out_buf[BLAKE2B_OUT_BYTES];
-#if defined (UEFI) && defined (__x86_64__)
- void *file_buf = freadall_mode(ret, MEMMAP_BOOTLOADER_RECLAIMABLE, true);
-#else
- void *file_buf = freadall(ret, MEMMAP_BOOTLOADER_RECLAIMABLE);
-#endif
- blake2b(out_buf, file_buf, ret->size);
uint8_t hash_buf[BLAKE2B_OUT_BYTES];
for (size_t i = 0; i < sizeof(hash_buf); i++) {
hash_buf[i] = digit_to_int(hash[i * 2]) << 4 | digit_to_int(hash[i * 2 + 1]);
}
- if (memcmp(hash_buf, out_buf, sizeof(out_buf)) != 0) {
+ if (!blake2b_verify_file(ret, hash_buf)) {
if (hash_mismatch_panic) {
panic(true, "Blake2b hash for URI `%#` does not match!", uri);
} else {
