hash.h: scaffolding for _unsafe hashing variants

Git's default SHA-1 implementation is collision-detecting, which hardens us against known SHA-1 attacks against Git objects. This makes Git object writes safer at the expense of some speed when hashing through the collision-detecting implementation, which is slower than non-collision detecting alternatives. Prepare for loading a separate "unsafe" SHA-1 implementation that can be used for non-cryptographic purposes, like computing the checksum of files that use the hashwrite() API. This commit does not actually introduce any new compile-time knobs to control which implementation is used as the unsafe SHA-1 variant, but does add scaffolding so that the "git_hash_algo" structure has five new function pointers which are "unsafe" variants of the five existing hashing-related function pointers: - git_hash_init_fn unsafe_init_fn - git_hash_clone_fn unsafe_clone_fn - git_hash_update_fn unsafe_update_fn - git_hash_final_fn unsafe_final_fn - git_hash_final_oid_fn unsafe_final_oid_fn The following commit will introduce compile-time knobs to specify which SHA-1 implementation is used for non-cryptographic uses. Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Taylor Blau committed Sep 26, 2024 at 11:22 UTC 253ed9ecfffa3e50b95e08bb513fdf9efcc5a85f
2 files changed +84
hash.h
+42
@@ -44,14 +44,32 @@
44 #define platform_SHA1_Final SHA1_Final
45 #endif
46
47 +#ifndef platform_SHA_CTX_unsafe
48 +# define platform_SHA_CTX_unsafe platform_SHA_CTX
49 +# define platform_SHA1_Init_unsafe platform_SHA1_Init
50 +# define platform_SHA1_Update_unsafe platform_SHA1_Update
51 +# define platform_SHA1_Final_unsafe platform_SHA1_Final
52 +# ifdef platform_SHA1_Clone
53 +# define platform_SHA1_Clone_unsafe platform_SHA1_Clone
54 +# endif
55 +#endif
56 +
57 #define git_SHA_CTX platform_SHA_CTX
58 #define git_SHA1_Init platform_SHA1_Init
59 #define git_SHA1_Update platform_SHA1_Update
60 #define git_SHA1_Final platform_SHA1_Final
61
62 +#define git_SHA_CTX_unsafe platform_SHA_CTX_unsafe
63 +#define git_SHA1_Init_unsafe platform_SHA1_Init_unsafe
64 +#define git_SHA1_Update_unsafe platform_SHA1_Update_unsafe
65 +#define git_SHA1_Final_unsafe platform_SHA1_Final_unsafe
66 +
67 #ifdef platform_SHA1_Clone
68 #define git_SHA1_Clone platform_SHA1_Clone
69 #endif
70 +#ifdef platform_SHA1_Clone_unsafe
71 +# define git_SHA1_Clone_unsafe platform_SHA1_Clone_unsafe
72 +#endif
73
74 #ifndef platform_SHA256_CTX
75 #define platform_SHA256_CTX SHA256_CTX
@@ -81,6 +99,13 @@ static inline void git_SHA1_Clone(git_SHA_CTX *dst, const git_SHA_CTX *src)
99 memcpy(dst, src, sizeof(*dst));
100 }
101 #endif
102 +#ifndef SHA1_NEEDS_CLONE_HELPER_UNSAFE
103 +static inline void git_SHA1_Clone_unsafe(git_SHA_CTX_unsafe *dst,
104 + const git_SHA_CTX_unsafe *src)
105 +{
106 + memcpy(dst, src, sizeof(*dst));
107 +}
108 +#endif
109
110 #ifndef SHA256_NEEDS_CLONE_HELPER
111 static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *src)
@@ -178,6 +203,8 @@ enum get_oid_result {
203 /* A suitably aligned type for stack allocations of hash contexts. */
204 union git_hash_ctx {
205 git_SHA_CTX sha1;
206 + git_SHA_CTX_unsafe sha1_unsafe;
207 +
208 git_SHA256_CTX sha256;
209 };
210 typedef union git_hash_ctx git_hash_ctx;
@@ -222,6 +249,21 @@ struct git_hash_algo {
249 /* The hash finalization function for object IDs. */
250 git_hash_final_oid_fn final_oid_fn;
251
252 + /* The non-cryptographic hash initialization function. */
253 + git_hash_init_fn unsafe_init_fn;
254 +
255 + /* The non-cryptographic hash context cloning function. */
256 + git_hash_clone_fn unsafe_clone_fn;
257 +
258 + /* The non-cryptographic hash update function. */
259 + git_hash_update_fn unsafe_update_fn;
260 +
261 + /* The non-cryptographic hash finalization function. */
262 + git_hash_final_fn unsafe_final_fn;
263 +
264 + /* The non-cryptographic hash finalization function. */
265 + git_hash_final_oid_fn unsafe_final_oid_fn;
266 +
267 /* The OID of the empty tree. */
268 const struct object_id *empty_tree;
269
object-file.c
+42
@@ -115,6 +115,33 @@ static void git_hash_sha1_final_oid(struct object_id *oid, git_hash_ctx *ctx)
115 oid->algo = GIT_HASH_SHA1;
116 }
117
118 +static void git_hash_sha1_init_unsafe(git_hash_ctx *ctx)
119 +{
120 + git_SHA1_Init_unsafe(&ctx->sha1_unsafe);
121 +}
122 +
123 +static void git_hash_sha1_clone_unsafe(git_hash_ctx *dst, const git_hash_ctx *src)
124 +{
125 + git_SHA1_Clone_unsafe(&dst->sha1_unsafe, &src->sha1_unsafe);
126 +}
127 +
128 +static void git_hash_sha1_update_unsafe(git_hash_ctx *ctx, const void *data,
129 + size_t len)
130 +{
131 + git_SHA1_Update_unsafe(&ctx->sha1_unsafe, data, len);
132 +}
133 +
134 +static void git_hash_sha1_final_unsafe(unsigned char *hash, git_hash_ctx *ctx)
135 +{
136 + git_SHA1_Final_unsafe(hash, &ctx->sha1_unsafe);
137 +}
138 +
139 +static void git_hash_sha1_final_oid_unsafe(struct object_id *oid, git_hash_ctx *ctx)
140 +{
141 + git_SHA1_Final_unsafe(oid->hash, &ctx->sha1_unsafe);
142 + memset(oid->hash + GIT_SHA1_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA1_RAWSZ);
143 + oid->algo = GIT_HASH_SHA1;
144 +}
145
146 static void git_hash_sha256_init(git_hash_ctx *ctx)
147 {
@@ -189,6 +216,11 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
216 .update_fn = git_hash_unknown_update,
217 .final_fn = git_hash_unknown_final,
218 .final_oid_fn = git_hash_unknown_final_oid,
219 + .unsafe_init_fn = git_hash_unknown_init,
220 + .unsafe_clone_fn = git_hash_unknown_clone,
221 + .unsafe_update_fn = git_hash_unknown_update,
222 + .unsafe_final_fn = git_hash_unknown_final,
223 + .unsafe_final_oid_fn = git_hash_unknown_final_oid,
224 .empty_tree = NULL,
225 .empty_blob = NULL,
226 .null_oid = NULL,
@@ -204,6 +236,11 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
236 .update_fn = git_hash_sha1_update,
237 .final_fn = git_hash_sha1_final,
238 .final_oid_fn = git_hash_sha1_final_oid,
239 + .unsafe_init_fn = git_hash_sha1_init_unsafe,
240 + .unsafe_clone_fn = git_hash_sha1_clone_unsafe,
241 + .unsafe_update_fn = git_hash_sha1_update_unsafe,
242 + .unsafe_final_fn = git_hash_sha1_final_unsafe,
243 + .unsafe_final_oid_fn = git_hash_sha1_final_oid_unsafe,
244 .empty_tree = &empty_tree_oid,
245 .empty_blob = &empty_blob_oid,
246 .null_oid = &null_oid_sha1,
@@ -219,6 +256,11 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
256 .update_fn = git_hash_sha256_update,
257 .final_fn = git_hash_sha256_final,
258 .final_oid_fn = git_hash_sha256_final_oid,
259 + .unsafe_init_fn = git_hash_sha256_init,
260 + .unsafe_clone_fn = git_hash_sha256_clone,
261 + .unsafe_update_fn = git_hash_sha256_update,
262 + .unsafe_final_fn = git_hash_sha256_final,
263 + .unsafe_final_oid_fn = git_hash_sha256_final_oid,
264 .empty_tree = &empty_tree_oid_sha256,
265 .empty_blob = &empty_blob_oid_sha256,
266 .null_oid = &null_oid_sha256,