You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

含Message-Authenticator的Radius请求验证失败问题求助

问题:FreeRADIUS返回Message-Authenticator无效错误,共享密钥已正确配置

使用tinyradius-1.1.3 jar包向FreeRADIUS服务器(IP:10.255.68.68)发送带Message-Authenticator属性的Radius请求时,服务器返回错误:
"Received packet from 172.21.248.41 with invalid Message-Authenticator! (Shared secret is incorrect.) (from client localhost)"
但共享密钥已正确配置为"testing123",示例代码如下:

package test;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.tinyradius.attribute.RadiusAttribute;
import org.tinyradius.packet.AccessRequest;
import org.tinyradius.packet.RadiusPacket;
import org.tinyradius.util.RadiusClient;

public class RadiusAuthenticatorClient {

    public static void main(String[] args) throws Exception {
        String server = "<<Example IP>>";
        String sharedSecret = "<<secret>>";
        RadiusClient client = new RadiusClient(server, sharedSecret);
        client.setAuthPort(1812);  // Set to your RADIUS authentication port
 
        // Example: Username and password
        String username = "admin";
        String password = "password1";
 
        // Create and send the Access-Request packet
        AccessRequest accessRequest = new AccessRequest(username, password);
        
        SecureRandom random = new SecureRandom();
        byte[] requestAuthenticator = new byte[16];
        random.nextBytes(requestAuthenticator);
        accessRequest.setAuthenticator(requestAuthenticator);
        addMessageAuthenticator(accessRequest, client, sharedSecret);
 
        RadiusPacket response = client.authenticate(accessRequest);
      
    }
    
public static void addMessageAuthenticator(AccessRequest accessRequest, RadiusClient client, String sharedSecret) throws Exception {
    // Create a 16-byte authenticator (MD5 HMAC of the shared secret)
   
     byte[] messageAuthenticator = new byte[16];
     
    // Generate the HMAC MD5 hash
    Mac mac = Mac.getInstance("HmacMD5");
    SecretKeySpec keySpec = new SecretKeySpec(sharedSecret.getBytes("UTF-8"), "HmacMD5");
    mac.init(keySpec);
 
    byte[] packetBytes = createPacketBytes(accessRequest);
    
    mac.update(packetBytes);
    mac.update(new byte[16]); // Zeroed-out Message-Authenticator placeholder
    messageAuthenticator = mac.doFinal();
    
    // Add updated Message-Authenticator to the request
    RadiusAttribute messageAuthenticatorAttr = new RadiusAttribute(80, messageAuthenticator);
    accessRequest.addAttribute(messageAuthenticatorAttr);
}

public static byte[] createPacketBytes(AccessRequest accessRequest) throws IOException {

    List attributes = accessRequest.getAttributes();
    ByteArrayOutputStream bos = new ByteArrayOutputStream(4096);
    for (Iterator i = attributes.iterator(); i.hasNext();) {
        RadiusAttribute a = (RadiusAttribute) i.next();
        bos.write(a.writeAttribute());
    }
    bos.flush();
    byte[] attrs = bos.toByteArray();
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    DataOutputStream dos = new DataOutputStream(out);
    dos.writeByte(accessRequest.getPacketType());
    dos.writeByte(accessRequest.getPacketIdentifier());
    dos.writeShort(20+attrs.length);
    dos.write(accessRequest.getAuthenticator());
    dos.write(attrs);
    dos.flush();
    return out.toByteArray();
}
}

错误原因分析

核心问题出在Message-Authenticator的计算逻辑顺序错误,具体问题点:

  1. 计算HMAC-MD5时,需要先在请求中添加全0的Message-Authenticator占位符,再生成完整数据包字节流进行哈希;你的代码是先生成无占位符的数据包,再补全0字节,导致哈希计算的基础数据错误。
  2. createPacketBytes方法计算数据包长度时,未提前考虑Message-Authenticator占位符的长度,导致头部长度字段与实际数据包不匹配。
  3. 错误提示中from client localhost说明服务器可能将你的请求匹配到了localhost的客户端条目,而非你配置的172.21.248.41条目,需检查客户端配置。

