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.