package jane.tool;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.filterchain.IoFilterAdapter;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.core.write.WriteRequest;
/**
* RC4加密算法的mina网络过滤器
* <p>
* 此类可直接使用或作为示例编写其它的加密或压缩相关的过滤器<br>
* 可在合适的时机调用下面几行代码来启用:<br>
* <code><pre>
* RC4Filter filter = new RC4Filter();
* filter.setInputKey(...);
* filter.setOutputKey(...);
* session.getFilterChain().addFirst("enc", filter);
* </pre></code>
*/
public final class RC4Filter extends IoFilterAdapter
{
private final byte[] _ctxI = new byte[256];
private final byte[] _ctxO = new byte[256];
private int _idx1I, _idx2I;
private int _idx1O, _idx2O;
private static void setKey(byte[] ctx, byte[] key, int len)
{
for(int i = 0; i < 256; ++i)
ctx[i] = (byte)i;
if(len > key.length) len = key.length;
if(len <= 0) return;
for(int i = 0, j = 0, k = 0; i < 256; ++i)
{
k = (k + ctx[i] + key[j]) & 0xff;
if(++j >= len) j = 0;
byte t = ctx[i];
ctx[i] = ctx[k];
ctx[k] = t;
}
}
/**
* 设置网络输入流的对称密钥
* <p>
* @param key 密钥内容,可以是任意数据
* @param len 密钥的长度,最多256字节有效
*/
public void setInputKey(byte[] key, int len)
{
setKey(_ctxI, key, len);
_idx1I = _idx2I = 0;
}
/**
* 设置网络输出流的对称密钥
* <p>
* @param key 密钥内容,可以是任意数据
* @param len 密钥的长度,最多256字节有效
*/
public void setOutputKey(byte[] key, int len)
{
setKey(_ctxO, key, len);
_idx1O = _idx2O = 0;
}
private static int update(byte[] ctx, int idx1, int idx2, byte[] buf, int pos, int len)
{
for(int i = 0; i < len; ++i)
{
idx1 = (idx1 + 1) & 0xff;
idx2 = (idx2 + ctx[idx1]) & 0xff;
byte k = ctx[idx1];
ctx[idx1] = ctx[idx2];
ctx[idx2] = k;
buf[pos + i] ^= ctx[(ctx[idx1] + ctx[idx2]) & 0xff];
}
return idx2;
}
/**
* 加解密一段输入数据
* <p>
* 加解密是对称的
* @param buf 数据的缓冲区
* @param pos 数据缓冲区的起始位置
* @param len 数据的长度
*/
public void updateInput(byte[] buf, int pos, int len)
{
_idx2I = update(_ctxI, _idx1I, _idx2I, buf, pos, len);
_idx1I = (_idx1I + len) & 0xff;
}
/**
* 加解密一段输出数据
* <p>
* 加解密是对称的
* @param buf 数据的缓冲区
* @param pos 数据缓冲区的起始位置
* @param len 数据的长度
*/
public void updateOutput(byte[] buf, int pos, int len)
{
_idx2O = update(_ctxO, _idx1O, _idx2O, buf, pos, len);
_idx1O = (_idx1O + len) & 0xff;
}
@Override
public void messageReceived(NextFilter nextFilter, IoSession session, Object message)
{
if(message instanceof IoBuffer)
{
IoBuffer ioBuf = (IoBuffer)message;
if(ioBuf.hasArray())
updateInput(ioBuf.array(), ioBuf.position(), ioBuf.remaining());
else
{
int len = ioBuf.remaining();
byte[] buf = new byte[len];
int pos = ioBuf.position();
ioBuf.get(buf, 0, len);
ioBuf.position(pos);
updateInput(buf, 0, len);
ioBuf.put(buf, 0, len);
ioBuf.position(pos);
}
}
nextFilter.messageReceived(session, message);
}
@Override
public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest)
{
Object message = writeRequest.getMessage();
if(message instanceof IoBuffer)
{
IoBuffer ioBuf = (IoBuffer)message;
if(ioBuf.hasArray())
updateOutput(ioBuf.array(), ioBuf.position(), ioBuf.remaining());
else
{
int len = ioBuf.remaining();
byte[] buf = new byte[len];
int pos = ioBuf.position();
ioBuf.get(buf, 0, len);
ioBuf.position(pos);
updateOutput(buf, 0, len);
ioBuf.put(buf, 0, len);
ioBuf.position(pos);
}
}
nextFilter.filterWrite(session, writeRequest);
}
}