/** * @brief Calculate the MD5 hash of a string. * * Example: "%{md5:foo}" == "acbd18db4cc2f85cedef654fccc4a4d8" */ static size_t xlat_md5(UNUSED void *instance, REQUEST *request, char *fmt, char *out, size_t outlen, UNUSED RADIUS_ESCAPE_STRING func) { int i; uint8_t digest[16]; FR_MD5_CTX ctx; char buffer[1024]; if (!radius_xlat(buffer, sizeof(buffer), fmt, request, func)) { *out = '\0'; return 0; } fr_MD5Init(&ctx); fr_MD5Update(&ctx, (void *) buffer, strlen(buffer)); fr_MD5Final(digest, &ctx); if (outlen < 33) { snprintf(out, outlen, "md5_overflow"); return strlen(out); } for (i = 0; i < 16; i++) { snprintf(out + i * 2, 3, "%02x", digest[i]); } return strlen(out); }
/** * @brief Calculate the MD5 hash of a string. * * Example: "%{md5:foo}" == "acbd18db4cc2f85cedef654fccc4a4d8" */ static size_t md5_xlat(UNUSED void *instance, UNUSED REQUEST *request, char const *fmt, char *out, size_t outlen) { uint8_t digest[16]; int i, len; FR_MD5_CTX ctx; /* * We need room for at least one octet of output. */ if (outlen < 3) { *out = '\0'; return 0; } fr_MD5Init(&ctx); fr_MD5Update(&ctx, (const void *) fmt, strlen(fmt)); fr_MD5Final(digest, &ctx); /* * Each digest octet takes two hex digits, plus one for * the terminating NUL. */ len = (outlen / 2) - 1; if (len > 16) len = 16; for (i = 0; i < len; i++) { snprintf(out + i * 2, 3, "%02x", digest[i]); } return strlen(out); }
static void calc_md5_digest(uint8_t *buffer, uint8_t const *challenge, size_t challen, char const *password) { uint8_t buf[1024]; int i; FR_MD5_CTX context; memset(buf, 0, 1024); memset(buf, 0x36, 64); for(i=0; i<64 && password[i]; i++) buf[i]^=password[i]; memcpy(buf+64, challenge, challen); fr_MD5Init(&context); fr_MD5Update(&context, buf, 64+challen); memset(buf, 0x5c, 64); for(i=0; i<64 && password[i]; i++) buf[i]^=password[i]; fr_MD5Final(buf+64,&context); fr_MD5Init(&context); fr_MD5Update(&context,buf,64+16); fr_MD5Final(buffer,&context); }
static void calc_apop_digest(uint8_t *buffer, uint8_t const *challenge, size_t challen, char const *password) { FR_MD5_CTX context; fr_MD5Init(&context); fr_MD5Update(&context, challenge, challen); fr_MD5Update(&context, (uint8_t const *) password, strlen(password)); fr_MD5Final(buffer, &context); }
static int respond_eap_md5(RADIUS_PACKET *req, RADIUS_PACKET *rep) { VALUE_PAIR *vp, *id, *state; size_t valuesize; uint8_t identifier; uint8_t const *value; FR_MD5_CTX context; uint8_t response[16]; cleanresp(rep); if ((state = paircopy2(NULL, req->vps, PW_STATE, 0, TAG_ANY)) == NULL) { fprintf(stderr, "radeapclient: no state attribute found\n"); return 0; } if ((id = paircopy2(NULL, req->vps, ATTRIBUTE_EAP_ID, 0, TAG_ANY)) == NULL) { fprintf(stderr, "radeapclient: no EAP-ID attribute found\n"); return 0; } identifier = id->vp_integer; if ((vp = pairfind(req->vps, ATTRIBUTE_EAP_BASE+PW_EAP_MD5, 0, TAG_ANY)) == NULL) { fprintf(stderr, "radeapclient: no EAP-MD5 attribute found\n"); return 0; } /* got the details of the MD5 challenge */ valuesize = vp->vp_octets[0]; value = &vp->vp_octets[1]; /* sanitize items */ if(valuesize > vp->length) { fprintf(stderr, "radeapclient: md5 valuesize if too big (%u > %u)\n", (unsigned int) valuesize, (unsigned int) vp->length); return 0; } /* now do the CHAP operation ourself, rather than build the * buffer. We could also call rad_chap_encode, but it wants * a CHAP-Challenge, which we don't want to bother with. */ fr_MD5Init(&context); fr_MD5Update(&context, &identifier, 1); fr_MD5Update(&context, (uint8_t *) password, strlen(password)); fr_MD5Update(&context, value, valuesize); fr_MD5Final(response, &context); { uint8_t *p; uint8_t lg_response; vp = paircreate(rep, ATTRIBUTE_EAP_BASE+PW_EAP_MD5, 0); vp->length = 17; p = talloc_zero_array(vp, uint8_t, 17); lg_response = 16; memcpy(p, &lg_response, 1); memcpy(p + 1, response, 16); pairmemsteal(vp, p); } pairreplace(&(rep->vps), vp); pairreplace(&(rep->vps), id); /* copy the state object in */ pairreplace(&(rep->vps), state); return 1; }
void fr_hmac_md5(const uint8_t *text, int text_len, const uint8_t *key, int key_len, uint8_t *digest) { FR_MD5_CTX context; uint8_t k_ipad[65]; /* inner padding - * key XORd with ipad */ uint8_t k_opad[65]; /* outer padding - * key XORd with opad */ uint8_t tk[16]; int i; /* if key is longer than 64 bytes reset it to key=MD5(key) */ if (key_len > 64) { FR_MD5_CTX tctx; fr_MD5Init(&tctx); fr_MD5Update(&tctx, key, key_len); fr_MD5Final(tk, &tctx); key = tk; key_len = 16; } /* * the HMAC_MD5 transform looks like: * * MD5(K XOR opad, MD5(K XOR ipad, text)) * * where K is an n byte key * ipad is the byte 0x36 repeated 64 times * opad is the byte 0x5c repeated 64 times * and text is the data being protected */ /* start out by storing key in pads */ memset( k_ipad, 0, sizeof(k_ipad)); memset( k_opad, 0, sizeof(k_opad)); memcpy( k_ipad, key, key_len); memcpy( k_opad, key, key_len); /* XOR key with ipad and opad values */ for (i = 0; i < 64; i++) { k_ipad[i] ^= 0x36; k_opad[i] ^= 0x5c; } /* * perform inner MD5 */ fr_MD5Init(&context); /* init context for 1st * pass */ fr_MD5Update(&context, k_ipad, 64); /* start with inner pad */ fr_MD5Update(&context, text, text_len); /* then text of datagram */ fr_MD5Final(digest, &context); /* finish up 1st pass */ /* * perform outer MD5 */ fr_MD5Init(&context); /* init context for 2nd * pass */ fr_MD5Update(&context, k_opad, 64); /* start with outer pad */ fr_MD5Update(&context, digest, 16); /* then results of 1st * hash */ fr_MD5Final(digest, &context); /* finish up 2nd pass */ }
static int respond_eap_md5(RADIUS_PACKET *req, RADIUS_PACKET *rep,const char* pwd) { VALUE_PAIR *vp, *id, *state; size_t valuesize; uint8_t identifier; uint8_t *value; FR_MD5_CTX context; uint8_t response[16]; cleanresp(rep); if ((state = paircopy2(req->vps, PW_STATE)) == NULL) { fr_strerror_printf("radeapclient: no state attribute found"); return 0; } if ((id = paircopy2(req->vps, ATTRIBUTE_EAP_ID)) == NULL) { fr_strerror_printf("radeapclient: no EAP-ID attribute found"); return 0; } identifier = id->vp_integer; if ((vp = pairfind(req->vps, ATTRIBUTE_EAP_BASE+PW_EAP_MD5)) == NULL) { fr_strerror_printf("radeapclient: no EAP-MD5 attribute found"); return 0; } /* got the details of the MD5 challenge */ valuesize = vp->vp_octets[0]; value = &vp->vp_octets[1]; /* sanitize items */ if(valuesize > vp->length) { fr_strerror_printf("radeapclient: md5 valuesize if too big (%u > %u)\n", (unsigned int) valuesize, (unsigned int) vp->length); return 0; } /* now do the CHAP operation ourself, rather than build the * buffer. We could also call rad_chap_encode, but it wants * a CHAP-Challenge, which we don't want to bother with. */ fr_MD5Init(&context); fr_MD5Update(&context, &identifier, 1); fr_MD5Update(&context, (uint8_t *) pwd, strlen(pwd)); fr_MD5Update(&context, value, valuesize); fr_MD5Final(response, &context); vp = paircreate(ATTRIBUTE_EAP_BASE+PW_EAP_MD5, PW_TYPE_OCTETS); vp->vp_octets[0]=16; memcpy(&vp->vp_strvalue[1], response, 16); vp->length = 17; pairreplace(&(rep->vps), vp); pairreplace(&(rep->vps), id); /* copy the state object in */ pairreplace(&(rep->vps), state); return 1; }