org.h2.security.XTEA Maven / Gradle / Ivy
/*
* Copyright 2004-2019 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (https://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.security;
import org.h2.message.DbException;
import org.h2.util.Bits;
/**
* An implementation of the XTEA block cipher algorithm.
*
* This implementation uses 32 rounds.
* The best attack reported as of 2009 is 36 rounds (Wikipedia).
*/
public class XTEA implements BlockCipher {
private static final int DELTA = 0x9E3779B9;
private int k0, k1, k2, k3, k4, k5, k6, k7;
private int k8, k9, k10, k11, k12, k13, k14, k15;
private int k16, k17, k18, k19, k20, k21, k22, k23;
private int k24, k25, k26, k27, k28, k29, k30, k31;
@Override
public void setKey(byte[] b) {
int[] key = new int[4];
for (int i = 0; i < 16; i += 4) {
key[i / 4] = Bits.readInt(b, i);
}
int[] r = new int[32];
for (int i = 0, sum = 0; i < 32;) {
r[i++] = sum + key[sum & 3];
sum += DELTA;
r[i++] = sum + key[ (sum >>> 11) & 3];
}
k0 = r[0]; k1 = r[1]; k2 = r[2]; k3 = r[3];
k4 = r[4]; k5 = r[5]; k6 = r[6]; k7 = r[7];
k8 = r[8]; k9 = r[9]; k10 = r[10]; k11 = r[11];
k12 = r[12]; k13 = r[13]; k14 = r[14]; k15 = r[15];
k16 = r[16]; k17 = r[17]; k18 = r[18]; k19 = r[19];
k20 = r[20]; k21 = r[21]; k22 = r[22]; k23 = r[23];
k24 = r[24]; k25 = r[25]; k26 = r[26]; k27 = r[27];
k28 = r[28]; k29 = r[29]; k30 = r[30]; k31 = r[31];
}
@Override
public void encrypt(byte[] bytes, int off, int len) {
if (len % ALIGN != 0) {
DbException.throwInternalError("unaligned len " + len);
}
for (int i = off; i < off + len; i += 8) {
encryptBlock(bytes, bytes, i);
}
}
@Override
public void decrypt(byte[] bytes, int off, int len) {
if (len % ALIGN != 0) {
DbException.throwInternalError("unaligned len " + len);
}
for (int i = off; i < off + len; i += 8) {
decryptBlock(bytes, bytes, i);
}
}
private void encryptBlock(byte[] in, byte[] out, int off) {
int y = Bits.readInt(in, off);
int z = Bits.readInt(in, off + 4);
y += (((z << 4) ^ (z >>> 5)) + z) ^ k0;
z += (((y >>> 5) ^ (y << 4)) + y) ^ k1;
y += (((z << 4) ^ (z >>> 5)) + z) ^ k2;
z += (((y >>> 5) ^ (y << 4)) + y) ^ k3;
y += (((z << 4) ^ (z >>> 5)) + z) ^ k4;
z += (((y >>> 5) ^ (y << 4)) + y) ^ k5;
y += (((z << 4) ^ (z >>> 5)) + z) ^ k6;
z += (((y >>> 5) ^ (y << 4)) + y) ^ k7;
y += (((z << 4) ^ (z >>> 5)) + z) ^ k8;
z += (((y >>> 5) ^ (y << 4)) + y) ^ k9;
y += (((z << 4) ^ (z >>> 5)) + z) ^ k10;
z += (((y >>> 5) ^ (y << 4)) + y) ^ k11;
y += (((z << 4) ^ (z >>> 5)) + z) ^ k12;
z += (((y >>> 5) ^ (y << 4)) + y) ^ k13;
y += (((z << 4) ^ (z >>> 5)) + z) ^ k14;
z += (((y >>> 5) ^ (y << 4)) + y) ^ k15;
y += (((z << 4) ^ (z >>> 5)) + z) ^ k16;
z += (((y >>> 5) ^ (y << 4)) + y) ^ k17;
y += (((z << 4) ^ (z >>> 5)) + z) ^ k18;
z += (((y >>> 5) ^ (y << 4)) + y) ^ k19;
y += (((z << 4) ^ (z >>> 5)) + z) ^ k20;
z += (((y >>> 5) ^ (y << 4)) + y) ^ k21;
y += (((z << 4) ^ (z >>> 5)) + z) ^ k22;
z += (((y >>> 5) ^ (y << 4)) + y) ^ k23;
y += (((z << 4) ^ (z >>> 5)) + z) ^ k24;
z += (((y >>> 5) ^ (y << 4)) + y) ^ k25;
y += (((z << 4) ^ (z >>> 5)) + z) ^ k26;
z += (((y >>> 5) ^ (y << 4)) + y) ^ k27;
y += (((z << 4) ^ (z >>> 5)) + z) ^ k28;
z += (((y >>> 5) ^ (y << 4)) + y) ^ k29;
y += (((z << 4) ^ (z >>> 5)) + z) ^ k30;
z += (((y >>> 5) ^ (y << 4)) + y) ^ k31;
Bits.writeInt(out, off, y);
Bits.writeInt(out, off + 4, z);
}
private void decryptBlock(byte[] in, byte[] out, int off) {
int y = Bits.readInt(in, off);
int z = Bits.readInt(in, off + 4);
z -= (((y >>> 5) ^ (y << 4)) + y) ^ k31;
y -= (((z << 4) ^ (z >>> 5)) + z) ^ k30;
z -= (((y >>> 5) ^ (y << 4)) + y) ^ k29;
y -= (((z << 4) ^ (z >>> 5)) + z) ^ k28;
z -= (((y >>> 5) ^ (y << 4)) + y) ^ k27;
y -= (((z << 4) ^ (z >>> 5)) + z) ^ k26;
z -= (((y >>> 5) ^ (y << 4)) + y) ^ k25;
y -= (((z << 4) ^ (z >>> 5)) + z) ^ k24;
z -= (((y >>> 5) ^ (y << 4)) + y) ^ k23;
y -= (((z << 4) ^ (z >>> 5)) + z) ^ k22;
z -= (((y >>> 5) ^ (y << 4)) + y) ^ k21;
y -= (((z << 4) ^ (z >>> 5)) + z) ^ k20;
z -= (((y >>> 5) ^ (y << 4)) + y) ^ k19;
y -= (((z << 4) ^ (z >>> 5)) + z) ^ k18;
z -= (((y >>> 5) ^ (y << 4)) + y) ^ k17;
y -= (((z << 4) ^ (z >>> 5)) + z) ^ k16;
z -= (((y >>> 5) ^ (y << 4)) + y) ^ k15;
y -= (((z << 4) ^ (z >>> 5)) + z) ^ k14;
z -= (((y >>> 5) ^ (y << 4)) + y) ^ k13;
y -= (((z << 4) ^ (z >>> 5)) + z) ^ k12;
z -= (((y >>> 5) ^ (y << 4)) + y) ^ k11;
y -= (((z << 4) ^ (z >>> 5)) + z) ^ k10;
z -= (((y >>> 5) ^ (y << 4)) + y) ^ k9;
y -= (((z << 4) ^ (z >>> 5)) + z) ^ k8;
z -= (((y >>> 5) ^ (y << 4)) + y) ^ k7;
y -= (((z << 4) ^ (z >>> 5)) + z) ^ k6;
z -= (((y >>> 5) ^ (y << 4)) + y) ^ k5;
y -= (((z << 4) ^ (z >>> 5)) + z) ^ k4;
z -= (((y >>> 5) ^ (y << 4)) + y) ^ k3;
y -= (((z << 4) ^ (z >>> 5)) + z) ^ k2;
z -= (((y >>> 5) ^ (y << 4)) + y) ^ k1;
y -= (((z << 4) ^ (z >>> 5)) + z) ^ k0;
Bits.writeInt(out, off, y);
Bits.writeInt(out, off + 4, z);
}
@Override
public int getKeyLength() {
return 16;
}
}