正确的Message-Authenticator实现方法

核心步骤

  1. 创建AccessRequest并设置随机请求认证符(Request-Authenticator)。
  2. 添加值为全0的Message-Authenticator属性作为占位符。
  3. 生成包含占位符的完整请求数据包字节流。
  4. 用共享密钥对字节流计算HMAC-MD5,得到Message-Authenticator有效值。
  5. 替换占位符的属性值为计算结果。
  6. 发送请求。

修正后的完整代码

package test;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.security.SecureRandom;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.tinyradius.attribute.RadiusAttribute;
import org.tinyradius.packet.AccessRequest;
import org.tinyradius.packet.RadiusPacket;
import org.tinyradius.util.RadiusClient;

public class RadiusAuthenticatorClient {

    public static void main(String[] args) throws Exception {
        String server = "10.255.68.68";
        String sharedSecret = "testing123";
        RadiusClient client = new RadiusClient(server, sharedSecret);
        client.setAuthPort(1812);

        String username = "admin";
        String password = "password1";

        // 创建AccessRequest并设置用户信息
        AccessRequest accessRequest = new AccessRequest(username, password);
        
        // 生成随机的Request-Authenticator
        SecureRandom random = new SecureRandom();
        byte[] requestAuthenticator = new byte[16];
        random.nextBytes(requestAuthenticator);
        accessRequest.setAuthenticator(requestAuthenticator);
        
        // 添加并计算正确的Message-Authenticator
        addMessageAuthenticator(accessRequest, sharedSecret);

        // 发送请求并处理响应
        RadiusPacket response = client.authenticate(accessRequest);
        if (response != null) {
            System.out.println("响应类型: " + response.getPacketType());
            System.out.println("响应属性: " + response.getAttributes());
        } else {
            System.out.println("未收到服务器响应");
        }
    }

    public static void addMessageAuthenticator(AccessRequest accessRequest, String sharedSecret) throws Exception {
        // 1. 添加全0的Message-Authenticator占位符(属性类型80,值为16字节全0)
        byte[] zeroedMA = new byte[16];
        RadiusAttribute maPlaceholder = new RadiusAttribute(80, zeroedMA);
        accessRequest.addAttribute(maPlaceholder);

        // 2. 生成包含占位符的完整数据包字节流
        byte[] packetBytes = generatePacketBytes(accessRequest);

        // 3. 计算HMAC-MD5得到Message-Authenticator有效值
        Mac mac = Mac.getInstance("HmacMD5");
        SecretKeySpec keySpec = new SecretKeySpec(sharedSecret.getBytes("UTF-8"), "HmacMD5");
        mac.init(keySpec);
        byte[] messageAuthenticator = mac.doFinal(packetBytes);

        // 4. 替换占位符的值为计算结果
        maPlaceholder.setValue(messageAuthenticator);
    }

    private static byte[] generatePacketBytes(AccessRequest accessRequest) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(out);

        // 写入Radius头部字段
        dos.writeByte(accessRequest.getPacketType());
        dos.writeByte(accessRequest.getPacketIdentifier());
        
        // 计算并写入总长度:20字节头部 + 所有属性的总长度
        int attrTotalLength = 0;
        for (RadiusAttribute attr : accessRequest.getAttributes()) {
            attrTotalLength += attr.writeAttribute().length;
        }
        dos.writeShort(20 + attrTotalLength);
        
        dos.write(accessRequest.getAuthenticator());

        // 写入所有属性
        for (RadiusAttribute attr : accessRequest.getAttributes()) {
            dos.write(attr.writeAttribute());
        }

        dos.flush();
        return out.toByteArray();
    }
}

服务器端配置检查

  1. 确保FreeRADIUS的clients.conf中,你的客户端IP(172.21.248.41)配置了正确的共享密钥:
client 172.21.248.41 {
    secret = testing123
    shortname = your-client
}
  1. 确认服务器没有将请求错误匹配到localhost客户端条目,可暂时注释localhost相关配置进行测试。

内容的提问来源于stack exchange,提问作者the7729

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 15:59:53