PAP認證協議
基本描述:
Password Authentication Protocol 口令認證協議
PAP認證過程非常簡單,二次握手機制,使用明文格式發送用戶名和密碼,發起方為被認證方,可以做無限次的嘗試(暴力破解),只在鏈路建立的階段進行PAP認證,一旦鏈路建立成功將不再進行認證檢測。
rfc參考:rfc2865.txt
使用場景:
PPPOE撥號和Radius認證環境中。

加密原理:
加密時將明文按照16字節分塊為p1, p2, ..., pi多個小塊。

| 字段 | 意義 |
| S | 共享密鑰 |
| RA | 128位的請求認證碼 |
| p1,p2,...,pi | 將明文密碼按照16字節分塊 |
| c(1),c(2),...,c(i) | 加密后的密文串 |
最終得到的加密密文串是 c(1)+c(2)+...+c(i)連接起來的串。
解密原理:
解密時將密文按照16字節分塊為c(1), c(2), ..., c(i)多個小塊。

最終得到的解密后的明文串是 p1+p2+...+pi連接起來的串。
代碼實現:
加密:
#define RAD_PSWDSEG_LEN 16
#define RAD_AUTHCATOR_LEN 16
#define RET_ERROR -1
#define RET_OK 0
std::string peerShareSecret_ = "88----89";
// ---------------------------------------------------------------------------
// int :PasswdXor
//
// Use for encrypt the password attribute.
// ---------------------------------------------------------------------------
//
int PasswdXor(const char *aPasswd, string &aOutPasswd)
{
if (aPasswd == NULL) {
return RET_ERROR;
}
char localPwd[RAD_PASSWORD_LEN+1] = {0};
int pwLen = strlen(aPasswd);
// Pad the password. If the length of the passwd isn't multiples of 16, pad it.
if (pwLen > RAD_PASSWORD_LEN) {
return RET_ERROR;
}
char *pwStr = localPwd;
strcpy(localPwd, aPasswd);
int n = pwLen - (pwLen/RAD_PSWDSEG_LEN) * RAD_PSWDSEG_LEN;
if (n != 0) {
memset(pwStr+pwLen, 0, RAD_PSWDSEG_LEN - n);
pwLen += 16 - n;
}
// Encrypted.
char md5Input[RAD_SECRET_LEN + RAD_AUTHCATOR_LEN] = {0};
char md5Output[RAD_AUTHCATOR_LEN] = {0};
char * inStr = md5Input;
int inlen = peerShareSecret_.length() + RAD_AUTHCATOR_LEN;
strcpy(inStr, peerShareSecret_.c_str());
inStr += peerShareSecret_.length();
memcpy(inStr, (char *)authcator_, RAD_AUTHCATOR_LEN);
int passEncodeLen = pwLen;
for (; pwLen > 0; pwLen -= RAD_PSWDSEG_LEN) {
MD5Calc((unsigned char *)md5Input, inlen, (unsigned char *)md5Output);
int i ;
for (i =0; i<RAD_PSWDSEG_LEN; ++i)
pwStr[i] ^= md5Output[i];
memcpy(inStr, pwStr, RAD_PSWDSEG_LEN);
pwStr += RAD_PSWDSEG_LEN;
}
aOutPasswd = EndcodePwd(localPwd, passEncodeLen);
return RET_OK;
}
解密:
int PasswdDecodeXor(const char *aPasswd, string &aOutPasswd)
{
if (aPasswd == NULL) {
return RET_ERROR;
}
int pwLen = strlen(aPasswd);
if (pwLen < 32) {
return RET_ERROR;
}
char md5Input[RAD_SECRET_LEN + RAD_AUTHCATOR_LEN] = {0};
char md5Output[RAD_AUTHCATOR_LEN] = {0};
char * inStr = md5Input;
int inlen = peerShareSecret_.length() + RAD_AUTHCATOR_LEN;
strcpy(inStr, peerShareSecret_.c_str());
inStr += peerShareSecret_.length();
memcpy(inStr, (char *)authcator_, RAD_AUTHCATOR_LEN);
aOutPasswd = "";
for(int i = 0; i < pwLen / 32; i++){
char pwStr[RAD_PSWDSEG_LEN + 1] = { 0 };
string hexPass = fromHex(aPasswd+i*32, 32);
memcpy(pwStr, hexPass.data(), 16);
MD5Calc((unsigned char *)md5Input, inlen, (unsigned char *)md5Output);
for (int i = 0; i < RAD_PSWDSEG_LEN; ++i)
pwStr[i] ^= md5Output[i];
pwStr[RAD_PSWDSEG_LEN] = 0x00;
aOutPasswd += pwStr;
if (strlen(pwStr) < RAD_PSWDSEG_LEN) {
break;
} else {
memcpy(inStr, hexPass.data(), 16);
}
}
return RET_OK;
}
Done.
