Add support for dmd 2.070.2
This commit is contained in:
		| @@ -10,6 +10,7 @@ d: | ||||
|  - dmd-2.073.0 | ||||
|  - dmd-2.072.2 | ||||
|  - dmd-2.071.2 | ||||
|  - dmd-2.070.2 | ||||
|  | ||||
| env:  | ||||
|  matrix: | ||||
|   | ||||
							
								
								
									
										25
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								README.md
									
									
									
									
									
								
							| @@ -19,7 +19,7 @@ Tanya consists of the following packages: | ||||
|  | ||||
| * `async`: Event loop (epoll, kqueue and IOCP). | ||||
| * `container`: Queue, Vector, Singly linked list, buffers. | ||||
| * `math`: Multiple precision integer and a set of functions. | ||||
| * `math`: Arbitrary precision integer and a set of functions. | ||||
| * `memory`: Tools for manual memory management (allocator, reference counting, | ||||
| helper functions). | ||||
| * `network`: URL-Parsing, sockets. | ||||
| @@ -29,24 +29,21 @@ helper functions). | ||||
| * dmd 2.073.0 | ||||
| * dmd 2.072.2 | ||||
| * dmd 2.071.2 | ||||
| * dmd 2.070.2 | ||||
|  | ||||
| ### Current status | ||||
|  | ||||
| The library is currently under development, but some parts of it can already be | ||||
| used. | ||||
| The library is currently under development, but the API is becoming gradually | ||||
| stable. | ||||
|  | ||||
| `network` and `async` exist for quite some time and are better tested than | ||||
| other components. | ||||
| `container`s are being extended to support ranges. Also following modules are | ||||
| coming soon: | ||||
| * UTF-8 string. | ||||
| * Hash table. | ||||
|  | ||||
| `container`s were newly reworked and the API won't change significantly, but | ||||
| will be only extended. The same is true for the `memory` package. | ||||
|  | ||||
| `math` package contains an arbitrary precision integer implementation that has | ||||
| a stable API (that mostly consists of operator overloads), but still needs | ||||
| testing and work on its performance. | ||||
|  | ||||
| I'm currently mostly working on `crypto` that is not a complete cryptographic | ||||
| suite, but contains (will contain) algorithm implementations required by TLS. | ||||
| `math` package contains an arbitrary precision integer implementation that | ||||
| needs more test cases, better performance and some additional features | ||||
| (constructing from a string and an ubyte array, and converting it back). | ||||
|  | ||||
| ### Further characteristics | ||||
|  | ||||
|   | ||||
| @@ -1,510 +0,0 @@ | ||||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||||
|  | ||||
| /** | ||||
|  * Copyright: Eugene Wissner 2016. | ||||
|  * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, | ||||
|  *                  Mozilla Public License, v. 2.0). | ||||
|  * Authors: $(LINK2 mailto:belka@caraus.de, Eugene Wissner) | ||||
|  */ | ||||
| module tanya.crypto.bit; | ||||
|  | ||||
| /** | ||||
|  * Wrapper that allows bit manipulation on $(D_KEYWORD ubyte[]) array. | ||||
|  */ | ||||
| struct BitVector | ||||
| { | ||||
|     protected ubyte[] vector; | ||||
|  | ||||
|     /** | ||||
|      * Params: | ||||
|      *     array = Array should be manipulated on. | ||||
|      */ | ||||
|     this(inout(ubyte[]) array) inout pure nothrow @safe @nogc | ||||
|     in | ||||
|     { | ||||
|         assert(array.length <= size_t.max / 8); | ||||
|         assert(array !is null); | ||||
|     } | ||||
|     body | ||||
|     { | ||||
|         vector = array; | ||||
|     } | ||||
|  | ||||
|     /// | ||||
|     unittest | ||||
|     { | ||||
|         ubyte[5] array1 = [234, 3, 252, 10, 18]; | ||||
|         ubyte[3] array2 = [65, 13, 173]; | ||||
|         auto bits = BitVector(array1); | ||||
|  | ||||
|         assert(bits[] is array1); | ||||
|         assert(bits[] !is array2); | ||||
|  | ||||
|         bits = BitVector(array2); | ||||
|         assert(bits[] is array2); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns: Number of bits in the vector. | ||||
|      */ | ||||
|     @property inout(size_t) length() inout const pure nothrow @safe @nogc | ||||
|     { | ||||
|         return vector.length * 8; | ||||
|     } | ||||
|  | ||||
|     /// Ditto. | ||||
|     inout(size_t) opDollar() inout const pure nothrow @safe @nogc | ||||
|     { | ||||
|         return vector.length * 8; | ||||
|     } | ||||
|  | ||||
|     /// | ||||
|     unittest | ||||
|     { | ||||
|         // [01000001, 00001101, 10101101] | ||||
|         ubyte[3] arr = [65, 13, 173]; | ||||
|         auto bits = BitVector(arr); | ||||
|  | ||||
|         assert(bits.length == 24); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Params: | ||||
|      *     bit = Bit position. | ||||
|      * | ||||
|      * Returns: $(D_KEYWORD true) if the bit on position $(D_PARAM bit) is set, | ||||
|      *          $(D_KEYWORD false) if not set. | ||||
|      */ | ||||
|     inout(bool) opIndex(size_t bit) inout const pure nothrow @safe @nogc | ||||
|     in | ||||
|     { | ||||
|         assert(bit / 8 <= vector.length); | ||||
|     } | ||||
|     body | ||||
|     { | ||||
|         return (vector[bit / 8] & (0x80 >> (bit % 8))) != 0; | ||||
|     } | ||||
|  | ||||
|     /// | ||||
|     unittest | ||||
|     { | ||||
|         // [01000001, 00001101, 10101101] | ||||
|         ubyte[3] arr = [65, 13, 173]; | ||||
|         auto bits = BitVector(arr); | ||||
|  | ||||
|         assert(!bits[0]); | ||||
|         assert(bits[1]); | ||||
|         assert(bits[7]); | ||||
|         assert(!bits[8]); | ||||
|         assert(!bits[11]); | ||||
|         assert(bits[12]); | ||||
|         assert(bits[20]); | ||||
|         assert(bits[23]); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns: Underlying array. | ||||
|      */ | ||||
|     inout(ubyte[]) opIndex() inout pure nothrow @safe @nogc | ||||
|     { | ||||
|         return vector; | ||||
|     } | ||||
|  | ||||
|     /// | ||||
|     unittest | ||||
|     { | ||||
|         // [01000001, 00001101, 10101101] | ||||
|         ubyte[3] arr = [65, 13, 173]; | ||||
|         auto bits = BitVector(arr); | ||||
|  | ||||
|         assert(bits[] is arr); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Params: | ||||
|      *     value = $(D_KEYWORD true) if the bit should be set, | ||||
|      *             $(D_KEYWORD false) if cleared. | ||||
|      *     bit   = Bit position. | ||||
|      * | ||||
|      * Returns: $(D_PSYMBOL this). | ||||
|      */ | ||||
|     bool opIndexAssign(bool value, size_t bit) pure nothrow @safe @nogc | ||||
|     in | ||||
|     { | ||||
|         assert(bit / 8 <= vector.length); | ||||
|     } | ||||
|     body | ||||
|     { | ||||
|         if (value) | ||||
|         { | ||||
|             vector[bit / 8] |= (0x80 >> (bit % 8)); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             vector[bit / 8] &= ~(0x80 >> (bit % 8)); | ||||
|         } | ||||
|         return value; | ||||
|     } | ||||
|  | ||||
|     /// | ||||
|     unittest | ||||
|     { | ||||
|         // [01000001, 00001101, 10101101] | ||||
|         ubyte[3] arr = [65, 13, 173]; | ||||
|         auto bits = BitVector(arr); | ||||
|  | ||||
|         bits[5] = bits[6] = true; | ||||
|         assert(bits[][0] == 71); | ||||
|  | ||||
|         bits[14] = true; | ||||
|         bits[15] = false; | ||||
|         assert(bits[][1] == 14); | ||||
|  | ||||
|         bits[16] = bits[23] = false; | ||||
|         assert(bits[][2] == 44); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Copies bits from $(D_PARAM vector) into this $(D_PSYMBOL BitVector). | ||||
|      * | ||||
|      * The array that should be assigned, can be smaller (but not larger) than | ||||
|      * the underlying array of this $(D_PSYMBOL BitVector), leading zeros will | ||||
|      * be added in this case to the left. | ||||
|      * | ||||
|      * Params: | ||||
|      *     vector = $(D_KEYWORD ubyte[]) array not larger than | ||||
|      *              `$(D_PSYMBOL length) / 8`. | ||||
|      * | ||||
|      * Returns: $(D_KEYWORD this). | ||||
|      */ | ||||
|     BitVector opAssign(ubyte[] vector) pure nothrow @safe @nogc | ||||
|     in | ||||
|     { | ||||
|         assert(vector.length <= this.vector.length); | ||||
|     } | ||||
|     body | ||||
|     { | ||||
|         immutable delta = this.vector.length - vector.length; | ||||
|         if (delta > 0) | ||||
|         { | ||||
|             this.vector[0..delta] = 0; | ||||
|         } | ||||
|         this.vector[delta..$] = vector[0..$]; | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     /// | ||||
|     unittest | ||||
|     { | ||||
|         ubyte[5] array1 = [234, 3, 252, 10, 18]; | ||||
|         ubyte[3] array2 = [65, 13, 173]; | ||||
|         auto bits = BitVector(array1); | ||||
|  | ||||
|         bits = array2; | ||||
|         assert(bits[][0] == 0); | ||||
|         assert(bits[][1] == 0); | ||||
|         assert(bits[][2] == 65); | ||||
|         assert(bits[][3] == 13); | ||||
|         assert(bits[][4] == 173); | ||||
|  | ||||
|         bits = array2[0..2]; | ||||
|         assert(bits[][0] == 0); | ||||
|         assert(bits[][1] == 0); | ||||
|         assert(bits[][2] == 0); | ||||
|         assert(bits[][3] == 65); | ||||
|         assert(bits[][4] == 13); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Support for bitwise operations. | ||||
|      * | ||||
|      * Params: | ||||
|      *     that = Another bit vector. | ||||
|      * | ||||
|      * Returns: $(D_KEYWORD this). | ||||
|      */ | ||||
|     BitVector opOpAssign(string op)(BitVector that) pure nothrow @safe @nogc | ||||
|         if ((op == "^") || (op == "|") || (op == "&")) | ||||
|     { | ||||
|         return opOpAssign(op)(that.vector); | ||||
|     } | ||||
|  | ||||
|     /// Ditto. | ||||
|     BitVector opOpAssign(string op)(ubyte[] that) pure nothrow @safe @nogc | ||||
|         if ((op == "^") || (op == "|") || (op == "&")) | ||||
|     in | ||||
|     { | ||||
|         assert(that.length <= vector.length); | ||||
|     } | ||||
|     body | ||||
|     { | ||||
|         for (int i = cast(int) vector.length - 1; i >= 0; --i) | ||||
|         { | ||||
|             mixin("vector[i] " ~  op ~ "= " ~ "that[i];"); | ||||
|         } | ||||
|         immutable delta = vector.length - that.length; | ||||
|         if (delta) | ||||
|         { | ||||
|             static if (op == "&") | ||||
|             { | ||||
|                 vector[0..delta] = 0; | ||||
|             } | ||||
|         } | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     /// | ||||
|     unittest | ||||
|     { | ||||
|         // [01000001, 00001101, 10101101] | ||||
|         ubyte[3] array1 = [65, 13, 173]; | ||||
|         ubyte[3] array2 = [0b01010010, 0b10111110, 0b10111110]; | ||||
|         auto bits = BitVector(array1); | ||||
|  | ||||
|         bits |= array2; | ||||
|         assert(bits[][0] == 0b01010011); | ||||
|         assert(bits[][1] == 0b10111111); | ||||
|         assert(bits[][2] == 0b10111111); | ||||
|  | ||||
|         bits &= array2; | ||||
|         assert(bits[][0] == array2[0]); | ||||
|         assert(bits[][1] == array2[1]); | ||||
|         assert(bits[][2] == array2[2]); | ||||
|  | ||||
|         bits ^= array2; | ||||
|         assert(bits[][0] == 0); | ||||
|         assert(bits[][1] == 0); | ||||
|         assert(bits[][2] == 0); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Support for shift operations. | ||||
|      * | ||||
|      * Params: | ||||
|      *     n = Number of bits. | ||||
|      * | ||||
|      * Returns: $(D_KEYWORD this). | ||||
|      */ | ||||
|     BitVector opOpAssign(string op)(in size_t n) pure nothrow @safe @nogc | ||||
|         if ((op == "<<") || (op == ">>")) | ||||
|  | ||||
|     { | ||||
|         if (n >= length) | ||||
|         { | ||||
|             vector[0..$] = 0; | ||||
|         } | ||||
|         else if (n != 0) | ||||
|         { | ||||
|             immutable bit = n % 8, step = n / 8; | ||||
|             immutable delta = 8 - bit; | ||||
|             size_t i, j; | ||||
|  | ||||
|             static if (op == "<<") | ||||
|             { | ||||
|                 for (j = step; j < vector.length - 1; ++i) | ||||
|                 { | ||||
|                     vector[i] = cast(ubyte)((vector[j] << bit) | ||||
|                               | vector[++j] >> delta); | ||||
|                 } | ||||
|                 vector[i] = cast(ubyte)(vector[j] << bit); | ||||
|                 vector[$ - step ..$] = 0; | ||||
|             } | ||||
|             else static if (op == ">>") | ||||
|             { | ||||
|                 for (i = vector.length - 1, j = i - step; j > 0; --i) | ||||
|                 { | ||||
|                     vector[i] = cast(ubyte)((vector[j] >> bit) | ||||
|                               | vector[--j] << delta); | ||||
|                 } | ||||
|                 vector[i] = cast(ubyte)(vector[j] >> bit); | ||||
|                 vector[0..step] = 0; | ||||
|             } | ||||
|         } | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     /// | ||||
|     nothrow @safe @nogc unittest | ||||
|     { | ||||
|         ubyte[4] arr = [0b10111110, 0b11110010, 0b01010010, 0b01010011]; | ||||
|         auto bits = BitVector(arr); | ||||
|  | ||||
|         bits <<= 0; | ||||
|         assert(bits[][0] == 0b10111110 && bits[][1] == 0b11110010 | ||||
|             && bits[][2] == 0b01010010 && bits[][3] == 0b01010011); | ||||
|  | ||||
|         bits <<= 2; | ||||
|         assert(bits[][0] == 0b11111011 && bits[][1] == 0b11001001 | ||||
|             && bits[][2] == 0b01001001 && bits[][3] == 0b01001100); | ||||
|  | ||||
|         bits <<= 4; | ||||
|         assert(bits[][0] == 0b10111100 && bits[][1] == 0b10010100 | ||||
|             && bits[][2] == 0b10010100 && bits[][3] == 0b11000000); | ||||
|  | ||||
|         bits <<= 8; | ||||
|         assert(bits[][0] == 0b10010100 && bits[][1] == 0b10010100 | ||||
|             && bits[][2] == 0b11000000 && bits[][3] == 0b00000000); | ||||
|  | ||||
|         bits <<= 7; | ||||
|         assert(bits[][0] == 0b01001010 && bits[][1] == 0b01100000 | ||||
|             && bits[][2] == 0b00000000 && bits[][3] == 0b00000000); | ||||
|  | ||||
|         bits <<= 25; | ||||
|         assert(bits[][0] == 0b00000000 && bits[][1] == 0b00000000 | ||||
|             && bits[][2] == 0b00000000 && bits[][3] == 0b00000000); | ||||
|  | ||||
|         arr = [0b00110011, 0b11001100, 0b11111111, 0b01010101]; | ||||
|         bits <<= 24; | ||||
|         assert(bits[][0] == 0b01010101 && bits[][1] == 0b00000000 | ||||
|             && bits[][2] == 0b00000000 && bits[][3] == 0b00000000); | ||||
|  | ||||
|         arr[1] = 0b11001100; | ||||
|         arr[2] = 0b11111111; | ||||
|         arr[3] = 0b01010101; | ||||
|         bits <<= 12; | ||||
|         assert(bits[][0] == 0b11001111 && bits[][1] == 0b11110101 | ||||
|             && bits[][2] == 0b01010000 && bits[][3] == 0b00000000); | ||||
|  | ||||
|         bits <<= 100; | ||||
|         assert(bits[][0] == 0b00000000 && bits[][1] == 0b00000000 | ||||
|             && bits[][2] == 0b00000000 && bits[][3] == 0b00000000); | ||||
|  | ||||
|         arr = [0b10111110, 0b11110010, 0b01010010, 0b01010011]; | ||||
|         bits >>= 0; | ||||
|         assert(bits[][0] == 0b10111110 && bits[][1] == 0b11110010 | ||||
|             && bits[][2] == 0b01010010 && bits[][3] == 0b01010011); | ||||
|  | ||||
|         bits >>= 2; | ||||
|         assert(bits[][0] == 0b00101111 && bits[][1] == 0b10111100 | ||||
|             && bits[][2] == 0b10010100 && bits[][3] == 0b10010100); | ||||
|  | ||||
|         bits >>= 4; | ||||
|         assert(bits[][0] == 0b00000010 && bits[][1] == 0b11111011 | ||||
|             && bits[][2] == 0b11001001 && bits[][3] == 0b01001001); | ||||
|  | ||||
|         bits >>= 8; | ||||
|         assert(bits[][0] == 0b00000000 && bits[][1] == 0b00000010 | ||||
|             && bits[][2] == 0b11111011 && bits[][3] == 0b11001001); | ||||
|  | ||||
|         bits >>= 7; | ||||
|         assert(bits[][0] == 0b00000000 && bits[][1] == 0b00000000 | ||||
|             && bits[][2] == 0b00000101 && bits[][3] == 0b11110111); | ||||
|  | ||||
|         bits >>= 25; | ||||
|         assert(bits[][0] == 0b00000000 && bits[][1] == 0b00000000 | ||||
|             && bits[][2] == 0b00000000 && bits[][3] == 0b00000000); | ||||
|  | ||||
|         arr = [0b00110011, 0b11001100, 0b11111111, 0b01010101]; | ||||
|         bits >>= 24; | ||||
|         assert(bits[][0] == 0b00000000 && bits[][1] == 0b00000000 | ||||
|             && bits[][2] == 0b00000000 && bits[][3] == 0b00110011); | ||||
|  | ||||
|         arr[1] = 0b11001100; | ||||
|         arr[2] = 0b11111111; | ||||
|         arr[3] = 0b01010101; | ||||
|         bits >>= 12; | ||||
|         assert(bits[][0] == 0b00000000 && bits[][1] == 0b00000000 | ||||
|             && bits[][2] == 0b00001100 && bits[][3] == 0b11001111); | ||||
|  | ||||
|         bits >>= 100; | ||||
|         assert(bits[][0] == 0b00000000 && bits[][1] == 0b00000000 | ||||
|             && bits[][2] == 0b00000000 && bits[][3] == 0b00000000); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Negates all bits. | ||||
|      * | ||||
|      * Returns: $(D_KEYWORD this). | ||||
|      */ | ||||
|     BitVector opUnary(string op)() pure nothrow @safe @nogc | ||||
|         if (op == "~") | ||||
|     { | ||||
|         foreach (ref b; vector) | ||||
|         { | ||||
|             b = ~b; | ||||
|         } | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     /// | ||||
|     unittest | ||||
|     { | ||||
|         // [01000001, 00001101, 10101101] | ||||
|         ubyte[3] arr = [65, 13, 173]; | ||||
|         auto bits = BitVector(arr); | ||||
|  | ||||
|         ~bits; | ||||
|         assert(bits[][0] == 0b10111110); | ||||
|         assert(bits[][1] == 0b11110010); | ||||
|         assert(bits[][2] == 0b01010010); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Iterates through all bits. | ||||
|      * | ||||
|      * Params: | ||||
|      *     dg = $(D_KEYWORD foreach) delegate. | ||||
|      * | ||||
|      * Returns: By $(D_PARAM dg) returned value. | ||||
|      */ | ||||
|     int opApply(int delegate(size_t, bool) dg) | ||||
|     { | ||||
|         int result; | ||||
|         foreach (i, ref v; vector) | ||||
|         { | ||||
|             foreach (c; 0..8) | ||||
|             { | ||||
|                 result = dg(i * 8 + c, (v & (0x80 >> c)) != 0); | ||||
|                 if (result) | ||||
|                 { | ||||
|                     return result; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     /// Ditto. | ||||
|     int opApply(int delegate(bool) dg) | ||||
|     { | ||||
|         int result; | ||||
|         foreach (ref v; vector) | ||||
|         { | ||||
|             foreach (c; 0..8) | ||||
|             { | ||||
|                 result = dg((v & (0x80 >> c)) != 0); | ||||
|                 if (result) | ||||
|                 { | ||||
|                     return result; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     /// | ||||
|     unittest | ||||
|     { | ||||
|         ubyte[2] arr = [0b01000001, 0b00001101]; | ||||
|         auto bits = BitVector(arr); | ||||
|         size_t c; | ||||
|  | ||||
|         foreach (i, v; bits) | ||||
|         { | ||||
|             assert(i == c); | ||||
|             if (i == 1 || i == 7 || i == 15 || i == 13 || i == 12) | ||||
|             { | ||||
|                 assert(v); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 assert(!v); | ||||
|             } | ||||
|             ++c; | ||||
|         } | ||||
|         assert(c == 16); | ||||
|     } | ||||
| } | ||||
| @@ -1,607 +0,0 @@ | ||||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||||
|  | ||||
| /** | ||||
|  * Copyright: Eugene Wissner 2016. | ||||
|  * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, | ||||
|  *                  Mozilla Public License, v. 2.0). | ||||
|  * Authors: $(LINK2 mailto:belka@caraus.de, Eugene Wissner) | ||||
|  */ | ||||
| module tanya.crypto.des; | ||||
|  | ||||
| import tanya.crypto.bit; | ||||
| import tanya.crypto.symmetric; | ||||
|  | ||||
| /// Initial permutation table. | ||||
| private immutable ubyte[64] ipTable = [58, 50, 42, 34, 26, 18, 10, 2, | ||||
|                                        60, 52, 44, 36, 28, 20, 12, 4, | ||||
|                                        62, 54, 46, 38, 30, 22, 14, 6, | ||||
|                                        64, 56, 48, 40, 32, 24, 16, 8, | ||||
|                                        57, 49, 41, 33, 25, 17, 9,  1, | ||||
|                                        59, 51, 43, 35, 27, 19, 11, 3, | ||||
|                                        61, 53, 45, 37, 29, 21, 13, 5, | ||||
|                                        63, 55, 47, 39, 31, 23, 15, 7]; | ||||
|  | ||||
| /// Final permutation table. | ||||
| private immutable ubyte[64] fpTable = [40, 8, 48, 16, 56, 24, 64, 32, | ||||
|                                        39, 7, 47, 15, 55, 23, 63, 31, | ||||
|                                        38, 6, 46, 14, 54, 22, 62, 30, | ||||
|                                        37, 5, 45, 13, 53, 21, 61, 29, | ||||
|                                        36, 4, 44, 12, 52, 20, 60, 28, | ||||
|                                        35, 3, 43, 11, 51, 19, 59, 27, | ||||
|                                        34, 2, 42, 10, 50, 18, 58, 26, | ||||
|                                        33, 1, 41, 9,  49, 17, 57, 25]; | ||||
|  | ||||
| /// Key permutation table 1. | ||||
| private immutable ubyte[64] pc1Table = [57, 49, 41, 33, 25, 17, 9, 1, | ||||
|                                         58, 50, 42, 34, 26, 18, 10, 2, | ||||
|                                         59, 51, 43, 35, 27, 19, 11, 3, | ||||
|                                         60, 52, 44, 36, 63, 55, 47, 39, | ||||
|                                         31, 23, 15, 7,  62, 54, 46, 38, | ||||
|                                         30, 22, 14, 6,  61, 53, 45, 37, | ||||
|                                         29, 21, 13, 5,  28, 20, 12, 4]; | ||||
|  | ||||
| /// Key permutation table 2. | ||||
| private immutable ubyte[48] pc2Table = [14, 17, 11, 24, 1,  5,  3,  28, | ||||
|                                         15, 6,  21, 10, 23, 19, 12, 4, | ||||
|                                         26, 8,  16, 7,  27, 20, 13, 2, | ||||
|                                         41, 52, 31, 37, 47, 55, 30, 40, | ||||
|                                         51, 45, 33, 48, 44, 49, 39, 56, | ||||
|                                         34, 53, 46, 42, 50, 36, 29, 32]; | ||||
|  | ||||
| /// Expansion table. | ||||
| private immutable ubyte[48] expansionTable = [32, 1,  2,  3,  4,  5,  4,  5, | ||||
|                                               6,  7,  8,  9,  8,  9,  10, 11, | ||||
|                                               12, 13, 12, 13, 14, 15, 16, 17, | ||||
|                                               16, 17, 18, 19, 20, 21, 20, 21, | ||||
|                                               22, 23, 24, 25, 24, 25, 26, 27, | ||||
|                                               28, 29, 28, 29, 30, 31, 32, 1]; | ||||
|  | ||||
| /// Final input block permutation. | ||||
| private immutable ubyte[32] pTable = [16, 7,  20, 21, 29, 12, 28, 17, | ||||
|                                       1,  15, 23, 26, 5,  18, 31, 10, | ||||
|                                       2,  8,  24, 14, 32, 27, 3,  9, | ||||
|                                       19, 13, 30, 6,  22, 11, 4, 25]; | ||||
|  | ||||
| /// The (in)famous S-boxes. | ||||
| private immutable ubyte[64][8] sBox = [[ | ||||
|                                          14, 0,  4,  15, 13, 7,  1,  4,  2, 14,  15, 2, 11, 13, 8,  1, | ||||
|                                          3,  10, 10, 6,  6,  12, 12, 11, 5,  9,  9,  5, 0,  3,  7,  8, | ||||
|                                          4,  15, 1,  12, 14, 8,  8,  2,  13, 4,  6,  9, 2,  1,  11, 7, | ||||
|                                          15, 5,  12, 11, 9,  3,  7,  14, 3,  10, 10, 0, 5,  6,  0,  13, | ||||
|                                       ],[ | ||||
|                                          15, 3,  1,  13, 8,  4,  14, 7,  6,  15, 11, 2,  3,  8,  4,  14, | ||||
|                                          9,  12, 7,  0,  2,  1,  13, 10, 12, 6,  0,  9,  5,  11, 10, 5, | ||||
|                                          0,  13, 14, 8,  7,  10, 11, 1,  10, 3,  4,  15, 13, 4,  1,  2, | ||||
|                                          5,  11, 8,  6,  12, 7,  6,  12, 9,  0,  3,  5,  2,  14, 15, 9, | ||||
|                                       ],[ | ||||
|                                          10, 13, 0,  7,  9,  0,  14, 9,  6,  3,  3,  4,  15, 6,  5,  10, | ||||
|                                          1,  2,  13, 8,  12, 5,  7,  14, 11, 12, 4,  11, 2,  15, 8,  1, | ||||
|                                          13, 1,  6,  10, 4,  13, 9,  0,  8,  6,  15, 9,  3,  8,  0,  7, | ||||
|                                          11, 4,  1,  15, 2,  14, 12, 3,  5,  11, 10, 5,  14, 2,  7,  12, | ||||
|                                       ],[ | ||||
|                                          7,  13, 13, 8,  14, 11, 3,  5,  0,  6,  6,  15, 9,  0,  10, 3, | ||||
|                                          1,  4,  2,  7,  8,  2,  5,  12, 11, 1,  12, 10, 4,  14, 15, 9, | ||||
|                                          10, 3,  6,  15, 9,  0,  0,  6,  12, 10, 11, 1,  7,  13, 13, 8, | ||||
|                                          15, 9,  1,  4,  3,  5,  14, 11, 5,  12, 2,  7,  8,  2,  4,  14, | ||||
|                                       ],[ | ||||
|                                          2,  14, 12, 11, 4,  2,  1,  12, 7,  4,  10, 7,  11, 13, 6,  1, | ||||
|                                          8,  5,  5,  0,  3,  15, 15, 10, 13, 3,  0,  9,  14, 8,  9,  6, | ||||
|                                          4,  11, 2,  8,  1,  12, 11, 7,  10, 1,  13, 14, 7,  2,  8,  13, | ||||
|                                          15, 6,  9,  15, 12, 0,  5,  9,  6,  10, 3,  4,  0,  5,  14, 3, | ||||
|                                       ],[ | ||||
|                                          12, 10, 1,  15, 10, 4,  15, 2,  9,  7,  2,  12, 6,  9,  8,  5, | ||||
|                                          0,  6,  13, 1,  3,  13, 4,  14, 14, 0,  7,  11, 5,  3,  11, 8, | ||||
|                                          9,  4,  14, 3,  15, 2,  5,  12, 2,  9,  8,  5,  12, 15, 3,  10, | ||||
|                                          7,  11, 0,  14, 4,  1,  10, 7,  1,  6,  13, 0,  11, 8,  6,  13, | ||||
|                                       ],[ | ||||
|                                          4,  13, 11, 0,  2,  11, 14, 7,  15, 4,  0,  9,  8,  1,  13, 10, | ||||
|                                          3,  14, 12, 3,  9,  5,  7,  12, 5,  2,  10, 15, 6,  8,  1,  6, | ||||
|                                          1,  6,  4,  11, 11, 13, 13, 8,  12, 1,  3,  4,  7,  10, 14, 7, | ||||
|                                          10, 9,  15, 5,  6,  0,  8,  15, 0,  14, 5,  2,  9,  3,  2,  12, | ||||
|                                       ],[ | ||||
|                                          13, 1,  2,  15, 8,  13, 4,  8,  6,  10, 15, 3,  11, 7,  1,  4, | ||||
|                                          10, 12, 9,  5,  3,  6,  14, 11, 5,  0,  0,  14, 12, 9,  7,  2, | ||||
|                                          7,  2,  11, 1,  4,  14, 1,  7,  9,  4,  12, 10, 14, 8,  2,  13, | ||||
|                                          0,  15, 6,  12, 10, 9,  13, 0,  15, 3,  3,  5,  5,  6,  8,  11, | ||||
|                                       ]]; | ||||
|  | ||||
| /** | ||||
|  * Data Encryption Standard. | ||||
|  * | ||||
|  * Params: | ||||
|  *     L = Number of keys. | ||||
|  */ | ||||
| class DES(ushort L = 1) : BlockCipher | ||||
|     if (L == 1) | ||||
| { | ||||
|     mixin FixedBlockSize!8; | ||||
|     mixin KeyLength!8; | ||||
|  | ||||
|     private enum expansionBlockSize = 6; | ||||
|     private enum pc1KeyLength = 7; | ||||
|     private enum subkeyLength = 6; | ||||
|     private ubyte[] key_; | ||||
|  | ||||
|     /** | ||||
|      * Params: | ||||
|      *     key = Key. | ||||
|      */ | ||||
|     @property void key(ubyte[] key) pure nothrow @safe @nogc | ||||
|     in | ||||
|     { | ||||
|         assert(key.length >= minKeyLength); | ||||
|         assert(key.length <= maxKeyLength); | ||||
|     } | ||||
|     body | ||||
|     { | ||||
|         key_ = key; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Encrypts a block. | ||||
|      * | ||||
|      * Params: | ||||
|      *    plain  = Plain text, input. | ||||
|      *    cipher = Cipher text, output. | ||||
|      */ | ||||
|     void encrypt(in ubyte[] plain, ubyte[] cipher) | ||||
|     nothrow | ||||
|     in | ||||
|     { | ||||
|         assert(plain.length == blockSize); | ||||
|         assert(cipher.length == blockSize); | ||||
|     } | ||||
|     body | ||||
|     { | ||||
|         operateBlock!(Direction.encryption)(plain, cipher); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Decrypts a block. | ||||
|      * | ||||
|      * Params: | ||||
|      *    cipher = Cipher text, input. | ||||
|      *    plain  = Plain text, output. | ||||
|      */ | ||||
|     void decrypt(in ubyte[] cipher, ubyte[] plain) | ||||
|     nothrow | ||||
|     in | ||||
|     { | ||||
|         assert(plain.length == blockSize); | ||||
|         assert(cipher.length == blockSize); | ||||
|     } | ||||
|     body | ||||
|     { | ||||
|         operateBlock!(Direction.decryption)(cipher, plain); | ||||
|     } | ||||
|  | ||||
|     private void operateBlock(Direction D)(in ubyte[] source, ref ubyte[] target) | ||||
|     { | ||||
|         ubyte[blockSize_] ipBlock; | ||||
|         ubyte[expansionBlockSize] expansionBlock; | ||||
|         ubyte[4] substitutionBlock; | ||||
|         ubyte[4] pBoxTarget; | ||||
|         ubyte[pc1KeyLength] pc1Key; | ||||
|         ubyte[subkeyLength] subkey; | ||||
|  | ||||
|         // Initial permutation | ||||
|         permute(source, ipBlock, ipTable, blockSize); | ||||
|  | ||||
|         // Key schedule computation | ||||
|         permute(key_, pc1Key, pc1Table, pc1KeyLength); | ||||
|  | ||||
|         // Feistel function | ||||
|         for (ubyte round; round < 16; ++round) | ||||
|         { | ||||
|             auto bitVector = BitVector(expansionBlock); | ||||
|             /* Expansion. This permutation only looks at the first 4 bytes (32 | ||||
|                bits of ipBlock); 16 of these are repeated in expansion table.*/ | ||||
|             permute(BitVector(ipBlock[4..$]), bitVector, expansionTable, 6); | ||||
|  | ||||
|             // Key mixing | ||||
|             static if (D == Direction.encryption) | ||||
|             { | ||||
|                 rotateLeft(pc1Key); | ||||
|                 if (!(round <= 1 || round == 8 || round == 15)) | ||||
|                 { | ||||
|                     // Rotate twice. | ||||
|                     rotateLeft(pc1Key); | ||||
|                 } | ||||
|             } | ||||
|             permute(pc1Key, subkey, pc2Table, subkeyLength); | ||||
|             static if (D == Direction.decryption) | ||||
|             { | ||||
|                 rotateRight(pc1Key); | ||||
|                 if (!(round >= 14 || round == 7 || round == 0)) | ||||
|                 { | ||||
|                     // Rotate twice. | ||||
|                     rotateRight(pc1Key); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             bitVector ^= subkey; | ||||
|  | ||||
|             // Substitution; copy from updated expansion block to ciphertext block | ||||
|             substitutionBlock[0] = cast(ubyte) (sBox[0][(expansionBlock[0] & 0xfc ) >> 2] << 4); | ||||
|             substitutionBlock[0] |= sBox[1][(expansionBlock[0] & 0x03) << 4 | (expansionBlock[1] & 0xf0) >> 4]; | ||||
|             substitutionBlock[1] = cast(ubyte) (sBox[2][(expansionBlock[1] & 0x0f) << 2 | (expansionBlock[2] & 0xc0) >> 6] << 4); | ||||
|             substitutionBlock[1] |= sBox[3][(expansionBlock[2] & 0x3f)]; | ||||
|             substitutionBlock[2] = cast(ubyte) (sBox[4][(expansionBlock[3] & 0xfc) >> 2 ] << 4); | ||||
|             substitutionBlock[2] |= sBox[5][(expansionBlock[3] & 0x03) << 4 | (expansionBlock[4] & 0xf0) >> 4]; | ||||
|             substitutionBlock[3] = cast(ubyte) (sBox[6][(expansionBlock[4] & 0x0F) << 2 | (expansionBlock[5] & 0xc0) >> 6] << 4); | ||||
|             substitutionBlock[3] |= sBox[7][(expansionBlock[5] & 0x3f)]; | ||||
|  | ||||
|             // Permutation | ||||
|             bitVector = BitVector(substitutionBlock); | ||||
|             permute(bitVector, pBoxTarget, pTable, blockSize / 2); | ||||
|  | ||||
|             // Swap the halves. | ||||
|             substitutionBlock = ipBlock[0..4]; | ||||
|             ipBlock[0..4] = ipBlock[4..$]; | ||||
|  | ||||
|             bitVector ^= pBoxTarget; | ||||
|             ipBlock[4..$] = substitutionBlock; | ||||
|         } | ||||
|  | ||||
|         substitutionBlock = ipBlock[0..4]; | ||||
|         ipBlock[0..4] = ipBlock[4..$]; | ||||
|         ipBlock[4..$] = substitutionBlock; | ||||
|  | ||||
|         // Final permutaion (undo initial permuation). | ||||
|         permute(ipBlock, target, fpTable, blockSize); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Performs the left rotation operation on the key. | ||||
|      * | ||||
|      * Params: | ||||
|      *     key = The key to rotate. | ||||
|      */ | ||||
|     private void rotateLeft(ref ubyte[7] key) const pure nothrow @safe @nogc | ||||
|     { | ||||
|         immutable carryLeft = (key[0] & 0x80) >> 3; | ||||
|  | ||||
|         key[0] = cast(ubyte) ((key[0] << 1) | ((key[1] & 0x80) >> 7)); | ||||
|         key[1] = cast(ubyte) ((key[1] << 1) | ((key[2] & 0x80) >> 7)); | ||||
|         key[2] = cast(ubyte) ((key[2] << 1) | ((key[3] & 0x80) >> 7)); | ||||
|  | ||||
|         immutable carryRight = (key[3] & 0x08) >> 3; | ||||
|         key[3] = cast(ubyte) ((((key[3] << 1) | ((key[4] & 0x80) >> 7)) & ~0x10) | carryLeft); | ||||
|  | ||||
|         key[4] = cast(ubyte) ((key[4] << 1) | ((key[5] & 0x80) >> 7)); | ||||
|         key[5] = cast(ubyte) ((key[5] << 1) | ((key[6] & 0x80) >> 7)); | ||||
|         key[6] = cast(ubyte) ((key[6] << 1) | carryRight); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Performs the right rotation operation on the key. | ||||
|      * | ||||
|      * Params: | ||||
|      *     key = The key to rotate. | ||||
|      */ | ||||
|     private void rotateRight(ref ubyte[7] key) const pure nothrow @safe @nogc | ||||
|     { | ||||
|         immutable carryRight = (key[6] & 0x01) << 3; | ||||
|  | ||||
|         key[6] = cast(ubyte) ((key[6] >> 1) | ((key[5] & 0x01) << 7)); | ||||
|         key[5] = cast(ubyte) ((key[5] >> 1) | ((key[4] & 0x01) << 7)); | ||||
|         key[4] = cast(ubyte) ((key[4] >> 1) | ((key[3] & 0x01) << 7)); | ||||
|  | ||||
|         immutable carryLeft = (key[3] & 0x10) << 3; | ||||
|         key[3] = cast(ubyte) ((((key[3] >> 1) | ((key[2] & 0x01) << 7)) & ~0x08) | carryRight); | ||||
|  | ||||
|         key[2] = cast(ubyte) ((key[2] >> 1) | ((key[1] & 0x01) << 7)); | ||||
|         key[1] = cast(ubyte) ((key[1] >> 1) | ((key[0] & 0x01) << 7)); | ||||
|         key[0] = cast(ubyte) ((key[0] >> 1) | carryLeft); | ||||
|     } | ||||
|  | ||||
|     private void permute(in ubyte[] source, ubyte[] target, immutable(ubyte[]) permuteTable, size_t length) | ||||
|     const pure nothrow @safe @nogc | ||||
|     { | ||||
|         const sourceVector = const BitVector(source); | ||||
|         auto targetVector = BitVector(target); | ||||
|  | ||||
|         permute(sourceVector, targetVector, permuteTable, length); | ||||
|     } | ||||
|  | ||||
|     private void permute(in BitVector source, ubyte[] target, immutable(ubyte[]) permuteTable, size_t length) | ||||
|     const pure nothrow @safe @nogc | ||||
|     { | ||||
|         auto targetVector = BitVector(target); | ||||
|  | ||||
|         permute(source, targetVector, permuteTable, length); | ||||
|     } | ||||
|  | ||||
|     private void permute(in BitVector source, ref BitVector target, immutable(ubyte[]) permuteTable, size_t length) | ||||
|     const pure nothrow @safe @nogc | ||||
|     { | ||||
|         for (uint i; i < length * 8; ++i) | ||||
|         { | ||||
|             target[i] = source[permuteTable[i] - 1]; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| version (unittest) | ||||
| { | ||||
|     import std.typecons; | ||||
|  | ||||
|     /* Test vectors for DES. Source: | ||||
|        "Validating the Correctness of Hardware  | ||||
|        Implementations of the NBS Data Encryption Standard" | ||||
|        NBS Special Publication 500-20, 1980. Appendix B */ | ||||
|  | ||||
|     // Initial and reverse Permutation and Expansion tests. Encrypt. | ||||
|     ubyte[8][64] desTestVectors1 = [ | ||||
|         [0x95, 0xf8, 0xa5, 0xe5, 0xdd, 0x31, 0xd9, 0x00], | ||||
|         [0xdd, 0x7f, 0x12, 0x1c, 0xa5, 0x01, 0x56, 0x19], | ||||
|         [0x2e, 0x86, 0x53, 0x10, 0x4f, 0x38, 0x34, 0xea], | ||||
|         [0x4b, 0xd3, 0x88, 0xff, 0x6c, 0xd8, 0x1d, 0x4f], | ||||
|         [0x20, 0xb9, 0xe7, 0x67, 0xb2, 0xfb, 0x14, 0x56], | ||||
|         [0x55, 0x57, 0x93, 0x80, 0xd7, 0x71, 0x38, 0xef], | ||||
|         [0x6c, 0xc5, 0xde, 0xfa, 0xaf, 0x04, 0x51, 0x2f], | ||||
|         [0x0d, 0x9f, 0x27, 0x9b, 0xa5, 0xd8, 0x72, 0x60], | ||||
|         [0xd9, 0x03, 0x1b, 0x02, 0x71, 0xbd, 0x5a, 0x0a], | ||||
|         [0x42, 0x42, 0x50, 0xb3, 0x7c, 0x3d, 0xd9, 0x51], | ||||
|         [0xb8, 0x06, 0x1b, 0x7e, 0xcd, 0x9a, 0x21, 0xe5], | ||||
|         [0xf1, 0x5d, 0x0f, 0x28, 0x6b, 0x65, 0xbd, 0x28], | ||||
|         [0xad, 0xd0, 0xcc, 0x8d, 0x6e, 0x5d, 0xeb, 0xa1], | ||||
|         [0xe6, 0xd5, 0xf8, 0x27, 0x52, 0xad, 0x63, 0xd1], | ||||
|         [0xec, 0xbf, 0xe3, 0xbd, 0x3f, 0x59, 0x1a, 0x5e], | ||||
|         [0xf3, 0x56, 0x83, 0x43, 0x79, 0xd1, 0x65, 0xcd], | ||||
|         [0x2b, 0x9f, 0x98, 0x2f, 0x20, 0x03, 0x7f, 0xa9], | ||||
|         [0x88, 0x9d, 0xe0, 0x68, 0xa1, 0x6f, 0x0b, 0xe6], | ||||
|         [0xe1, 0x9e, 0x27, 0x5d, 0x84, 0x6a, 0x12, 0x98], | ||||
|         [0x32, 0x9a, 0x8e, 0xd5, 0x23, 0xd7, 0x1a, 0xec], | ||||
|         [0xe7, 0xfc, 0xe2, 0x25, 0x57, 0xd2, 0x3c, 0x97], | ||||
|         [0x12, 0xa9, 0xf5, 0x81, 0x7f, 0xf2, 0xd6, 0x5d], | ||||
|         [0xa4, 0x84, 0xc3, 0xad, 0x38, 0xdc, 0x9c, 0x19], | ||||
|         [0xfb, 0xe0, 0x0a, 0x8a, 0x1e, 0xf8, 0xad, 0x72], | ||||
|         [0x75, 0x0d, 0x07, 0x94, 0x07, 0x52, 0x13, 0x63], | ||||
|         [0x64, 0xfe, 0xed, 0x9c, 0x72, 0x4c, 0x2f, 0xaf], | ||||
|         [0xf0, 0x2b, 0x26, 0x3b, 0x32, 0x8e, 0x2b, 0x60], | ||||
|         [0x9d, 0x64, 0x55, 0x5a, 0x9a, 0x10, 0xb8, 0x52], | ||||
|         [0xd1, 0x06, 0xff, 0x0b, 0xed, 0x52, 0x55, 0xd7], | ||||
|         [0xe1, 0x65, 0x2c, 0x6b, 0x13, 0x8c, 0x64, 0xa5], | ||||
|         [0xe4, 0x28, 0x58, 0x11, 0x86, 0xec, 0x8f, 0x46], | ||||
|         [0xae, 0xb5, 0xf5, 0xed, 0xe2, 0x2d, 0x1a, 0x36], | ||||
|         [0xe9, 0x43, 0xd7, 0x56, 0x8a, 0xec, 0x0c, 0x5c], | ||||
|         [0xdf, 0x98, 0xc8, 0x27, 0x6f, 0x54, 0xb0, 0x4b], | ||||
|         [0xb1, 0x60, 0xe4, 0x68, 0x0f, 0x6c, 0x69, 0x6f], | ||||
|         [0xfa, 0x07, 0x52, 0xb0, 0x7d, 0x9c, 0x4a, 0xb8], | ||||
|         [0xca, 0x3a, 0x2b, 0x03, 0x6d, 0xbc, 0x85, 0x02], | ||||
|         [0x5e, 0x09, 0x05, 0x51, 0x7b, 0xb5, 0x9b, 0xcf], | ||||
|         [0x81, 0x4e, 0xeb, 0x3b, 0x91, 0xd9, 0x07, 0x26], | ||||
|         [0x4d, 0x49, 0xdb, 0x15, 0x32, 0x91, 0x9c, 0x9f], | ||||
|         [0x25, 0xeb, 0x5f, 0xc3, 0xf8, 0xcf, 0x06, 0x21], | ||||
|         [0xab, 0x6a, 0x20, 0xc0, 0x62, 0x0d, 0x1c, 0x6f], | ||||
|         [0x79, 0xe9, 0x0d, 0xbc, 0x98, 0xf9, 0x2c, 0xca], | ||||
|         [0x86, 0x6e, 0xce, 0xdd, 0x80, 0x72, 0xbb, 0x0e], | ||||
|         [0x8b, 0x54, 0x53, 0x6f, 0x2f, 0x3e, 0x64, 0xa8], | ||||
|         [0xea, 0x51, 0xd3, 0x97, 0x55, 0x95, 0xb8, 0x6b], | ||||
|         [0xca, 0xff, 0xc6, 0xac, 0x45, 0x42, 0xde, 0x31], | ||||
|         [0x8d, 0xd4, 0x5a, 0x2d, 0xdf, 0x90, 0x79, 0x6c], | ||||
|         [0x10, 0x29, 0xd5, 0x5e, 0x88, 0x0e, 0xc2, 0xd0], | ||||
|         [0x5d, 0x86, 0xcb, 0x23, 0x63, 0x9d, 0xbe, 0xa9], | ||||
|         [0x1d, 0x1c, 0xa8, 0x53, 0xae, 0x7c, 0x0c, 0x5f], | ||||
|         [0xce, 0x33, 0x23, 0x29, 0x24, 0x8f, 0x32, 0x28], | ||||
|         [0x84, 0x05, 0xd1, 0xab, 0xe2, 0x4f, 0xb9, 0x42], | ||||
|         [0xe6, 0x43, 0xd7, 0x80, 0x90, 0xca, 0x42, 0x07], | ||||
|         [0x48, 0x22, 0x1b, 0x99, 0x37, 0x74, 0x8a, 0x23], | ||||
|         [0xdd, 0x7c, 0x0b, 0xbd, 0x61, 0xfa, 0xfd, 0x54], | ||||
|         [0x2f, 0xbc, 0x29, 0x1a, 0x57, 0x0d, 0xb5, 0xc4], | ||||
|         [0xe0, 0x7c, 0x30, 0xd7, 0xe4, 0xe2, 0x6e, 0x12], | ||||
|         [0x09, 0x53, 0xe2, 0x25, 0x8e, 0x8e, 0x90, 0xa1], | ||||
|         [0x5b, 0x71, 0x1b, 0xc4, 0xce, 0xeb, 0xf2, 0xee], | ||||
|         [0xcc, 0x08, 0x3f, 0x1e, 0x6d, 0x9e, 0x85, 0xf6], | ||||
|         [0xd2, 0xfd, 0x88, 0x67, 0xd5, 0x0d, 0x2d, 0xfe], | ||||
|         [0x06, 0xe7, 0xea, 0x22, 0xce, 0x92, 0x70, 0x8f], | ||||
|         [0x16, 0x6b, 0x40, 0xb4, 0x4a, 0xba, 0x4b, 0xd6], | ||||
|     ]; | ||||
|  | ||||
|     // Key Permutation test. Encrypt. | ||||
|     // Test of right-shifts. Decrypt. | ||||
|     ubyte[8][56] desTestVectors2 = [ | ||||
|         [0x95, 0xa8, 0xd7, 0x28, 0x13, 0xda, 0xa9, 0x4d], | ||||
|         [0x0e, 0xec, 0x14, 0x87, 0xdd, 0x8c, 0x26, 0xd5], | ||||
|         [0x7a, 0xd1, 0x6f, 0xfb, 0x79, 0xc4, 0x59, 0x26], | ||||
|         [0xd3, 0x74, 0x62, 0x94, 0xca, 0x6a, 0x6c, 0xf3], | ||||
|         [0x80, 0x9f, 0x5f, 0x87, 0x3c, 0x1f, 0xd7, 0x61], | ||||
|         [0xc0, 0x2f, 0xaf, 0xfe, 0xc9, 0x89, 0xd1, 0xfc], | ||||
|         [0x46, 0x15, 0xaa, 0x1d, 0x33, 0xe7, 0x2f, 0x10], | ||||
|         [0x20, 0x55, 0x12, 0x33, 0x50, 0xc0, 0x08, 0x58], | ||||
|         [0xdf, 0x3b, 0x99, 0xd6, 0x57, 0x73, 0x97, 0xc8], | ||||
|         [0x31, 0xfe, 0x17, 0x36, 0x9b, 0x52, 0x88, 0xc9], | ||||
|         [0xdf, 0xdd, 0x3c, 0xc6, 0x4d, 0xae, 0x16, 0x42], | ||||
|         [0x17, 0x8c, 0x83, 0xce, 0x2b, 0x39, 0x9d, 0x94], | ||||
|         [0x50, 0xf6, 0x36, 0x32, 0x4a, 0x9b, 0x7f, 0x80], | ||||
|         [0xa8, 0x46, 0x8e, 0xe3, 0xbc, 0x18, 0xf0, 0x6d], | ||||
|         [0xa2, 0xdc, 0x9e, 0x92, 0xfd, 0x3c, 0xde, 0x92], | ||||
|         [0xca, 0xc0, 0x9f, 0x79, 0x7d, 0x03, 0x12, 0x87], | ||||
|         [0x90, 0xba, 0x68, 0x0b, 0x22, 0xae, 0xb5, 0x25], | ||||
|         [0xce, 0x7a, 0x24, 0xf3, 0x50, 0xe2, 0x80, 0xb6], | ||||
|         [0x88, 0x2b, 0xff, 0x0a, 0xa0, 0x1a, 0x0b, 0x87], | ||||
|         [0x25, 0x61, 0x02, 0x88, 0x92, 0x45, 0x11, 0xc2], | ||||
|         [0xc7, 0x15, 0x16, 0xc2, 0x9c, 0x75, 0xd1, 0x70], | ||||
|         [0x51, 0x99, 0xc2, 0x9a, 0x52, 0xc9, 0xf0, 0x59], | ||||
|         [0xc2, 0x2f, 0x0a, 0x29, 0x4a, 0x71, 0xf2, 0x9f], | ||||
|         [0xee, 0x37, 0x14, 0x83, 0x71, 0x4c, 0x02, 0xea], | ||||
|         [0xa8, 0x1f, 0xbd, 0x44, 0x8f, 0x9e, 0x52, 0x2f], | ||||
|         [0x4f, 0x64, 0x4c, 0x92, 0xe1, 0x92, 0xdf, 0xed], | ||||
|         [0x1a, 0xfa, 0x9a, 0x66, 0xa6, 0xdf, 0x92, 0xae], | ||||
|         [0xb3, 0xc1, 0xcc, 0x71, 0x5c, 0xb8, 0x79, 0xd8], | ||||
|         [0x19, 0xd0, 0x32, 0xe6, 0x4a, 0xb0, 0xbd, 0x8b], | ||||
|         [0x3c, 0xfa, 0xa7, 0xa7, 0xdc, 0x87, 0x20, 0xdc], | ||||
|         [0xb7, 0x26, 0x5f, 0x7f, 0x44, 0x7a, 0xc6, 0xf3], | ||||
|         [0x9d, 0xb7, 0x3b, 0x3c, 0x0d, 0x16, 0x3f, 0x54], | ||||
|         [0x81, 0x81, 0xb6, 0x5b, 0xab, 0xf4, 0xa9, 0x75], | ||||
|         [0x93, 0xc9, 0xb6, 0x40, 0x42, 0xea, 0xa2, 0x40], | ||||
|         [0x55, 0x70, 0x53, 0x08, 0x29, 0x70, 0x55, 0x92], | ||||
|         [0x86, 0x38, 0x80, 0x9e, 0x87, 0x87, 0x87, 0xa0], | ||||
|         [0x41, 0xb9, 0xa7, 0x9a, 0xf7, 0x9a, 0xc2, 0x08], | ||||
|         [0x7a, 0x9b, 0xe4, 0x2f, 0x20, 0x09, 0xa8, 0x92], | ||||
|         [0x29, 0x03, 0x8d, 0x56, 0xba, 0x6d, 0x27, 0x45], | ||||
|         [0x54, 0x95, 0xc6, 0xab, 0xf1, 0xe5, 0xdf, 0x51], | ||||
|         [0xae, 0x13, 0xdb, 0xd5, 0x61, 0x48, 0x89, 0x33], | ||||
|         [0x02, 0x4d, 0x1f, 0xfa, 0x89, 0x04, 0xe3, 0x89], | ||||
|         [0xd1, 0x39, 0x97, 0x12, 0xf9, 0x9b, 0xf0, 0x2e], | ||||
|         [0x14, 0xc1, 0xd7, 0xc1, 0xcf, 0xfe, 0xc7, 0x9e], | ||||
|         [0x1d, 0xe5, 0x27, 0x9d, 0xae, 0x3b, 0xed, 0x6f], | ||||
|         [0xe9, 0x41, 0xa3, 0x3f, 0x85, 0x50, 0x13, 0x03], | ||||
|         [0xda, 0x99, 0xdb, 0xbc, 0x9a, 0x03, 0xf3, 0x79], | ||||
|         [0xb7, 0xfc, 0x92, 0xf9, 0x1d, 0x8e, 0x92, 0xe9], | ||||
|         [0xae, 0x8e, 0x5c, 0xaa, 0x3c, 0xa0, 0x4e, 0x85], | ||||
|         [0x9c, 0xc6, 0x2d, 0xf4, 0x3b, 0x6e, 0xed, 0x74], | ||||
|         [0xd8, 0x63, 0xdb, 0xb5, 0xc5, 0x9a, 0x91, 0xa0], | ||||
|         [0xa1, 0xab, 0x21, 0x90, 0x54, 0x5b, 0x91, 0xd7], | ||||
|         [0x08, 0x75, 0x04, 0x1e, 0x64, 0xc5, 0x70, 0xf7], | ||||
|         [0x5a, 0x59, 0x45, 0x28, 0xbe, 0xbe, 0xf1, 0xcc], | ||||
|         [0xfc, 0xdb, 0x32, 0x91, 0xde, 0x21, 0xf0, 0xc0], | ||||
|         [0x86, 0x9e, 0xfd, 0x7f, 0x9f, 0x26, 0x5a, 0x09], | ||||
|     ]; | ||||
|  | ||||
|     // Data permutation test. Encrypt. | ||||
|     ubyte[8][2][32] desTestVectors3 = [ | ||||
|         [[0x10, 0x46, 0x91, 0x34, 0x89, 0x98, 0x01, 0x31], [0x88, 0xd5, 0x5e, 0x54, 0xf5, 0x4c, 0x97, 0xb4]], | ||||
|         [[0x10, 0x07, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20], [0x0c, 0x0c, 0xc0, 0x0c, 0x83, 0xea, 0x48, 0xfd]], | ||||
|         [[0x10, 0x07, 0x10, 0x34, 0xc8, 0x98, 0x01, 0x20], [0x83, 0xbc, 0x8e, 0xf3, 0xa6, 0x57, 0x01, 0x83]], | ||||
|         [[0x10, 0x46, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20], [0xdf, 0x72, 0x5d, 0xca, 0xd9, 0x4e, 0xa2, 0xe9]], | ||||
|         [[0x10, 0x86, 0x91, 0x15, 0x19, 0x19, 0x01, 0x01], [0xe6, 0x52, 0xb5, 0x3b, 0x55, 0x0b, 0xe8, 0xb0]], | ||||
|         [[0x10, 0x86, 0x91, 0x15, 0x19, 0x58, 0x01, 0x01], [0xaf, 0x52, 0x71, 0x20, 0xc4, 0x85, 0xcb, 0xb0]], | ||||
|         [[0x51, 0x07, 0xb0, 0x15, 0x19, 0x58, 0x01, 0x01], [0x0f, 0x04, 0xce, 0x39, 0x3d, 0xb9, 0x26, 0xd5]], | ||||
|         [[0x10, 0x07, 0xb0, 0x15, 0x19, 0x19, 0x01, 0x01], [0xc9, 0xf0, 0x0f, 0xfc, 0x74, 0x07, 0x90, 0x67]], | ||||
|         [[0x31, 0x07, 0x91, 0x54, 0x98, 0x08, 0x01, 0x01], [0x7c, 0xfd, 0x82, 0xa5, 0x93, 0x25, 0x2b, 0x4e]], | ||||
|         [[0x31, 0x07, 0x91, 0x94, 0x98, 0x08, 0x01, 0x01], [0xcb, 0x49, 0xa2, 0xf9, 0xe9, 0x13, 0x63, 0xe3]], | ||||
|         [[0x10, 0x07, 0x91, 0x15, 0xb9, 0x08, 0x01, 0x40], [0x00, 0xb5, 0x88, 0xbe, 0x70, 0xd2, 0x3f, 0x56]], | ||||
|         [[0x31, 0x07, 0x91, 0x15, 0x98, 0x08, 0x01, 0x40], [0x40, 0x6a, 0x9a, 0x6a, 0xb4, 0x33, 0x99, 0xae]], | ||||
|         [[0x10, 0x07, 0xd0, 0x15, 0x89, 0x98, 0x01, 0x01], [0x6c, 0xb7, 0x73, 0x61, 0x1d, 0xca, 0x9a, 0xda]], | ||||
|         [[0x91, 0x07, 0x91, 0x15, 0x89, 0x98, 0x01, 0x01], [0x67, 0xfd, 0x21, 0xc1, 0x7d, 0xbb, 0x5d, 0x70]], | ||||
|         [[0x91, 0x07, 0xd0, 0x15, 0x89, 0x19, 0x01, 0x01], [0x95, 0x92, 0xcb, 0x41, 0x10, 0x43, 0x07, 0x87]], | ||||
|         [[0x10, 0x07, 0xd0, 0x15, 0x98, 0x98, 0x01, 0x20], [0xa6, 0xb7, 0xff, 0x68, 0xa3, 0x18, 0xdd, 0xd3]], | ||||
|         [[0x10, 0x07, 0x94, 0x04, 0x98, 0x19, 0x01, 0x01], [0x4d, 0x10, 0x21, 0x96, 0xc9, 0x14, 0xca, 0x16]], | ||||
|         [[0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x04, 0x01], [0x2d, 0xfa, 0x9f, 0x45, 0x73, 0x59, 0x49, 0x65]], | ||||
|         [[0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x01, 0x01], [0xb4, 0x66, 0x04, 0x81, 0x6c, 0x0e, 0x07, 0x74]], | ||||
|         [[0x01, 0x07, 0x94, 0x04, 0x91, 0x19, 0x04, 0x01], [0x6e, 0x7e, 0x62, 0x21, 0xa4, 0xf3, 0x4e, 0x87]], | ||||
|         [[0x19, 0x07, 0x92, 0x10, 0x98, 0x1a, 0x01, 0x01], [0xaa, 0x85, 0xe7, 0x46, 0x43, 0x23, 0x31, 0x99]], | ||||
|         [[0x10, 0x07, 0x91, 0x19, 0x98, 0x19, 0x08, 0x01], [0x2e, 0x5a, 0x19, 0xdb, 0x4d, 0x19, 0x62, 0xd6]], | ||||
|         [[0x10, 0x07, 0x91, 0x19, 0x98, 0x1a, 0x08, 0x01], [0x23, 0xa8, 0x66, 0xa8, 0x09, 0xd3, 0x08, 0x94]], | ||||
|         [[0x10, 0x07, 0x92, 0x10, 0x98, 0x19, 0x01, 0x01], [0xd8, 0x12, 0xd9, 0x61, 0xf0, 0x17, 0xd3, 0x20]], | ||||
|         [[0x10, 0x07, 0x91, 0x15, 0x98, 0x19, 0x01, 0x0b], [0x05, 0x56, 0x05, 0x81, 0x6e, 0x58, 0x60, 0x8f]], | ||||
|         [[0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x01], [0xab, 0xd8, 0x8e, 0x8b, 0x1b, 0x77, 0x16, 0xf1]], | ||||
|         [[0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x02], [0x53, 0x7a, 0xc9, 0x5b, 0xe6, 0x9d, 0xa1, 0xe1]], | ||||
|         [[0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x08], [0xae, 0xd0, 0xf6, 0xae, 0x3c, 0x25, 0xcd, 0xd8]], | ||||
|         [[0x10, 0x02, 0x91, 0x14, 0x98, 0x10, 0x01, 0x04], [0xb3, 0xe3, 0x5a, 0x5e, 0xe5, 0x3e, 0x7b, 0x8d]], | ||||
|         [[0x10, 0x02, 0x91, 0x15, 0x98, 0x19, 0x01, 0x04], [0x61, 0xc7, 0x9c, 0x71, 0x92, 0x1a, 0x2e, 0xf8]], | ||||
|         [[0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x02, 0x01], [0xe2, 0xf5, 0x72, 0x8f, 0x09, 0x95, 0x01, 0x3c]], | ||||
|         [[0x10, 0x02, 0x91, 0x16, 0x98, 0x10, 0x01, 0x01], [0x1a, 0xea, 0xc3, 0x9a, 0x61, 0xf0, 0xa4, 0x64]], | ||||
|     ]; | ||||
|  | ||||
|     // S-Box test. Encrypt. | ||||
|     ubyte[8][3][19] desTestVectors4 = [ | ||||
|         [[0x7c, 0xa1, 0x10, 0x45, 0x4a, 0x1a, 0x6e, 0x57], [0x01, 0xa1, 0xd6, 0xd0, 0x39, 0x77, 0x67, 0x42], | ||||
|         [0x69, 0x0f, 0x5b, 0x0d, 0x9a, 0x26, 0x93, 0x9b]], | ||||
|         [[0x01, 0x31, 0xd9, 0x61, 0x9d, 0xc1, 0x37, 0x6e], [0x5c, 0xd5, 0x4c, 0xa8, 0x3d, 0xef, 0x57, 0xda], | ||||
|         [0x7a, 0x38, 0x9d, 0x10, 0x35, 0x4b, 0xd2, 0x71]], | ||||
|         [[0x07, 0xa1, 0x13, 0x3e, 0x4a, 0x0b, 0x26, 0x86], [0x02, 0x48, 0xd4, 0x38, 0x06, 0xf6, 0x71, 0x72], | ||||
|         [0x86, 0x8e, 0xbb, 0x51, 0xca, 0xb4, 0x59, 0x9a]], | ||||
|         [[0x38, 0x49, 0x67, 0x4c, 0x26, 0x02, 0x31, 0x9e], [0x51, 0x45, 0x4b, 0x58, 0x2d, 0xdf, 0x44, 0x0a], | ||||
|         [0x71, 0x78, 0x87, 0x6e, 0x01, 0xf1, 0x9b, 0x2a]], | ||||
|         [[0x04, 0xb9, 0x15, 0xba, 0x43, 0xfe, 0xb5, 0xb6], [0x42, 0xfd, 0x44, 0x30, 0x59, 0x57, 0x7f, 0xa2], | ||||
|         [0xaf, 0x37, 0xfb, 0x42, 0x1f, 0x8c, 0x40, 0x95]], | ||||
|         [[0x01, 0x13, 0xb9, 0x70, 0xfd, 0x34, 0xf2, 0xce], [0x05, 0x9b, 0x5e, 0x08, 0x51, 0xcf, 0x14, 0x3a], | ||||
|         [0x86, 0xa5, 0x60, 0xf1, 0x0e, 0xc6, 0xd8, 0x5b]], | ||||
|         [[0x01, 0x70, 0xf1, 0x75, 0x46, 0x8f, 0xb5, 0xe6], [0x07, 0x56, 0xd8, 0xe0, 0x77, 0x47, 0x61, 0xd2], | ||||
|         [0x0c, 0xd3, 0xda, 0x02, 0x00, 0x21, 0xdc, 0x09]], | ||||
|         [[0x43, 0x29, 0x7f, 0xad, 0x38, 0xe3, 0x73, 0xfe], [0x76, 0x25, 0x14, 0xb8, 0x29, 0xbf, 0x48, 0x6a], | ||||
|         [0xea, 0x67, 0x6b, 0x2c, 0xb7, 0xdb, 0x2b, 0x7a]], | ||||
|         [[0x07, 0xa7, 0x13, 0x70, 0x45, 0xda, 0x2a, 0x16], [0x3b, 0xdd, 0x11, 0x90, 0x49, 0x37, 0x28, 0x02], | ||||
|         [0xdf, 0xd6, 0x4a, 0x81, 0x5c, 0xaf, 0x1a, 0x0f]], | ||||
|         [[0x04, 0x68, 0x91, 0x04, 0xc2, 0xfd, 0x3b, 0x2f], [0x26, 0x95, 0x5f, 0x68, 0x35, 0xaf, 0x60, 0x9a], | ||||
|         [0x5c, 0x51, 0x3c, 0x9c, 0x48, 0x86, 0xc0, 0x88]], | ||||
|         [[0x37, 0xd0, 0x6b, 0xb5, 0x16, 0xcb, 0x75, 0x46], [0x16, 0x4d, 0x5e, 0x40, 0x4f, 0x27, 0x52, 0x32], | ||||
|         [0x0a, 0x2a, 0xee, 0xae, 0x3f, 0xf4, 0xab, 0x77]], | ||||
|         [[0x1f, 0x08, 0x26, 0x0d, 0x1a, 0xc2, 0x46, 0x5e], [0x6b, 0x05, 0x6e, 0x18, 0x75, 0x9f, 0x5c, 0xca], | ||||
|         [0xef, 0x1b, 0xf0, 0x3e, 0x5d, 0xfa, 0x57, 0x5a]], | ||||
|         [[0x58, 0x40, 0x23, 0x64, 0x1a, 0xba, 0x61, 0x76], [0x00, 0x4b, 0xd6, 0xef, 0x09, 0x17, 0x60, 0x62], | ||||
|         [0x88, 0xbf, 0x0d, 0xb6, 0xd7, 0x0d, 0xee, 0x56]], | ||||
|         [[0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xb0, 0x07], [0x48, 0x0d, 0x39, 0x00, 0x6e, 0xe7, 0x62, 0xf2], | ||||
|         [0xa1, 0xf9, 0x91, 0x55, 0x41, 0x02, 0x0b, 0x56]], | ||||
|         [[0x49, 0x79, 0x3e, 0xbc, 0x79, 0xb3, 0x25, 0x8f], [0x43, 0x75, 0x40, 0xc8, 0x69, 0x8f, 0x3c, 0xfa], | ||||
|         [0x6f, 0xbf, 0x1c, 0xaf, 0xcf, 0xfd, 0x05, 0x56]], | ||||
|         [[0x4f, 0xb0, 0x5e, 0x15, 0x15, 0xab, 0x73, 0xa7], [0x07, 0x2d, 0x43, 0xa0, 0x77, 0x07, 0x52, 0x92], | ||||
|         [0x2f, 0x22, 0xe4, 0x9b, 0xab, 0x7c, 0xa1, 0xac]], | ||||
|         [[0x49, 0xe9, 0x5d, 0x6d, 0x4c, 0xa2, 0x29, 0xbf], [0x02, 0xfe, 0x55, 0x77, 0x81, 0x17, 0xf1, 0x2a], | ||||
|         [0x5a, 0x6b, 0x61, 0x2c, 0xc2, 0x6c, 0xce, 0x4a]], | ||||
|         [[0x01, 0x83, 0x10, 0xdc, 0x40, 0x9b, 0x26, 0xd6], [0x1d, 0x9d, 0x5c, 0x50, 0x18, 0xf7, 0x28, 0xc2], | ||||
|         [0x5f, 0x4c, 0x03, 0x8e, 0xd1, 0x2b, 0x2e, 0x41]], | ||||
|         [[0x1c, 0x58, 0x7f, 0x1c, 0x13, 0x92, 0x4f, 0xef], [0x30, 0x55, 0x32, 0x28, 0x6d, 0x6f, 0x29, 0x5a], | ||||
|         [0x63, 0xfa, 0xc0, 0xd0, 0x34, 0xd9, 0xf7, 0x93]], | ||||
|     ]; | ||||
| } | ||||
|  | ||||
| /// | ||||
| unittest | ||||
| { | ||||
|     auto des = scoped!(DES!1); | ||||
|     ubyte[8] key = [0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01]; | ||||
|     ubyte[8] plain = [0x80, 0, 0, 0, 0, 0, 0, 0]; | ||||
|     ubyte[8] cipher; | ||||
|  | ||||
|     des.key = key; | ||||
|     foreach (ubyte i; 0..64) | ||||
|     { | ||||
|         if (i != 0) | ||||
|         { | ||||
|             plain[i / 8] = i % 8 ? plain[i / 8] >> 1 : 0x80; | ||||
|             if (i % 8 == 0) | ||||
|             { | ||||
|                 plain[i / 8 - 1] = 0; | ||||
|             } | ||||
|         } | ||||
|         // Initial Permutation and Expansion test. | ||||
|         des.encrypt(plain, cipher); | ||||
|         assert(cipher == desTestVectors1[i]); | ||||
|  | ||||
|         // Inverse Permutation and Expansion test. | ||||
|         des.encrypt(cipher, cipher); | ||||
|         assert(cipher == plain); | ||||
|     } | ||||
|  | ||||
|     plain[0..$] = 0; | ||||
|     foreach (ubyte i; 0..56) | ||||
|     { | ||||
|         key[i / 7] = i % 7 ? key[i / 7] >> 1 : 0x80; | ||||
|         if (i % 7 == 0 && i != 0) | ||||
|         { | ||||
|             key[i / 7 - 1] = 0x01; | ||||
|         } | ||||
|         des.key = key; | ||||
|  | ||||
|         // Initial Permutation and Expansion test. | ||||
|         des.encrypt(plain, cipher); | ||||
|         assert(cipher == desTestVectors2[i]); | ||||
|  | ||||
|         // Test of right-shifts in Decryption. | ||||
|         des.decrypt(desTestVectors2[i], cipher); | ||||
|         assert(cipher == plain); | ||||
|     } | ||||
|  | ||||
|     // Data permutation test. | ||||
|     plain[0..$] = 0; | ||||
|     foreach (i; desTestVectors3) | ||||
|     { | ||||
|         des.key = i[0]; | ||||
|         des.encrypt(plain, cipher); | ||||
|         assert(cipher == i[1]); | ||||
|     } | ||||
|  | ||||
|     // S-Box test. | ||||
|     foreach (i; desTestVectors4) | ||||
|     { | ||||
|         des.key = i[0]; | ||||
|         des.encrypt(i[1], cipher); | ||||
|         assert(cipher == i[2]); | ||||
|     } | ||||
| } | ||||
| @@ -1,279 +0,0 @@ | ||||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||||
|  | ||||
| /** | ||||
|  * Block cipher modes of operation. | ||||
|  * | ||||
|  * Copyright: Eugene Wissner 2016. | ||||
|  * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, | ||||
|  *                  Mozilla Public License, v. 2.0). | ||||
|  * Authors: $(LINK2 mailto:belka@caraus.de, Eugene Wissner) | ||||
|  */ | ||||
| module tanya.crypto.mode; | ||||
|  | ||||
| import tanya.memory; | ||||
| import std.algorithm.iteration; | ||||
| import std.typecons; | ||||
|  | ||||
| /** | ||||
|  * Supported padding mode. | ||||
|  * | ||||
|  * See_Also: | ||||
|  * 	$(D_PSYMBOL pad) | ||||
|  */ | ||||
| enum PaddingMode | ||||
| { | ||||
| 	zero, | ||||
| 	pkcs7, | ||||
| 	ansiX923, | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Params: | ||||
|  * 	input     = Sequence that should be padded. | ||||
|  * 	mode      = Padding mode. | ||||
|  * 	blockSize = Block size. | ||||
|  * 	allocator = Allocator was used to allocate $(D_PARAM input). | ||||
|  * | ||||
|  * Returns: The function modifies the initial array and returns it. | ||||
|  * | ||||
|  * See_Also: | ||||
|  * 	$(D_PSYMBOL PaddingMode) | ||||
|  */ | ||||
| ubyte[] pad(ref ubyte[] input, | ||||
|             in PaddingMode mode, | ||||
|             in ushort blockSize, | ||||
|             shared Allocator allocator = defaultAllocator) | ||||
| in | ||||
| { | ||||
| 	assert(blockSize > 0 && blockSize <= 256); | ||||
| 	assert(blockSize % 64 == 0); | ||||
| 	assert(input.length > 0); | ||||
| } | ||||
| body | ||||
| { | ||||
| 	immutable rest = cast(ubyte) input.length % blockSize; | ||||
| 	immutable size_t lastBlock = input.length - (rest > 0 ? rest : blockSize); | ||||
| 	immutable needed = cast(ubyte) (rest > 0 ? blockSize - rest : 0); | ||||
|  | ||||
| 	final switch (mode) with (PaddingMode) | ||||
| 	{ | ||||
| 		case zero: | ||||
| 			allocator.resizeArray(input, input.length + needed); | ||||
| 			break; | ||||
| 		case pkcs7: | ||||
| 			if (needed) | ||||
| 			{ | ||||
| 				allocator.resizeArray(input, input.length + needed); | ||||
| 				input[input.length - needed ..$].each!((ref e) => e = needed); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				allocator.resizeArray(input, input.length + blockSize); | ||||
| 			} | ||||
| 			break; | ||||
| 		case ansiX923: | ||||
| 			allocator.resizeArray(input, input.length + (needed ? needed : blockSize)); | ||||
| 			input[$ - 1] = needed; | ||||
| 			break; | ||||
| 	} | ||||
|  | ||||
| 	return input; | ||||
| } | ||||
|  | ||||
| /// | ||||
| unittest | ||||
| { | ||||
| 	{ // Zeros | ||||
| 		auto input = defaultAllocator.makeArray!ubyte(50); | ||||
|  | ||||
| 		pad(input, PaddingMode.zero, 64); | ||||
| 		assert(input.length == 64); | ||||
|  | ||||
| 		pad(input, PaddingMode.zero, 64); | ||||
| 		assert(input.length == 64); | ||||
| 		assert(input[63] == 0); | ||||
|  | ||||
| 		defaultAllocator.dispose(input); | ||||
| 	} | ||||
| 	{ // PKCS#7 | ||||
| 		auto input = defaultAllocator.makeArray!ubyte(50); | ||||
| 		for (ubyte i; i < 40; ++i) | ||||
| 		{ | ||||
| 			input[i] = i; | ||||
| 		} | ||||
|  | ||||
| 		pad(input, PaddingMode.pkcs7, 64); | ||||
| 		assert(input.length == 64); | ||||
| 		for (ubyte i; i < 64; ++i) | ||||
| 		{ | ||||
| 			if (i >= 40 && i < 50) | ||||
| 			{ | ||||
| 				assert(input[i] == 0); | ||||
| 			} | ||||
| 			else if (i >= 50) | ||||
| 			{ | ||||
| 				assert(input[i] == 14); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				assert(input[i] == i); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		pad(input, PaddingMode.pkcs7, 64); | ||||
| 		assert(input.length == 128); | ||||
| 		for (ubyte i; i < 128; ++i) | ||||
| 		{ | ||||
| 			if (i >= 64 || (i >= 40 && i < 50)) | ||||
| 			{ | ||||
| 				assert(input[i] == 0); | ||||
| 			} | ||||
| 			else if (i >= 50 && i < 64) | ||||
| 			{ | ||||
| 				assert(input[i] == 14); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				assert(input[i] == i); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		defaultAllocator.dispose(input); | ||||
| 	} | ||||
| 	{ // ANSI X.923 | ||||
| 		auto input = defaultAllocator.makeArray!ubyte(50); | ||||
| 		for (ubyte i; i < 40; ++i) | ||||
| 		{ | ||||
| 			input[i] = i; | ||||
| 		} | ||||
|  | ||||
| 		pad(input, PaddingMode.ansiX923, 64); | ||||
| 		assert(input.length == 64); | ||||
| 		for (ubyte i; i < 64; ++i) | ||||
| 		{ | ||||
| 			if (i < 40) | ||||
| 			{ | ||||
| 				assert(input[i] == i); | ||||
| 			} | ||||
| 			else if (i == 63) | ||||
| 			{ | ||||
| 				assert(input[i] == 14); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				assert(input[i] == 0); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		pad(input, PaddingMode.pkcs7, 64); | ||||
| 		assert(input.length == 128); | ||||
| 		for (ubyte i = 0; i < 128; ++i) | ||||
| 		{ | ||||
| 			if (i < 40) | ||||
| 			{ | ||||
| 				assert(input[i] == i); | ||||
| 			} | ||||
| 			else if (i == 63) | ||||
| 			{ | ||||
| 				assert(input[i] == 14); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				assert(input[i] == 0); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		defaultAllocator.dispose(input); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Params: | ||||
|  * 	input     = Sequence that should be padded. | ||||
|  * 	mode      = Padding mode. | ||||
|  * 	blockSize = Block size. | ||||
|  * 	allocator = Allocator was used to allocate $(D_PARAM input). | ||||
|  * | ||||
|  * Returns: The function modifies the initial array and returns it. | ||||
|  * | ||||
|  * See_Also: | ||||
|  * 	$(D_PSYMBOL pad) | ||||
|  */ | ||||
| ref ubyte[] unpad(ref ubyte[] input, | ||||
|                   in PaddingMode mode, | ||||
|                   in ushort blockSize, | ||||
|                   shared Allocator allocator = defaultAllocator) | ||||
| in | ||||
| { | ||||
| 	assert(input.length != 0); | ||||
| 	assert(input.length % 64 == 0); | ||||
| } | ||||
| body | ||||
| { | ||||
| 	final switch (mode) with (PaddingMode) | ||||
| 	{ | ||||
| 		case zero: | ||||
| 			break; | ||||
| 		case pkcs7: | ||||
| 		case ansiX923: | ||||
| 			immutable last = input[$ - 1]; | ||||
|  | ||||
| 			allocator.resizeArray(input, input.length - (last ? last : blockSize)); | ||||
| 			break; | ||||
| 	} | ||||
|  | ||||
| 	return input; | ||||
| } | ||||
|  | ||||
| /// | ||||
| unittest | ||||
| { | ||||
| 	{ // Zeros | ||||
| 		auto input = defaultAllocator.makeArray!ubyte(50); | ||||
| 		auto inputDup = defaultAllocator.makeArray!ubyte(50); | ||||
|  | ||||
| 		pad(input, PaddingMode.zero, 64); | ||||
| 		pad(inputDup, PaddingMode.zero, 64); | ||||
|  | ||||
| 		unpad(input, PaddingMode.zero, 64); | ||||
| 		assert(input == inputDup); | ||||
|  | ||||
| 		defaultAllocator.dispose(input); | ||||
| 		defaultAllocator.dispose(inputDup); | ||||
|  | ||||
| 	} | ||||
| 	{ // PKCS#7 | ||||
| 		auto input = defaultAllocator.makeArray!ubyte(50); | ||||
| 		auto inputDup = defaultAllocator.makeArray!ubyte(50); | ||||
| 		for (ubyte i; i < 40; ++i) | ||||
| 		{ | ||||
| 			input[i] = i; | ||||
| 			inputDup[i] = i; | ||||
| 		} | ||||
|  | ||||
| 		pad(input, PaddingMode.pkcs7, 64); | ||||
| 		unpad(input, PaddingMode.pkcs7, 64); | ||||
| 		assert(input == inputDup); | ||||
|  | ||||
| 		defaultAllocator.dispose(input); | ||||
| 		defaultAllocator.dispose(inputDup); | ||||
| 	} | ||||
| 	{ // ANSI X.923 | ||||
| 		auto input = defaultAllocator.makeArray!ubyte(50); | ||||
| 		auto inputDup = defaultAllocator.makeArray!ubyte(50); | ||||
| 		for (ubyte i; i < 40; ++i) | ||||
| 		{ | ||||
| 			input[i] = i; | ||||
| 			inputDup[i] = i; | ||||
| 		} | ||||
|  | ||||
| 		pad(input, PaddingMode.pkcs7, 64); | ||||
| 		unpad(input, PaddingMode.pkcs7, 64); | ||||
| 		assert(input == inputDup); | ||||
|  | ||||
| 		defaultAllocator.dispose(input); | ||||
| 		defaultAllocator.dispose(inputDup); | ||||
| 	} | ||||
| } | ||||
| @@ -1,16 +0,0 @@ | ||||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||||
|  | ||||
| /** | ||||
|  * Copyright: Eugene Wissner 2016. | ||||
|  * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, | ||||
|  *                  Mozilla Public License, v. 2.0). | ||||
|  * Authors: $(LINK2 mailto:belka@caraus.de, Eugene Wissner) | ||||
|  */ | ||||
| module tanya.crypto; | ||||
|  | ||||
| public import tanya.crypto.bit; | ||||
| public import tanya.crypto.des; | ||||
| public import tanya.crypto.mode; | ||||
| public import tanya.crypto.symmetric; | ||||
| @@ -1,177 +0,0 @@ | ||||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||||
|  | ||||
| /** | ||||
|  * Interfaces for implementing secret key algorithms. | ||||
|  * | ||||
|  * Copyright: Eugene Wissner 2016. | ||||
|  * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, | ||||
|  *                  Mozilla Public License, v. 2.0). | ||||
|  * Authors: $(LINK2 mailto:belka@caraus.de, Eugene Wissner) | ||||
|  */ | ||||
| module tanya.crypto.symmetric; | ||||
|  | ||||
| /** | ||||
|  * Implemented by secret key algorithms. | ||||
|  */ | ||||
| interface SymmetricCipher | ||||
| { | ||||
|     /** | ||||
|      * Returns: Key length. | ||||
|      */ | ||||
|     @property inout(uint) keyLength() inout const pure nothrow @safe @nogc; | ||||
|  | ||||
|     /** | ||||
|      * Returns: Minimum key length. | ||||
|      */ | ||||
|     @property inout(uint) minKeyLength() inout const pure nothrow @safe @nogc; | ||||
|  | ||||
|     /** | ||||
|      * Returns: Maximum key length. | ||||
|      */ | ||||
|     @property inout(uint) maxKeyLength() inout const pure nothrow @safe @nogc; | ||||
|  | ||||
|     /// Cipher direction. | ||||
|     protected enum Direction : ushort | ||||
|     { | ||||
|         encryption, | ||||
|         decryption, | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Params: | ||||
|      *     key = Key. | ||||
|      */ | ||||
|     @property void key(ubyte[] key) pure nothrow @safe @nogc | ||||
|     in | ||||
|     { | ||||
|         assert(key.length >= minKeyLength); | ||||
|         assert(key.length <= maxKeyLength); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Implemented by block ciphers. | ||||
|  */ | ||||
| interface BlockCipher : SymmetricCipher | ||||
| { | ||||
|     /** | ||||
|      * Returns: Block size. | ||||
|      */ | ||||
|     @property inout(uint) blockSize() inout const pure nothrow @safe @nogc; | ||||
|  | ||||
|     /** | ||||
|      * Encrypts a block. | ||||
|      * | ||||
|      * Params: | ||||
|      *    plain  = Plain text, input. | ||||
|      *    cipher = Cipher text, output. | ||||
|      */ | ||||
|     void encrypt(in ubyte[] plain, ubyte[] cipher) | ||||
|     in | ||||
|     { | ||||
|         assert(plain.length == blockSize); | ||||
|         assert(cipher.length == blockSize); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Decrypts a block. | ||||
|      * | ||||
|      * Params: | ||||
|      *    cipher = Cipher text, input. | ||||
|      *    plain  = Plain text, output. | ||||
|      */ | ||||
|     void decrypt(in ubyte[] cipher, ubyte[] plain) | ||||
|     in | ||||
|     { | ||||
|         assert(plain.length == blockSize); | ||||
|         assert(cipher.length == blockSize); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Mixed in by algorithms with fixed block size. | ||||
|  * | ||||
|  * Params: | ||||
|  *     N = Block size. | ||||
|  */ | ||||
| mixin template FixedBlockSize(uint N) | ||||
|     if (N != 0) | ||||
| { | ||||
|     private enum uint blockSize_ = N; | ||||
|  | ||||
|     /** | ||||
|      * Returns: Fixed block size. | ||||
|      */ | ||||
|     final @property inout(uint) blockSize() inout const pure nothrow @safe @nogc | ||||
|     { | ||||
|         return blockSize_; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Mixed in by symmetric algorithms. | ||||
|  * If $(D_PARAM Min) equals $(D_PARAM Max) fixed key length is assumed. | ||||
|  * | ||||
|  * Params: | ||||
|  *     Min = Minimum key length. | ||||
|  *     Max = Maximum key length. | ||||
|  */ | ||||
| mixin template KeyLength(uint Min, uint Max = Min) | ||||
|     if (Min != 0 && Max != 0) | ||||
| { | ||||
|     static if (Min == Max) | ||||
|     { | ||||
|         private enum uint keyLength_ = Min; | ||||
|  | ||||
|         /** | ||||
|          * Returns: Key length. | ||||
|          */ | ||||
|         final @property inout(uint) keyLength() inout const pure nothrow @safe @nogc | ||||
|         { | ||||
|             return keyLength_; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * Returns: Minimum key length. | ||||
|          */ | ||||
|         final @property inout(uint) minKeyLength() inout const pure nothrow @safe @nogc | ||||
|         { | ||||
|             return keyLength_; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * Returns: Maximum key length. | ||||
|          */ | ||||
|         final @property inout(uint) maxKeyLength() inout const pure nothrow @safe @nogc | ||||
|         { | ||||
|             return keyLength_; | ||||
|         } | ||||
|     } | ||||
|     else static if (Min < Max) | ||||
|     { | ||||
|         private enum uint minKeyLength_ = Min; | ||||
|         private enum uint maxKeyLength_ = Max; | ||||
|  | ||||
|         /** | ||||
|          * Returns: Minimum key length. | ||||
|          */ | ||||
|         final @property inout(uint) minKeyLength() inout const pure nothrow @safe @nogc | ||||
|         { | ||||
|             return minKeyLength_; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * Returns: Maximum key length. | ||||
|          */ | ||||
|         final @property inout(uint) maxKeyLength() inout const pure nothrow @safe @nogc | ||||
|         { | ||||
|             return maxKeyLength_; | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         static assert(false, "Max should be larger or equal to Min"); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user