2 * Base template for stream ciphers.
3 * Copyright (C) 2014 Ketmar Dark // Invisible Vector (ketmar@ketmar.no-ip.org)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * Get a copy of the GNU GPL from <http://www.gnu.org/licenses/>.
16 module iv
.stc.core
/*is aliced*/;
21 package(iv
.stc) template isValidRE(R
) { enum isValidRE
= is(ElementEncodingType
!R
: ubyte); }
22 package(iv
.stc) template isValidIR(R
) { enum isValidIR
= isInputRange
!R
&& isValidRE
!R
; }
23 package(iv
.stc) template isValidOR(R
) { enum isValidOR
= isOutputRange
!(R
, ubyte) || isOutputRange
!(R
, char); }
26 /// cipher parameters:
27 /// enum BlockSize = 16; // in bytes
28 /// enum IVSize = 8; // in bytes
29 /// enum KeySize = 16; // in bytes
30 /// enum SupportIV = true; // or false
32 mixin template StreamCipherCore() {
35 * Initialize ciper context and setup key.
40 this(R0
) (R0 key
) @trusted if (isValidIR
!R0
) { reset(key
); }
43 * Initialize ciper context and setup key.
49 this(R0
, R1
) (R0 key
, R1 iv
) @trusted if (isValidIR
!R0
&& isValidIR
!R1
) { reset(key
, iv
); }
51 ~this () nothrow @trusted @nogc { cleanup(); }
54 * Reinitialize ciper context and setup key.
59 void reset(R0
) (R0 key
) @trusted if (isValidIR
!R0
) {
66 * Reinitialize ciper context and setup key.
72 void reset(R0
, R1
) (R0 key
, R1 iv
) @trusted if (isValidIR
!R0
&& isValidIR
!R1
) {
78 * Regenerate xor buffer if necessary. Regenerates only if some bytes
79 * from buffer was already used (i.e. second and following calls to
80 * flush() without any stream processing will have no effect if
81 * 'force' flag is not true).
84 * force = regenerate xor buffer even if it's not necessary
89 void flush() (bool force
=false) @trusted {
90 if (bufpos
!= 0 || force
) {
97 * Process byte stream. This function can be called continuously
98 * to encrypt or decrypt byte stream (much like RC4).
101 * output = output buffer, it's size must be at least the same as input bufer size
102 * input = input buffer
107 void process(R0
, R1
) (R0 output
, R1 input
) @trusted if (isValidOR
!R0
&& isValidIR
!R1
) {
108 while (!input
.empty
) {
109 static if (isOutputRange
!(R0
, ubyte)) {
110 output
.put(cast(ubyte)(cast(ubyte)input
.front^
this.front
));
112 output
.put(cast(char)(cast(ubyte)input
.front^
this.front
));
119 // let this thing be input range
120 @property ubyte front() () @trusted {
121 if (bufpos
>= BlockSize
) {
125 return buf
.ptr
[bufpos
];
128 void popFront() () @trusted {
129 if (bufpos
>= BlockSize
) {
137 @property typeof(this) save() () @trusted {
142 * Always $(D false) (ciphers are infinite ranges).
144 enum bool empty
= false;
147 * Clean state, so there will be no cipher-related bytes in memory.
149 void cleanup() () @trusted {
155 static uint bitRotLeft (uint v
, uint n
) pure nothrow @safe @nogc { pragma(inline
, true); return (v
<<n
)|
(v
>>(32-n
)); }
156 static uint bitRotRight (uint v
, uint n
) pure nothrow @safe @nogc { pragma(inline
, true); return (v
<<(32-n
))|
(v
>>n
); }
158 void clearBuf () nothrow @trusted @nogc {
163 // this should generate new 'buf'
164 //void getBuf () nothrow @trusted;
166 // this should clear state
167 //void clearState () nothrow @trusted;
169 // this should reset cipher state
170 // must understand empty iv
171 // note that there is no need to check if R0 and R1 are
172 // input ranges with correct element types
173 //@trusted void resetState(R0, R1) (R0 key, R1 iv)
176 ubyte[BlockSize
] buf
;
182 * Compare two ranges in constant time.
183 * Ranges must be of the same length.
185 private import std
.range
: isInputRange
, ElementEncodingType
;
186 public bool cryptoEqu(R0
, R1
) (R0 r0
, R1 r1
) @trusted
187 if (isInputRange
!R0
&& isInputRange
!R1
&& is(ElementEncodingType
!R0
== ElementEncodingType
!R1
) && is(ElementEncodingType
!R0
: ubyte))
190 while (!r0
.empty
&& !r1
.empty
) {
191 d |
= r0
.front^r1
.front
;
196 if (!r0
.empty ||
!r1
.empty
) d |
= 0xff;
197 while (!r0
.empty
) r0
.popFront
;
198 while (!r1
.empty
) r1
.popFront
;
199 return (1&((d
-1)>>8)) != 0;
205 ubyte[] a
= [1,2,3,4];
206 ubyte[] b
= [1,2,3,5];
207 assert(!cryptoEqu(a
, b
));
208 assert(!cryptoEqu(b
, a
));
209 assert(cryptoEqu(a
, a
));
210 assert(cryptoEqu(b
, b
));
211 assert(a
== [1,2,3,4]);
212 assert(b
== [1,2,3,5]);