PJ_DEF(void) pj_hmac_md5_init(pj_hmac_md5_context *hctx, 
			      const pj_uint8_t *key, unsigned key_len)
{
    pj_uint8_t k_ipad[64];
    pj_uint8_t tk[16];
    int i;

    /* if key is longer than 64 bytes reset it to key=MD5(key) */
    if (key_len > 64) {
        pj_md5_context      tctx;

        pj_md5_init(&tctx);
        pj_md5_update(&tctx, key, key_len);
        pj_md5_final(&tctx, tk);

        key = tk;
        key_len = 16;
    }

    /*
     * HMAC = H(K XOR opad, H(K XOR ipad, text))
     */

    /* start out by storing key in pads */
    pj_bzero( k_ipad, sizeof(k_ipad));
    pj_bzero( hctx->k_opad, sizeof(hctx->k_opad));
    pj_memcpy( k_ipad, key, key_len);
    pj_memcpy( hctx->k_opad, key, key_len);

    /* XOR key with ipad and opad values */
    for (i=0; i<64; i++) {
        k_ipad[i] ^= 0x36;
        hctx->k_opad[i] ^= 0x5c;
    }
    /*
     * perform inner MD5
     */
    pj_md5_init(&hctx->context);
    pj_md5_update(&hctx->context, k_ipad, 64);

}
PJ_DEF(void) pj_hmac_md5_final(pj_hmac_md5_context *hctx,
				pj_uint8_t digest[16])
{
    pj_md5_final(&hctx->context, digest);

    /*
     * perform outer MD5
     */
    pj_md5_init(&hctx->context);
    pj_md5_update(&hctx->context, hctx->k_opad, 64);
    pj_md5_update(&hctx->context, digest, 16);
    pj_md5_final(&hctx->context, digest);
}
Exemplo n.º 3
0
PJ_DEF(pj_str_t) pjsip_calculate_branch_id( pjsip_rx_data *rdata )
{
    pj_md5_context ctx;
    pj_uint8_t digest[16];
    pj_str_t branch;
    pj_str_t rfc3261_branch = {PJSIP_RFC3261_BRANCH_ID, 
                               PJSIP_RFC3261_BRANCH_LEN};

    /* If incoming request does not have RFC 3261 branch value, create
     * a branch value from GUID .
     */
    if (pj_strncmp(&rdata->msg_info.via->branch_param, 
		   &rfc3261_branch, PJSIP_RFC3261_BRANCH_LEN) != 0 ) 
    {
	pj_str_t tmp;

	branch.ptr = (char*)
		     pj_pool_alloc(rdata->tp_info.pool, PJSIP_MAX_BRANCH_LEN);
	branch.slen = PJSIP_RFC3261_BRANCH_LEN;
	pj_memcpy(branch.ptr, PJSIP_RFC3261_BRANCH_ID, 
	          PJSIP_RFC3261_BRANCH_LEN);

	tmp.ptr = branch.ptr + PJSIP_RFC3261_BRANCH_LEN + 2;
	*(tmp.ptr-2) = (pj_int8_t)(branch.slen+73); 
	*(tmp.ptr-1) = (pj_int8_t)(branch.slen+99);
	pj_generate_unique_string( &tmp );

	branch.slen = PJSIP_MAX_BRANCH_LEN;
	return branch;
    }

    /* Create branch ID for new request by calculating MD5 hash
     * of the branch parameter in top-most Via header.
     */
    pj_md5_init(&ctx);
    pj_md5_update(&ctx, (pj_uint8_t*)rdata->msg_info.via->branch_param.ptr,
		  rdata->msg_info.via->branch_param.slen);
    pj_md5_final(&ctx, digest);

    branch.ptr = (char*)
    		 pj_pool_alloc(rdata->tp_info.pool, 
			       34 + PJSIP_RFC3261_BRANCH_LEN);
    pj_memcpy(branch.ptr, PJSIP_RFC3261_BRANCH_ID, PJSIP_RFC3261_BRANCH_LEN);
    branch.slen = PJSIP_RFC3261_BRANCH_LEN;
    *(branch.ptr+PJSIP_RFC3261_BRANCH_LEN) = (pj_int8_t)(branch.slen+73);
    *(branch.ptr+PJSIP_RFC3261_BRANCH_LEN+1) = (pj_int8_t)(branch.slen+99);
    digest2str(digest, branch.ptr+PJSIP_RFC3261_BRANCH_LEN+2);
    branch.slen = 34 + PJSIP_RFC3261_BRANCH_LEN;

    return branch;
}
Exemplo n.º 4
0
/* Calculate HMAC-SHA1 key for long term credential, by getting
 * MD5 digest of username, realm, and password. 
 */
