Beispiel #1
0
C4Err TestHashKAT(
            int                 algor,
            char				*name,
            uint8_t				*msg,
            size_t				msgsize,
            int                 passes,
            uint8_t *              expected,
            size_t              expectedLen)

{
    uint8_t        hashBuf [256];
    
    uint8_t        hashState [kHASH_ContextAllocSize];
    size_t         hashStateLen = 0;
    
    C4Err err = kC4Err_NoErr;
    
    int i;
    
    HASH_ContextRef hash = kInvalidHASH_ContextRef;
    
    err = HASH_Init(algor, &hash);
    
    err = HASH_Export(hash, hashState, sizeof(hashState), &hashStateLen);
    HASH_Free(hash); hash = NULL;
    err = HASH_Import(hashState, hashStateLen, &hash); CKERR;
    ZERO(hashState, sizeof(hashState));
    
    /* calculate the hash..  */
    for (i = 0; i < passes; i++)
    {
        err = HASH_Update( hash, msg, msgsize); CKERR;
        
        err = HASH_Export(hash, hashState, sizeof(hashState), &hashStateLen);
        HASH_Free(hash); hash = NULL;
        err = HASH_Import(hashState, hashStateLen, &hash); CKERR;
        ZERO(hashState, sizeof(hashState));
        
    }
    
    err = HASH_Final (hash, hashBuf); CKERR;
    
    err = ( compareResults( expected, hashBuf, expectedLen , kResultFormat_Byte, "Message Digest")); CKERR;
    
    
    /* quick HASH API */
    if(passes == 1)
    {
        err = HASH_DO(algor, msg, msgsize, sizeof(hashBuf), hashBuf); CKERR;
        err = ( compareResults( expected, hashBuf, expectedLen , kResultFormat_Byte, "Quick HASH")); CKERR;
    }
    
    
done:
    
    if( HASH_ContextRefIsValid(hash))
        HASH_Free(hash);
    
    return err;
}
/**
 * @brief  Compute the HASH SHA1 digest.
 * @param  Input: pointer to the Input buffer to be treated.
 * @param  Ilen: length of the Input buffer.
 * @param  Output: the returned digest
 * @retval An ErrorStatus enumeration value:
 *          - SUCCESS: digest computation done
 *          - ERROR: digest computation failed
 */
ErrorStatus HASH_SHA1(uint8_t *Input, uint32_t Ilen, uint8_t Output[20]) {
    HASH_InitTypeDef SHA1_HASH_InitStructure;
    HASH_MsgDigest SHA1_MessageDigest;
    __IO uint16_t nbvalidbitsdata = 0;
    uint32_t i = 0;
    __IO uint32_t counter = 0;
    uint32_t busystatus = 0;
    ErrorStatus status = SUCCESS;
    uint32_t inputaddr = (uint32_t) Input;
    uint32_t outputaddr = (uint32_t) Output;

    /* Number of valid bits in last word of the Input data */
    nbvalidbitsdata = 8 * (Ilen % 4);

    /* HASH peripheral initialization */
    HASH_DeInit();

    /* HASH Configuration */
    SHA1_HASH_InitStructure.HASH_AlgoSelection = HASH_AlgoSelection_SHA1;
    SHA1_HASH_InitStructure.HASH_AlgoMode = HASH_AlgoMode_HASH;
    SHA1_HASH_InitStructure.HASH_DataType = HASH_DataType_8b;
    HASH_Init(&SHA1_HASH_InitStructure);

    /* Configure the number of valid bits in last word of the data */
    HASH_SetLastWordValidBitsNbr(nbvalidbitsdata);

    /* Write the Input block in the IN FIFO */
    for (i = 0; i < Ilen; i += 4) {
        HASH_DataIn(*(uint32_t*) inputaddr);
        inputaddr += 4;
    }

    /* Start the HASH processor */
    HASH_StartDigest();

    /* wait until the Busy flag is RESET */
    do {
        busystatus = HASH_GetFlagStatus(HASH_FLAG_BUSY);
        counter++;
    } while ((counter != SHA1BUSY_TIMEOUT) && (busystatus != RESET));

    if (busystatus != RESET) {
        status = ERROR;
    } else {
        /* Read the message digest */
        HASH_GetDigest(&SHA1_MessageDigest);
        *(uint32_t*) (outputaddr) = __REV(SHA1_MessageDigest.Data[0]);
        outputaddr += 4;
        *(uint32_t*) (outputaddr) = __REV(SHA1_MessageDigest.Data[1]);
        outputaddr += 4;
        *(uint32_t*) (outputaddr) = __REV(SHA1_MessageDigest.Data[2]);
        outputaddr += 4;
        *(uint32_t*) (outputaddr) = __REV(SHA1_MessageDigest.Data[3]);
        outputaddr += 4;
        *(uint32_t*) (outputaddr) = __REV(SHA1_MessageDigest.Data[4]);
    }
    return status;
}
Beispiel #3
0
/**
 * Creates MidpSession for the specified XRPC client id. Invoked on the XRPC
 * thread under synchronization.
 */
