/****************************************************************************** * FILE: Authenticate.cpp * Description: * Implementation for MD5 arithmetic calculation's class. * * Modified Code History * Mark Date By Modification Reason ******************************************************************************* * 01 2007-8-28 Song-Xiaowen Initial creation. ******************************************************************************/ #include #include #include #include "MD5Calc.h" CMD5Calc::CMD5Calc() { } CMD5Calc::~CMD5Calc() { } /* ASC-II char mapped table */ #define CHAR_LIST_NUMBER 62 static const char CHAR_LIST_MAP[CHAR_LIST_NUMBER] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; /****************************************************************************** * Function: * Authentication MD5 algorithm encode. ******************************************************************************/ bool CMD5Calc::MD5Encode(const char *pSource, char target[DIGEST_MD5HEX_LEN+1]) { unsigned char tmpstr[256] = {0}; char ff[8] = {0}; MD5_CTX context; int i = 0; unsigned int len; int clen = 0; if ( (pSource == NULL) || (target == NULL) ) { return false; } strcpy( (char*)tmpstr, pSource); len = strlen( (char*)tmpstr); clen = len; MD5Init(&context); MD5Update(&context,tmpstr, len); MD5Final(tmpstr, &context); for(i=0; i<16; i++) { sprintf(ff, "%02x", tmpstr[i]); strcat(target, ff); } return true; } /************************************************************************ * The contents of the nonce are implementation dependent. The quality * of the implementation depends on a good choice. A nonce might, for * example, be constructed as the base 64 encoding of * * time-stamp H(time-stamp ":" ETag ":" private-key) * * where time-stamp is a server-generated time or other non-repeating * value, **************************************************************************/ void CMD5Calc::SIPGenerateNonce(char *pTarget, UINT32 timestamp, const char *pETag) { char source[256] = {0}; time_t t1; long l = 0; l = timestamp == 0 ? (long)time(&t1) : timestamp; sprintf(source, "%ld:%s:%s", l, ( (pETag == NULL) || (strlen(pETag) > 218) ) ? "" : pETag, SIP_PRIVATE_KEY); pTarget[0] = '\0'; MD5Encode(source, pTarget); sprintf(source, "%ld-%s", l, pTarget); strcpy(pTarget, source); } /****************************************************************************** * Function: * Check server's nonce expire. ******************************************************************************/ bool CMD5Calc::SIPCheckNonceExpire(const char *pszNonce, const char *pETag) { char pszTimeStr[16] ={0}; UINT32 nonceTime = 0; UINT32 currTime = 0; char *pszNonceMd5Str = NULL; time_t t1; char pszMd5Str[16+DIGEST_MD5HEX_LEN+1] = {0}; if ( (pszNonce == NULL) || (strlen(pszNonce) <= 0) || (pETag == NULL) || (strlen(pETag) <= 0) ) { return false; } pszNonceMd5Str = strchr((char *)pszNonce, '-'); if ( (pszNonceMd5Str == NULL) || (pszNonceMd5Str <= pszNonce) || (pszNonceMd5Str-pszNonce > 15) ) { return false; } strncpy(pszTimeStr, pszNonce, pszNonceMd5Str-pszNonce); if (strlen(pszTimeStr) <= 0) { return false; } nonceTime = (UINT32)atol(pszTimeStr); if (nonceTime <= 0) { DBGPrint(M_AAACenter, ERROR_LEVEL, "SIPCheckNonceExpire: nonce error."); return false; } currTime = time(&t1); if (currTime < nonceTime ) { return false; } if ( (currTime- nonceTime) > SIP_REGISTER_NONCE_EXPIRE * 60) { return false; } SIPGenerateNonce(pszMd5Str, nonceTime, pETag); if (strcmp(pszMd5Str, pszNonce)) { DBGPrint(M_AAACenter, ERROR_LEVEL, "SIPCheckNonceExpire: nonce check error."); return false; } return true; } /*************************************************************** * calculate H(A1) as per spec * output :Sessaionkey 32 char length * ****************************************************************/ void CMD5Calc::DigestCalcHA1 ( char *pszAlg, char *pszUserName, char *pszRealm, char *pszPassword, char *pszNonce, char *pszCNonce, char SessionKey[DIGEST_MD5HEX_LEN+1] ) { MD5_CTX Md5Ctx; unsigned char HA1[DIGEST_HASH_LEN] = {0}; char ff[8] = {0}; int i = 0; MD5Init(&Md5Ctx); pszUserName == NULL ? MD5Update(&Md5Ctx, (UINT8 *)"", 0): MD5Update(&Md5Ctx, (UINT8 *)pszUserName, strlen(pszUserName) ); MD5Update(&Md5Ctx, (UINT8 *)":", 1); pszRealm == NULL ? MD5Update(&Md5Ctx, (UINT8 *)"", 0): MD5Update(&Md5Ctx, (UINT8 *)pszRealm, strlen(pszRealm)); MD5Update(&Md5Ctx, (UINT8 *)":", 1); pszPassword == NULL ? MD5Update(&Md5Ctx, (UINT8 *)"", 0): MD5Update(&Md5Ctx, (UINT8 *)pszPassword, strlen(pszPassword) ); MD5Final(HA1, &Md5Ctx); if (strcasecmp(pszAlg, "md5-sess") == 0) { MD5Init(&Md5Ctx); MD5Update(&Md5Ctx, HA1, DIGEST_HASH_LEN); MD5Update(&Md5Ctx, (UINT8 *)":", 1); pszNonce == NULL ? MD5Update(&Md5Ctx, (UINT8 *)"", 0): MD5Update(&Md5Ctx, (UINT8 *)pszNonce, strlen(pszNonce) ); MD5Update(&Md5Ctx, (UINT8 *)":", 1); pszCNonce == NULL?MD5Update(&Md5Ctx, (UINT8 *)"", 0): MD5Update(&Md5Ctx, (UINT8 *)pszCNonce, strlen(pszCNonce) ); MD5Final(HA1, &Md5Ctx); } for (i=0; i i2) { temp = i1; i1 = i2; i2 = temp; } if (i2 == i1) i2++; temp = (rand() % (i2-i1) + i1); /* gives us a random integer */ return temp; } /****************************************************************************** * Function: * Generate branch parameters. * Note: * This is asc-ii char string. ******************************************************************************/ char *CMD5Calc::GenerateRandomTag(char *pStr) { int suffix; int i; pStr[0] = '\0'; for (i=0; i<8; i++) { suffix = GenerateRandom(0, CHAR_LIST_NUMBER-1); sprintf(pStr+strlen(pStr), "%c", CHAR_LIST_MAP[suffix]); } return pStr; } /****************************************************************************** * Function: * Take out double quotation marks in the string. ******************************************************************************/ char *CMD5Calc::unquote(char *pStr) { char *pUnquoted = NULL; char *pTail = NULL; if (NULL == pStr) return NULL; if (strlen(pStr) > 1023) return NULL; pUnquoted = pStr; while (*pUnquoted == ' ') pUnquoted++; if (*pUnquoted == '\"' ) pUnquoted++; if (pUnquoted > pStr) { //Prompt: Source and destination overlap in strcpy //strcpy(pStr, pUnquoted); char *pDstStr = pStr; while (*pUnquoted != '\0') { *pDstStr++ = *pUnquoted++; } *pDstStr = '\0'; } pTail = pStr + strlen(pStr); /* start tail at EOS */ while ( (pStr < pTail) && isspace( (int)*(pTail-1) ) ) /* if preceding is space, trim */ pTail--; if (*(pTail - 1) == '\"') pTail--; *pTail = 0; return pStr; }