您的位置:首页 > 编程语言 > Java开发

Rabbit流密码的Java实现

2009-09-25 03:36 253 查看
1. Rabbit流密码(Rabbit Stream Cipher)简介

Rabbit流密码是由Cryptico公司(http://www.cryptico.com)设计的,密钥长度128位,

最大加密消息长度为264 Bytes,即16 TB,若消息超过该长度,则需要更换密钥对剩下的消息进行处理。它是目前安全性较高,加/解密速度比较高效的流密码之一,在各种处理器平台上都有不凡的表现。

详细资料:

1.http://www.cryptico.com/Files/filer/rabbit_fse.pdf

2.http://www.ietf.org/rfc/rfc4503.txt

本文实现了该算法的java语言实现,仅供参考。

Rabbit流密码的C/C++实现请参考我的加密算法库CryptoFBC: code.google.com/p/cryptofbc

2. 实现源码

/**
* The Java Implementation of Rabbit Stream Cipher
* @author cnbragon
* @email cnbragon_dot_163_dot_com
* @date 2009/09/25
* @note Not implemented IV scheme
* @Reference:
* 1.http://www.cryptico.com/Files/filer/rabbit_fse.pdf
* 2.http://www.ietf.org/rfc/rfc4503.txt
*/

class Rabbit
{
private int[] x = new int[8];
private int[] c = new int[8];
private int carry;

public void Rabbit()
{
for(int i = 0; i < 8; i++)
{
x[i] = c[i] = 0;
}
carry = 0;
}
private int g_func(int x)
{
int a = x & 0xffff;
int b = x >>> 16;

int h =( ( ( ( a * a ) >>> 17 ) + ( a * b ) ) >>> 15 ) + b * b;
int l = x * x;

return h ^ l;
}
/**
* @declaration 比较两个有符号整数的十六进制的大小,即作为无符号整数进行比较
* @param x
* @param y
* @return 若(unsigned x) < (unsigned y),则返回1,否则返回0
*/
private int compare(int x, int y)
{
long a = x;
long b = y;
a &= 0x00000000ffffffffl;
b &= 0x00000000ffffffffl;

return (a < b) ? 1 : 0;
}
private int rotL(int x, int y)
{
return ( x << y ) | ( x >>> (32 - y) );
}
private void next_state()
{
int[] g = new int[8];
int[] c_old = new int[8];
int i = 0;

for( i = 0; i < 8; i++)
{
c_old[i] = c[i];
}

c[0] += 0x4d34d34d + carry;
c[1] += 0xd34d34d3 + compare(c[0], c_old[0]);
c[2] += 0x34d34d34 + compare(c[1], c_old[1]);
c[3] += 0x4d34d34d + compare(c[2], c_old[2]);
c[4] += 0xd34d34d3 + compare(c[3], c_old[3]);
c[5] += 0x34d34d34 + compare(c[4], c_old[4]);
c[6] += 0x4d34d34d + compare(c[5], c_old[5]);
c[7] += 0xd34d34d3 + compare(c[6], c_old[6]);
carry = compare(c[7], c_old[7]);

for( i = 0; i < 8; i++)
{
g[i] = g_func(x[i] + c[i]);
}

x[0] = g[0] + rotL(g[7], 16) + rotL(g[6], 16);
x[1] = g[1] + rotL(g[0], 8 ) + g[7];
x[2] = g[2] + rotL(g[1], 16) + rotL(g[0], 16);
x[3] = g[3] + rotL(g[2], 8 ) + g[1];
x[4] = g[4] + rotL(g[3], 16) + rotL(g[2], 16);
x[5] = g[5] + rotL(g[4], 8 ) + g[3];
x[6] = g[6] + rotL(g[5], 16) + rotL(g[4], 16);
x[7] = g[7] + rotL(g[6], 8 ) + g[5];
}
/**
* @declaration 将一个字节数组转化为整数,采用Big-Endian格式进行解析
* @param a 待转化的字节数组
* @param i 字节数组的起始索引
* @return 转化后的整数
*/
public static int os2ip(byte[] a, int i)
{
int x0 = a[i + 3] & 0x000000ff;
int x1 = a[i + 2] << 8 & 0x0000ff00;
int x2 = a[i + 1] << 16 & 0x00ff0000;
int x3 = a[i] << 24 & 0xff000000;

return x0 | x1 | x2 | x3;
}
/**
* @declaration 将整数x转化为4字节数组,采用Big-Endian格式进行解析
* @param x 待转化的整数x
* @return 解析后的字节数组,长度为4
*/
public static byte[] i2osp(int x)
{
byte[] s = new byte[4];
s[3] = (byte)( x & 0x000000ff );
s[2] = (byte)( ( x & 0x0000ff00 ) >>> 8 );
s[1] = (byte)( ( x & 0x00ff0000 ) >>> 16 );
s[0] = (byte)( ( x & 0xff000000 ) >>> 24 );
return s;
}
/**
* @declaration 密钥初始化函数
* @param p_key 长度为128位的密钥数组,若密钥长度小于128位,
*               则必须在填充后再调用该函数
*/
public void keySetup(byte[] p_key)
{
int k0, k1, k2, k3, i;

k0 = os2ip(p_key, 12);
k1 = os2ip(p_key, 8);
k2 = os2ip(p_key, 4);
k3 = os2ip(p_key, 0);

x[0] = k0;
x[2] = k1;
x[4] = k2;
x[6] = k3;
x[1] = ( k3 << 16 ) | ( k2 >>> 16 );
x[3] = ( k0 << 16 ) | ( k3 >>> 16 );
x[5] = ( k1 << 16 ) | ( k0 >>> 16 );
x[7] = ( k2 << 16 ) | ( k1 >>> 16 );

c[0] = rotL(k2, 16);
c[2] = rotL(k3, 16);
c[4] = rotL(k0, 16);
c[6] = rotL(k1, 16);
c[1] = (k0 & 0xffff0000) | (k1 & 0x0000ffff);
c[3] = (k1 & 0xffff0000) | (k2 & 0x0000ffff);
c[5] = (k2 & 0xffff0000) | (k3 & 0x0000ffff);
c[7] = (k3 & 0xffff0000) | (k0 & 0x0000ffff);

carry = 0;
for( i = 0; i < 4; i++)
{
next_state();
}

for( i = 0; i < 8; i++)
{
c[ (i + 4) & 7 ] ^= x[i];
}
}

/**
* @declaration 该函数用于生成128位随机密钥,用于直接和明文进行异或处理
* @param p_dest  产生的128位随机密钥
* @param data_size 需要产生的随机密钥数量,必须是16的倍数
*/
public void getS(byte[] p_dest, long data_size)
{
int i, j, m;
int[] k = new int[4];
byte[] t = new byte[4];

for( i = 0; i < data_size; i+=16)
{
next_state();
k[0] = x[0] ^ ( x[5] >>> 16 ) ^ ( x[3] << 16 );
k[1] = x[2] ^ ( x[7] >>> 16 ) ^ ( x[5] << 16 );
k[2] = x[4] ^ ( x[1] >>> 16 ) ^ ( x[7] << 16 );
k[3] = x[6] ^ ( x[3] >>> 16 ) ^ ( x[1] << 16 );
for( j = 0; j < 4; j++)
{
t = i2osp(k[j]);
for( m = 0; m < 4; m++)
{
p_dest[ j * 4 + m ] = t[m];
}
}
}
}
/**
* @declaration 加密和解密函数
* @param p_src 需要加密或解密的消息,其长度必须是16的倍数,以字节为单位,
*               若不是16的倍数,则需要在调用该函数前进行填充,一般填充值
*               为0的字节
* @param p_dest 加密或解密的结果,其长度必须是16的倍数,以字节为单位
*                并且长度必须大于等于p_src的长度
* @param data_size 需要处理的消息的长度,必须是16的倍数,以字节为单位
*                   其值为p_src的长度
*/
public void cipher(byte[] p_src, byte[] p_dest, long data_size)
{
int i, j, m;
int[] k = new int[4];
byte[] t = new byte[4];

for( i = 0; i < data_size; i+=16)
{
next_state();
k[0] = os2ip(p_src, i * 16 + 0) ^ x[0] ^ ( x[5] >>> 16 ) ^ ( x[3] << 16 );
k[1] = os2ip(p_src, i * 16 + 4) ^ x[2] ^ ( x[7] >>> 16 ) ^ ( x[5] << 16 );
k[2] = os2ip(p_src, i * 16 + 8) ^ x[4] ^ ( x[1] >>> 16 ) ^ ( x[7] << 16 );
k[3] = os2ip(p_src, i * 16 + 12) ^ x[6] ^ ( x[3] >>> 16 ) ^ ( x[1] << 16 );
for( j = 0; j < 4; j++)
{
t = i2osp(k[j]);
for( m = 0; m < 4; m++)
{
p_dest[ i * 16 + j * 4 + m ] = t[m];
}
}
}
}
}
public class Main {
public static void main(String[] args) {
/**
* 定义测试密钥key,需要注意的是,由于java没有unsigned类型,
* 所以需要对大于等于0x80的字节进行类型转换,
* 比较方便的办法是都加上(byte)
*/
byte[] key = {
(byte)0xa0, (byte)0x33, (byte)0xd6, (byte)0x78,
(byte)0x6b, (byte)0x05, (byte)0x14, (byte)0xac,
(byte)0xfc, (byte)0x3d, (byte)0x8e, (byte)0x2d,
(byte)0x6a, (byte)0x2c, (byte)0x27, (byte)0x1d
};
/**
* 定义待加密的消息message,密文ciphertext,并初始化为0
*/
byte[] message = new byte[16];
byte[] ciphertext = new byte[16];
for( int i = 0; i < 16; i++)
{
message[i] = (byte)i;
ciphertext[i] = 0;
}
/**
* 调用Rabbit流密码进行加密
*/
Rabbit rtest = new Rabbit();
/*
* 初始化密钥
*/
rtest.keySetup(key);
/*
* 加密
*/
rtest.cipher(message, ciphertext, 16);
for( int i = 0; i < 16; i++)
{
System.out.printf("%02x ", ciphertext[i]);
}
System.out.println();
/**
* 调用Rabbit流密码进行解密
*/
Rabbit rtest2 = new Rabbit();
/*
* 初始化密钥
*/
rtest2.keySetup(key);
byte[] szT = new byte[16];
for( int i = 0; i < 16; i++)
{
szT[i] = 0;
}
/*
* 解密
*/
rtest2.cipher(ciphertext, szT, 16);
for( int i = 0; i < 16; i++)
{
System.out.printf("%02x ", szT[i]);
}
System.out.println();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: