RADIUS 库未正确加密或编码密码字符串

RADIUS Library not encrypting or encoding password string correctly

我目前正在从事一个项目,涉及使用 Java 和 Python 对 RADIUS 服务器进行直接身份验证。

我的 Python 实现工作正常,但是我已经尝试了两个 Java 库(TinyRADIUS 和 JRaD),两者表现出相同的行为:

当发送 PAP 请求时,密码中前 16 个之后的所有字符似乎都变成了乱码或半 UTF 编码,导致服务器无法通过身份验证。

见下文:

    JRaDclient rc = new JRaDclient();

    rc.setSecretKey("secrets");
    rc.setServer("127.0.0.1", 1812);
    rc.authenticate("testuser", "pass123LogeuCcoboJKidoDeVFesekSoluneCgaLttrjhrkrhn");

然而,服务器上的结果请求变成了这个

rad_recv: Access-Request packet from host 127.0.0.1 port 1337, id=210, length=96
        User-Name = "testuser"
        User-Password = "pass123LogeuCcob53?302A13mP63P[h4zL21/3[=11=]14233BuKM2\t31r135
673+W'b1"

这是库同时出现的问题还是 Radius 的 configuration/version 问题?

作为参考,这是 Java 8 上的 运行,使用 FreeRADIUS v2.1.12。

JRaD:https://github.com/punyal/JRaD 微小半径:http://tinyradius.sourceforge.net/

当密码超过 16 个字符时会出现问题 - 密码编码填充密码然后对其进行加密,这是不正确的。

我们在项目中包含了源代码,并替换了 pap 密码编码和 pap 密码解码方法(本质上,在填充之前加密密码,而不是用填充加密)。

基于此:http://sourceforge.net/p/tinyradius/discussion/461293/thread/dcedb4ed/

这是修改后的相关代码:

    /**
     * This method encodes the plaintext user password according to RFC 2865.
     * 
     * @param userPass
     *            the password to encrypt
     * @param sharedSecret
     *            shared secret
     * @return the byte array containing the encrypted password
     */
    private byte[] encodePapPassword(final byte[] userPass, byte[] sharedSecret) {
        // the password must be a multiple of 16 bytes and less than or equal
        // to 128 bytes. If it isn't a multiple of 16 bytes fill it out with zeroes
        // to make it a multiple of 16 bytes. If it is greater than 128 bytes
        // truncate it at 128.


    if (userPass == null) {
        throw new IllegalArgumentException("password is null");
    } else if (sharedSecret == null) {
        throw new IllegalArgumentException("shared secret is null");
    } else if (getAuthenticator() == null) {
        throw new IllegalArgumentException("authenticator is null");
    }

    byte[] userPassBytes = null;
    if (userPass.length > 128) {
        userPassBytes = new byte[128];
        System.arraycopy(userPass, 0, userPassBytes, 0, 128);
    } else {
        userPassBytes = userPass;
    }
    // declare the byte array to hold the final product
    byte[] encryptedPass = null;
    if (userPassBytes.length < 128) {
        if (userPassBytes.length % 16 == 0) {
            // tt is already a multiple of 16 bytes
            encryptedPass = new byte[userPassBytes.length];
        } else {
            // make it a multiple of 16 bytes
            encryptedPass = new byte[((userPassBytes.length / 16) * 16) + 16];
        }
    } else {
        // the encrypted password must be between 16 and 128 bytes
        encryptedPass = new byte[128];
    }
    // copy the userPass into the encrypted pass and then fill it out with zeroes
    System.arraycopy(userPassBytes, 0, encryptedPass, 0, userPassBytes.length);
    for (int i = userPassBytes.length; i < encryptedPass.length; i++) {
        encryptedPass[i] = 0;
    }
    // digest shared secret and authenticator
        MessageDigest md5 = getMd5Digest();

    md5.reset();
    byte[] bn = new byte[sharedSecret.length + getAuthenticator().length];
    for (int i = 0; i < bn.length; i++) {
        if (i < sharedSecret.length)
            bn[i] = sharedSecret[i];
        else
            bn[i] = getAuthenticator()[i - sharedSecret.length];
    }
    md5.update(bn);
    bn = md5.digest();
    // perform the XOR as specified by RFC 2865
    for (int i = 0; i < 16; i++) {
        encryptedPass[i] = (byte) (bn[i] ^ encryptedPass[i]);
    }
    if (encryptedPass.length > 16) {
        for (int i = 16; i < encryptedPass.length; i += 16) {
            md5.reset();
            md5.update(sharedSecret);
            // add the previous (encrypted) 16 bytes of the user password
            md5.update(encryptedPass, i - 16, 16);
            bn = md5.digest();
            // perform the XOR as specified by RFC 2865.
            for (int j = 0; j < 16; j++) {
                encryptedPass[i + j] = (byte) (bn[j] ^ encryptedPass[i + j]);
            }
        }
    }
    return encryptedPass;
}

    /**
     * Decodes the passed encrypted password and returns the clear-text form.
     *
     * @param encryptedPass
     *            encrypted password
     * @param sharedSecret
     *            shared secret
     * @return decrypted password
     */
    private String decodePapPassword(byte[] encryptedPass, byte[] sharedSecret) throws RadiusException {
        if (encryptedPass == null) {
            throw new IllegalArgumentException("encrypted password is null");
        } else if (sharedSecret == null) {
            throw new IllegalArgumentException("shared secret is null");
        } else if (getAuthenticator() == null) {
            throw new IllegalArgumentException("authenticator is null");
        } else if (encryptedPass.length < 16) {
            throw new IllegalArgumentException("invalid length of encrypted pass: " + encryptedPass.length);
        }

        // save original (encoded) encrypted pass
        byte[] encryptedPassOrig = encryptedPass.clone();
    //  MessageDigest md5;
        MessageDigest md5 = getMd5Digest();
        md5.reset();
        md5.update(sharedSecret);
        md5.update(getAuthenticator());
        byte bn[] = md5.digest();
        // perform the XOR as specified by RFC 2865
        for (int i = 0; i < 16; i++) {
            encryptedPass[i] = (byte) (bn[i] ^ encryptedPass[i]);
        }
        if (encryptedPass.length > 16) {
            for (int i = 16; i < encryptedPass.length; i += 16) {
                md5.reset();
                md5.update(sharedSecret);
                // now use original (encoded) pass to generate MD5
                md5.update(encryptedPassOrig, i - 16, 16);
                bn = md5.digest();
                // perform the XOR as specified by RFC 2865.
                for (int j = 0; j < 16; j++) {
                    encryptedPass[i + j] = (byte) (bn[j] ^ encryptedPass[i + j]);
                }
            }
        }
        // remove trailing zeros
        int len = encryptedPass.length;
        while (len > 0 && encryptedPass[len - 1] == 0) {
            len--;
        }

        byte[] passtrunc = new byte[len];
        System.arraycopy(encryptedPass, 0, passtrunc, 0, len);
        // convert to string
        return RadiusUtil.getStringFromUtf8(passtrunc);
    }