static void calc_md5_key(pj_uint8_t digest[16],
			 const pj_str_t *realm,
			 const pj_str_t *username,
			 const pj_str_t *passwd)
{
    /* The 16-byte key for MESSAGE-INTEGRITY HMAC is formed by taking
     * the MD5 hash of the result of concatenating the following five
     * fields: (1) The username, with any quotes and trailing nulls
     * removed, (2) A single colon, (3) The realm, with any quotes and
     * trailing nulls removed, (4) A single colon, and (5) The 
     * password, with any trailing nulls removed.
     */
    pj_md5_context ctx;
    pj_str_t s;

    pj_md5_init(&ctx);

#define REMOVE_QUOTE(s)	if (s.slen && *s.ptr=='"') \
			    s.ptr++, s.slen--; \
			if (s.slen && s.ptr[s.slen-1]=='"') \
			    s.slen--;

    /* Add username */
    s = *username;
    REMOVE_QUOTE(s);
    pj_md5_update(&ctx, (pj_uint8_t*)s.ptr, (unsigned)s.slen);

    /* Add single colon */
    pj_md5_update(&ctx, (pj_uint8_t*)":", 1);

    /* Add realm */
    s = *realm;
    REMOVE_QUOTE(s);
    pj_md5_update(&ctx, (pj_uint8_t*)s.ptr, (unsigned)s.slen);

#undef REMOVE_QUOTE

    /* Another colon */
    pj_md5_update(&ctx, (pj_uint8_t*)":", 1);

    /* Add password */
    pj_md5_update(&ctx, (pj_uint8_t*)passwd->ptr, (unsigned)passwd->slen);

    /* Done */
    pj_md5_final(&ctx, digest);
}
Exemplo n.º 5
0
/*
 * Create response digest based on the parameters and store the
 * digest ASCII in 'result'. 
 */
PJ_DEF(void) pjsip_auth_create_digest( pj_str_t *result,
				       const pj_str_t *nonce,
				       const pj_str_t *nc,
				       const pj_str_t *cnonce,
				       const pj_str_t *qop,
				       const pj_str_t *uri,
				       const pj_str_t *realm,
				       const pjsip_cred_info *cred_info,
				       const pj_str_t *method)
{
    char ha1[PJSIP_MD5STRLEN];
    char ha2[PJSIP_MD5STRLEN];
    unsigned char digest[16];
    pj_md5_context pms;

    pj_assert(result->slen >= PJSIP_MD5STRLEN);

    AUTH_TRACE_((THIS_FILE, "Begin creating digest"));

    if ((cred_info->data_type & PASSWD_MASK) == PJSIP_CRED_DATA_PLAIN_PASSWD) {
	/*** 
	 *** ha1 = MD5(username ":"******":" password) 
	 ***/
	pj_md5_init(&pms);
	MD5_APPEND( &pms, cred_info->username.ptr, cred_info->username.slen);
	MD5_APPEND( &pms, ":", 1);
	MD5_APPEND( &pms, realm->ptr, realm->slen);
	MD5_APPEND( &pms, ":", 1);
	MD5_APPEND( &pms, cred_info->data.ptr, cred_info->data.slen);
	pj_md5_final(&pms, digest);

	digest2str(digest, ha1);

    } else if ((cred_info->data_type & PASSWD_MASK) == PJSIP_CRED_DATA_DIGEST) {
	pj_assert(cred_info->data.slen == 32);
	pj_memcpy( ha1, cred_info->data.ptr, cred_info->data.slen );
    } else {
	pj_assert(!"Invalid data_type");
    }

    AUTH_TRACE_((THIS_FILE, "  ha1=%.32s", ha1));

    /***
     *** ha2 = MD5(method ":" req_uri) 
     ***/
    pj_md5_init(&pms);
    MD5_APPEND( &pms, method->ptr, method->slen);
    MD5_APPEND( &pms, ":", 1);
    MD5_APPEND( &pms, uri->ptr, uri->slen);
    pj_md5_final(&pms, digest);
    digest2str(digest, ha2);

    AUTH_TRACE_((THIS_FILE, "  ha2=%.32s", ha2));

    /***
     *** When qop is not used:
     ***    response = MD5(ha1 ":" nonce ":" ha2) 
     ***
     *** When qop=auth is used:
     ***    response = MD5(ha1 ":" nonce ":" nc ":" cnonce ":" qop ":" ha2)
     ***/
    pj_md5_init(&pms);
    MD5_APPEND( &pms, ha1, PJSIP_MD5STRLEN);
    MD5_APPEND( &pms, ":", 1);
    MD5_APPEND( &pms, nonce->ptr, nonce->slen);
    if (qop && qop->slen != 0) {
	MD5_APPEND( &pms, ":", 1);
	MD5_APPEND( &pms, nc->ptr, nc->slen);
	MD5_APPEND( &pms, ":", 1);
	MD5_APPEND( &pms, cnonce->ptr, cnonce->slen);
	MD5_APPEND( &pms, ":", 1);
	MD5_APPEND( &pms, qop->ptr, qop->slen);
    }
    MD5_APPEND( &pms, ":", 1);
    MD5_APPEND( &pms, ha2, PJSIP_MD5STRLEN);

    /* This is the final response digest. */
    pj_md5_final(&pms, digest);
    
    /* Convert digest to string and store in chal->response. */
    result->slen = PJSIP_MD5STRLEN;
    digest2str(digest, result->ptr);

    AUTH_TRACE_((THIS_FILE, "  digest=%.32s", result->ptr));
    AUTH_TRACE_((THIS_FILE, "Digest created"));
}