CHAP是一种挑战响应式协议。
CHAP全称为:Challenge Handshake Authentication Protocol。
CHAP密码 = 一个字节的标识符 + MD5(一个字节的标识符+明文密码+挑战码)
注:+号只是连接符,两个串之间没有任何多余字符;
如:
挑战码 = cce964fe4807b30ddcda0903413d1a3a560710a2
一个字节的标识符 = 0x97
明文密码 = 20151013
CHAP密码 = "97" + MD5(0x97 + 20151013 + fromHex(cce964fe4807b30ddcda0903413d1a3a560710a2))
CHAP密码 = 9721e6dda93ed253cfdcbc20bab959afed
即调用如下函数时,参数如下:
string reqChallenge = "cce964fe4807b30ddcda0903413d1a3a560710a2";
string challange = fromHex(reqChallenge.c_str(), reqChallenge.length());
string ChapPasswd;
CHAPPasswdXor("20151013", 0x97, challange, ChapPasswd);
如下是一个CHAP协议的实现算法:
#include <string>
#include "md5.h" #define RAD_PASSWORD_LEN 128
#define RAD_PSWDSEG_LEN 16
#define RAD_AUTHCATOR_LEN 16 std::string Hex(const char* cpSrcStr, int len, bool isUpper = false) {
if (cpSrcStr == NULL) {
return "";
}
std::string ret(len * 2, 0x00);
const char* hex = isUpper ? "0123456789ABCDEF" : "0123456789abcdef";
for (size_t i = 0; i < len; ++i) {
unsigned char v = static_cast<unsigned char>(cpSrcStr[i]);
ret[2*i] = hex[(v >> 4) & 0x0f];
ret[2*i+1] = hex[ v & 0x0f];
}
return ret;
} char asc_bcd(const char *aBcdStr) {
unsigned char digit; digit = (aBcdStr[0] >= 'a' ? ((aBcdStr[0]) - 'a')+10 : (aBcdStr[0] - '0'));
digit *= 16;
digit += (aBcdStr[1] >= 'a' ? ((aBcdStr[1]) - 'a')+10 : (aBcdStr[1] - '0'));
return digit;
} std::string fromHex(const char* from, size_t len) {
std::string ret(len / 2, 0x00);
for (size_t ii = 0; ii < len / 2; ii++)
ret[ii] = asc_bcd(from + ii * 2);
return ret;
} void MD5Calc(const unsigned char *input,
unsigned int inlen, unsigned char *output) {
MD5_CTX context;
MD5Init(&context);
MD5Update(&context, (unsigned char *)input, inlen);
MD5Final(output, &context);
} int CHAPPasswdXor(const char *aPasswd, unsigned char aIdentifier,
const std::string& aChallenge, std::string &aOutPasswd)
{
char localPwd[RAD_PASSWORD_LEN+1] = {0};
int pwLen = strlen(aPasswd); if (pwLen > RAD_PASSWORD_LEN) {
//LOG_INFO("%s:Password is too long.");
return -1;
} char *pwStr = localPwd;
*pwStr++ = aIdentifier;
strcpy(pwStr, aPasswd);
pwStr += pwLen;
// challenge is append if challenge is exist.
memcpy(pwStr, aChallenge.data(), aChallenge.length());
pwLen += aChallenge.length() + 1; // Encrypted.
char md5Output[RAD_AUTHCATOR_LEN+1] = {0};
MD5Calc((unsigned char *)localPwd, pwLen, (unsigned char *)md5Output); // get the CHAP password
pwStr = localPwd;
*pwStr++ = aIdentifier;
memcpy(pwStr, md5Output, RAD_AUTHCATOR_LEN);
aOutPasswd = Hex(localPwd, RAD_PSWDSEG_LEN+1);
return 0;
}