/******************************************************************************
|
* 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 <time.h>
|
#include <sys/time.h>
|
#include <ctype.h>
|
#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<DIGEST_HASH_LEN; i++)
|
{
|
if (i == 0)
|
{
|
sprintf(SessionKey, "%02x", HA1[i]);
|
}
|
else
|
{
|
sprintf(ff, "%02x", HA1[i]);
|
strcat(SessionKey, ff);
|
}
|
}
|
}
|
|
/******************************************************************
|
calculate request-digest/response-digest as per HTTP Digest spec
|
output:Response 32 char length
|
******************************************************************/
|
void CMD5Calc::DigestCalcResponse
|
(
|
char HA1[DIGEST_MD5HEX_LEN+1], /* H(A1) */
|
char *pszNonce, /* nonce from server */
|
char *pszNonceCount, /* 8 hex digits */
|
char *pszCNonce, /* client nonce */
|
char *pszQop, /* qop-value: "", "auth", "auth-int" */
|
char *pszMethod, /* method from the request */
|
char *pszDigestUri, /* requested URL */
|
char HEntity[DIGEST_MD5HEX_LEN+1], /* H(entity body) if qop="auth-int" */
|
char Response[DIGEST_MD5HEX_LEN+1] /* request-digest or response-digest */
|
)
|
{
|
MD5_CTX Md5Ctx;
|
unsigned char HA2[DIGEST_HASH_LEN] ={0};
|
unsigned char RespHash[DIGEST_HASH_LEN] ={0};
|
char HA2Hex[DIGEST_MD5HEX_LEN+1] ={0};
|
char ff[8] = {0};
|
int i = 0;
|
|
//calculate H(A2)
|
MD5Init(&Md5Ctx);
|
pszMethod == NULL ? MD5Update(&Md5Ctx, (UINT8 *)"", 0):
|
MD5Update(&Md5Ctx, (UINT8 *)pszMethod, strlen(pszMethod));
|
MD5Update(&Md5Ctx, (UINT8 *)":", 1);
|
pszDigestUri == NULL ? MD5Update(&Md5Ctx, (UINT8 *)"", 0):
|
MD5Update(&Md5Ctx, (UINT8 *)pszDigestUri, strlen(pszDigestUri) );
|
|
if (strcasecmp(pszQop, "auth-int") == 0)
|
{
|
MD5Update(&Md5Ctx, (UINT8 *)":", 1);
|
MD5Update(&Md5Ctx, (UINT8 *)HEntity, DIGEST_MD5HEX_LEN);
|
}
|
MD5Final(HA2, &Md5Ctx);
|
for (i=0; i<DIGEST_HASH_LEN; i++)
|
{
|
sprintf(ff, "%02x", HA2[i]);
|
strcat(HA2Hex,ff);
|
}
|
|
// calculate response
|
MD5Init(&Md5Ctx);
|
HA1 == NULL ? MD5Update(&Md5Ctx, (UINT8 *)"", 0):
|
MD5Update(&Md5Ctx, (UINT8 *)HA1, DIGEST_MD5HEX_LEN);
|
MD5Update(&Md5Ctx, (UINT8 *)":", 1);
|
pszNonce ==NULL?MD5Update(&Md5Ctx, (UINT8 *)"", 0):
|
MD5Update(&Md5Ctx, (UINT8 *)pszNonce, strlen(pszNonce));
|
MD5Update(&Md5Ctx, (UINT8 *)":", 1);
|
if (pszQop && *pszQop)
|
{
|
pszNonceCount ==NULL?MD5Update(&Md5Ctx, (UINT8 *)"", 0):
|
MD5Update(&Md5Ctx, (UINT8 *)pszNonceCount, strlen(pszNonceCount));
|
MD5Update(&Md5Ctx, (UINT8 *)":",1);
|
pszCNonce ==NULL?MD5Update(&Md5Ctx, (UINT8 *)"", 0):
|
MD5Update(&Md5Ctx, (UINT8 *)pszCNonce, strlen(pszCNonce));
|
MD5Update(&Md5Ctx, (UINT8 *)":", 1);
|
MD5Update(&Md5Ctx, (UINT8 *)pszQop, strlen(pszQop));
|
MD5Update(&Md5Ctx, (UINT8 *)":", 1);
|
}
|
MD5Update(&Md5Ctx, (UINT8 *)HA2Hex, DIGEST_MD5HEX_LEN);
|
MD5Final(RespHash, &Md5Ctx);
|
for (i=0; i<DIGEST_HASH_LEN; i++)
|
{
|
if (i == 0)
|
{
|
sprintf(Response, "%02x", RespHash[i]);
|
}
|
else
|
{
|
sprintf(ff, "%02x", RespHash[i]);
|
strcat(Response,ff);
|
}
|
}
|
}
|
|
/******************************************************************************
|
* Function:
|
* Generate random unsigned integer between i1 and i2.
|
******************************************************************************/
|
UINT32 CMD5Calc::GenerateRandom(UINT32 i1, UINT32 i2)
|
{
|
static bool FirstTime = false;
|
UINT32 entity;
|
UINT32 temp;
|
|
/* on 1st call, seed rand with time */
|
if (!FirstTime)
|
{
|
struct timeval tval;
|
gettimeofday(&tval, NULL);
|
entity = tval.tv_sec + tval.tv_usec;
|
srand(entity);
|
FirstTime = true;
|
}
|
|
/* we want i1 to be less than i2 */
|
if (i1 > 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;
|
}
|