| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| #include "sechash.h" |
| #include "secoidt.h" |
| #include "secerr.h" |
| #include "blapi.h" |
| #include "pk11func.h" /* for the PK11_ calls below. */ |
| |
| static void * |
| null_hash_new_context(void) |
| { |
| return NULL; |
| } |
| |
| static void * |
| null_hash_clone_context(void *v) |
| { |
| PORT_Assert(v == NULL); |
| return NULL; |
| } |
| |
| static void |
| null_hash_begin(void *v) |
| { |
| } |
| |
| static void |
| null_hash_update(void *v, const unsigned char *input, unsigned int length) |
| { |
| } |
| |
| static void |
| null_hash_end(void *v, unsigned char *output, unsigned int *outLen, |
| unsigned int maxOut) |
| { |
| *outLen = 0; |
| } |
| |
| static void |
| null_hash_destroy_context(void *v, PRBool b) |
| { |
| PORT_Assert(v == NULL); |
| } |
| |
| static void * |
| md2_NewContext(void) |
| { |
| return (void *)PK11_CreateDigestContext(SEC_OID_MD2); |
| } |
| |
| static void * |
| md5_NewContext(void) |
| { |
| return (void *)PK11_CreateDigestContext(SEC_OID_MD5); |
| } |
| |
| static void * |
| sha1_NewContext(void) |
| { |
| return (void *)PK11_CreateDigestContext(SEC_OID_SHA1); |
| } |
| |
| static void * |
| sha224_NewContext(void) |
| { |
| return (void *)PK11_CreateDigestContext(SEC_OID_SHA224); |
| } |
| |
| static void * |
| sha256_NewContext(void) |
| { |
| return (void *)PK11_CreateDigestContext(SEC_OID_SHA256); |
| } |
| |
| static void * |
| sha384_NewContext(void) |
| { |
| return (void *)PK11_CreateDigestContext(SEC_OID_SHA384); |
| } |
| |
| static void * |
| sha512_NewContext(void) |
| { |
| return (void *)PK11_CreateDigestContext(SEC_OID_SHA512); |
| } |
| |
| const SECHashObject SECHashObjects[] = { |
| { 0, |
| (void *(*)(void))null_hash_new_context, |
| (void *(*)(void *))null_hash_clone_context, |
| (void (*)(void *, PRBool))null_hash_destroy_context, |
| (void (*)(void *))null_hash_begin, |
| (void (*)(void *, const unsigned char *, unsigned int))null_hash_update, |
| (void (*)(void *, unsigned char *, unsigned int *, |
| unsigned int))null_hash_end, |
| 0, |
| HASH_AlgNULL }, |
| { MD2_LENGTH, |
| (void *(*)(void))md2_NewContext, |
| (void *(*)(void *))PK11_CloneContext, |
| (void (*)(void *, PRBool))PK11_DestroyContext, |
| (void (*)(void *))PK11_DigestBegin, |
| (void (*)(void *, const unsigned char *, unsigned int))PK11_DigestOp, |
| (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) |
| PK11_DigestFinal, |
| MD2_BLOCK_LENGTH, |
| HASH_AlgMD2 }, |
| { MD5_LENGTH, |
| (void *(*)(void))md5_NewContext, |
| (void *(*)(void *))PK11_CloneContext, |
| (void (*)(void *, PRBool))PK11_DestroyContext, |
| (void (*)(void *))PK11_DigestBegin, |
| (void (*)(void *, const unsigned char *, unsigned int))PK11_DigestOp, |
| (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) |
| PK11_DigestFinal, |
| MD5_BLOCK_LENGTH, |
| HASH_AlgMD5 }, |
| { SHA1_LENGTH, |
| (void *(*)(void))sha1_NewContext, |
| (void *(*)(void *))PK11_CloneContext, |
| (void (*)(void *, PRBool))PK11_DestroyContext, |
| (void (*)(void *))PK11_DigestBegin, |
| (void (*)(void *, const unsigned char *, unsigned int))PK11_DigestOp, |
| (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) |
| PK11_DigestFinal, |
| SHA1_BLOCK_LENGTH, |
| HASH_AlgSHA1 }, |
| { SHA256_LENGTH, |
| (void *(*)(void))sha256_NewContext, |
| (void *(*)(void *))PK11_CloneContext, |
| (void (*)(void *, PRBool))PK11_DestroyContext, |
| (void (*)(void *))PK11_DigestBegin, |
| (void (*)(void *, const unsigned char *, unsigned int))PK11_DigestOp, |
| (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) |
| PK11_DigestFinal, |
| SHA256_BLOCK_LENGTH, |
| HASH_AlgSHA256 }, |
| { SHA384_LENGTH, |
| (void *(*)(void))sha384_NewContext, |
| (void *(*)(void *))PK11_CloneContext, |
| (void (*)(void *, PRBool))PK11_DestroyContext, |
| (void (*)(void *))PK11_DigestBegin, |
| (void (*)(void *, const unsigned char *, unsigned int))PK11_DigestOp, |
| (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) |
| PK11_DigestFinal, |
| SHA384_BLOCK_LENGTH, |
| HASH_AlgSHA384 }, |
| { SHA512_LENGTH, |
| (void *(*)(void))sha512_NewContext, |
| (void *(*)(void *))PK11_CloneContext, |
| (void (*)(void *, PRBool))PK11_DestroyContext, |
| (void (*)(void *))PK11_DigestBegin, |
| (void (*)(void *, const unsigned char *, unsigned int))PK11_DigestOp, |
| (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) |
| PK11_DigestFinal, |
| SHA512_BLOCK_LENGTH, |
| HASH_AlgSHA512 }, |
| { SHA224_LENGTH, |
| (void *(*)(void))sha224_NewContext, |
| (void *(*)(void *))PK11_CloneContext, |
| (void (*)(void *, PRBool))PK11_DestroyContext, |
| (void (*)(void *))PK11_DigestBegin, |
| (void (*)(void *, const unsigned char *, unsigned int))PK11_DigestOp, |
| (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) |
| PK11_DigestFinal, |
| SHA224_BLOCK_LENGTH, |
| HASH_AlgSHA224 }, |
| }; |
| |
| const SECHashObject * |
| HASH_GetHashObject(HASH_HashType type) |
| { |
| return &SECHashObjects[type]; |
| } |
| |
| HASH_HashType |
| HASH_GetHashTypeByOidTag(SECOidTag hashOid) |
| { |
| HASH_HashType ht = HASH_AlgNULL; |
| |
| switch (hashOid) { |
| case SEC_OID_MD2: |
| ht = HASH_AlgMD2; |
| break; |
| case SEC_OID_MD5: |
| ht = HASH_AlgMD5; |
| break; |
| case SEC_OID_SHA1: |
| ht = HASH_AlgSHA1; |
| break; |
| case SEC_OID_SHA224: |
| ht = HASH_AlgSHA224; |
| break; |
| case SEC_OID_SHA256: |
| ht = HASH_AlgSHA256; |
| break; |
| case SEC_OID_SHA384: |
| ht = HASH_AlgSHA384; |
| break; |
| case SEC_OID_SHA512: |
| ht = HASH_AlgSHA512; |
| break; |
| default: |
| PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
| break; |
| } |
| return ht; |
| } |
| |
| SECOidTag |
| HASH_GetHashOidTagByHashType(HASH_HashType type) |
| { |
| SECOidTag oid = SEC_OID_UNKNOWN; |
| |
| switch (type) { |
| case HASH_AlgMD2: |
| oid = SEC_OID_MD2; |
| break; |
| case HASH_AlgMD5: |
| oid = SEC_OID_MD5; |
| break; |
| case HASH_AlgSHA1: |
| oid = SEC_OID_SHA1; |
| break; |
| case HASH_AlgSHA224: |
| oid = SEC_OID_SHA224; |
| break; |
| case HASH_AlgSHA256: |
| oid = SEC_OID_SHA256; |
| break; |
| case HASH_AlgSHA384: |
| oid = SEC_OID_SHA384; |
| break; |
| case HASH_AlgSHA512: |
| oid = SEC_OID_SHA512; |
| break; |
| default: |
| PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
| break; |
| } |
| return oid; |
| } |
| |
| SECOidTag |
| HASH_GetHashOidTagByHMACOidTag(SECOidTag hmacOid) |
| { |
| SECOidTag hashOid = SEC_OID_UNKNOWN; |
| |
| switch (hmacOid) { |
| /* no oid exists for HMAC_MD2 */ |
| /* NSS does not define a oid for HMAC_MD4 */ |
| case SEC_OID_HMAC_SHA1: |
| hashOid = SEC_OID_SHA1; |
| break; |
| case SEC_OID_HMAC_SHA224: |
| hashOid = SEC_OID_SHA224; |
| break; |
| case SEC_OID_HMAC_SHA256: |
| hashOid = SEC_OID_SHA256; |
| break; |
| case SEC_OID_HMAC_SHA384: |
| hashOid = SEC_OID_SHA384; |
| break; |
| case SEC_OID_HMAC_SHA512: |
| hashOid = SEC_OID_SHA512; |
| break; |
| default: |
| hashOid = SEC_OID_UNKNOWN; |
| PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
| break; |
| } |
| return hashOid; |
| } |
| |
| SECOidTag |
| HASH_GetHMACOidTagByHashOidTag(SECOidTag hashOid) |
| { |
| SECOidTag hmacOid = SEC_OID_UNKNOWN; |
| |
| switch (hashOid) { |
| /* no oid exists for HMAC_MD2 */ |
| /* NSS does not define a oid for HMAC_MD4 */ |
| case SEC_OID_SHA1: |
| hmacOid = SEC_OID_HMAC_SHA1; |
| break; |
| case SEC_OID_SHA224: |
| hmacOid = SEC_OID_HMAC_SHA224; |
| break; |
| case SEC_OID_SHA256: |
| hmacOid = SEC_OID_HMAC_SHA256; |
| break; |
| case SEC_OID_SHA384: |
| hmacOid = SEC_OID_HMAC_SHA384; |
| break; |
| case SEC_OID_SHA512: |
| hmacOid = SEC_OID_HMAC_SHA512; |
| break; |
| default: |
| hmacOid = SEC_OID_UNKNOWN; |
| PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
| break; |
| } |
| return hmacOid; |
| } |
| |
| const SECHashObject * |
| HASH_GetHashObjectByOidTag(SECOidTag hashOid) |
| { |
| HASH_HashType ht = HASH_GetHashTypeByOidTag(hashOid); |
| |
| return (ht == HASH_AlgNULL) ? NULL : &SECHashObjects[ht]; |
| } |
| |
| /* returns zero for unknown hash OID */ |
| unsigned int |
| HASH_ResultLenByOidTag(SECOidTag hashOid) |
| { |
| const SECHashObject *hashObject = HASH_GetHashObjectByOidTag(hashOid); |
| unsigned int resultLen = 0; |
| |
| if (hashObject) |
| resultLen = hashObject->length; |
| return resultLen; |
| } |
| |
| /* returns zero if hash type invalid. */ |
| unsigned int |
| HASH_ResultLen(HASH_HashType type) |
| { |
| if ((type < HASH_AlgNULL) || (type >= HASH_AlgTOTAL)) { |
| PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
| return (0); |
| } |
| |
| return (SECHashObjects[type].length); |
| } |
| |
| unsigned int |
| HASH_ResultLenContext(HASHContext *context) |
| { |
| return (context->hashobj->length); |
| } |
| |
| SECStatus |
| HASH_HashBuf(HASH_HashType type, |
| unsigned char *dest, |
| const unsigned char *src, |
| PRUint32 src_len) |
| { |
| HASHContext *cx; |
| unsigned int part; |
| |
| if ((type < HASH_AlgNULL) || (type >= HASH_AlgTOTAL)) { |
| return (SECFailure); |
| } |
| |
| cx = HASH_Create(type); |
| if (cx == NULL) { |
| return (SECFailure); |
| } |
| HASH_Begin(cx); |
| HASH_Update(cx, src, src_len); |
| HASH_End(cx, dest, &part, HASH_ResultLenContext(cx)); |
| HASH_Destroy(cx); |
| |
| return (SECSuccess); |
| } |
| |
| HASHContext * |
| HASH_Create(HASH_HashType type) |
| { |
| void *hash_context = NULL; |
| HASHContext *ret = NULL; |
| |
| if ((type < HASH_AlgNULL) || (type >= HASH_AlgTOTAL)) { |
| return (NULL); |
| } |
| |
| hash_context = (*SECHashObjects[type].create)(); |
| if (hash_context == NULL) { |
| goto loser; |
| } |
| |
| ret = (HASHContext *)PORT_Alloc(sizeof(HASHContext)); |
| if (ret == NULL) { |
| goto loser; |
| } |
| |
| ret->hash_context = hash_context; |
| ret->hashobj = &SECHashObjects[type]; |
| |
| return (ret); |
| |
| loser: |
| if (hash_context != NULL) { |
| (*SECHashObjects[type].destroy)(hash_context, PR_TRUE); |
| } |
| |
| return (NULL); |
| } |
| |
| HASHContext * |
| HASH_Clone(HASHContext *context) |
| { |
| void *hash_context = NULL; |
| HASHContext *ret = NULL; |
| |
| hash_context = (*context->hashobj->clone)(context->hash_context); |
| if (hash_context == NULL) { |
| goto loser; |
| } |
| |
| ret = (HASHContext *)PORT_Alloc(sizeof(HASHContext)); |
| if (ret == NULL) { |
| goto loser; |
| } |
| |
| ret->hash_context = hash_context; |
| ret->hashobj = context->hashobj; |
| |
| return (ret); |
| |
| loser: |
| if (hash_context != NULL) { |
| (*context->hashobj->destroy)(hash_context, PR_TRUE); |
| } |
| |
| return (NULL); |
| } |
| |
| void |
| HASH_Destroy(HASHContext *context) |
| { |
| (*context->hashobj->destroy)(context->hash_context, PR_TRUE); |
| PORT_Free(context); |
| return; |
| } |
| |
| void |
| HASH_Begin(HASHContext *context) |
| { |
| (*context->hashobj->begin)(context->hash_context); |
| return; |
| } |
| |
| void |
| HASH_Update(HASHContext *context, |
| const unsigned char *src, |
| unsigned int len) |
| { |
| (*context->hashobj->update)(context->hash_context, src, len); |
| return; |
| } |
| |
| void |
| HASH_End(HASHContext *context, |
| unsigned char *result, |
| unsigned int *result_len, |
| unsigned int max_result_len) |
| { |
| (*context->hashobj->end)(context->hash_context, result, result_len, |
| max_result_len); |
| return; |
| } |
| |
| HASH_HashType |
| HASH_GetType(HASHContext *context) |
| { |
| return (context->hashobj->type); |
| } |