pq_crypto-seal 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +66 -0
  3. data/CHANGELOG.md +44 -0
  4. data/FORMAT.md +139 -0
  5. data/GET_STARTED.md +30 -0
  6. data/Gemfile +7 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +215 -0
  9. data/RELEASING.md +34 -0
  10. data/Rakefile +19 -0
  11. data/SECURITY.md +85 -0
  12. data/VENDORING.md +14 -0
  13. data/ext/pq_crypto_seal/aegis_unused_stubs.c +20 -0
  14. data/ext/pq_crypto_seal/extconf.rb +296 -0
  15. data/ext/pq_crypto_seal/pq_crypto_seal.c +390 -0
  16. data/ext/pq_crypto_seal/vendor/libaegis/LICENSE +21 -0
  17. data/ext/pq_crypto_seal/vendor/libaegis/TREE_SHA256 +1 -0
  18. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l.c +246 -0
  19. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_aesni.c +73 -0
  20. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_aesni.h +9 -0
  21. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_altivec.c +70 -0
  22. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_altivec.h +9 -0
  23. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_common.h +691 -0
  24. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_neon_aes.c +77 -0
  25. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_neon_aes.h +9 -0
  26. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_neon_sha3.c +86 -0
  27. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_neon_sha3.h +9 -0
  28. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_soft.c +63 -0
  29. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_soft.h +9 -0
  30. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/implementations.h +40 -0
  31. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2.c +247 -0
  32. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_aesni.c +108 -0
  33. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_aesni.h +9 -0
  34. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_altivec.c +103 -0
  35. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_altivec.h +9 -0
  36. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_avx2.c +79 -0
  37. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_avx2.h +11 -0
  38. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_common.h +795 -0
  39. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_neon_aes.c +111 -0
  40. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_neon_aes.h +9 -0
  41. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_soft.c +96 -0
  42. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_soft.h +9 -0
  43. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/implementations.h +40 -0
  44. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4.c +252 -0
  45. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_aesni.c +117 -0
  46. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_aesni.h +9 -0
  47. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_altivec.c +111 -0
  48. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_altivec.h +9 -0
  49. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_avx2.c +112 -0
  50. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_avx2.h +11 -0
  51. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_avx512.c +85 -0
  52. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_avx512.h +11 -0
  53. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_common.h +808 -0
  54. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_neon_aes.c +119 -0
  55. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_neon_aes.h +9 -0
  56. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_soft.c +104 -0
  57. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_soft.h +9 -0
  58. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/implementations.h +41 -0
  59. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256.c +240 -0
  60. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256_aesni.c +68 -0
  61. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256_aesni.h +9 -0
  62. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256_altivec.c +68 -0
  63. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256_altivec.h +9 -0
  64. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256_common.h +673 -0
  65. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256_neon_aes.c +75 -0
  66. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256_neon_aes.h +9 -0
  67. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256_soft.c +58 -0
  68. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256_soft.h +9 -0
  69. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/implementations.h +39 -0
  70. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2.c +247 -0
  71. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_aesni.c +103 -0
  72. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_aesni.h +9 -0
  73. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_altivec.c +101 -0
  74. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_altivec.h +9 -0
  75. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_avx2.c +74 -0
  76. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_avx2.h +11 -0
  77. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_common.h +790 -0
  78. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_neon_aes.c +109 -0
  79. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_neon_aes.h +9 -0
  80. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_soft.c +91 -0
  81. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_soft.h +9 -0
  82. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/implementations.h +41 -0
  83. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4.c +252 -0
  84. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_aesni.c +112 -0
  85. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_aesni.h +9 -0
  86. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_altivec.c +109 -0
  87. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_altivec.h +9 -0
  88. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_avx2.c +107 -0
  89. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_avx2.h +11 -0
  90. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_avx512.c +79 -0
  91. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_avx512.h +11 -0
  92. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_common.h +805 -0
  93. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_neon_aes.c +117 -0
  94. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_neon_aes.h +9 -0
  95. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_soft.c +99 -0
  96. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_soft.h +9 -0
  97. data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/implementations.h +42 -0
  98. data/ext/pq_crypto_seal/vendor/libaegis/src/common/common.c +81 -0
  99. data/ext/pq_crypto_seal/vendor/libaegis/src/common/common.h +144 -0
  100. data/ext/pq_crypto_seal/vendor/libaegis/src/common/cpu.c +378 -0
  101. data/ext/pq_crypto_seal/vendor/libaegis/src/common/cpu.h +34 -0
  102. data/ext/pq_crypto_seal/vendor/libaegis/src/common/keccak.c +187 -0
  103. data/ext/pq_crypto_seal/vendor/libaegis/src/common/keccak.h +13 -0
  104. data/ext/pq_crypto_seal/vendor/libaegis/src/common/softaes.c +338 -0
  105. data/ext/pq_crypto_seal/vendor/libaegis/src/common/softaes.h +69 -0
  106. data/ext/pq_crypto_seal/vendor/libaegis/src/include/aegis.h +77 -0
  107. data/ext/pq_crypto_seal/vendor/libaegis/src/include/aegis128l.h +311 -0
  108. data/ext/pq_crypto_seal/vendor/libaegis/src/include/aegis128x2.h +313 -0
  109. data/ext/pq_crypto_seal/vendor/libaegis/src/include/aegis128x4.h +313 -0
  110. data/ext/pq_crypto_seal/vendor/libaegis/src/include/aegis256.h +311 -0
  111. data/ext/pq_crypto_seal/vendor/libaegis/src/include/aegis256x2.h +313 -0
  112. data/ext/pq_crypto_seal/vendor/libaegis/src/include/aegis256x4.h +313 -0
  113. data/ext/pq_crypto_seal/vendor/libaegis/src/include/aegis_raf.h +580 -0
  114. data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf.c +87 -0
  115. data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_aegis128l.c +20 -0
  116. data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_aegis128x2.c +20 -0
  117. data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_aegis128x4.c +20 -0
  118. data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_aegis256.c +20 -0
  119. data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_aegis256x2.c +20 -0
  120. data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_aegis256x4.c +20 -0
  121. data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_internal.h +152 -0
  122. data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_merkle.c +268 -0
  123. data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_merkle.h +165 -0
  124. data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_variant.h +1119 -0
  125. data/fuzz/decrypt_fuzz.rb +119 -0
  126. data/lib/pq_crypto/seal/binary.rb +62 -0
  127. data/lib/pq_crypto/seal/core.rb +398 -0
  128. data/lib/pq_crypto/seal/errors.rb +15 -0
  129. data/lib/pq_crypto/seal/format.rb +275 -0
  130. data/lib/pq_crypto/seal/io.rb +336 -0
  131. data/lib/pq_crypto/seal/native.rb +13 -0
  132. data/lib/pq_crypto/seal/padding.rb +47 -0
  133. data/lib/pq_crypto/seal/version.rb +6 -0
  134. data/lib/pq_crypto/seal.rb +32 -0
  135. data/pq_crypto-seal.gemspec +37 -0
  136. data/script/vendor_libs.rb +79 -0
  137. data/test/aegis_vectors_test.rb +54 -0
  138. data/test/golden_vectors_test.rb +183 -0
  139. data/test/io_test.rb +125 -0
  140. data/test/native_test.rb +36 -0
  141. data/test/seal_test.rb +238 -0
  142. data/test/test_helper.rb +6 -0
  143. metadata +244 -0
