size_t ssh_digest_blocksize(struct ssh_digest_ctx *ctx) { const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); return digest == NULL ? 0 : digest->block_len; }
const char * ssh_digest_alg_name(int alg) { const struct ssh_digest *digest = ssh_digest_by_alg(alg); return digest == NULL ? NULL : digest->name; }
size_t ssh_digest_bytes(int alg) { const struct ssh_digest *digest = ssh_digest_by_alg(alg); return digest == NULL ? 0 : digest->digest_len; }
int ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen) { const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); if (digest == NULL) return SSH_ERR_INVALID_ARGUMENT; digest->md_update(ctx->mdctx, m, mlen); return 0; }
int ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to) { const struct ssh_digest *digest = ssh_digest_by_alg(from->alg); if (digest == NULL || from->alg != to->alg) return SSH_ERR_INVALID_ARGUMENT; memcpy(to->mdctx, from->mdctx, digest->ctx_len); return 0; }
int ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen) { const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); if (digest == NULL) return -1; digest->md_update(ctx->mdctx, m, mlen); return 0; }
int ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen) { const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); if (digest == NULL) return SSH_ERR_INVALID_ARGUMENT; if (dlen > UINT_MAX) return SSH_ERR_INVALID_ARGUMENT; if (dlen < digest->digest_len) /* No truncation allowed */ return SSH_ERR_INVALID_ARGUMENT; digest->md_final(d, ctx->mdctx); return 0; }
void ssh_digest_free(struct ssh_digest_ctx *ctx) { const struct ssh_digest *digest; if (ctx != NULL) { digest = ssh_digest_by_alg(ctx->alg); if (digest) { explicit_bzero(ctx->mdctx, digest->ctx_len); free(ctx->mdctx); explicit_bzero(ctx, sizeof(*ctx)); free(ctx); } } }
struct ssh_digest_ctx * ssh_digest_start(int alg) { const struct ssh_digest *digest = ssh_digest_by_alg(alg); struct ssh_digest_ctx *ret; if (digest == NULL || (ret = calloc(1, sizeof(*ret))) == NULL) return NULL; if ((ret->mdctx = calloc(1, digest->ctx_len)) == NULL) { free(ret); return NULL; } ret->alg = alg; digest->md_init(ret->mdctx); return ret; }
int ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen) { const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); u_int l = dlen; if (dlen > UINT_MAX) return SSH_ERR_INVALID_ARGUMENT; if (dlen < digest->digest_len) /* No truncation allowed */ return SSH_ERR_INVALID_ARGUMENT; if (EVP_DigestFinal_ex(&ctx->mdctx, d, &l) != 1) return SSH_ERR_LIBCRYPTO_ERROR; if (l != digest->digest_len) /* sanity */ return SSH_ERR_INTERNAL_ERROR; return 0; }
struct ssh_digest_ctx * ssh_digest_start(int alg) { const struct ssh_digest *digest = ssh_digest_by_alg(alg); struct ssh_digest_ctx *ret; if (digest == NULL || ((ret = calloc(1, sizeof(*ret))) == NULL)) return NULL; ret->alg = alg; EVP_MD_CTX_init(&ret->mdctx); if (EVP_DigestInit_ex(&ret->mdctx, digest->mdfunc(), NULL) != 1) { free(ret); return NULL; } return ret; }
int ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen) { const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); u_int l = dlen; if (dlen > UINT_MAX) return -1; if (dlen < digest->digest_len) /* No truncation allowed */ return -1; if (EVP_DigestFinal_ex(&ctx->mdctx, d, &l) != 1) return -1; if (l != digest->digest_len) /* sanity */ return -1; return 0; }
int ssh_digest_memory(int alg, const void *m, size_t mlen, u_char *d, size_t dlen) { const struct ssh_digest *digest = ssh_digest_by_alg(alg); u_int mdlen; if (digest == NULL) return SSH_ERR_INVALID_ARGUMENT; if (dlen > UINT_MAX) return SSH_ERR_INVALID_ARGUMENT; if (dlen < digest->digest_len) return SSH_ERR_INVALID_ARGUMENT; mdlen = dlen; if (!EVP_Digest(m, mlen, d, &mdlen, digest->mdfunc(), NULL)) return SSH_ERR_LIBCRYPTO_ERROR; return 0; }