<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>肉包子的摇滚生活 &#187; radius</title>
	<atom:link href="http://www.fangyuqiang.com/archives/tag/radius/feed" rel="self" type="application/rss+xml" />
	<link>http://www.fangyuqiang.com</link>
	<description>前端开发，交互设计，用户体验</description>
	<lastBuildDate>Wed, 01 Sep 2010 09:06:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>JRadius在windows下的编译错误，警惕windows与linux的编译环境差别</title>
		<link>http://www.fangyuqiang.com/archives/664</link>
		<comments>http://www.fangyuqiang.com/archives/664#comments</comments>
		<pubDate>Tue, 03 Nov 2009 02:38:46 +0000</pubDate>
		<dc:creator>fangyuqiang</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[radius]]></category>

		<guid isPermaLink="false">http://www.fangyuqiang.com/?p=664</guid>
		<description><![CDATA[目前在做radius项目，项目采用Freeradius，c语言写的，提供java开发接口，我们部门主要以java为主，所以需要调研JRadius的开发。 JRadius虽然是个不错的项目，但是看得出来，无论是作者还是使用JRadius的开发者都让人觉得漫不经心。。论坛空空荡荡，mailing list几乎为空，wiki上面的页面也相当少。杯具。 svn上面down下来JRadius，我采用的是tags下面的1.0版本，虽然官方文档上的例子是trunk版本，但是trunk其实一般都是出于开发阶段，我们不是想要研究而是想要使用的，所以还是采用正式的tags下的版本比较好。 mvn install。编译失败。 D:eclipseworkspacejradius-1.0dictionarytargetdictionary-srcnetjradiusdi ctionaryvsa_dhcpAttr_DHCPBootFilename.java:[20,13] 类 Attr_DHCPBootFileName 是 公共的，应在名为 Attr_DHCPBootFileName.java 的文件中声明 我囧，这是啥错误啊，看来看去这文件名跟类名没有错啊，尝试了无数次，反复查看了文件名跟类名，没错啊。。。 最终，终于让我发现了一个问题，生成的文件名是DHCPBootFilename，而类名是DHCPBootFileName，大小写不同。奇怪，这又是怎么回事，查看了下它用来生成这个文件的代码，没有错啊。为什么生成的文件大小写会不一样？ 查看它用来生成代码的工具类，反复调试。。没错。。完全没错。。郁闷了。。 查看了dictionary配置文件，艹，终于让我发现了端倪，配置文件需要2个属性，分别是： ATTRIBUTE    DHCP-Boot-Filename            269    string      # 128 octets ATTRIBUTE    DHCP-Boot-File-Name            67    string 按照生成器的逻辑，它会生成： DHCPBootFilename.java DHCPBootFileName.java 关键的问题就在于，我的环境是windows，windows文件名不区分大小写，结果文件内容会被直接覆盖掉。而开发者的环境是linux，所以他可以顺利编译发布出来。 解决这个问题，没什么特别的方法，要嘛就是开发了以后到linux上面编译。或者把dictionary的编译放到linux上面，然后作为依赖包引入到开发环境中。 个人建议是所有开发的代码都上传到linux下去编译，因为产品环境会在linux下面，在linux下面编译测试才最接近实际。毕竟项目的编译会依赖于操作系统。]]></description>
			<content:encoded><![CDATA[<p>目前在做radius项目，项目采用<a href="http://freeradius.org/" target="_blank">Freeradius</a>，c语言写的，提供java开发接口，我们部门主要以java为主，所以需要调研<a href="http://www.coova.org/JRadius" target="_blank">JRadius</a>的开发。</p>
<p><a href="http://www.coova.org/JRadius" target="_blank">JRadius</a><strong>虽然是个不错的项目，但是看得出来，无论是作者还是使用</strong><a href="http://www.coova.org/JRadius" target="_blank">JRadius</a><strong>的开发者都让人觉得漫不经心</strong>。。论坛空空荡荡，mailing list几乎为空，wiki上面的页面也相当少。杯具。<span id="more-664"></span></p>
<p>svn上面down下来<a href="http://www.coova.org/JRadius" target="_blank">JRadius</a>，我采用的是tags下面的1.0版本，虽然官方文档上的例子是trunk版本，但是trunk其实一般都是出于开发阶段，我们不是想要研究而是想要使用的，所以还是采用正式的tags下的版本比较好。</p>
<p>mvn install。编译失败。</p>
<p>D:eclipseworkspacejradius-1.0dictionarytargetdictionary-srcnetjradiusdi<br />
ctionaryvsa_dhcpAttr_DHCPBootFilename.java:[20,13] 类 Attr_DHCPBootFileName 是<br />
公共的，应在名为 Attr_DHCPBootFileName.java 的文件中声明</p>
<p>我囧，这是啥错误啊，看来看去这文件名跟类名没有错啊，尝试了无数次，反复查看了文件名跟类名，没错啊。。。</p>
<p>最终，<strong>终于让我发现了一个问题，生成的文件名是DHCPBootFilename，而类名是DHCPBootFileName，大小写不同。奇怪，这又是怎么回事</strong>，查看了下它用来生成这个文件的代码，没有错啊。为什么生成的文件大小写会不一样？</p>
<p>查看它用来生成代码的工具类，反复调试。。没错。。完全没错。。郁闷了。。</p>
<p>查看了dictionary配置文件，艹，终于让我发现了端倪，配置文件需要2个属性，分别是：</p>
<p>ATTRIBUTE    DHCP-Boot-Filename            269    string      # 128 octets</p>
<p>ATTRIBUTE    DHCP-Boot-File-Name            67    string</p>
<p>按照生成器的逻辑，它会生成：</p>
<p>DHCPBootFilename.java</p>
<p>DHCPBootFileName.java</p>
<p><strong>关键的问题就在于，我的环境是windows，windows文件名不区分大小写，结果文件内容会被直接覆盖掉。而开发者的环境是linux，所以他可以顺利编译发布出来。</strong></p>
<p>解决这个问题，没什么特别的方法，要嘛就是开发了以后到linux上面编译。或者把dictionary的编译放到linux上面，然后作为依赖包引入到开发环境中。</p>
<p>个人建议是所有开发的代码都上传到linux下去编译，因为产品环境会在linux下面，在linux下面编译测试才最接近实际。毕竟项目的编译会依赖于操作系统。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.fangyuqiang.com/archives/664/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Java实现RFC2865 Radius协议的密码加密</title>
		<link>http://www.fangyuqiang.com/archives/448</link>
		<comments>http://www.fangyuqiang.com/archives/448#comments</comments>
		<pubDate>Fri, 07 Aug 2009 02:20:18 +0000</pubDate>
		<dc:creator>fangyuqiang</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[radius]]></category>
		<category><![CDATA[算法]]></category>

		<guid isPermaLink="false">http://www.fangyuqiang.com/?p=448</guid>
		<description><![CDATA[最近项目中要做Radius协议的客户端，一看Radius几百页的协议，我头皮都发麻。放狗搜索一番，发现了一个实现好的Java的Radius客户端，哈哈，很好很强大： http://sourceforge.net/projects/jradius-client/ 摸索了一番，挖出了里面关于用户密码加密的一段代码，相信对很多想学习下Java MD5加密的同学会很有帮助。 首先来了解一番背景跟算法要求： User-Password 描述 该属性表示用户用来认证的用户密码，或者是用户在收到接入挑战报文后用户的输入。它只出现在接入请求报文中。 在传输的过程中，密码是隐藏起来的，首先，将密码用null（\0）填充到16的整数倍个字节长，然后对在请求认证字后面加上共享密钥的字节流进行MD5加密生成hash值，将该hash值和密码的第一个16字节进行异或，然后将结果放入User-Password属性的第一个16字节中。 如果密码长度超过16个字符，则对第一个异或值后面加上共享密钥的字节流进行MD5加密生成hash值。该hash值和密码的第二个16个字节进行异或，然后将异或值放入User-Password属性的第二个16字节中。 如果必要，重复这个操作，每一个异或值后面加上共享密钥产生下一个hash值，然后和密码下一段的16字节进行异或。密码最长不能超过128个字符。 这个方法引用自Kaufman, Perlman和Speciner合写的《网络安全》一书，在第109到第110页。该方法的一个更加精确的解释如下： 共享密钥为S，伪随机数Request Authenticator为RA，将密码拆分成多个16个字节的块p1，p2，等等。最后一块用null（\0）填充满16个字节，密码块为c(1)，c(2)，等等。中间值为b1，b2，等等。 b1 = MD5(S + RA) c(1) = p1 xor b1 b2 = MD5(S + c(1)) c(2) = p2 xor b2 . . . . . . bi = MD5(S + c(i-1)) c(i) = pi xor bi User-Password属性字符串为c(1)+c(2)+&#8230;c(i)，+表示连接。 一旦接收到报文，逆向处理就能得到密码明文。 User-Password属性的格式如下所示。各个域是按照自左向右的顺序传输的。 0 [...]]]></description>
			<content:encoded><![CDATA[<p>最近项目中要做Radius协议的客户端，一看Radius几百页的协议，我头皮都发麻。放狗搜索一番，发现了一个实现好的Java的Radius客户端，哈哈，很好很强大：</p>
<p><a href="http://sourceforge.net/projects/jradius-client/" target="_blank">http://sourceforge.net/projects/jradius-client/ </a></p>
<p>摸索了一番，挖出了里面关于用户密码加密的一段代码，相信对很多想学习下Java MD5加密的同学会很有帮助。</p>
<p><span id="more-448"></span>首先来了解一番背景跟算法要求：</p>
<p>User-Password</p>
<p><strong>描述</strong></p>
<p>该属性表示用户用来认证的用户密码，或者是用户在收到接入挑战报文后用户的输入。它只出现在接入请求报文中。</p>
<p>在传输的过程中，密码是隐藏起来的，首先，将密码用null（\0）填充到16的整数倍个字节长，然后对在请求认证字后面加上共享密钥的字节流进行MD5加密生成hash值，将该hash值和密码的第一个16字节进行异或，然后将结果放入User-Password属性的第一个16字节中。</p>
<p>如果密码长度超过16个字符，则对第一个异或值后面加上共享密钥的字节流进行MD5加密生成hash值。该hash值和密码的第二个16个字节进行异或，然后将异或值放入User-Password属性的第二个16字节中。</p>
<p>如果必要，重复这个操作，每一个异或值后面加上共享密钥产生下一个hash值，然后和密码下一段的16字节进行异或。密码最长不能超过128个字符。</p>
<p>这个方法引用自Kaufman, Perlman和Speciner合写的《网络安全》一书，在第109到第110页。该方法的一个更加精确的解释如下：</p>
<blockquote><p>共享密钥为S，伪随机数Request Authenticator为RA，将密码拆分成多个16个字节的块p1，p2，等等。最后一块用null（\0）填充满16个字节，密码块为c(1)，c(2)，等等。中间值为b1，b2，等等。</p>
<p>b1 = MD5(S + RA)       c(1) = p1 xor b1<br />
b2 = MD5(S + c(1))     c(2) = p2 xor b2<br />
.                       .<br />
.                       .<br />
.                       .<br />
bi = MD5(S + c(i-1))   c(i) = pi xor bi<br />
User-Password属性字符串为c(1)+c(2)+&#8230;c(i)，+表示连接。<br />
一旦接收到报文，逆向处理就能得到密码明文。</p></blockquote>
<p>User-Password属性的格式如下所示。各个域是按照自左向右的顺序传输的。</p>
<pre>    0              1               2
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
   |     Type      |    Length     |  String ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-</pre>
<p><strong>类型</strong></p>
<p>2               代表用户密码</p>
<p><strong>长度</strong></p>
<p>至少18字节，但不能超过130个字节</p>
<p><strong>字符串</strong></p>
<p>本字符串占位16到128（包含）个字节。</p>
<h3>Java RADIUS Client的密码生成实现</h3>
<p>//生成请求的Authenticator</p>
<pre title="code" class="java">byte [] requestAuthenticator = this.makeRFC2865RequestAuthenticator();

//Authenticator的生成
private byte[] makeRFC2865RequestAuthenticator() {
 byte [] requestAuthenticator = new byte[16];

 Random r = new Random();

 for (int i = 0; i &lt; 16; i++)
 {
 requestAuthenticator[i] = (byte) r.nextInt();
 }

 this.md5MessageDigest.reset();
 this.md5MessageDigest.update(this.sharedSecret.getBytes());//sharedSecret指的是服务器端与客户端的共享密钥
 this.md5MessageDigest.update(requestAuthenticator);

 return this.md5MessageDigest.digest();//返回生成的hash值
 }
//生成加密后的密钥，userPass指未加密的密码
byte [] encryptedPass = this.encodePapPassword(userPass, requestAuthenticator);

//用来加密的算法
	private byte[] encodePapPassword(final byte[] userPass,
			final byte[] requestAuthenticator) {
		// encrypt the password.
		byte[] userPassBytes = null;
//密码必须大于16小于或者等于128bytes,如果不是16的整数倍个字节长，不足的位补0。如果大于128位，则截断成128位。

		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) {
				 // 如果是16的整数倍长
				encryptedPass = new byte[userPassBytes.length];
			} else {
				// 数组长度变成16位的整数倍长
				encryptedPass = new byte[((userPassBytes.length / 16) * 16) + 16];
			}
		} else {
			// the encrypted password must be between 16 and 128 bytes
			encryptedPass = new byte[128];
		}

		 // 填充0
		System.arraycopy(userPassBytes, 0, encryptedPass, 0,
				userPassBytes.length);
		for (int i = userPassBytes.length; i < encryptedPass.length; i++) {
			encryptedPass[i] = 0; // fill it out with zeroes
		}
		this.md5MessageDigest.reset();
		 // 添加共享密钥
		this.md5MessageDigest.update(this.sharedSecret.getBytes());
		 // 添加请求Authenticator
		this.md5MessageDigest.update(requestAuthenticator);
		//  //获得md5 hash( b1 = MD5(S + RA) ).
		byte bn[] = this.md5MessageDigest.digest();

		for (int i = 0; i < 16; i++) {
			// perform the XOR as specified by RFC 2865.
			encryptedPass[i] = (byte) (bn[i] ^ encryptedPass[i]);
		}

		if (encryptedPass.length > 16) {
			for (int i = 16; i < encryptedPass.length; i += 16) {
				this.md5MessageDigest.reset();
				// add the shared secret
				this.md5MessageDigest.update(this.sharedSecret.getBytes());
				// add the previous(encrypted) 16 bytes of the user password
				this.md5MessageDigest.update(encryptedPass, i - 16, 16);
				// get the md5 hash( bn = MD5(S + c(i-1)) ).
				bn = this.md5MessageDigest.digest();
				for (int j = 0; j < 16; j++) {
					// perform the XOR as specified by RFC 2865.
					encryptedPass[i + j] = (byte) (bn[j] ^ encryptedPass[i + j]);
				}
			}
		}
		return encryptedPass;
	}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.fangyuqiang.com/archives/448/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