@@ -0,0 +1,1119 @@
1
+ #include "../common/keccak.h"
2
+
3
+ #define CONCAT_(a, b) a##b
4
+ #define CONCAT(a, b) CONCAT_(a, b)
5
+ #define CONCAT3_(a, b, c) a##b##c
6
+ #define CONCAT3(a, b, c) CONCAT3_(a, b, c)
7
+
8
+ #define FN(name) CONCAT3(VARIANT, _raf_, name)
9
+ #define CTX_TYPE CONCAT3(VARIANT, _raf_, ctx)
10
+ #define MAC_STATE_TYPE CONCAT3(VARIANT, _mac_, state)
11
+
12
+ #define KDF_CONST "aegis-raf-kdf-v1"
13
+ #define KDF_CONST_LEN 16
14
+
15
+ static void
16
+ derive_keys(uint8_t *enc_key, uint8_t *hdr_key, const uint8_t *master_key,
17
+ const uint8_t file_id[AEGIS_RAF_FILE_ID_BYTES])
18
+ {
19
+ uint8_t key_material[KEYBYTES * 2];
20
+
21
+ #if KEYBYTES == 16
22
+ aegis_kdf_128(key_material, sizeof key_material, (const uint8_t *) KDF_CONST, KDF_CONST_LEN,
23
+ master_key, KEYBYTES, file_id, AEGIS_RAF_FILE_ID_BYTES);
24
+ #else
25
+ aegis_kdf_256(key_material, sizeof key_material, (const uint8_t *) KDF_CONST, KDF_CONST_LEN,
26
+ master_key, KEYBYTES, file_id, AEGIS_RAF_FILE_ID_BYTES);
27
+ #endif
28
+
29
+ memcpy(enc_key, key_material, KEYBYTES);
30
+ memcpy(hdr_key, key_material + KEYBYTES, KEYBYTES);
31
+ }
32
+
33
+ static int
34
+ compute_header_mac(uint8_t mac[AEGIS_RAF_TAG_BYTES], const uint8_t hdr[AEGIS_RAF_HEADER_SIZE],
35
+ const uint8_t *hdr_key)
36
+ {
37
+ MAC_STATE_TYPE st;
38
+ VARIANT_mac_init(&st, hdr_key, NULL);
39
+ if (VARIANT_mac_update(&st, hdr, AEGIS_RAF_HEADER_SIZE - AEGIS_RAF_TAG_BYTES) != 0) {
40
+ return -1;
41
+ }
42
+ if (VARIANT_mac_final(&st, mac, AEGIS_RAF_TAG_BYTES) != 0) {
43
+ return -1;
44
+ }
45
+ return 0;
46
+ }
47
+
48
+ static int
49
+ verify_header_mac(const uint8_t hdr[AEGIS_RAF_HEADER_SIZE], const uint8_t *hdr_key)
50
+ {
51
+ MAC_STATE_TYPE st;
52
+ int ret;
53
+
54
+ VARIANT_mac_init(&st, hdr_key, NULL);
55
+ if (VARIANT_mac_update(&st, hdr, AEGIS_RAF_HEADER_SIZE - AEGIS_RAF_TAG_BYTES) != 0) {
56
+ return -1;
57
+ }
58
+ ret = VARIANT_mac_verify(&st, hdr + AEGIS_RAF_HEADER_SIZE - AEGIS_RAF_TAG_BYTES,
59
+ AEGIS_RAF_TAG_BYTES);
60
+ if (ret != 0) {
61
+ errno = EBADMSG;
62
+ }
63
+ return ret;
64
+ }
65
+
66
+ static inline uint64_t
67
+ record_size(uint32_t chunk_size)
68
+ {
69
+ return (uint64_t) NPUBBYTES + chunk_size + AEGIS_RAF_TAG_BYTES;
70
+ }
71
+
72
+ static inline uint64_t
73
+ get_chunk_offset(uint32_t chunk_size, uint64_t chunk_idx)
74
+ {
75
+ return AEGIS_RAF_HEADER_SIZE + chunk_idx * record_size(chunk_size);
76
+ }
77
+
78
+ static inline uint64_t
79
+ get_chunk_count(uint32_t chunk_size, uint64_t file_size)
80
+ {
81
+ if (file_size == 0) {
82
+ return 0;
83
+ }
84
+ return (file_size - 1) / chunk_size + 1;
85
+ }
86
+
87
+ static int
88
+ write_header(aegis_raf_ctx_internal *ctx)
89
+ {
90
+ uint8_t hdr[AEGIS_RAF_HEADER_SIZE];
91
+
92
+ memcpy(hdr, AEGIS_RAF_MAGIC, 8);
93
+ STORE16_LE(hdr + 8, AEGIS_RAF_HEADER_SIZE);
94
+ hdr[10] = AEGIS_RAF_VERSION;
95
+ hdr[11] = (uint8_t) ctx->alg_id;
96
+ STORE32_LE(hdr + 12, ctx->chunk_size);
97
+ STORE64_LE(hdr + 16, ctx->file_size);
98
+ memcpy(hdr + 24, ctx->file_id, AEGIS_RAF_FILE_ID_BYTES);
99
+
100
+ if (compute_header_mac(hdr + AEGIS_RAF_HEADER_SIZE - AEGIS_RAF_TAG_BYTES, hdr, ctx->hdr_key) !=
101
+ 0) {
102
+ return -1;
103
+ }
104
+
105
+ return ctx->io.write_at(ctx->io.user, hdr, AEGIS_RAF_HEADER_SIZE, 0);
106
+ }
107
+
108
+ static int
109
+ verify_header(aegis_raf_ctx_internal *ctx, const uint8_t hdr[AEGIS_RAF_HEADER_SIZE])
110
+ {
111
+ uint16_t header_size;
112
+ uint8_t version;
113
+ uint8_t alg_id;
114
+
115
+ if (memcmp(hdr, AEGIS_RAF_MAGIC, 8) != 0) {
116
+ errno = EINVAL;
117
+ return -1;
118
+ }
119
+
120
+ header_size = LOAD16_LE(hdr + 8);
121
+ if (header_size != AEGIS_RAF_HEADER_SIZE) {
122
+ errno = EINVAL;
123
+ return -1;
124
+ }
125
+
126
+ version = hdr[10];
127
+ if (version != AEGIS_RAF_VERSION) {
128
+ errno = EINVAL;
129
+ return -1;
130
+ }
131
+
132
+ ctx->chunk_size = LOAD32_LE(hdr + 12);
133
+ if (ctx->chunk_size < AEGIS_RAF_CHUNK_MIN || ctx->chunk_size > AEGIS_RAF_CHUNK_MAX ||
134
+ (ctx->chunk_size % 16) != 0) {
135
+ errno = EINVAL;
136
+ return -1;
137
+ }
138
+
139
+ alg_id = hdr[11];
140
+ if (alg_id != ALG_ID) {
141
+ errno = EINVAL;
142
+ return -1;
143
+ }
144
+
145
+ ctx->file_size = LOAD64_LE(hdr + 16);
146
+ memcpy(ctx->file_id, hdr + 24, AEGIS_RAF_FILE_ID_BYTES);
147
+
148
+ if (verify_header_mac(hdr, ctx->hdr_key) != 0) {
149
+ return -1;
150
+ }
151
+
152
+ ctx->alg_id = alg_id;
153
+ ctx->version = version;
154
+ return 0;
155
+ }
156
+
157
+ size_t
158
+ FN(scratch_size)(uint32_t chunk_size)
159
+ {
160
+ size_t rec_size = (size_t) NPUBBYTES + chunk_size + AEGIS_RAF_TAG_BYTES;
161
+ size_t aligned_rec = AEGIS_RAF_ALIGN_UP(rec_size, AEGIS_RAF_SCRATCH_ALIGN);
162
+ size_t aligned_chk = AEGIS_RAF_ALIGN_UP((size_t) chunk_size, AEGIS_RAF_SCRATCH_ALIGN);
163
+ return aligned_rec + aligned_chk;
164
+ }
165
+
166
+ int
167
+ FN(scratch_validate)(const aegis_raf_scratch *scratch, uint32_t chunk_size)
168
+ {
169
+ size_t required;
170
+
171
+ if (chunk_size < AEGIS_RAF_CHUNK_MIN || chunk_size > AEGIS_RAF_CHUNK_MAX ||
172
+ (chunk_size % 16) != 0) {
173
+ errno = EINVAL;
174
+ return -1;
175
+ }
176
+ if (scratch == NULL || scratch->buf == NULL) {
177
+ errno = EINVAL;
178
+ return -1;
179
+ }
180
+ if (((uintptr_t) scratch->buf % AEGIS_RAF_SCRATCH_ALIGN) != 0) {
181
+ errno = EINVAL;
182
+ return -1;
183
+ }
184
+ required = FN(scratch_size)(chunk_size);
185
+ if (scratch->len < required) {
186
+ errno = EINVAL;
187
+ return -1;
188
+ }
189
+ return 0;
190
+ }
191
+
192
+ static int
193
+ setup_scratch_buffers(aegis_raf_ctx_internal *ctx, const aegis_raf_scratch *scratch)
194
+ {
195
+ size_t rec_size = (size_t) record_size(ctx->chunk_size);
196
+ size_t aligned_rec = AEGIS_RAF_ALIGN_UP(rec_size, AEGIS_RAF_SCRATCH_ALIGN);
197
+
198
+ if (FN(scratch_validate)(scratch, ctx->chunk_size) != 0) {
199
+ return -1;
200
+ }
201
+
202
+ ctx->scratch_buf = scratch->buf;
203
+ ctx->scratch_len = scratch->len;
204
+ ctx->record_buf = scratch->buf;
205
+ ctx->record_buf_size = rec_size;
206
+ ctx->chunk_buf = scratch->buf + aligned_rec;
207
+ ctx->chunk_buf_size = ctx->chunk_size;
208
+
209
+ return 0;
210
+ }
211
+
212
+ static void
213
+ zeroize_scratch_buffers(aegis_raf_ctx_internal *ctx)
214
+ {
215
+ if (ctx->scratch_buf != NULL && ctx->scratch_len > 0) {
216
+ memset(ctx->scratch_buf, 0, ctx->scratch_len);
217
+ }
218
+ ctx->scratch_buf = NULL;
219
+ ctx->scratch_len = 0;
220
+ ctx->record_buf = NULL;
221
+ ctx->record_buf_size = 0;
222
+ ctx->chunk_buf = NULL;
223
+ ctx->chunk_buf_size = 0;
224
+ }
225
+
226
+ static int
227
+ setup_merkle_config(aegis_raf_ctx_internal *ctx, const aegis_raf_merkle_config *merkle,
228
+ uint64_t current_file_size, uint32_t chunk_size)
229
+ {
230
+ uint64_t current_chunks;
231
+ uint64_t i;
232
+ int ret;
233
+
234
+ if (merkle == NULL) {
235
+ ctx->merkle_enabled = 0;
236
+ memset(&ctx->merkle_cfg, 0, sizeof(ctx->merkle_cfg));
237
+ return 0;
238
+ }
239
+
240
+ if (aegis_raf_merkle_config_validate(merkle) != 0) {
241
+ return -1;
242
+ }
243
+
244
+ current_chunks = get_chunk_count(chunk_size, current_file_size);
245
+ if (current_chunks > merkle->max_chunks) {
246
+ errno = EOVERFLOW;
247
+ return -1;
248
+ }
249
+
250
+ ctx->merkle_cfg = *merkle;
251
+ ctx->merkle_enabled = 1;
252
+
253
+ for (i = 0; i < merkle->max_chunks; i++) {
254
+ ret = raf_merkle_clear_leaf(&ctx->merkle_cfg, i);
255
+ if (ret != 0) {
256
+ return ret;
257
+ }
258
+ }
259
+ if (merkle->max_chunks > 0) {
260
+ ret = raf_merkle_update_parents(&ctx->merkle_cfg, 0, merkle->max_chunks - 1);
261
+ if (ret != 0) {
262
+ return ret;
263
+ }
264
+ }
265
+
266
+ return 0;
267
+ }
268
+
269
+ static int
270
+ read_chunk(aegis_raf_ctx_internal *ctx, uint64_t chunk_idx)
271
+ {
272
+ uint64_t off = get_chunk_offset(ctx->chunk_size, chunk_idx);
273
+ uint64_t rec_size = record_size(ctx->chunk_size);
274
+ uint8_t *record = ctx->record_buf;
275
+ uint8_t *nonce;
276
+ uint8_t *ciphertext;
277
+ uint8_t *tag;
278
+ uint8_t aad[AAD_BYTES];
279
+ int ret;
280
+
281
+ if (ctx->io.read_at(ctx->io.user, record, rec_size, off) != 0) {
282
+ return -1;
283
+ }
284
+
285
+ nonce = record;
286
+ ciphertext = record + NPUBBYTES;
287
+ tag = record + NPUBBYTES + ctx->chunk_size;
288
+
289
+ build_aad(aad, ctx->file_id, chunk_idx, ctx->chunk_size);
290
+
291
+ ret = VARIANT_decrypt_detached(ctx->chunk_buf, ciphertext, ctx->chunk_size, tag,
292
+ AEGIS_RAF_TAG_BYTES, aad, AAD_BYTES, nonce, ctx->enc_key);
293
+
294
+ memset(record, 0, rec_size);
295
+
296
+ if (ret != 0) {
297
+ errno = EBADMSG;
298
+ }
299
+ return ret;
300
+ }
301
+
302
+ static int
303
+ write_chunk(aegis_raf_ctx_internal *ctx, size_t plaintext_len, uint64_t chunk_idx)
304
+ {
305
+ uint64_t off = get_chunk_offset(ctx->chunk_size, chunk_idx);
306
+ uint64_t rec_size = record_size(ctx->chunk_size);
307
+ uint8_t *record = ctx->record_buf;
308
+ uint8_t *nonce;
309
+ uint8_t *ciphertext;
310
+ uint8_t *tag;
311
+ uint8_t aad[AAD_BYTES];
312
+ int ret;
313
+
314
+ nonce = record;
315
+ ciphertext = record + NPUBBYTES;
316
+ tag = record + NPUBBYTES + ctx->chunk_size;
317
+
318
+ if (ctx->rng.random(ctx->rng.user, nonce, NPUBBYTES) != 0) {
319
+ return -1;
320
+ }
321
+
322
+ if (plaintext_len < ctx->chunk_size) {
323
+ memset(ctx->chunk_buf + plaintext_len, 0, ctx->chunk_size - plaintext_len);
324
+ }
325
+
326
+ build_aad(aad, ctx->file_id, chunk_idx, ctx->chunk_size);
327
+
328
+ ret = VARIANT_encrypt_detached(ciphertext, tag, AEGIS_RAF_TAG_BYTES, ctx->chunk_buf,
329
+ ctx->chunk_size, aad, AAD_BYTES, nonce, ctx->enc_key);
330
+
331
+ if (ret != 0) {
332
+ memset(record, 0, rec_size);
333
+ return -1;
334
+ }
335
+
336
+ ret = ctx->io.write_at(ctx->io.user, record, rec_size, off);
337
+ memset(record, 0, rec_size);
338
+ return ret;
339
+ }
340
+
341
+ int
342
+ FN(create)(CTX_TYPE *ctx, const aegis_raf_io *io, const aegis_raf_rng *rng,
343
+ const aegis_raf_config *cfg, const uint8_t *master_key)
344
+ {
345
+ uint64_t backing_size;
346
+ int file_exists;
347
+ aegis_raf_ctx_internal *internal;
348
+
349
+ if (ctx == NULL || io == NULL || rng == NULL || cfg == NULL || master_key == NULL) {
350
+ errno = EINVAL;
351
+ return -1;
352
+ }
353
+ if (io->read_at == NULL || io->write_at == NULL || io->get_size == NULL ||
354
+ io->set_size == NULL) {
355
+ errno = EINVAL;
356
+ return -1;
357
+ }
358
+ if (rng->random == NULL) {
359
+ errno = EINVAL;
360
+ return -1;
361
+ }
362
+ if (cfg->chunk_size < AEGIS_RAF_CHUNK_MIN || cfg->chunk_size > AEGIS_RAF_CHUNK_MAX ||
363
+ (cfg->chunk_size % 16) != 0) {
364
+ errno = EINVAL;
365
+ return -1;
366
+ }
367
+ if (cfg->scratch == NULL) {
368
+ errno = EINVAL;
369
+ return -1;
370
+ }
371
+
372
+ if (io->get_size(io->user, &backing_size) != 0) {
373
+ return -1;
374
+ }
375
+
376
+ file_exists = (backing_size >= AEGIS_RAF_HEADER_SIZE);
377
+
378
+ if (file_exists && !(cfg->flags & AEGIS_RAF_TRUNCATE)) {
379
+ errno = EEXIST;
380
+ return -1;
381
+ }
382
+ if (!file_exists && !(cfg->flags & AEGIS_RAF_CREATE)) {
383
+ errno = ENOENT;
384
+ return -1;
385
+ }
386
+
387
+ internal = (aegis_raf_ctx_internal *) ctx;
388
+ COMPILER_ASSERT(sizeof(CTX_TYPE) >= sizeof(aegis_raf_ctx_internal));
389
+ memset(internal, 0, sizeof(aegis_raf_ctx_internal));
390
+
391
+ internal->io = *io;
392
+ internal->rng = *rng;
393
+ internal->chunk_size = cfg->chunk_size;
394
+ internal->alg_id = ALG_ID;
395
+ internal->version = AEGIS_RAF_VERSION;
396
+ internal->file_size = 0;
397
+ internal->keybytes = KEYBYTES;
398
+ internal->npubbytes = NPUBBYTES;
399
+
400
+ if (setup_scratch_buffers(internal, cfg->scratch) != 0) {
401
+ memset(internal, 0, sizeof(aegis_raf_ctx_internal));
402
+ return -1;
403
+ }
404
+
405
+ if (rng->random(rng->user, internal->file_id, AEGIS_RAF_FILE_ID_BYTES) != 0) {
406
+ zeroize_scratch_buffers(internal);
407
+ memset(internal, 0, sizeof(aegis_raf_ctx_internal));
408
+ return -1;
409
+ }
410
+
411
+ derive_keys(internal->enc_key, internal->hdr_key, master_key, internal->file_id);
412
+
413
+ if (internal->io.set_size(internal->io.user, AEGIS_RAF_HEADER_SIZE) != 0) {
414
+ zeroize_scratch_buffers(internal);
415
+ memset(internal, 0, sizeof(aegis_raf_ctx_internal));
416
+ return -1;
417
+ }
418
+
419
+ if (write_header(internal) != 0) {
420
+ zeroize_scratch_buffers(internal);
421
+ memset(internal, 0, sizeof(aegis_raf_ctx_internal));
422
+ return -1;
423
+ }
424
+
425
+ if (setup_merkle_config(internal, cfg->merkle, 0, internal->chunk_size) != 0) {
426
+ zeroize_scratch_buffers(internal);
427
+ memset(internal, 0, sizeof(aegis_raf_ctx_internal));
428
+ return -1;
429
+ }
430
+
431
+ return 0;
432
+ }
433
+
434
+ int
435
+ FN(open)(CTX_TYPE *ctx, const aegis_raf_io *io, const aegis_raf_rng *rng,
436
+ const aegis_raf_config *cfg, const uint8_t *master_key)
437
+ {
438
+ aegis_raf_ctx_internal *internal;
439
+ uint64_t backing_size;
440
+ uint64_t backing_needed;
441
+ uint64_t max_chunks;
442
+ uint64_t rec_size;
443
+ uint8_t hdr[AEGIS_RAF_HEADER_SIZE];
444
+
445
+ if (ctx == NULL || io == NULL || rng == NULL || cfg == NULL || master_key == NULL) {
446
+ errno = EINVAL;
447
+ return -1;
448
+ }
449
+ if (io->read_at == NULL || io->write_at == NULL || io->get_size == NULL ||
450
+ io->set_size == NULL) {
451
+ errno = EINVAL;
452
+ return -1;
453
+ }
454
+ if (rng->random == NULL) {
455
+ errno = EINVAL;
456
+ return -1;
457
+ }
458
+ if (cfg->scratch == NULL) {
459
+ errno = EINVAL;
460
+ return -1;
461
+ }
462
+
463
+ internal = (aegis_raf_ctx_internal *) ctx;
464
+ COMPILER_ASSERT(sizeof(CTX_TYPE) >= sizeof(aegis_raf_ctx_internal));
465
+ memset(internal, 0, sizeof(aegis_raf_ctx_internal));
466
+
467
+ internal->io = *io;
468
+ internal->rng = *rng;
469
+ internal->keybytes = KEYBYTES;
470
+ internal->npubbytes = NPUBBYTES;
471
+
472
+ if (io->get_size(io->user, &backing_size) != 0) {
473
+ memset(internal, 0, sizeof(aegis_raf_ctx_internal));
474
+ return -1;
475
+ }
476
+ if (backing_size < AEGIS_RAF_HEADER_SIZE) {
477
+ memset(internal, 0, sizeof(aegis_raf_ctx_internal));
478
+ errno = EINVAL;
479
+ return -1;
480
+ }
481
+
482
+ if (io->read_at(io->user, hdr, AEGIS_RAF_HEADER_SIZE, 0) != 0) {
483
+ memset(internal, 0, sizeof(aegis_raf_ctx_internal));
484
+ return -1;
485
+ }
486
+
487
+ memcpy(internal->file_id, hdr + 24, AEGIS_RAF_FILE_ID_BYTES);
488
+ derive_keys(internal->enc_key, internal->hdr_key, master_key, internal->file_id);
489
+
490
+ if (verify_header(internal, hdr) != 0) {
491
+ memset(internal, 0, sizeof(aegis_raf_ctx_internal));
492
+ return -1;
493
+ }
494
+ rec_size = (uint64_t) record_size(internal->chunk_size);
495
+ max_chunks = get_chunk_count(internal->chunk_size, internal->file_size);
496
+ if (max_chunks != 0 && max_chunks > (UINT64_MAX - AEGIS_RAF_HEADER_SIZE) / rec_size) {
497
+ errno = EOVERFLOW;
498
+ memset(internal, 0, sizeof(aegis_raf_ctx_internal));
499
+ return -1;
500
+ }
501
+ backing_needed = AEGIS_RAF_HEADER_SIZE + max_chunks * rec_size;
502
+ if (backing_size < backing_needed) {
503
+ errno = EINVAL;
504
+ memset(internal, 0, sizeof(aegis_raf_ctx_internal));
505
+ return -1;
506
+ }
507
+
508
+ if (setup_scratch_buffers(internal, cfg->scratch) != 0) {
509
+ memset(internal, 0, sizeof(aegis_raf_ctx_internal));
510
+ return -1;
511
+ }
512
+
513
+ if (setup_merkle_config(internal, cfg->merkle, internal->file_size, internal->chunk_size) !=
514
+ 0) {
515
+ zeroize_scratch_buffers(internal);
516
+ memset(internal, 0, sizeof(aegis_raf_ctx_internal));
517
+ return -1;
518
+ }
519
+
520
+ return 0;
521
+ }
522
+
523
+ int
524
+ FN(read)(CTX_TYPE *ctx, uint8_t *out, size_t *bytes_read, size_t len, uint64_t offset)
525
+ {
526
+ aegis_raf_ctx_internal *internal = (aegis_raf_ctx_internal *) ctx;
527
+ size_t total_read;
528
+ uint64_t chunk_idx;
529
+ size_t offset_in_chunk;
530
+ size_t bytes_to_read;
531
+
532
+ if (ctx == NULL || bytes_read == NULL || (len > 0 && out == NULL)) {
533
+ errno = EINVAL;
534
+ return -1;
535
+ }
536
+
537
+ *bytes_read = 0;
538
+ if (len == 0 || offset >= internal->file_size) {
539
+ return 0;
540
+ }
541
+
542
+ if (len > internal->file_size - offset) {
543
+ len = (size_t) (internal->file_size - offset);
544
+ }
545
+
546
+ total_read = 0;
547
+ while (total_read < len) {
548
+ chunk_idx = (offset + total_read) / internal->chunk_size;
549
+ offset_in_chunk = (offset + total_read) % internal->chunk_size;
550
+ bytes_to_read = internal->chunk_size - offset_in_chunk;
551
+ if (bytes_to_read > len - total_read) {
552
+ bytes_to_read = len - total_read;
553
+ }
554
+
555
+ if (read_chunk(internal, chunk_idx) != 0) {
556
+ return -1;
557
+ }
558
+
559
+ memcpy(out + total_read, internal->chunk_buf + offset_in_chunk, bytes_to_read);
560
+ total_read += bytes_to_read;
561
+ }
562
+
563
+ *bytes_read = total_read;
564
+ return 0;
565
+ }
566
+
567
+ static int
568
+ write_impl(aegis_raf_ctx_internal *internal, size_t *bytes_written, const uint8_t *in, size_t len,
569
+ uint64_t offset)
570
+ {
571
+ uint64_t new_file_size;
572
+ uint64_t old_num_chunks;
573
+ uint64_t new_num_chunks;
574
+ uint64_t rec_size;
575
+ uint64_t chunks_size;
576
+ uint64_t new_backing_size;
577
+ uint64_t gap_start;
578
+ uint64_t gap_end;
579
+ uint64_t first_gap_chunk;
580
+ uint64_t last_gap_chunk;
581
+ uint64_t ci;
582
+ uint64_t chunk_start;
583
+ uint64_t chunk_end;
584
+ uint64_t effective_file_size;
585
+ size_t zero_start;
586
+ size_t zero_end;
587
+ size_t total_written;
588
+ uint64_t chunk_idx;
589
+ size_t offset_in_chunk;
590
+ size_t bytes_to_write;
591
+ int need_read_modify_write;
592
+ size_t chunk_valid_len;
593
+ uint64_t chunk_end_offset;
594
+
595
+ *bytes_written = 0;
596
+
597
+ if (len > 0 && offset > UINT64_MAX - len) {
598
+ errno = EOVERFLOW;
599
+ return -1;
600
+ }
601
+ new_file_size = offset + len;
602
+
603
+ old_num_chunks = get_chunk_count(internal->chunk_size, internal->file_size);
604
+ new_num_chunks = get_chunk_count(internal->chunk_size, new_file_size);
605
+ rec_size = record_size(internal->chunk_size);
606
+
607
+ if (new_num_chunks > UINT64_MAX / rec_size) {
608
+ errno = EOVERFLOW;
609
+ return -1;
610
+ }
611
+ chunks_size = new_num_chunks * rec_size;
612
+ if (chunks_size > UINT64_MAX - AEGIS_RAF_HEADER_SIZE) {
613
+ errno = EOVERFLOW;
614
+ return -1;
615
+ }
616
+
617
+ if (internal->merkle_enabled && new_num_chunks > internal->merkle_cfg.max_chunks) {
618
+ errno = EOVERFLOW;
619
+ return -1;
620
+ }
621
+
622
+ if (new_file_size > internal->file_size) {
623
+ new_backing_size = AEGIS_RAF_HEADER_SIZE + chunks_size;
624
+ if (internal->io.set_size(internal->io.user, new_backing_size) != 0) {
625
+ return -1;
626
+ }
627
+ }
628
+
629
+ if (offset > internal->file_size) {
630
+ gap_start = internal->file_size;
631
+ gap_end = offset;
632
+ first_gap_chunk = gap_start / internal->chunk_size;
633
+ last_gap_chunk = (gap_end > 0) ? (gap_end - 1) / internal->chunk_size : 0;
634
+
635
+ for (ci = first_gap_chunk; ci <= last_gap_chunk && ci < new_num_chunks; ci++) {
636
+ chunk_start = ci * internal->chunk_size;
637
+ chunk_end = chunk_start + internal->chunk_size;
638
+
639
+ if (ci < old_num_chunks) {
640
+ if (read_chunk(internal, ci) != 0) {
641
+ return -1;
642
+ }
643
+ } else {
644
+ memset(internal->chunk_buf, 0, internal->chunk_size);
645
+ }
646
+
647
+ zero_start = 0;
648
+ zero_end = internal->chunk_size;
649
+ if (gap_start > chunk_start) {
650
+ zero_start = (size_t) (gap_start - chunk_start);
651
+ }
652
+ if (gap_end < chunk_end) {
653
+ zero_end = (size_t) (gap_end - chunk_start);
654
+ }
655
+ if (zero_end > zero_start) {
656
+ memset(internal->chunk_buf + zero_start, 0, zero_end - zero_start);
657
+ }
658
+
659
+ chunk_valid_len = (chunk_end <= new_file_size) ? internal->chunk_size
660
+ : (size_t) (new_file_size - chunk_start);
661
+
662
+ if (write_chunk(internal, chunk_valid_len, ci) != 0) {
663
+ return -1;
664
+ }
665
+
666
+ if (internal->merkle_enabled) {
667
+ if (raf_merkle_update_chunk(&internal->merkle_cfg, internal->chunk_buf,
668
+ chunk_valid_len, ci) != 0) {
669
+ return -1;
670
+ }
671
+ }
672
+ }
673
+ }
674
+
675
+ total_written = 0;
676
+ while (total_written < len) {
677
+ chunk_idx = (offset + total_written) / internal->chunk_size;
678
+ offset_in_chunk = (offset + total_written) % internal->chunk_size;
679
+ bytes_to_write = internal->chunk_size - offset_in_chunk;
680
+ if (bytes_to_write > len - total_written) {
681
+ bytes_to_write = len - total_written;
682
+ }
683
+
684
+ need_read_modify_write = (offset_in_chunk != 0 || bytes_to_write < internal->chunk_size);
685
+ if (need_read_modify_write) {
686
+ chunk_start = chunk_idx * internal->chunk_size;
687
+ if (chunk_start < internal->file_size) {
688
+ if (read_chunk(internal, chunk_idx) != 0) {
689
+ return -1;
690
+ }
691
+ } else {
692
+ memset(internal->chunk_buf, 0, internal->chunk_size);
693
+ }
694
+ }
695
+
696
+ memcpy(internal->chunk_buf + offset_in_chunk, in + total_written, bytes_to_write);
697
+
698
+ effective_file_size =
699
+ new_file_size > internal->file_size ? new_file_size : internal->file_size;
700
+
701
+ chunk_end_offset = (chunk_idx + 1) * internal->chunk_size;
702
+ if (chunk_end_offset <= effective_file_size) {
703
+ chunk_valid_len = internal->chunk_size;
704
+ } else if (effective_file_size > chunk_idx * internal->chunk_size) {
705
+ chunk_valid_len = (size_t) (effective_file_size - chunk_idx * internal->chunk_size);
706
+ } else {
707
+ chunk_valid_len = offset_in_chunk + bytes_to_write;
708
+ }
709
+
710
+ if (write_chunk(internal, chunk_valid_len, chunk_idx) != 0) {
711
+ return -1;
712
+ }
713
+
714
+ if (internal->merkle_enabled) {
715
+ if (raf_merkle_update_chunk(&internal->merkle_cfg, internal->chunk_buf, chunk_valid_len,
716
+ chunk_idx) != 0) {
717
+ return -1;
718
+ }
719
+ }
720
+
721
+ total_written += bytes_to_write;
722
+ }
723
+
724
+ if (new_file_size > internal->file_size) {
725
+ internal->file_size = new_file_size;
726
+ if (write_header(internal) != 0) {
727
+ return -1;
728
+ }
729
+ }
730
+
731
+ *bytes_written = total_written;
732
+ return 0;
733
+ }
734
+
735
+ int
736
+ FN(write)(CTX_TYPE *ctx, size_t *bytes_written, const uint8_t *in, size_t len, uint64_t offset)
737
+ {
738
+ aegis_raf_ctx_internal *internal = (aegis_raf_ctx_internal *) ctx;
739
+
740
+ if (ctx == NULL || bytes_written == NULL || (len > 0 && in == NULL)) {
741
+ errno = EINVAL;
742
+ return -1;
743
+ }
744
+
745
+ *bytes_written = 0;
746
+ if (len == 0) {
747
+ return 0;
748
+ }
749
+
750
+ return write_impl(internal, bytes_written, in, len, offset);
751
+ }
752
+
753
+ int
754
+ FN(truncate)(CTX_TYPE *ctx, uint64_t size)
755
+ {
756
+ aegis_raf_ctx_internal *internal = (aegis_raf_ctx_internal *) ctx;
757
+ size_t written;
758
+ uint64_t old_num_chunks;
759
+ uint64_t new_num_chunks;
760
+ uint64_t rec_size;
761
+ uint64_t chunks_size;
762
+ uint64_t new_backing_size;
763
+ uint64_t last_chunk_idx;
764
+ size_t new_chunk_len;
765
+
766
+ if (ctx == NULL) {
767
+ errno = EINVAL;
768
+ return -1;
769
+ }
770
+
771
+ if (size == internal->file_size) {
772
+ return 0;
773
+ }
774
+
775
+ if (size > internal->file_size) {
776
+ return write_impl(internal, &written, NULL, 0, size);
777
+ }
778
+
779
+ old_num_chunks = get_chunk_count(internal->chunk_size, internal->file_size);
780
+ new_num_chunks = get_chunk_count(internal->chunk_size, size);
781
+ rec_size = record_size(internal->chunk_size);
782
+
783
+ if (new_num_chunks > UINT64_MAX / rec_size) {
784
+ errno = EOVERFLOW;
785
+ return -1;
786
+ }
787
+ chunks_size = new_num_chunks * rec_size;
788
+ if (chunks_size > UINT64_MAX - AEGIS_RAF_HEADER_SIZE) {
789
+ errno = EOVERFLOW;
790
+ return -1;
791
+ }
792
+ new_backing_size = AEGIS_RAF_HEADER_SIZE + chunks_size;
793
+
794
+ if (internal->io.set_size(internal->io.user, new_backing_size) != 0) {
795
+ return -1;
796
+ }
797
+
798
+ if (internal->merkle_enabled) {
799
+ if (new_num_chunks < old_num_chunks) {
800
+ if (raf_merkle_clear_range(&internal->merkle_cfg, new_num_chunks, old_num_chunks - 1) !=
801
+ 0) {
802
+ return -1;
803
+ }
804
+ }
805
+
806
+ if (size > 0 && new_num_chunks > 0) {
807
+ last_chunk_idx = new_num_chunks - 1;
808
+ new_chunk_len = (size_t) (size - last_chunk_idx * internal->chunk_size);
809
+
810
+ if (read_chunk(internal, last_chunk_idx) != 0) {
811
+ return -1;
812
+ }
813
+ if (raf_merkle_update_chunk(&internal->merkle_cfg, internal->chunk_buf, new_chunk_len,
814
+ last_chunk_idx) != 0) {
815
+ return -1;
816
+ }
817
+ }
818
+ }
819
+
820
+ internal->file_size = size;
821
+ return write_header(internal);
822
+ }
823
+
824
+ int
825
+ FN(get_size)(const CTX_TYPE *ctx, uint64_t *size)
826
+ {
827
+ const aegis_raf_ctx_internal *internal = (const aegis_raf_ctx_internal *) ctx;
828
+
829
+ if (ctx == NULL || size == NULL) {
830
+ errno = EINVAL;
831
+ return -1;
832
+ }
833
+
834
+ *size = internal->file_size;
835
+ return 0;
836
+ }
837
+
838
+ int
839
+ FN(sync)(CTX_TYPE *ctx)
840
+ {
841
+ aegis_raf_ctx_internal *internal = (aegis_raf_ctx_internal *) ctx;
842
+
843
+ if (ctx == NULL) {
844
+ errno = EINVAL;
845
+ return -1;
846
+ }
847
+
848
+ if (internal->io.sync != NULL) {
849
+ return internal->io.sync(internal->io.user);
850
+ }
851
+ return 0;
852
+ }
853
+
854
+ void
855
+ FN(close)(CTX_TYPE *ctx)
856
+ {
857
+ aegis_raf_ctx_internal *internal = (aegis_raf_ctx_internal *) ctx;
858
+
859
+ if (ctx == NULL) {
860
+ return;
861
+ }
862
+
863
+ if (internal->io.sync != NULL) {
864
+ (void) internal->io.sync(internal->io.user);
865
+ }
866
+ zeroize_scratch_buffers(internal);
867
+ memset(internal, 0, sizeof(aegis_raf_ctx_internal));
868
+ }
869
+
870
+ int
871
+ FN(merkle_rebuild)(CTX_TYPE *ctx)
872
+ {
873
+ aegis_raf_ctx_internal *internal = (aegis_raf_ctx_internal *) ctx;
874
+ uint64_t num_chunks;
875
+ uint64_t ci;
876
+ size_t chunk_len;
877
+ uint64_t chunk_end;
878
+ int ret;
879
+
880
+ if (ctx == NULL) {
881
+ errno = EINVAL;
882
+ return -1;
883
+ }
884
+
885
+ if (!internal->merkle_enabled) {
886
+ errno = ENOTSUP;
887
+ return -1;
888
+ }
889
+
890
+ num_chunks = get_chunk_count(internal->chunk_size, internal->file_size);
891
+
892
+ for (ci = 0; ci < num_chunks; ci++) {
893
+ if (read_chunk(internal, ci) != 0) {
894
+ return -1;
895
+ }
896
+
897
+ chunk_end = (ci + 1) * internal->chunk_size;
898
+ if (chunk_end <= internal->file_size) {
899
+ chunk_len = internal->chunk_size;
900
+ } else {
901
+ chunk_len = (size_t) (internal->file_size - ci * internal->chunk_size);
902
+ }
903
+
904
+ ret = raf_merkle_update_leaf(&internal->merkle_cfg, internal->chunk_buf, chunk_len, ci);
905
+ if (ret != 0) {
906
+ return ret;
907
+ }
908
+ }
909
+
910
+ for (ci = num_chunks; ci < internal->merkle_cfg.max_chunks; ci++) {
911
+ ret = raf_merkle_clear_leaf(&internal->merkle_cfg, ci);
912
+ if (ret != 0) {
913
+ return ret;
914
+ }
915
+ }
916
+
917
+ if (internal->merkle_cfg.max_chunks > 0) {
918
+ ret = raf_merkle_update_parents(&internal->merkle_cfg, 0,
919
+ internal->merkle_cfg.max_chunks - 1);
920
+ if (ret != 0) {
921
+ return ret;
922
+ }
923
+ }
924
+
925
+ return 0;
926
+ }
927
+
928
+ int
929
+ FN(merkle_verify)(CTX_TYPE *ctx, uint64_t *corrupted_chunk)
930
+ {
931
+ aegis_raf_ctx_internal *internal = (aegis_raf_ctx_internal *) ctx;
932
+ uint64_t num_chunks;
933
+ uint64_t ci;
934
+ size_t chunk_len;
935
+ uint64_t chunk_end;
936
+ uint64_t level_count;
937
+ uint32_t level = 0;
938
+ uint64_t parent_count;
939
+ uint64_t i;
940
+ size_t leaf_off;
941
+ size_t left_off;
942
+ size_t right_off;
943
+ size_t parent_off;
944
+ uint8_t computed_hash[AEGIS_RAF_MERKLE_HASH_MAX];
945
+ uint8_t empty_hash[AEGIS_RAF_MERKLE_HASH_MAX];
946
+ int ret = 0;
947
+
948
+ if (ctx == NULL) {
949
+ errno = EINVAL;
950
+ return -1;
951
+ }
952
+
953
+ if (!internal->merkle_enabled) {
954
+ errno = ENOTSUP;
955
+ return -1;
956
+ }
957
+
958
+ if (internal->merkle_cfg.hash_len < AEGIS_RAF_MERKLE_HASH_MIN ||
959
+ internal->merkle_cfg.hash_len > AEGIS_RAF_MERKLE_HASH_MAX) {
960
+ errno = EINVAL;
961
+ ret = -1;
962
+ goto cleanup;
963
+ }
964
+
965
+ num_chunks = get_chunk_count(internal->chunk_size, internal->file_size);
966
+ if (num_chunks > internal->merkle_cfg.max_chunks) {
967
+ if (corrupted_chunk != NULL) {
968
+ *corrupted_chunk = UINT64_MAX;
969
+ }
970
+ errno = EOVERFLOW;
971
+ ret = -1;
972
+ goto cleanup;
973
+ }
974
+
975
+ for (ci = 0; ci < num_chunks; ci++) {
976
+ if (read_chunk(internal, ci) != 0) {
977
+ if (corrupted_chunk != NULL) {
978
+ *corrupted_chunk = ci;
979
+ }
980
+ ret = -1;
981
+ goto cleanup;
982
+ }
983
+
984
+ chunk_end = (ci + 1) * internal->chunk_size;
985
+ if (chunk_end <= internal->file_size) {
986
+ chunk_len = internal->chunk_size;
987
+ } else {
988
+ chunk_len = (size_t) (internal->file_size - ci * internal->chunk_size);
989
+ }
990
+
991
+ ret = internal->merkle_cfg.hash_leaf(internal->merkle_cfg.user, computed_hash,
992
+ internal->merkle_cfg.hash_len, internal->chunk_buf,
993
+ chunk_len, ci);
994
+ if (ret != 0) {
995
+ if (corrupted_chunk != NULL) {
996
+ *corrupted_chunk = ci;
997
+ }
998
+ goto cleanup;
999
+ }
1000
+
1001
+ leaf_off = (size_t) (ci * internal->merkle_cfg.hash_len);
1002
+ if (memcmp(computed_hash, internal->merkle_cfg.buf + leaf_off,
1003
+ internal->merkle_cfg.hash_len) != 0) {
1004
+ if (corrupted_chunk != NULL) {
1005
+ *corrupted_chunk = ci;
1006
+ }
1007
+ errno = EBADMSG;
1008
+ ret = -1;
1009
+ goto cleanup;
1010
+ }
1011
+ }
1012
+
1013
+ for (ci = num_chunks; ci < internal->merkle_cfg.max_chunks; ci++) {
1014
+ ret = internal->merkle_cfg.hash_empty(internal->merkle_cfg.user, computed_hash,
1015
+ internal->merkle_cfg.hash_len, 0, ci);
1016
+ if (ret != 0) {
1017
+ if (corrupted_chunk != NULL) {
1018
+ *corrupted_chunk = ci;
1019
+ }
1020
+ goto cleanup;
1021
+ }
1022
+
1023
+ leaf_off = (size_t) (ci * internal->merkle_cfg.hash_len);
1024
+ if (memcmp(computed_hash, internal->merkle_cfg.buf + leaf_off,
1025
+ internal->merkle_cfg.hash_len) != 0) {
1026
+ if (corrupted_chunk != NULL) {
1027
+ *corrupted_chunk = ci;
1028
+ }
1029
+ errno = EBADMSG;
1030
+ ret = -1;
1031
+ goto cleanup;
1032
+ }
1033
+ }
1034
+
1035
+ level_count = internal->merkle_cfg.max_chunks;
1036
+ for (level = 0; level_count > 1; level++) {
1037
+ parent_count = (level_count + 1) / 2;
1038
+
1039
+ for (i = 0; i < parent_count; i++) {
1040
+ uint64_t left_child = i * 2;
1041
+ uint64_t right_child = left_child + 1;
1042
+
1043
+ left_off = raf_merkle_node_offset(internal->merkle_cfg.max_chunks,
1044
+ internal->merkle_cfg.hash_len, level, left_child);
1045
+
1046
+ if (right_child < level_count) {
1047
+ right_off =
1048
+ raf_merkle_node_offset(internal->merkle_cfg.max_chunks,
1049
+ internal->merkle_cfg.hash_len, level, right_child);
1050
+ ret = internal->merkle_cfg.hash_parent(
1051
+ internal->merkle_cfg.user, computed_hash, internal->merkle_cfg.hash_len,
1052
+ internal->merkle_cfg.buf + left_off, internal->merkle_cfg.buf + right_off,
1053
+ level, i);
1054
+ } else {
1055
+ ret = internal->merkle_cfg.hash_empty(internal->merkle_cfg.user, empty_hash,
1056
+ internal->merkle_cfg.hash_len, level,
1057
+ right_child);
1058
+ if (ret != 0) {
1059
+ goto cleanup;
1060
+ }
1061
+ ret = internal->merkle_cfg.hash_parent(
1062
+ internal->merkle_cfg.user, computed_hash, internal->merkle_cfg.hash_len,
1063
+ internal->merkle_cfg.buf + left_off, empty_hash, level, i);
1064
+ }
1065
+ if (ret != 0) {
1066
+ goto cleanup;
1067
+ }
1068
+
1069
+ parent_off = raf_merkle_node_offset(internal->merkle_cfg.max_chunks,
1070
+ internal->merkle_cfg.hash_len, level + 1, i);
1071
+ if (memcmp(computed_hash, internal->merkle_cfg.buf + parent_off,
1072
+ internal->merkle_cfg.hash_len) != 0) {
1073
+ if (corrupted_chunk != NULL) {
1074
+ *corrupted_chunk = UINT64_MAX;
1075
+ }
1076
+ errno = EBADMSG;
1077
+ ret = -1;
1078
+ goto cleanup;
1079
+ }
1080
+ }
1081
+
1082
+ level_count = parent_count;
1083
+ }
1084
+
1085
+ cleanup:
1086
+ return ret;
1087
+ }
1088
+
1089
+ int
1090
+ FN(merkle_commitment)(const CTX_TYPE *ctx, uint8_t *out, size_t out_len)
1091
+ {
1092
+ const aegis_raf_ctx_internal *internal = (const aegis_raf_ctx_internal *) ctx;
1093
+ uint8_t commit_ctx[AEGIS_RAF_COMMITMENT_CONTEXT_BYTES];
1094
+
1095
+ if (ctx == NULL) {
1096
+ errno = EINVAL;
1097
+ return -1;
1098
+ }
1099
+ if (!internal->merkle_enabled) {
1100
+ errno = ENOTSUP;
1101
+ return -1;
1102
+ }
1103
+
1104
+ build_commitment_context(commit_ctx, internal->version, internal->alg_id, internal->chunk_size,
1105
+ internal->file_id);
1106
+
1107
+ return aegis_raf_merkle_root(&internal->merkle_cfg, out, out_len, commit_ctx, sizeof commit_ctx,
1108
+ internal->file_size);
1109
+ }
1110
+
1111
+ #undef CONCAT_
1112
+ #undef CONCAT
1113
+ #undef CONCAT3_
1114
+ #undef CONCAT3
1115
+ #undef FN
1116
+ #undef CTX_TYPE
1117
+ #undef MAC_STATE_TYPE
1118
+ #undef KDF_CONST
1119
+ #undef KDF_CONST_LEN