1 | /* |
2 | * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, |
3 | * and the EPL 1.0 (http://h2database.com/html/license.html). |
4 | * Initial Developer: H2 Group |
5 | */ |
6 | package org.h2.security; |
7 | |
8 | import org.h2.engine.SysProperties; |
9 | import org.h2.message.DbException; |
10 | |
11 | /** |
12 | * An implementation of the XTEA block cipher algorithm. |
13 | * <p> |
14 | * This implementation uses 32 rounds. |
15 | * The best attack reported as of 2009 is 36 rounds (Wikipedia). |
16 | */ |
17 | public class XTEA implements BlockCipher { |
18 | |
19 | private static final int DELTA = 0x9E3779B9; |
20 | private int k0, k1, k2, k3, k4, k5, k6, k7; |
21 | private int k8, k9, k10, k11, k12, k13, k14, k15; |
22 | private int k16, k17, k18, k19, k20, k21, k22, k23; |
23 | private int k24, k25, k26, k27, k28, k29, k30, k31; |
24 | |
25 | @Override |
26 | public void setKey(byte[] b) { |
27 | int[] key = new int[4]; |
28 | for (int i = 0; i < 16;) { |
29 | key[i / 4] = (b[i++] << 24) + ((b[i++] & 255) << 16) |
30 | + ((b[i++] & 255) << 8) + (b[i++] & 255); |
31 | } |
32 | int[] r = new int[32]; |
33 | for (int i = 0, sum = 0; i < 32;) { |
34 | r[i++] = sum + key[sum & 3]; |
35 | sum += DELTA; |
36 | r[i++] = sum + key[ (sum >>> 11) & 3]; |
37 | } |
38 | k0 = r[0]; k1 = r[1]; k2 = r[2]; k3 = r[3]; |
39 | k4 = r[4]; k5 = r[5]; k6 = r[6]; k7 = r[7]; |
40 | k8 = r[8]; k9 = r[9]; k10 = r[10]; k11 = r[11]; |
41 | k12 = r[12]; k13 = r[13]; k14 = r[14]; k15 = r[15]; |
42 | k16 = r[16]; k17 = r[17]; k18 = r[18]; k19 = r[19]; |
43 | k20 = r[20]; k21 = r[21]; k22 = r[22]; k23 = r[23]; |
44 | k24 = r[24]; k25 = r[25]; k26 = r[26]; k27 = r[27]; |
45 | k28 = r[28]; k29 = r[29]; k30 = r[30]; k31 = r[31]; |
46 | } |
47 | |
48 | @Override |
49 | public void encrypt(byte[] bytes, int off, int len) { |
50 | if (SysProperties.CHECK) { |
51 | if (len % ALIGN != 0) { |
52 | DbException.throwInternalError("unaligned len " + len); |
53 | } |
54 | } |
55 | for (int i = off; i < off + len; i += 8) { |
56 | encryptBlock(bytes, bytes, i); |
57 | } |
58 | } |
59 | |
60 | @Override |
61 | public void decrypt(byte[] bytes, int off, int len) { |
62 | if (SysProperties.CHECK) { |
63 | if (len % ALIGN != 0) { |
64 | DbException.throwInternalError("unaligned len " + len); |
65 | } |
66 | } |
67 | for (int i = off; i < off + len; i += 8) { |
68 | decryptBlock(bytes, bytes, i); |
69 | } |
70 | } |
71 | |
72 | private void encryptBlock(byte[] in, byte[] out, int off) { |
73 | int y = (in[off] << 24) | ((in[off + 1] & 255) << 16) |
74 | | ((in[off + 2] & 255) << 8) | (in[off + 3] & 255); |
75 | int z = (in[off + 4] << 24) | ((in[off + 5] & 255) << 16) |
76 | | ((in[off + 6] & 255) << 8) | (in[off + 7] & 255); |
77 | y += (((z << 4) ^ (z >>> 5)) + z) ^ k0; |
78 | z += (((y >>> 5) ^ (y << 4)) + y) ^ k1; |
79 | y += (((z << 4) ^ (z >>> 5)) + z) ^ k2; |
80 | z += (((y >>> 5) ^ (y << 4)) + y) ^ k3; |
81 | y += (((z << 4) ^ (z >>> 5)) + z) ^ k4; |
82 | z += (((y >>> 5) ^ (y << 4)) + y) ^ k5; |
83 | y += (((z << 4) ^ (z >>> 5)) + z) ^ k6; |
84 | z += (((y >>> 5) ^ (y << 4)) + y) ^ k7; |
85 | y += (((z << 4) ^ (z >>> 5)) + z) ^ k8; |
86 | z += (((y >>> 5) ^ (y << 4)) + y) ^ k9; |
87 | y += (((z << 4) ^ (z >>> 5)) + z) ^ k10; |
88 | z += (((y >>> 5) ^ (y << 4)) + y) ^ k11; |
89 | y += (((z << 4) ^ (z >>> 5)) + z) ^ k12; |
90 | z += (((y >>> 5) ^ (y << 4)) + y) ^ k13; |
91 | y += (((z << 4) ^ (z >>> 5)) + z) ^ k14; |
92 | z += (((y >>> 5) ^ (y << 4)) + y) ^ k15; |
93 | y += (((z << 4) ^ (z >>> 5)) + z) ^ k16; |
94 | z += (((y >>> 5) ^ (y << 4)) + y) ^ k17; |
95 | y += (((z << 4) ^ (z >>> 5)) + z) ^ k18; |
96 | z += (((y >>> 5) ^ (y << 4)) + y) ^ k19; |
97 | y += (((z << 4) ^ (z >>> 5)) + z) ^ k20; |
98 | z += (((y >>> 5) ^ (y << 4)) + y) ^ k21; |
99 | y += (((z << 4) ^ (z >>> 5)) + z) ^ k22; |
100 | z += (((y >>> 5) ^ (y << 4)) + y) ^ k23; |
101 | y += (((z << 4) ^ (z >>> 5)) + z) ^ k24; |
102 | z += (((y >>> 5) ^ (y << 4)) + y) ^ k25; |
103 | y += (((z << 4) ^ (z >>> 5)) + z) ^ k26; |
104 | z += (((y >>> 5) ^ (y << 4)) + y) ^ k27; |
105 | y += (((z << 4) ^ (z >>> 5)) + z) ^ k28; |
106 | z += (((y >>> 5) ^ (y << 4)) + y) ^ k29; |
107 | y += (((z << 4) ^ (z >>> 5)) + z) ^ k30; |
108 | z += (((y >>> 5) ^ (y << 4)) + y) ^ k31; |
109 | out[off] = (byte) (y >> 24); |
110 | out[off + 1] = (byte) (y >> 16); |
111 | out[off + 2] = (byte) (y >> 8); |
112 | out[off + 3] = (byte) y; |
113 | out[off + 4] = (byte) (z >> 24); |
114 | out[off + 5] = (byte) (z >> 16); |
115 | out[off + 6] = (byte) (z >> 8); |
116 | out[off + 7] = (byte) z; |
117 | } |
118 | |
119 | private void decryptBlock(byte[] in, byte[] out, int off) { |
120 | int y = (in[off] << 24) | ((in[off + 1] & 255) << 16) |
121 | | ((in[off + 2] & 255) << 8) | (in[off + 3] & 255); |
122 | int z = (in[off + 4] << 24) | ((in[off + 5] & 255) << 16) |
123 | | ((in[off + 6] & 255) << 8) | (in[off + 7] & 255); |
124 | z -= (((y >>> 5) ^ (y << 4)) + y) ^ k31; |
125 | y -= (((z << 4) ^ (z >>> 5)) + z) ^ k30; |
126 | z -= (((y >>> 5) ^ (y << 4)) + y) ^ k29; |
127 | y -= (((z << 4) ^ (z >>> 5)) + z) ^ k28; |
128 | z -= (((y >>> 5) ^ (y << 4)) + y) ^ k27; |
129 | y -= (((z << 4) ^ (z >>> 5)) + z) ^ k26; |
130 | z -= (((y >>> 5) ^ (y << 4)) + y) ^ k25; |
131 | y -= (((z << 4) ^ (z >>> 5)) + z) ^ k24; |
132 | z -= (((y >>> 5) ^ (y << 4)) + y) ^ k23; |
133 | y -= (((z << 4) ^ (z >>> 5)) + z) ^ k22; |
134 | z -= (((y >>> 5) ^ (y << 4)) + y) ^ k21; |
135 | y -= (((z << 4) ^ (z >>> 5)) + z) ^ k20; |
136 | z -= (((y >>> 5) ^ (y << 4)) + y) ^ k19; |
137 | y -= (((z << 4) ^ (z >>> 5)) + z) ^ k18; |
138 | z -= (((y >>> 5) ^ (y << 4)) + y) ^ k17; |
139 | y -= (((z << 4) ^ (z >>> 5)) + z) ^ k16; |
140 | z -= (((y >>> 5) ^ (y << 4)) + y) ^ k15; |
141 | y -= (((z << 4) ^ (z >>> 5)) + z) ^ k14; |
142 | z -= (((y >>> 5) ^ (y << 4)) + y) ^ k13; |
143 | y -= (((z << 4) ^ (z >>> 5)) + z) ^ k12; |
144 | z -= (((y >>> 5) ^ (y << 4)) + y) ^ k11; |
145 | y -= (((z << 4) ^ (z >>> 5)) + z) ^ k10; |
146 | z -= (((y >>> 5) ^ (y << 4)) + y) ^ k9; |
147 | y -= (((z << 4) ^ (z >>> 5)) + z) ^ k8; |
148 | z -= (((y >>> 5) ^ (y << 4)) + y) ^ k7; |
149 | y -= (((z << 4) ^ (z >>> 5)) + z) ^ k6; |
150 | z -= (((y >>> 5) ^ (y << 4)) + y) ^ k5; |
151 | y -= (((z << 4) ^ (z >>> 5)) + z) ^ k4; |
152 | z -= (((y >>> 5) ^ (y << 4)) + y) ^ k3; |
153 | y -= (((z << 4) ^ (z >>> 5)) + z) ^ k2; |
154 | z -= (((y >>> 5) ^ (y << 4)) + y) ^ k1; |
155 | y -= (((z << 4) ^ (z >>> 5)) + z) ^ k0; |
156 | out[off] = (byte) (y >> 24); |
157 | out[off + 1] = (byte) (y >> 16); |
158 | out[off + 2] = (byte) (y >> 8); |
159 | out[off + 3] = (byte) y; |
160 | out[off + 4] = (byte) (z >> 24); |
161 | out[off + 5] = (byte) (z >> 16); |
162 | out[off + 6] = (byte) (z >> 8); |
163 | out[off + 7] = (byte) z; |
164 | } |
165 | |
166 | @Override |
167 | public int getKeyLength() { |
168 | return 16; |
169 | } |
170 | |
171 | } |