2 * checksum.c: checksum routines
4 * ====================================================================
5 * Copyright (c) 2008 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
25 #include "svn_checksum.h"
26 #include "svn_error.h"
33 /* Returns the digest size of it's argument. */
34 #define DIGESTSIZE(k) ((k) == svn_checksum_md5 ? APR_MD5_DIGESTSIZE : \
35 (k) == svn_checksum_sha1 ? APR_SHA1_DIGESTSIZE : 0)
38 /* Check to see if KIND is something we recognize. If not, return
39 * SVN_ERR_BAD_CHECKSUM_KIND */
41 validate_kind(svn_checksum_kind_t kind
)
43 if (kind
== svn_checksum_md5
|| kind
== svn_checksum_sha1
)
46 return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND
, NULL
, NULL
);
51 svn_checksum_create(svn_checksum_kind_t kind
,
54 svn_checksum_t
*checksum
;
58 case svn_checksum_md5
:
59 case svn_checksum_sha1
:
60 checksum
= apr_pcalloc(pool
, sizeof(*checksum
) + DIGESTSIZE(kind
));
61 checksum
->digest
= (unsigned char *)checksum
+ sizeof(*checksum
);
62 checksum
->kind
= kind
;
71 svn_checksum__from_digest(const unsigned char *digest
,
72 svn_checksum_kind_t kind
,
73 apr_pool_t
*result_pool
)
75 svn_checksum_t
*checksum
= svn_checksum_create(kind
, result_pool
);
77 memcpy((unsigned char *)checksum
->digest
, digest
, DIGESTSIZE(kind
));
82 svn_checksum_clear(svn_checksum_t
*checksum
)
84 SVN_ERR(validate_kind(checksum
->kind
));
86 memset((unsigned char *) checksum
->digest
, 0, DIGESTSIZE(checksum
->kind
));
91 svn_checksum_match(const svn_checksum_t
*checksum1
,
92 const svn_checksum_t
*checksum2
)
94 if (checksum1
== NULL
|| checksum2
== NULL
)
97 if (checksum1
->kind
!= checksum2
->kind
)
100 switch (checksum1
->kind
)
102 case svn_checksum_md5
:
103 return svn_md5__digests_match(checksum1
->digest
, checksum2
->digest
);
104 case svn_checksum_sha1
:
105 return svn_sha1__digests_match(checksum1
->digest
, checksum2
->digest
);
107 /* We really shouldn't get here, but if we do... */
113 svn_checksum_to_cstring_display(const svn_checksum_t
*checksum
,
116 switch (checksum
->kind
)
118 case svn_checksum_md5
:
119 return svn_md5__digest_to_cstring_display(checksum
->digest
, pool
);
120 case svn_checksum_sha1
:
121 return svn_sha1__digest_to_cstring_display(checksum
->digest
, pool
);
123 /* We really shouldn't get here, but if we do... */
129 svn_checksum_to_cstring(const svn_checksum_t
*checksum
,
132 switch (checksum
->kind
)
134 case svn_checksum_md5
:
135 return svn_md5__digest_to_cstring(checksum
->digest
, pool
);
136 case svn_checksum_sha1
:
137 return svn_sha1__digest_to_cstring(checksum
->digest
, pool
);
139 /* We really shouldn't get here, but if we do... */
145 svn_checksum_parse_hex(svn_checksum_t
**checksum
,
146 svn_checksum_kind_t kind
,
152 unsigned char is_zeros
= '\0';
160 SVN_ERR(validate_kind(kind
));
162 *checksum
= svn_checksum_create(kind
, pool
);
163 len
= DIGESTSIZE(kind
);
165 for (i
= 0; i
< len
; i
++)
167 if ((! isxdigit(hex
[i
* 2])) || (! isxdigit(hex
[i
* 2 + 1])))
168 return svn_error_create(SVN_ERR_BAD_CHECKSUM_PARSE
, NULL
, NULL
);
170 ((unsigned char *)(*checksum
)->digest
)[i
] =
171 (( isalpha(hex
[i
*2]) ? hex
[i
*2] - 'a' + 10 : hex
[i
*2] - '0') << 4) |
172 ( isalpha(hex
[i
*2+1]) ? hex
[i
*2+1] - 'a' + 10 : hex
[i
*2+1] - '0');
173 is_zeros
|= (*checksum
)->digest
[i
];
176 if (is_zeros
== '\0')
183 svn_checksum_dup(const svn_checksum_t
*checksum
,
186 /* The duplicate of a NULL checksum is a NULL... */
187 if (checksum
== NULL
)
190 return svn_checksum__from_digest(checksum
->digest
, checksum
->kind
, pool
);
194 svn_checksum(svn_checksum_t
**checksum
,
195 svn_checksum_kind_t kind
,
200 apr_sha1_ctx_t sha1_ctx
;
202 SVN_ERR(validate_kind(kind
));
203 *checksum
= svn_checksum_create(kind
, pool
);
207 case svn_checksum_md5
:
208 apr_md5((unsigned char *)(*checksum
)->digest
, data
, len
);
211 case svn_checksum_sha1
:
212 apr_sha1_init(&sha1_ctx
);
213 apr_sha1_update(&sha1_ctx
, data
, len
);
214 apr_sha1_final((unsigned char *)(*checksum
)->digest
, &sha1_ctx
);
218 /* We really shouldn't get here, but if we do... */
219 return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND
, NULL
, NULL
);
227 svn_checksum_empty_checksum(svn_checksum_kind_t kind
,
230 const unsigned char *digest
;
234 case svn_checksum_md5
:
235 digest
= svn_md5__empty_string_digest();
238 case svn_checksum_sha1
:
239 digest
= svn_sha1__empty_string_digest();
243 /* We really shouldn't get here, but if we do... */
247 return svn_checksum__from_digest(digest
, kind
, pool
);
250 struct svn_checksum_ctx_t
253 svn_checksum_kind_t kind
;
257 svn_checksum_ctx_create(svn_checksum_kind_t kind
,
260 svn_checksum_ctx_t
*ctx
= apr_palloc(pool
, sizeof(*ctx
));
265 case svn_checksum_md5
:
266 ctx
->apr_ctx
= apr_palloc(pool
, sizeof(apr_md5_ctx_t
));
267 apr_md5_init(ctx
->apr_ctx
);
270 case svn_checksum_sha1
:
271 ctx
->apr_ctx
= apr_palloc(pool
, sizeof(apr_sha1_ctx_t
));
272 apr_sha1_init(ctx
->apr_ctx
);
283 svn_checksum_update(svn_checksum_ctx_t
*ctx
,
289 case svn_checksum_md5
:
290 apr_md5_update(ctx
->apr_ctx
, data
, len
);
293 case svn_checksum_sha1
:
294 apr_sha1_update(ctx
->apr_ctx
, data
, len
);
298 /* We really shouldn't get here, but if we do... */
299 return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND
, NULL
, NULL
);
306 svn_checksum_final(svn_checksum_t
**checksum
,
307 const svn_checksum_ctx_t
*ctx
,
310 *checksum
= svn_checksum_create(ctx
->kind
, pool
);
314 case svn_checksum_md5
:
315 apr_md5_final((unsigned char *)(*checksum
)->digest
, ctx
->apr_ctx
);
318 case svn_checksum_sha1
:
319 apr_sha1_final((unsigned char *)(*checksum
)->digest
, ctx
->apr_ctx
);
323 /* We really shouldn't get here, but if we do... */
324 return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND
, NULL
, NULL
);
331 svn_checksum_size(const svn_checksum_t
*checksum
)
333 return DIGESTSIZE(checksum
->kind
);