egra: even more comments
[iv.d.git] / stc / core.d
blob5cb4b19d23f05b0b4c013a66d6cc91f1fdb67b98
1 /*
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*/;
18 import iv.alice;
19 import std.range;
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() {
33 public:
34 /**
35 * Initialize ciper context and setup key.
37 * Params:
38 * key = key
40 this(R0) (R0 key) @trusted if (isValidIR!R0) { reset(key); }
42 /**
43 * Initialize ciper context and setup key.
45 * Params:
46 * key = key
47 * iv = initial vector
49 this(R0, R1) (R0 key, R1 iv) @trusted if (isValidIR!R0 && isValidIR!R1) { reset(key, iv); }
51 ~this () nothrow @trusted @nogc { cleanup(); }
53 /**
54 * Reinitialize ciper context and setup key.
56 * Params:
57 * key = key
59 void reset(R0) (R0 key) @trusted if (isValidIR!R0) {
60 clearBuf();
61 ubyte[] iv;
62 resetState(key, iv);
65 /**
66 * Reinitialize ciper context and setup key.
68 * Params:
69 * key = key
70 * iv = initial vector
72 void reset(R0, R1) (R0 key, R1 iv) @trusted if (isValidIR!R0 && isValidIR!R1) {
73 clearBuf();
74 resetState(key, iv);
77 /**
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).
83 * Params:
84 * force = regenerate xor buffer even if it's not necessary
86 * Returns:
87 * nothing
89 void flush() (bool force=false) @trusted {
90 if (bufpos != 0 || force) {
91 getBuf();
92 bufpos = 0;
96 /**
97 * Process byte stream. This function can be called continuously
98 * to encrypt or decrypt byte stream (much like RC4).
100 * Params:
101 * output = output buffer, it's size must be at least the same as input bufer size
102 * input = input buffer
104 * Returns:
105 * nothing
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));
111 } else {
112 output.put(cast(char)(cast(ubyte)input.front^this.front));
114 input.popFront;
115 this.popFront;
119 // let this thing be input range
120 @property ubyte front() () @trusted {
121 if (bufpos >= BlockSize) {
122 getBuf();
123 bufpos = 0;
125 return buf.ptr[bufpos];
128 void popFront() () @trusted {
129 if (bufpos >= BlockSize) {
130 getBuf();
131 bufpos = 0;
133 ++bufpos;
136 /// make snapshot
137 @property typeof(this) save() () @trusted {
138 return this;
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 {
150 clearBuf();
151 clearState();
154 private:
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 {
159 buf[] = 0;
160 bufpos = BlockSize;
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)
175 private:
176 ubyte[BlockSize] buf;
177 usize bufpos;
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))
189 uint d = 0;
190 while (!r0.empty && !r1.empty) {
191 d |= r0.front^r1.front;
192 r0.popFront;
193 r1.popFront;
195 // just in case
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;
203 unittest {
204 import std.stdio;
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]);