我尝试从这段代码中测试 spritz 密码学。它在使用 N =256 时有效,但我想将 N 减少到 8 。当我运行它显示 assertEquals error 的代码时,我设置了 N=8 并将 255 更改为 7 。当我将数组 256 减少到 8 或者它应该等于结果时,我不确定这个错误是否正常。请帮助我如何将数组 N 从 256 减少到 8
主要的
public class JavaApplication1 {
final static byte[][][] REF_DATA_STREAM = {
{ "ABC" .getBytes(), new byte[]{(byte)0x77,(byte)0x9a,(byte)0x8e,(byte)0x01,(byte)0xf9,(byte)0xe9,(byte)0xcb,(byte)0xc0}}
};
final static byte[][][] REF_DATA_HASH = {
{ "ABC" .getBytes(), new byte[]{(byte)0x02,(byte)0x8f,(byte)0xa2,(byte)0xb4,(byte)0x8b,(byte)0x93,(byte)0x4a,(byte)0x18}},
{ "spam" .getBytes(), new byte[]{(byte)0xac,(byte)0xbb,(byte)0xa0,(byte)0x81,(byte)0x3f,(byte)0x30,(byte)0x0d,(byte)0x3a}},
{ "arcfour".getBytes(), new byte[]{(byte)0xff,(byte)0x8c,(byte)0xf2,(byte)0x68,(byte)0x09,(byte)0x4c,(byte)0x87,(byte)0xb9}}
};
@Test
public static void testStream() {
for (byte[][] refData : REF_DATA_STREAM) {
SpritzState ss = new SpritzState();
byte[] key = refData[0];
ss.streamInit(key, 0, key.length);
byte[] expected = refData[1];
byte[] out = new byte[3];
for (int i = 0; i < expected.length; i++) {
out[0] = 55;
out[2] = 8;
ss.streamRead(out, 1, 1);
System.out.println(out[1]);
System.out.println(expected[i]);
//assertEquals(out[1], expected[i]);
}
}
}
@Test
public static void testHash() {
for (byte[][] refData : REF_DATA_HASH) {
SpritzState ss = new SpritzState();
ss.hashInit();
byte[] buf = refData[0];
for (int ofs = 0; ofs < buf.length; ofs++) {
ss.hashUpdate(buf, ofs, 1);
}
byte[] hash = new byte[33];
hash[0] = (byte)0xcc;
ss.hashFinal(hash, 1, 32);
byte[] must = refData[1];
for (int i = 0; i < must.length; i++) {
assertEquals(hash[i + 1], must[i]);
}
assertEquals(hash[0], (byte)0xcc);
}
}
@Test
public void testCipher() {
final byte[] key = new byte[101];
for (int i = 1; i < key.length; i++)
key[i] = (byte)(80 + i);
final byte[] iv = new byte[51];
for (int i = 1; i < iv.length; i++)
iv[i] = (byte)i;
byte[] plainText = new byte[257];
for (int i = 1; i < plainText.length; i++)
plainText[i] = (byte)i;
SpritzState ss = new SpritzState();
ss.cipherInit(key, 1, 100, iv, 1, 50);
byte[] cipherText = new byte[1 + plainText.length + 1];
ss.cipherEncrypt(plainText, 1, 256, cipherText, 1);
assertEquals(0, cipherText[0]);
assertEquals(0, cipherText[257]);
for (int i = 1; i < plainText.length; i++)
assertEquals(plainText[i], (byte)i);
key[0] = iv[0] = (byte)0xcc;
ss = new SpritzState();
ss.cipherInit(key, 1, 100, iv, 1, 50);
byte[] plainText2 = new byte[256];
ss.cipherDecrypt(cipherText, 1, 256, plainText2, 0);
byte[] a = Arrays.copyOfRange(plainText , 1, 257);
byte[] b = Arrays.copyOfRange(plainText2, 0, 256);
assertTrue(Arrays.equals(a, b));
ss.erase();
}
@Test
public void testCipher2() {
final int IV_LEN = 10;
byte[] ref = new byte[] {
(byte)0x04,(byte)0x15,(byte)0xaa,(byte)0xf4,(byte)0x1e,(byte)0xd4,
(byte)0xc9,(byte)0x20,(byte)0xec,(byte)0xcc,(byte)0x7e,(byte)0x1c,
(byte)0x8a,(byte)0x0e,(byte)0x80,(byte)0x43,(byte)0x21,(byte)0xe2,
(byte)0x4d,(byte)0xb2,(byte)0xae};
byte[] key = "test123".getBytes();
SpritzState ss = new SpritzState();
ss.cipherInit(key, 0, key.length, ref, 0, IV_LEN);
byte[] must = "spritzsaber".getBytes();
assertEquals(IV_LEN + must.length, ref.length);
byte[] decr = new byte[must.length];
ss.cipherDecrypt(ref, IV_LEN, must.length, decr, 0);
byte[] a = Arrays.copyOfRange(must, 0, must.length);
byte[] b = Arrays.copyOfRange(decr, 0, must.length);
assertTrue(Arrays.equals(a, b));
}
public static void main(String[] args) {
JavaApplication1.testStream();
}
}
SpritzState.java
public class SpritzState {
final static int N = 8;
final static int[] S_INIT = new int[N];
static {
for (int i = 0; i < S_INIT.length; i++)
S_INIT[i] = i;
}
///////////////////////////////////////////////////////////////////////////
private int[] s;
private int a, i, j, k, w, z;
private void initializeState() {
this.s = S_INIT.clone();
this.a = this.i = this.j = this.k = this.z = 0;
this.w = 1;
}
private void update() {
this.i += this.w;
this.i &= 7;
int y = (this.j + this.s[this.i]) & 7;
this.j = (this.k + this.s[y]) & 7;
this.k = (this.i + this.k + this.s[this.j]) & 7;
int t = this.s[this.i & 0xff];
this.s[this.i] = this.s[this.j];
this.s[this.j] = t;
}
private int output() {
int y1 = (this.z + this.k) & 7;
int x1 = (this.i + this.s[y1]) & 7;
int y2 = (this.j + this.s[x1]) & 7;
this.z = this.s[y2];
return this.z;
}
private void crush() {
for (int v = 0; v < N / 2; v++) {
int y = (N - 1) - v;
int x1 = this.s[v];
int x2 = this.s[y];
if (x1 > x2) {
this.s[v] = x2;
this.s[y] = x1;
} else {
this.s[v] = x1;
this.s[y] = x2;
}
}
}
private void whip() {
for (int v = 0; v < N * 2; v++) {
update();
}
this.w += 2;
}
private void shuffle() {
whip();
crush();
whip();
crush();
whip();
this.a = 0;
}
private void absorbStop() {
if (this.a == N / 2) {
shuffle();
}
this.a++;
}
private void absorbNibble(int x) {
if (this.a == N / 2) {
shuffle();
}
int y = (N / 2 + x) & 7;
int t = this.s[this.a];
this.s[this.a] = this.s[y];
this.s[y] = t;
this.a++;
}
private void absorbByte(int b) {
absorbNibble( b & 0x0F ); // low bits
absorbNibble( (b & 0xFF) >> 4 ); // high bits
}
private void absorb(byte[] msg, int ofs, int len) {
for (int end = ofs + len; ofs < end; ofs++) {
absorbByte(msg[ofs] & 7);
}
}
private int drip() {
if (this.a > 0) {
shuffle();
}
update();
return output();
}
private void squeeze(byte[] out, int ofs, int len) {
if (this.a > 0) {
shuffle();
}
for (int end = ofs + len; ofs < end; ofs++) {
out[ofs] = (byte)drip();
}
}
private void keySetup(byte[] key, int ofs, int len) {
initializeState();
absorb(key, ofs, len);
// One C implementation does this, but it's not in the paper...
//if (this.a > 0) {
// shuffle();
//}
}
///////////////////////////////////////////////////////////////////////////
public void erase() {
Arrays.fill(this.s, 0);
this.a = this.i = this.j = this.k = this.w = this.z = 0;
}
///////////////////////////////////////////////////////////////////////////
// streaming API ...
public void streamInit(byte[] key, int ofs, int len) {
initializeState();
absorb(key, ofs, len);
}
public void streamRead(byte[] out, int ofs, int len) {
squeeze(out, ofs, len);
}
///////////////////////////////////////////////////////////////////////////
// hash API ...
public void hashInit() {
initializeState();
this.a = 0;
this.i = 0;
this.j = 0;
this.k = 0;
this.w = 1;
this.z = 0;
}
public void hashUpdate(int aByte) {
absorbByte(aByte);
}
public void hashUpdate(byte[] buf, int ofs, int len) {
for (int end = ofs + len; ofs < end; ofs++) {
absorbByte(buf[ofs]);
}
}
public void hashFinal(byte[] hash, int ofs, int len) {
absorbStop();
absorbByte(len & 7);
squeeze(hash, ofs, len);
}
///////////////////////////////////////////////////////////////////////////
// encryption API ...
public void cipherInit(byte[] key, int keyOfs, int keyLen,
byte[] iv , int ivOfs , int ivLen) {
keySetup(key, keyOfs, keyLen);
absorbStop();
absorb(iv, ivOfs, ivLen);
}
public void cipherEncrypt(byte[] in , int inOfs , int len,
byte[] out, int outOfs) {
for (int i = 0; i < len; i++)
out[outOfs + i] = (byte)(in[inOfs + i] + drip());
}
public void cipherDecrypt(byte[] in , int inOfs , int len,
byte[] out, int outOfs) {
for (int i = 0; i < len; i++)
out[outOfs + i] = (byte)(in[inOfs + i] - drip());
}
///////////////////////////////////////////////////////////////////////////
// void printState() {
// System.out.println(String.format("STATE i=%d j=%d k=%d z=%d a=%d w=%d",
// this.i, this.j, this.k, this.z, this.a, this.w));
// for (int s: this.s)
// System.out.print(String.format("%02x:", s));
// System.out.println("-----------");
// }
}
这条线的输出是
System.out.println(out[1]);
4 0 0 2 6 3 3 3
System.out.println(expected[i]);
//assertEquals(out[1], expected[i]);
119 -102 -114 1 -7 -23 -53 -64