STATIC MidpSession* GWENG_MidpCreateSession(EcmtGateway* gw, int xrpcSid)
{
    MidpSession* ses = MEM_New(MidpSession);
    if (ses) {
        LUID luid;
        /* Just in case if AllocateLocallyUniqueId fails... */
        luid.LowPart = (DWORD)ses;
        AllocateLocallyUniqueId(&luid);
        memset(ses, 0, sizeof(*ses));
        ses->key.xrpcSid = xrpcSid;
        ses->key.xrpcSession = XRPC_GetCurrentSession(gw->xrpc);
        ses->sid = luid.LowPart;
        ASSERT(!HASH_Contains(&gw->ecmtSessionMap,(HashKey)ses->sid));
        ASSERT(!HASH_Contains(&gw->midpSessionMap,&ses->key));
        if (HASH_Init(&ses->connMap, 1, NULL, NULL, hashFreeValueProc)) {
            /* Create context for the control connection (number zero) */
            MidpConnection* conn = MEM_New(MidpConnection);
            if (conn) {
                memset(conn, 0, sizeof(*conn));
                if (HASH_Put(&ses->connMap, (HashKey)0, conn)) {
                    if (HASH_Put(&gw->ecmtSessionMap,(HashKey)ses->sid,ses)) {
                        if (HASH_Put(&gw->midpSessionMap, &ses->key, ses)) {
                            if (MUTEX_Init(&ses->xrpcMutex)) {
                                ses->xrpcWorkThread = WKQ_Create();
                                if (ses->xrpcWorkThread) {
                                    ses->xrpcWorkItem = WKI_Create(
                                        ses->xrpcWorkThread, GWENG_AsyncXRpc,
                                        ses);
                                    if (ses->xrpcWorkItem) {
                                        QUEUE_Init(&ses->xrpcQueue);
                                        TRACE3("GW: new session %08x for "
                                            "%08x.%08x\n", ses->sid,
                                            ses->key.xrpcSession,
                                            ses->key.xrpcSid);
                                        return ses;
                                    }
                                    WKQ_Delete(ses->xrpcWorkThread);
                                }
                                MUTEX_Destroy(&ses->xrpcMutex);
                            }
                            HASH_Remove(&gw->midpSessionMap, &ses->key);
                        }
                        HASH_Remove(&gw->ecmtSessionMap, (HashKey)ses->sid);
                    }
                } else {
                    MEM_Free(conn);
                }
            }
            HASH_Destroy(&ses->connMap);
        }
        MEM_Free(ses);
    }
    return NULL;
}
Beispiel #4
0
/**
  * @brief  HASH MD5 Digest computation (using DMA for data transfer) 
  * @note   DMA2 stream7 channel2 is used to transfer data from memory
  *         (MessageToHash[] array) to HASH Peripheral (the INPUT data register).
  * @param  None
  * @retval None
  */
