diff --git a/source/actions.d b/source/actions.d index dbc8a65..ae1b964 100644 --- a/source/actions.d +++ b/source/actions.d @@ -1,7 +1,7 @@ module actions; -import std.stdio; -import std.base64: Base64; +import std.stdio : File, stdin, stdout, writeln; +import std.base64 : Base64; import std.random : Random, uniform; import std.algorithm : joiner; @@ -17,24 +17,24 @@ void encrypt(string keyFileName, Cipher cipher, bool armor) { auto key = loadKey(keyFileName, armor); ubyte[8] nonce; - if(armor) + if (armor) { ubyte[] buf; - foreach(b; stdin.byChunk(chunkSize).joiner.cipherFunction(key, nonce, cipher)) + foreach (b; stdin.byChunk(chunkSize).joiner.cipherFunction(key, nonce, cipher)) { buf ~= [b]; - if(buf.length == 57) + if (buf.length == 57) { stdout.writeln(Base64.encode(buf)); buf = []; } } - if(buf !is null) + if (buf !is null) stdout.writeln(Base64.encode(buf)); } else { - foreach(b; stdin.byChunk(chunkSize).joiner.cipherFunction(key, nonce, cipher)) + foreach (b; stdin.byChunk(chunkSize).joiner.cipherFunction(key, nonce, cipher)) stdout.rawWrite([b]); } } @@ -43,17 +43,17 @@ void decrypt(string keyFileName, Cipher cipher, bool armor) { auto key = loadKey(keyFileName, armor); ubyte[8] nonce; - if(armor) + if (armor) { ubyte[] buf; - foreach(b; Base64.decoder(stdin.byLine).joiner.cipherFunction(key, nonce, cipher)) + foreach (b; Base64.decoder(stdin.byLine).joiner.cipherFunction(key, nonce, cipher)) { stdout.rawWrite([b]); } } else { - foreach(b; stdin.byChunk(chunkSize).joiner.cipherFunction(key, nonce, cipher)) + foreach (b; stdin.byChunk(chunkSize).joiner.cipherFunction(key, nonce, cipher)) stdout.rawWrite([b]); } } @@ -62,7 +62,8 @@ void generateKey(bool armor) { auto rng = Random(); auto randomDevice = File(randomDeviceName, "r"); - scope(exit) randomDevice.close(); + scope (exit) + randomDevice.close(); uint[1] seed; randomDevice.rawRead(seed); rng.seed(seed[0]); @@ -71,7 +72,7 @@ void generateKey(bool armor) foreach (ref b; key) b = uniform!ubyte(rng); - if(armor) + if (armor) { writeln(Base64.encode(key)); } @@ -86,11 +87,13 @@ private: ubyte[32] loadKey(string filename, bool armor) { auto keyFile = File(filename, "r"); + scope (exit) + keyFile.close(); ubyte[32] key; - if(armor) + if (armor) { ubyte[] tempKey; - foreach(line; keyFile.byLine) + foreach (line; keyFile.byLine) tempKey ~= Base64.decode(line); key = tempKey; } diff --git a/source/app.d b/source/app.d index 272cfc0..498d213 100644 --- a/source/app.d +++ b/source/app.d @@ -1,15 +1,13 @@ import std.getopt; import std.string : format; -import std.stdio: stderr, writeln; +import std.stdio : stderr, writeln; import cipher : Cipher; import actions; int main(string[] args) { - bool[string] actions = [ "genKey" : false, - "encrypt" : false, - "decrypt" : false ]; + bool[string] actions = ["genKey" : false, "encrypt" : false, "decrypt" : false]; Cipher cipher = Cipher.chacha20; string keyFileName = "symkey.asc"; @@ -18,44 +16,43 @@ int main(string[] args) GetoptResult result; try { - result = getopt( - args, - std.getopt.config.bundling, - "gen-key|g", "Generate a new 256 bit key.", &actions["genKey"], - "encrypt|e", "Encrypt a message.", &actions["encrypt"], - "decrypt|d", "Decrypt a message.", &actions["decrypt"], - "cipher|c", "The cipher to use (default: %s).".format(cipher), &cipher, - "key|k", "The file which contains the key (default: %s).".format(keyFileName), &keyFileName, - "armor|a", "use ascii-armored I/O.", &armor); + result = getopt(args, + std.getopt.config.bundling, + "gen-key|g", "Generate a new 256 bit key.", &actions["genKey"], + "encrypt|e", "Encrypt a message.", &actions["encrypt"], + "decrypt|d", "Decrypt a message.", &actions["decrypt"], + "cipher|c", "The cipher to use (default: %s).".format(cipher), &cipher, + "key|k", "The file which contains the key (default: %s).".format(keyFileName), &keyFileName, + "armor|a", "use ascii-armored I/O.", &armor); } - catch(Exception e) + catch (Exception e) { stderr.writeln(e.msg); return 1; } size_t numberOfActions; - foreach(value; actions.values) + foreach (value; actions.values) numberOfActions += value; - if(numberOfActions == 1) + if (numberOfActions == 1) { try { - if(actions["genKey"]) + if (actions["genKey"]) { generateKey(armor); } - else if(actions["encrypt"]) + else if (actions["encrypt"]) { encrypt(keyFileName, cipher, armor); } - else if(actions["decrypt"]) + else if (actions["decrypt"]) { decrypt(keyFileName, cipher, armor); } } - catch(Exception e) + catch (Exception e) { stderr.writeln(e.msg); return 1; @@ -66,7 +63,7 @@ int main(string[] args) result.helpWanted = true; } - if(result.helpWanted) + if (result.helpWanted) printHelp(result.options); return 0; @@ -75,11 +72,11 @@ int main(string[] args) void printHelp(Option[] options) { defaultGetoptPrinter("Usage: ./learncrypt [options]\n\nCommon options:", - options[$-1..$]); + options[$-1..$]); defaultGetoptPrinter("\nGlobal options:", - options[$-2..$-1]); + options[$-2..$-1]); defaultGetoptPrinter("\nActions:", - options[0..3]); + options[0..3]); defaultGetoptPrinter("\nAction options:", - options[3..5]); + options[3..5]); } diff --git a/source/bitmanip.d b/source/bitmanip.d index 1d4f5cb..93e8335 100644 --- a/source/bitmanip.d +++ b/source/bitmanip.d @@ -4,7 +4,7 @@ private import std.traits : isUnsigned; private import std.bitmanip : nativeToLittleEndian, littleEndianToNative; UIntType rotateLeft(UIntType)(in UIntType val, in size_t len) nothrow @nogc pure @safe - if(isUnsigned!UIntType) + if (isUnsigned!UIntType) { auto reducedLen = len % (8 * UIntType.sizeof); // TODO: ensure the compiler does not create different code paths here @@ -21,7 +21,7 @@ unittest } UIntType rotateRight(UIntType)(in UIntType val, in size_t len) nothrow @nogc pure @safe - if(isUnsigned!UIntType) + if (isUnsigned!UIntType) { auto reducedLen = len % (8 * UIntType.sizeof); // TODO: ensure the compiler does not create different code paths here diff --git a/source/chacha20.d b/source/chacha20.d index a4e4f5c..408bd3e 100644 --- a/source/chacha20.d +++ b/source/chacha20.d @@ -3,7 +3,6 @@ module chacha20; private import std.string : format; private import std.range : isInputRange, isForwardRange, ElementType; private import std.array; -private import std.traits : hasElaborateCopyConstructor; private import bitmanip; @@ -12,7 +11,7 @@ public: // TODO: Check unittests (Use reliable software to check if the results are correct) auto chacha20Cipher(R)(R range, ubyte[32] key, ubyte[8] nonce) - if(isInputRange!R && is(ElementType!R : ubyte)) + if (isInputRange!R && is(ElementType!R : ubyte)) { static struct rangeResult { @@ -47,7 +46,7 @@ auto chacha20Cipher(R)(R range, ubyte[32] key, ubyte[8] nonce) { assert(!empty); chachaSection.popFront(); - if(chachaSection.empty) + if (chachaSection.empty) { ++count; chachaSection = chacha20Exp(key, nonce ~ littleEndianInv(count)); @@ -138,10 +137,10 @@ unittest x12 = 0xe859c100, x13 = 0xea4d84b7, x14 = 0x0f619bff, x15 = 0xbc6e965a; mixin(rowRound!(y00, y01, y02, y03, y04, y05, y06, y07, - y08, y09, y10, y11, y12, y13, y14, y15)); + y08, y09, y10, y11, y12, y13, y14, y15)); mixin(rowRound!(x00, x01, x02, x03, x04, x05, x06, x07, - x08, x09, x10, x11, x12, x13, x14, x15)); + x08, x09, x10, x11, x12, x13, x14, x15)); uint[] test0 = [y00, y01, y02, y03, y04, y05, y06, y07, y08, y09, y10, y11, y12, y13, y14, y15]; @@ -150,9 +149,9 @@ unittest x08, x09, x10, x11, x12, x13, x14, x15]; assert(test0 == [0x10000001, 0x10000000, 0x00001000, 0x10001001, - 0x88888808, 0x80808808, 0x80800808, 0x08080080, - 0x00100001, 0x01110110, 0x01010110, 0x01010010, - 0x01000010, 0x00100000, 0x01100110, 0x01000110]); + 0x88888808, 0x80808808, 0x80800808, 0x08080080, + 0x00100001, 0x01110110, 0x01010110, 0x01010010, + 0x01000010, 0x00100000, 0x01100110, 0x01000110]); assert(test1 == [0x9318dab2, 0x6219299a, 0xd68946c3, 0x3eb5b75f, 0xe0df816c, 0x476df40b, 0xbb2e1d6f, 0x7608ad18, @@ -223,8 +222,8 @@ out(result) } body { - auto x00 = littleEndian(input[0..4]), x01 = littleEndian(input[4..8]), - x02 = littleEndian(input[8..12]), x03 = littleEndian(input[12..16]), + auto x00 = littleEndian(input[00..04]), x01 = littleEndian(input[04..08]), + x02 = littleEndian(input[08..12]), x03 = littleEndian(input[12..16]), x04 = littleEndian(input[16..20]), x05 = littleEndian(input[20..24]), x06 = littleEndian(input[24..28]), x07 = littleEndian(input[28..32]), x08 = littleEndian(input[32..36]), x09 = littleEndian(input[36..40]), @@ -237,7 +236,7 @@ body y08 = x08, y09 = x09, y10 = x10, y11 = x11, y12 = x12, y13 = x13, y14 = x14, y15 = x15; - foreach(i; 0..10) + foreach (i; 0..10) { mixin(colRound!(x00, x01, x02, x03, x04, x05, x06, x07, x08, x09, x10, x11, x12, x13, x14, x15)); @@ -280,7 +279,7 @@ unittest 75, 27, 0,216, 16,122, 7, 89,162,104,101,147,213, 21, 54, 95, 225,253,139,176,105,132, 23,116, 76, 41,176,207,221, 34,157,108, 94, 94, 99, 52, 90,117, 91,220,146,190,239,143,196,176,130,186]; - foreach(i; 0..1000000) + foreach (i; 0..1000000) test3 = chacha20(test3); assert(test0 == [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -330,12 +329,12 @@ unittest ubyte[] n; key.length = 32; n.length = 16; - foreach(i; 0..16) + foreach (i; 0..16) key[i] = cast(ubyte)(i + 1); - foreach(i; 16..32) + foreach (i; 16..32) key[i] = cast(ubyte)(i + 200 - 15); - foreach(i; 0..16) + foreach (i; 0..16) n[i] = cast(ubyte)(i + 1+ 100); assert(chacha20Exp(key, n) == [ 2, 7, 55,183,240,232, 0,145,207,208,120,131,146, 9,130, 31, diff --git a/source/cipher.d b/source/cipher.d index 77bced6..ca470b2 100644 --- a/source/cipher.d +++ b/source/cipher.d @@ -1,6 +1,8 @@ module cipher; -private import std.range : isInputRange, ElementType, InputRange, ForwardRange, inputRangeObject; +private import std.range : isInputRange, isForwardRange, ElementType, InputRange, ForwardRange, inputRangeObject; +private import std.string : format; + private import salsa20; private import chacha20; @@ -12,8 +14,11 @@ enum Cipher chacha20 } -mixin(cipherFunctionString.format(q{InputRange}, q{isInputRange!R && !(isForwardRange!R)})); -mixin(cipherFunctionString.format(q{ForwardRange}, q{isForwardRange!R})); +mixin(cipherFunctionString.format(q{InputRange}, + q{isInputRange!R && !(isForwardRange!R)})); + +mixin(cipherFunctionString.format(q{ForwardRange}, + q{isForwardRange!R})); unittest { @@ -34,9 +39,9 @@ private: enum cipherFunctionString = q{ %s!(ElementType!R) cipherFunction(R)(R range, ubyte[32] key, ubyte[8] nonce, Cipher cipher) - if(is(ElementType!R : ubyte) && %s) + if (is(ElementType!R : ubyte) && %s) { - final switch(cipher) + final switch (cipher) { case Cipher.salsa20: return range.salsa20Cipher(key, nonce).inputRangeObject; diff --git a/source/salsa20.d b/source/salsa20.d index dd80cd8..b06b7e4 100644 --- a/source/salsa20.d +++ b/source/salsa20.d @@ -3,14 +3,13 @@ module salsa20; private import std.string : format; private import std.range : isInputRange, isForwardRange, ElementType; private import std.array; -private import std.traits : hasElaborateCopyConstructor; private import bitmanip; public: auto salsa20Cipher(R)(R range, ubyte[32] key, ubyte[8] nonce) - if(isInputRange!R && is(ElementType!R : ubyte)) + if (isInputRange!R && is(ElementType!R : ubyte)) { static struct rangeResult { @@ -45,7 +44,7 @@ auto salsa20Cipher(R)(R range, ubyte[32] key, ubyte[8] nonce) { assert(!empty); salsaSection.popFront(); - if(salsaSection.empty) + if (salsaSection.empty) { ++count; salsaSection = salsa20Exp(key, nonce ~ littleEndianInv(count)); @@ -137,10 +136,10 @@ unittest x12 = 0xe859c100, x13 = 0xea4d84b7, x14 = 0x0f619bff, x15 = 0xbc6e965a; mixin(rowRound!(y00, y01, y02, y03, y04, y05, y06, y07, - y08, y09, y10, y11, y12, y13, y14, y15)); + y08, y09, y10, y11, y12, y13, y14, y15)); mixin(rowRound!(x00, x01, x02, x03, x04, x05, x06, x07, - x08, x09, x10, x11, x12, x13, x14, x15)); + x08, x09, x10, x11, x12, x13, x14, x15)); uint[] test0 = [y00, y01, y02, y03, y04, y05, y06, y07, y08, y09, y10, y11, y12, y13, y14, y15]; @@ -223,8 +222,8 @@ out(result) } body { - auto x00 = littleEndian(input[0..4]), x01 = littleEndian(input[4..8]), - x02 = littleEndian(input[8..12]), x03 = littleEndian(input[12..16]), + auto x00 = littleEndian(input[00..04]), x01 = littleEndian(input[04..08]), + x02 = littleEndian(input[08..12]), x03 = littleEndian(input[12..16]), x04 = littleEndian(input[16..20]), x05 = littleEndian(input[20..24]), x06 = littleEndian(input[24..28]), x07 = littleEndian(input[28..32]), x08 = littleEndian(input[32..36]), x09 = littleEndian(input[36..40]), @@ -237,7 +236,7 @@ body y08 = x08, y09 = x09, y10 = x10, y11 = x11, y12 = x12, y13 = x13, y14 = x14, y15 = x15; - foreach(i; 0..10) + foreach (i; 0..10) { mixin(colRound!(x00, x01, x02, x03, x04, x05, x06, x07, x08, x09, x10, x11, x12, x13, x14, x15)); @@ -280,7 +279,7 @@ unittest 75, 27, 0,216, 16,122, 7, 89,162,104,101,147,213, 21, 54, 95, 225,253,139,176,105,132, 23,116, 76, 41,176,207,221, 34,157,108, 94, 94, 99, 52, 90,117, 91,220,146,190,239,143,196,176,130,186]; - foreach(i; 0..1000000) + foreach (i; 0..1000000) test3 = salsa20(test3); assert(test0 == [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -330,12 +329,12 @@ unittest ubyte[] n; key.length = 32; n.length = 16; - foreach(i; 0..16) + foreach (i; 0..16) key[i] = cast(ubyte)(i + 1); - foreach(i; 16..32) + foreach (i; 16..32) key[i] = cast(ubyte)(i + 200 - 15); - foreach(i; 0..16) + foreach (i; 0..16) n[i] = cast(ubyte)(i + 1+ 100); assert(salsa20Exp(key, n) == [ 69, 37, 68, 39, 41, 15,107,193,255,139,122, 6,170,233,217, 98,