Add support for dmd 2.070.2
This commit is contained in:
parent
5be89e4858
commit
3e36ec0984
@ -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");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user