Fork me on GitHub

【加解密】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.

posted @ 2016-04-01 16:20  Mr.YF  阅读(4017)  评论(0编辑  收藏  举报