| /* 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: ht = HASH_AlgNULL; |
| PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
| break; |
| } |
| return ht; |
| } |
| |
| 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); |
| } |