【加解密】PAP认证方式原理和实现
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.