static void HASH_MD5_DMA(void)
{
  HASH_InitTypeDef HASH_InitStructure;
  DMA_InitTypeDef DMA_InitStructure;

  /* HASH Configuration */
  HASH_InitStructure.HASH_AlgoSelection = HASH_AlgoSelection_MD5;
  HASH_InitStructure.HASH_AlgoMode = HASH_AlgoMode_HASH;
  HASH_InitStructure.HASH_DataType = HASH_DataType_8b;
  HASH_InitStructure.HASH_HMACKeyType = HASH_HMACKeyType_ShortKey;
  HASH_Init(&HASH_InitStructure);

  /*DMA Configuration*/
  DMA_DeInit(DMA2_Stream7);
  DMA_InitStructure.DMA_Channel = DMA_Channel_2;
  DMA_InitStructure.DMA_PeripheralBaseAddr = HASH_DIN_REG_ADDR;
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)MessageToHash;
  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
  DMA_InitStructure.DMA_BufferSize = SIZE_MSG_TO_HASH_IN_WORDS;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

  /* Configure the DMA Stream */
  DMA_Init(DMA2_Stream7, &DMA_InitStructure);

  /* Enable HASH DMA */
  HASH_DMACmd(ENABLE);

  /* Enable DMA2 Transfer */
  DMA_Cmd(DMA2_Stream7, ENABLE);

  /* Note :  When the DMA is enabled, it provides the information to the hash 
             processor when it is transferring the last data word. Then the 
             padding and digest computation are performed automatically as if 
             DCAL had been written to 1.*/

  /* wait until DMA Transfer completed */
  while (DMA_GetFlagStatus(DMA2_Stream7, DMA_FLAG_TCIF7) == RESET);

  /* wait until the Busy flag is RESET */
  while (HASH_GetFlagStatus(HASH_FLAG_BUSY) != RESET);

  /* Get the MD5 Digest */
  HASH_GetDigest(&MsgDigest);
}
Beispiel #5
0
//*****************************************************************************
//! Board Initialization & Configuration
//*****************************************************************************
static void bootmgr_board_init(void) {
    // Set vector table base
    MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]);

    // Enable Processor Interrupts
    MAP_IntMasterEnable();
    MAP_IntEnable(FAULT_SYSTICK);

    // Mandatory MCU Initialization
    PRCMCC3200MCUInit();

    mperror_bootloader_check_reset_cause();

    // Enable the Data Hashing Engine
    HASH_Init();

    // Init the system led and the system switch
    mperror_init0();

    // clear the safe boot flag, since we can't trust its content after reset
    PRCMClearSafeBootRequest();
}
Beispiel #6
0
//*****************************************************************************
//! Board Initialization & Configuration
//*****************************************************************************
static void bootmgr_board_init(void) {
    // Set vector table base
    MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]);

    // Enable Processor Interrupts
    MAP_IntMasterEnable();
    MAP_IntEnable(FAULT_SYSTICK);

    // Mandatory MCU Initialization
    PRCMCC3200MCUInit();

    pybwdt_check_reset_cause();

    // Enable the Data Hashing Engine
    HASH_Init();

    // Init the system led and the system switch
    mperror_init0();

    // clear the safe boot request, since we should not trust
    // the register's state after reset
    mperror_clear_safe_boot();
}
Beispiel #7
0
C4Err ECC_PubKeyHash( ECC_ContextRef  ctx, void *outData, size_t bufSize, size_t *outDataLen)
{
    C4Err  err = kC4Err_NoErr;
    HASH_ContextRef hash = kInvalidHASH_ContextRef;
     uint8_t         pubKey[256];
    size_t          pubKeyLen = 0;
    
    u08b_t          hashBuf[16];
    size_t          hashBytes = 0;
   
    validateECCContext(ctx);
    ValidateParam(ctx->isInited);
    ValidateParam(outData);
    
    err  = HASH_Init(kHASH_Algorithm_SHA256, &hash); CKERR;
    err =  ECC_Export_ANSI_X963( ctx, pubKey, sizeof(pubKey), &pubKeyLen);CKERR;
    
    err  = HASH_Update(hash, pubKey, pubKeyLen) ;CKERR;
    
    err = HASH_Final(hash,hashBuf);
    
    err = HASH_GetSize(hash, &hashBytes);
    
    hashBytes = bufSize < hashBytes ? bufSize :hashBytes;
    
    memcpy( outData,hashBuf, hashBytes);
   
    if(outDataLen)
        *outDataLen = hashBytes;
    
done:
    
    if(HASH_ContextRefIsValid(hash))
        HASH_Free(hash);

    return err;
}
Beispiel #8
0
/**
  * @brief  Compute the HMAC MD5 digest.
  * @param  Key: pointer to the Key used for HMAC.
  * @param  Keylen: length of the Key used for HMAC.
  * @param  Input: pointer to the Input buffer to be treated.
  * @param  Ilen: length of the Input buffer.
  * @param  Output: the returned digest  
  * @retval An ErrorStatus enumeration value:
  *          - SUCCESS: digest computation done
  *          - ERROR: digest computation failed
  */
