apk-tools/src/crypto_digest.c

248 lines
4.8 KiB
C

#include <bearssl.h>
#include <sodium.h>
#include "apk_crypto.h"
// Union tag is in apk_digest_ctx->alg
union digest_state {
crypto_hash_sha256_state sha256;
crypto_hash_sha512_state sha512;
br_sha1_context sha1;
br_md5_context md5;
};
static const char *apk_digest_str[] = {
[APK_DIGEST_NONE] = "none",
[APK_DIGEST_MD5] = "md5",
[APK_DIGEST_SHA1] = "sha1",
[APK_DIGEST_SHA256_160] = "sha256-160",
[APK_DIGEST_SHA256] = "sha256",
[APK_DIGEST_SHA512] = "sha512",
};
const char *apk_digest_alg_str(uint8_t alg)
{
const char *alg_str = "unknown";
if (alg < ARRAY_SIZE(apk_digest_str))
alg_str = apk_digest_str[alg];
return alg_str;
}
int apk_digest_alg_len(uint8_t alg)
{
switch (alg) {
case APK_DIGEST_MD5:
return 16;
case APK_DIGEST_SHA1:
return 20;
case APK_DIGEST_SHA256_160:
return 20;
case APK_DIGEST_SHA256:
return 32;
case APK_DIGEST_SHA512:
return 64;
default:
return 0;
}
}
uint8_t apk_digest_alg_by_len(int len)
{
switch (len) {
case 0:
return APK_DIGEST_NONE;
case 16:
return APK_DIGEST_MD5;
case 20:
return APK_DIGEST_SHA1;
case 32:
return APK_DIGEST_SHA256;
case 64:
return APK_DIGEST_SHA512;
default:
return APK_DIGEST_NONE;
}
}
uint8_t apk_digest_alg_from_csum(int csum)
{
switch (csum) {
case APK_CHECKSUM_NONE:
return APK_DIGEST_NONE;
case APK_CHECKSUM_MD5:
return APK_DIGEST_MD5;
case APK_CHECKSUM_SHA1:
return APK_DIGEST_SHA1;
default:
return APK_DIGEST_NONE;
}
}
uint8_t apk_digest_from_blob(struct apk_digest *d, apk_blob_t b)
{
d->alg = apk_digest_alg_by_len(b.len);
d->len = 0;
if (d->alg != APK_DIGEST_NONE) {
d->len = b.len;
memcpy(d->data, b.ptr, d->len);
}
return d->alg;
}
int apk_digest_calc(struct apk_digest *d, uint8_t alg, const void *ptr, size_t sz)
{
union digest_state state;
switch (alg) {
case APK_DIGEST_SHA256:
case APK_DIGEST_SHA256_160:
crypto_hash_sha256(d->data, ptr, sz);
break;
case APK_DIGEST_SHA512:
crypto_hash_sha512(d->data, ptr, sz);
break;
case APK_DIGEST_NONE:
break;
case APK_DIGEST_MD5:
br_md5_init(&state.md5);
br_md5_update(&state.md5, ptr, sz);
br_md5_out(&state.md5, d->data);
break;
case APK_DIGEST_SHA1:
br_sha1_init(&state.sha1);
br_sha1_update(&state.sha1, ptr, sz);
br_sha1_out(&state.sha1, d->data);
break;
default:
return -APKE_CRYPTO_NOT_SUPPORTED;
}
d->alg = alg;
d->len = apk_digest_alg_len(d->alg);
return 0;
}
int apk_digest_ctx_init(struct apk_digest_ctx *dctx, uint8_t alg)
{
union digest_state *state;
dctx->impl = malloc(sizeof(union digest_state));
if (dctx->impl == NULL) {
return -ENOMEM;
}
state = (union digest_state *) dctx->impl;
dctx->alg = alg;
switch (alg) {
case APK_DIGEST_SHA256:
case APK_DIGEST_SHA256_160:
crypto_hash_sha256_init(&state->sha256);
break;
case APK_DIGEST_SHA512:
crypto_hash_sha512_init(&state->sha512);
break;
case APK_DIGEST_MD5:
br_md5_init(&state->md5);
break;
case APK_DIGEST_SHA1:
br_sha1_init(&state->sha1);
break;
case APK_DIGEST_NONE:
break;
default:
free(dctx->impl);
return -APKE_CRYPTO_NOT_SUPPORTED;
}
return 0;
}
int apk_digest_ctx_reset(struct apk_digest_ctx *dctx, uint8_t alg)
{
apk_digest_ctx_free(dctx);
return apk_digest_ctx_init(dctx, alg);
}
void apk_digest_ctx_free(struct apk_digest_ctx *dctx)
{
if (dctx->impl == NULL) {
return;
}
switch (dctx->alg) {
case APK_DIGEST_NONE:
case APK_DIGEST_MD5:
case APK_DIGEST_SHA1:
case APK_DIGEST_SHA256:
case APK_DIGEST_SHA512:
case APK_DIGEST_SHA256_160:
free(dctx->impl);
dctx->impl = NULL;
break;
default:
/* illegal state, don't touch impl? */
return;
}
}
int apk_digest_ctx_update(struct apk_digest_ctx *dctx, const void *ptr, size_t sz)
{
union digest_state *state = (union digest_state *) dctx->impl;
switch (dctx->alg) {
case APK_DIGEST_SHA256:
case APK_DIGEST_SHA256_160:
crypto_hash_sha256_update(&state->sha256, ptr, sz);
break;
case APK_DIGEST_SHA512:
crypto_hash_sha512_update(&state->sha512, ptr, sz);
break;
case APK_DIGEST_MD5:
br_md5_update(&state->md5, ptr, sz);
break;
case APK_DIGEST_SHA1:
br_sha1_update(&state->sha1, ptr, sz);
break;
case APK_DIGEST_NONE:
break;
default:
return -APKE_CRYPTO_NOT_SUPPORTED;
}
return 0;
}
int apk_digest_ctx_final(struct apk_digest_ctx *dctx, struct apk_digest *d)
{
union digest_state *state = (union digest_state *) dctx->impl;
switch (dctx->alg) {
case APK_DIGEST_SHA256:
case APK_DIGEST_SHA256_160:
crypto_hash_sha256_final(&state->sha256, d->data);
break;
case APK_DIGEST_SHA512:
crypto_hash_sha512_final(&state->sha512, d->data);
break;
case APK_DIGEST_MD5:
br_md5_out(&state->md5, d->data);
break;
case APK_DIGEST_SHA1:
br_sha1_out(&state->sha1, d->data);
break;
case APK_DIGEST_NONE:
break;
default:
return -APKE_CRYPTO_NOT_SUPPORTED;
}
d->alg = dctx->alg;
d->len = apk_digest_alg_len(d->alg);
return 0;
}