1 /**********************************************************\ 2 * * 3 * xxtea.d * 4 * * 5 * hprose bytes io library for D. * 6 * * 7 * LastModified: Feb 13, 2016 * 8 * Author: Ma Bingyao <andot@hprose.com> * 9 * * 10 \**********************************************************/ 11 12 module xxtea; 13 14 @safe: 15 16 import std.base64; 17 import std.utf; 18 import std.traits; 19 20 static class XXTEA { 21 private: 22 enum DELTA = 0x9e3779b9; 23 pure static uint mx(uint sum, uint y, uint z, ulong p, uint e, uint[] k) { 24 return (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z); 25 } 26 pure static uint[] encrypt(uint[] v, uint[] k) { 27 if (v.length < 2) return v; 28 ulong n = v.length - 1, p; 29 uint z = v[n], y, sum = 0u, e; 30 int q = 6 + 52 / (n + 1); 31 while (0 < q--) { 32 sum += DELTA; 33 e = sum >> 2 & 3; 34 for (p = 0; p < n; p++) { 35 y = v[p + 1]; 36 z = v[p] += mx(sum, y, z, p, e, k); 37 } 38 y = v[0]; 39 z = v[n] += mx(sum, y, z, p, e, k); 40 } 41 return v; 42 } 43 pure static uint[] decrypt(uint[] v, uint[] k) { 44 if (v.length < 2) return v; 45 ulong n = v.length - 1, p; 46 uint z, y = v[0], sum, e; 47 int q = 6 + 52 / (n + 1); 48 sum = q * DELTA; 49 while (sum != 0) { 50 e = sum >> 2 & 3; 51 for (p = n; p > 0; p--) { 52 z = v[p - 1]; 53 y = v[p] -= mx(sum, y, z, p, e, k); 54 } 55 z = v[n]; 56 y = v[0] -= mx(sum, y, z, p, e, k); 57 sum -= DELTA; 58 } 59 return v; 60 } 61 pure static const(ubyte[]) fixkey(in ubyte[] key) { 62 if (key.length == 16) return key; 63 if (key.length > 16) { 64 return key[0..16]; 65 } 66 else { 67 ubyte[] fixedkey = key.dup(); 68 fixedkey.length = 16; 69 return fixedkey; 70 } 71 } 72 pure static uint[] touints(in ubyte[] data, bool includeLength) { 73 ulong length = data.length; 74 ulong n = (((length & 3) == 0) ? (length >> 2) : ((length >> 2) + 1)); 75 uint[] result; 76 if (includeLength) { 77 result = new uint[n + 1]; 78 result[n] = cast(uint)length; 79 } 80 else { 81 result = new uint[n]; 82 } 83 for (ulong i = 0; i < length; ++i) { 84 result[i >> 2] |= cast(uint)data[i] << ((i & 3) << 3); 85 } 86 return result; 87 } 88 pure static ubyte[] tobytes(in uint[] data, bool includeLength) { 89 ulong n = data.length << 2; 90 if (includeLength) { 91 ulong m = data[data.length - 1]; 92 n -= 4; 93 if ((m < n - 3) || (m > n)) { 94 return null; 95 } 96 n = m; 97 } 98 ubyte[] result = new ubyte[n]; 99 for (ulong i = 0; i < n; ++i) { 100 result[i] = cast(ubyte)(data[i >> 2] >> ((i & 3) << 3)); 101 } 102 return result; 103 } 104 public: 105 pure static ubyte[] encrypt(in ubyte[] data, in ubyte[] key) { 106 if (data.length == 0) return null; 107 return tobytes(encrypt(touints(data, true), touints(fixkey(key), false)), false); 108 } 109 pure static ubyte[] decrypt(in ubyte[] data, in ubyte[] key) { 110 if (data.length == 0) return null; 111 return tobytes(decrypt(touints(data, false), touints(fixkey(key), false)), true); 112 } 113 pure static ubyte[] encrypt(T, U)(in T data, in U key) 114 if ((isSomeString!T || is(T == byte[]) || is(T == ubyte[])) && 115 (isSomeString!U || is(U == byte[]) || is(U == ubyte[]))) { 116 static if (isSomeString!T && isSomeString!U) { 117 return encrypt(cast(const(ubyte[]))toUTF8(data), cast(const(ubyte[]))toUTF8(key)); 118 } 119 else static if (isSomeString!T && !isSomeString!U) { 120 return encrypt(cast(const(ubyte[]))toUTF8(data), cast(const(ubyte[]))key); 121 } 122 else static if (!isSomeString!T && isSomeString!U) { 123 return encrypt(cast(const(ubyte[]))data, cast(const(ubyte[]))toUTF8(key)); 124 } 125 else { 126 return encrypt(cast(const(ubyte[]))data, cast(const(ubyte[]))key); 127 } 128 } 129 pure static ubyte[] decrypt(T)(in ubyte[] data, in T key) 130 if (isSomeString!T || is(T == byte[])) { 131 static if (isSomeString!T) { 132 return decrypt(data, cast(const(ubyte[]))toUTF8(key)); 133 } 134 else { 135 return decrypt(data, cast(const(ubyte[]))key); 136 } 137 } 138 pure static string encryptToBase64(T, U)(in T data, in U key) 139 if ((isSomeString!T || is(T == byte[]) || is(T == ubyte[])) && 140 (isSomeString!U || is(U == byte[]) || is(U == ubyte[]))) { 141 return Base64.encode(encrypt(data, key)); 142 } 143 pure static ubyte[] decryptFromBase64(T)(in string data, in T key) 144 if (isSomeString!T || is(T == byte[]) || is(T == ubyte[])) { 145 return decrypt(Base64.decode(data), key); 146 } 147 } 148 149 unittest { 150 enum text = "Hello World! 你好,中国!"; 151 enum key = "1234567890"; 152 enum encrypt_data = XXTEA.encryptToBase64(text, key); 153 enum decrypt_data = XXTEA.decryptFromBase64(encrypt_data, key); 154 static assert(text == decrypt_data); 155 } 156 157 unittest { 158 enum text = "Hello World! 你好,中国!"; 159 enum key = "1234567890"; 160 enum encrypt_data = XXTEA.encrypt(text, key); 161 enum decrypt_data = XXTEA.decrypt(encrypt_data, key); 162 static assert(text == decrypt_data); 163 } 164 165 166 unittest { 167 import std.conv; 168 enum text = to!(wchar[])("Hello World! 你好,中国!"); 169 enum key = "1234567890"; 170 enum encrypt_data = XXTEA.encryptToBase64(text, key); 171 enum decrypt_data = XXTEA.decryptFromBase64(encrypt_data, key); 172 static assert(toUTF8(text) == decrypt_data); 173 } 174 175 unittest { 176 import std.conv; 177 enum text = to!(wchar[])("Hello World! 你好,中国!"); 178 enum key = "1234567890"; 179 enum encrypt_data = XXTEA.encrypt(text, key); 180 enum decrypt_data = XXTEA.decrypt(encrypt_data, key); 181 static assert(toUTF8(text) == decrypt_data); 182 } 183 184 unittest { 185 enum text = cast(wstring)"Hello World! 你好,中国!"; 186 enum key = "1234567890"; 187 enum encrypt_data = XXTEA.encryptToBase64(text, key); 188 enum decrypt_data = XXTEA.decryptFromBase64(encrypt_data, key); 189 static assert(toUTF8(text) == decrypt_data); 190 } 191 192 unittest { 193 enum text = cast(wstring)"Hello World! 你好,中国!"; 194 enum key = "1234567890"; 195 enum encrypt_data = XXTEA.encrypt(text, key); 196 enum decrypt_data = XXTEA.decrypt(encrypt_data, key); 197 static assert(toUTF8(text) == decrypt_data); 198 } 199 200 unittest { 201 import std.conv; 202 enum text = to!(dchar[])("Hello World! 你好,中国!"); 203 enum key = "1234567890"; 204 enum encrypt_data = XXTEA.encryptToBase64(text, key); 205 enum decrypt_data = XXTEA.decryptFromBase64(encrypt_data, key); 206 static assert(toUTF8(text) == decrypt_data); 207 } 208 209 unittest { 210 import std.conv; 211 enum text = to!(dchar[])("Hello World! 你好,中国!"); 212 enum key = "1234567890"; 213 enum encrypt_data = XXTEA.encrypt(text, key); 214 enum decrypt_data = XXTEA.decrypt(encrypt_data, key); 215 static assert(toUTF8(text) == decrypt_data); 216 } 217 218 unittest { 219 enum text = cast(dstring)"Hello World! 你好,中国!"; 220 enum key = "1234567890"; 221 enum encrypt_data = XXTEA.encryptToBase64(text, key); 222 enum decrypt_data = XXTEA.decryptFromBase64(encrypt_data, key); 223 static assert(toUTF8(text) == decrypt_data); 224 } 225 226 unittest { 227 enum text = cast(dstring)"Hello World! 你好,中国!"; 228 enum key = "1234567890"; 229 enum encrypt_data = XXTEA.encrypt(text, key); 230 enum decrypt_data = XXTEA.decrypt(encrypt_data, key); 231 static assert(toUTF8(text) == decrypt_data); 232 } 233 234 unittest { 235 auto text = "Hello World! 你好,中国!"; 236 auto key = "1234567890"; 237 auto encrypt_data = XXTEA.encryptToBase64(text, key); 238 auto decrypt_data = XXTEA.decryptFromBase64(encrypt_data, key); 239 assert(text == decrypt_data); 240 } 241 242 unittest { 243 auto text = "Hello World! 你好,中国!"; 244 auto key = "1234567890"; 245 auto encrypt_data = XXTEA.encrypt(text, key); 246 auto decrypt_data = XXTEA.decrypt(encrypt_data, key); 247 assert(text == decrypt_data); 248 } 249 250 unittest { 251 import std.conv; 252 auto text = to!(wchar[])("Hello World! 你好,中国!"); 253 auto key = "1234567890"; 254 auto encrypt_data = XXTEA.encryptToBase64(text, key); 255 auto decrypt_data = XXTEA.decryptFromBase64(encrypt_data, key); 256 assert(toUTF8(text) == decrypt_data); 257 } 258 259 unittest { 260 import std.conv; 261 auto text = to!(wchar[])("Hello World! 你好,中国!"); 262 auto key = "1234567890"; 263 auto encrypt_data = XXTEA.encrypt(text, key); 264 auto decrypt_data = XXTEA.decrypt(encrypt_data, key); 265 assert(toUTF8(text) == decrypt_data); 266 } 267 268 unittest { 269 auto text = cast(wstring)"Hello World! 你好,中国!"; 270 auto key = "1234567890"; 271 auto encrypt_data = XXTEA.encryptToBase64(text, key); 272 auto decrypt_data = XXTEA.decryptFromBase64(encrypt_data, key); 273 assert(toUTF8(text) == decrypt_data); 274 } 275 276 unittest { 277 auto text = cast(wstring)"Hello World! 你好,中国!"; 278 auto key = "1234567890"; 279 auto encrypt_data = XXTEA.encrypt(text, key); 280 auto decrypt_data = XXTEA.decrypt(encrypt_data, key); 281 assert(toUTF8(text) == decrypt_data); 282 } 283 284 unittest { 285 import std.conv; 286 auto text = to!(dchar[])("Hello World! 你好,中国!"); 287 auto key = "1234567890"; 288 auto encrypt_data = XXTEA.encryptToBase64(text, key); 289 auto decrypt_data = XXTEA.decryptFromBase64(encrypt_data, key); 290 assert(toUTF8(text) == decrypt_data); 291 } 292 293 unittest { 294 import std.conv; 295 enum text = to!(dchar[])("Hello World! 你好,中国!"); 296 enum key = "1234567890"; 297 enum encrypt_data = XXTEA.encrypt(text, key); 298 enum decrypt_data = XXTEA.decrypt(encrypt_data, key); 299 static assert(toUTF8(text) == decrypt_data); 300 } 301 302 unittest { 303 auto text = cast(dstring)"Hello World! 你好,中国!"; 304 auto key = "1234567890"; 305 auto encrypt_data = XXTEA.encryptToBase64(text, key); 306 auto decrypt_data = XXTEA.decryptFromBase64(encrypt_data, key); 307 assert(toUTF8(text) == decrypt_data); 308 } 309 310 unittest { 311 auto text = cast(dstring)"Hello World! 你好,中国!"; 312 auto key = "1234567890"; 313 auto encrypt_data = XXTEA.encrypt(text, key); 314 auto decrypt_data = XXTEA.decrypt(encrypt_data, key); 315 assert(toUTF8(text) == decrypt_data); 316 }