ErrorStatus HMAC_MD5(uint8_t *Key, uint32_t Keylen, uint8_t *Input, 
                     uint32_t Ilen, uint8_t Output[16])
{
  HASH_InitTypeDef MD5_HASH_InitStructure;
  HASH_MsgDigest MD5_MessageDigest;
  __IO uint16_t nbvalidbitsdata = 0;
  __IO uint16_t nbvalidbitskey = 0;
  uint32_t i = 0;
  __IO uint32_t counter = 0;
  uint32_t busystatus = 0;
  ErrorStatus status = SUCCESS;
  uint32_t keyaddr    = (uint32_t)Key;
  uint32_t inputaddr  = (uint32_t)Input;
  uint32_t outputaddr = (uint32_t)Output;

  /* Number of valid bits in last word of the Input data */
  nbvalidbitsdata = 8 * (Ilen % 4);

  /* Number of valid bits in last word of the Key */
  nbvalidbitskey = 8 * (Keylen % 4);
   
  /* HASH peripheral initialization */
  HASH_DeInit();

  /* HASH Configuration */
  MD5_HASH_InitStructure.HASH_AlgoSelection = HASH_AlgoSelection_MD5;
  MD5_HASH_InitStructure.HASH_AlgoMode = HASH_AlgoMode_HMAC;
  MD5_HASH_InitStructure.HASH_DataType = HASH_DataType_8b;
  if(Keylen > 64)
  {
    /* HMAC long Key */
    MD5_HASH_InitStructure.HASH_HMACKeyType = HASH_HMACKeyType_LongKey;
  }
  else
  {
    /* HMAC short Key */
    MD5_HASH_InitStructure.HASH_HMACKeyType = HASH_HMACKeyType_ShortKey;
  }
  HASH_Init(&MD5_HASH_InitStructure);

  /* Configure the number of valid bits in last word of the Key */
  HASH_SetLastWordValidBitsNbr(nbvalidbitskey);

  /* Write the Key */
  for(i=0; i<Keylen; i+=4)
  {
    HASH_DataIn(*(uint32_t*)keyaddr);
    keyaddr+=4;
  }
  
  /* Start the HASH processor */
  HASH_StartDigest();

  /* wait until the Busy flag is RESET */
  do
  {
    busystatus = HASH_GetFlagStatus(HASH_FLAG_BUSY);
    counter++;
  }while ((counter != MD5BUSY_TIMEOUT) && (busystatus != RESET));

  if (busystatus != RESET)
  {
     status = ERROR;
  }
  else
  {
    /* Configure the number of valid bits in last word of the Input data */
    HASH_SetLastWordValidBitsNbr(nbvalidbitsdata);

    /* Write the Input block in the IN FIFO */
    for(i=0; i<Ilen; i+=4)
    {
      HASH_DataIn(*(uint32_t*)inputaddr);
      inputaddr+=4;
    }

    /* Start the HASH processor */
    HASH_StartDigest();

    /* wait until the Busy flag is RESET */
    counter =0;
    do
    {
       busystatus = HASH_GetFlagStatus(HASH_FLAG_BUSY);
       counter++;
    }while ((counter != MD5BUSY_TIMEOUT) && (busystatus != RESET));

    if (busystatus != RESET)
    {
      status = ERROR;
    }
    else
    {  
      /* Configure the number of valid bits in last word of the Key */
      HASH_SetLastWordValidBitsNbr(nbvalidbitskey);

      /* Write the Key */
      keyaddr = (uint32_t)Key;
      for(i=0; i<Keylen; i+=4)
      {
        HASH_DataIn(*(uint32_t*)keyaddr);
        keyaddr+=4;
      }
  
       /* Start the HASH processor */
       HASH_StartDigest();

       /* wait until the Busy flag is RESET */
       counter =0;
       do
       {
          busystatus = HASH_GetFlagStatus(HASH_FLAG_BUSY);
          counter++;
      }while ((counter != MD5BUSY_TIMEOUT) && (busystatus != RESET));

      if (busystatus != RESET)
      {
         status = ERROR;
      }
      else
      {
         /* Read the message digest */
         HASH_GetDigest(&MD5_MessageDigest);
         *(uint32_t*)(outputaddr)  = __REV(MD5_MessageDigest.Data[0]);
         outputaddr+=4;
         *(uint32_t*)(outputaddr)  = __REV(MD5_MessageDigest.Data[1]);
         outputaddr+=4;
         *(uint32_t*)(outputaddr)  = __REV(MD5_MessageDigest.Data[2]);
         outputaddr+=4;
         *(uint32_t*)(outputaddr)  = __REV(MD5_MessageDigest.Data[3]);
      }
    }
  }
  return status;  
}
Beispiel #9
0
int main(int argc, char *argv[]) // returns 1 if an error occurs, 0 otherwise
{
    int error_code=0;
    board_t position;
    move_t moves[4];
    int i;
    int steps=0;
    
    BOARD_Message_Init();
    if (argc<2)
    {
        sprintf(message,"Program requires an argument (name of file containing position).\n");
        BOARD_Message();
        error_code=1;
    }
    {
        srand(0);
        HASH_Init();
        #ifdef TESTING
        {
            HASH_Set_Size(32*1024*1024);
        }
        #else
        {
            HASH_Set_Size(512*1024*1024);
        }
        #endif
        BOARD_Init(&position);
        if (BOARD_Read_Position(&position, argv[1]))
        {
            sprintf(message,"Couldn't read position from file.\n");
            BOARD_Message();
            error_code=1;
        } else
        {
            if (position.move==0)
            {
                printf("Ra1 Rb1 Rc1 Rd1 Re1 Rf1 Rg1 Rh1 Ha2 Db2 Cc2 Md2 Ee2 Cf2 Dg2 Hh2\n");
            } else if (position.move==1) 
            {
                if ((position.board[75] & PIECE_MASK)==ELEPHANT_PIECE)
                {
                    printf("ra8 rb8 rc8 rd8 re8 rf8 rg8 rh8 ha7 db7 cc7 ed7 me7 cf7 dg7 hh7\n");
                } else
                {
                    printf("ra8 rb8 rc8 rd8 re8 rf8 rg8 rh8 ha7 db7 cc7 md7 ee7 cf7 dg7 hh7\n");
                }
            } else
            {
                position.steps=0;
                BOARD_Calculate_Hashkey(&position);
                EVAL_Eval(&position,TRUE);
                SEARCH_Start_Search(&position,moves,NULL);
                for (i=0; steps<4; i++)
                {
                    BOARD_Send_Move(&moves[i]);
                    printf(" ");
                    steps+=moves[i].steps;
                }
                printf("\n");
            }
        }
    }
    BOARD_Message_Exit();
    return error_code;
}
Beispiel #10
0
C4Err HASH_DO(HASH_Algorithm algorithm, const unsigned char *in, unsigned long inlen, unsigned long outLen, uint8_t *out)
{
    
    C4Err             err         = kC4Err_NoErr;
    HASH_ContextRef     hashRef     = kInvalidHASH_ContextRef;
    uint8_t             hashBuf[128];
    uint8_t             *p = (outLen < sizeof(hashBuf))?hashBuf:out;
    
    
#if  _USES_COMMON_CRYPTO_
    
    /* use apple algorithms if possible*/
    switch(algorithm)
    {
        case kHASH_Algorithm_MD5:
            CC_MD5(in, (CC_LONG) inlen, hashBuf);
            goto complete;
            break;
            
        case  kHASH_Algorithm_SHA1:
            CC_SHA1(in, (CC_LONG) inlen, hashBuf);
            goto complete;
            break;
            
        case  kHASH_Algorithm_SHA224:
            CC_SHA224(in, (CC_LONG) inlen, hashBuf);
            goto complete;
            break;
            
        case  kHASH_Algorithm_SHA256:
            CC_SHA256(in, (CC_LONG) inlen, hashBuf);
            goto complete;
            break;
            
        case  kHASH_Algorithm_SHA384:
            CC_SHA384(in, (CC_LONG) inlen, hashBuf);
            goto complete;
            break;
            
        case  kHASH_Algorithm_SHA512:
            CC_SHA512(in, (CC_LONG) inlen, hashBuf);
            goto complete;
            break;
            
        default:
            break;
    }
    
#endif
    
    err = HASH_Init( algorithm, & hashRef); CKERR;
    err = HASH_Update( hashRef, in,  inlen); CKERR;
    err = HASH_Final( hashRef, p); CKERR;
    
complete:
    if((err == kC4Err_NoErr) & (p!= out))
        COPY(hashBuf, out, outLen);
    
done:
    if(!IsNull(hashRef))
        HASH_Free(hashRef);
    
    return err;
}
Beispiel #11
0
SCLError  Siren_ComputeHash(    HASH_Algorithm  hash,
                            const char*         sirenData,
                            uint8_t*            hashOut,
                            bool                sorted)
{
    SCLError        err = kSCLError_NoErr;
    
    yajl_gen_status         stat = yajl_gen_status_ok;
    yajl_handle             pHand = NULL;
    SirenJSONcontext       *jctx = NULL;
    
    static yajl_callbacks callbacks = {
        NULL,
        sParse_bool,
        NULL,
        NULL,
        sParse_number,
        sParse_string,
        sParse_start_map,
        sParse_map_key,
        sParse_end_map,
        NULL,
        NULL
    };
    
    yajl_alloc_funcs allocFuncs = {
        yajlMalloc,
        yajlRealloc,
        yajlFree,
        (void *) NULL
    };
    
    
    jctx = XMALLOC(sizeof (SirenJSONcontext)); CKNULL(jctx);
    ZERO(jctx, sizeof(SirenJSONcontext));
    err  = HASH_Init(hash, &jctx->hash); CKERR;
    
    // use yajl to fill the hashableItems with tags and values we can hash
    pHand = yajl_alloc(&callbacks, &allocFuncs, (void *) jctx);
    yajl_config(pHand, yajl_allow_comments, 1);
    stat = (yajl_gen_status) yajl_parse(pHand, (uint8_t*)sirenData,  strlen(sirenData)); CKSTAT;
    stat = (yajl_gen_status) yajl_complete_parse(pHand); CKSTAT;
    
    
    // hash the items found in hashableItems using sHashable_tags_list order
    int items2Hash = jctx->hashableItemsCount;
    
#if DEBUG_HASH
    DPRINTF(XCODE_COLORS_RED_TXT,"\nSiren_ComputeHash %s\n",  sorted?"sorted":""  );
#endif
    
    if(sorted)
    {
        for(int j = 0; sHashable_tags_list[j] && items2Hash > 0; j++)
        {
            for(int i = 0; i < jctx->hashableItemsCount; i++)
            {
                char* tag = sHashable_tags_list[j];
                HashableItem *item = &jctx->hashableItems[i];
                
                if(item->tag && strncmp(tag, item->tag, strlen(tag)) == 0 )
                {
                    err = shashItem(jctx->hash, item);
                    items2Hash--;
                    break;
                }
            }
        }
    }
    else
    {
        for(int i = 0; i < items2Hash; i++)
        {
            HashableItem *item = &jctx->hashableItems[i];
            
            if(item->tag)
            {
                err = shashItem(jctx->hash, item);
            }
        }
        
    }
    
    err = HASH_Final(jctx->hash, hashOut); CKERR;
    
#if DEBUG_HASH
    DPRINTF(XCODE_COLORS_RED_TXT,"\n");
    dumpHex(hashOut,  32, 0);
    DPRINTF(XCODE_COLORS_RED_TXT,"\n");
#endif
    
done:
    
    if(IsntNull(jctx))
    {
        ZERO(jctx, sizeof(SirenJSONcontext));
        XFREE(jctx);
    }
    
    if(IsntNull(pHand))
        yajl_free(pHand);
    
    return err;
    
}