含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的计算逻辑顺序错误,具体问题点:
- 计算HMAC-MD5时,需要先在请求中添加全0的Message-Authenticator占位符,再生成完整数据包字节流进行哈希;你的代码是先生成无占位符的数据包,再补全0字节,导致哈希计算的基础数据错误。
createPacketBytes方法计算数据包长度时,未提前考虑Message-Authenticator占位符的长度,导致头部长度字段与实际数据包不匹配。- 错误提示中
from client localhost说明服务器可能将你的请求匹配到了localhost的客户端条目,而非你配置的172.21.248.41条目,需检查客户端配置。
正确的Message-Authenticator实现方法
核心步骤
- 创建AccessRequest并设置随机请求认证符(Request-Authenticator)。
- 添加值为全0的Message-Authenticator属性作为占位符。
- 生成包含占位符的完整请求数据包字节流。
- 用共享密钥对字节流计算HMAC-MD5,得到Message-Authenticator有效值。
- 替换占位符的属性值为计算结果。
- 发送请求。
修正后的完整代码
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(); } }
服务器端配置检查
- 确保FreeRADIUS的
clients.conf中,你的客户端IP(172.21.248.41)配置了正确的共享密钥:
client 172.21.248.41 { secret = testing123 shortname = your-client }
- 确认服务器没有将请求错误匹配到
localhost客户端条目,可暂时注释localhost相关配置进行测试。
内容的提问来源于stack exchange,提问作者the7729
相关产品推荐
相关产品推荐

