1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
import std.algorithm;
import std.file;
import std.random;
import std.stdio;
import std.stream;
uint decideBufferLength(string inputFilename, string keyFilename)
{
immutable uint maxBuffer = 64 * 1024 * 1024;
immutable uint minBuffer = 1024 * 1024;
auto temp = inputFilename.getSize;
alias inputFilename I;
alias keyFilename K;
alias getSize S;
if (keyFilename.exists && keyFilename.isFile && keyFilename.getSize != 0)
temp = (S(I) + S(K)) * min(S(I), S(K)) / max(S(I), S(K));
if (temp > maxBuffer)
return maxBuffer;
if (temp < minBuffer)
return minBuffer;
return cast(uint)(temp);
}
int main(string[] args)
{
if (args.length != 4)
{
stderr.writeln("\nXorCrypt3 usage:\n"
"\tprogram.exe inputFile outputFile keyFile\n\n"
"ATTN:\tIf the keyFile doesn't exist, it will be created.\n"
"\tIf the keyFile is empty, it will be filled with random data\n"
"\t\tuntil it reaches the size of inputFile.\n"
"\tThe outputFile will be overwritten.");
return 1;
}
if (args[1] == args[2] || args[2] == args[3] || args[1] == args[3])
{
stderr.writeln("\ninputFile, outputFile and keyFile must be distinct.");
return 1;
}
if (args[1].getSize == 0)
{
stderr.writeln("\ninputFile is empty. Nothing to do.");
return 1;
}
const uint bufferLength = decideBufferLength(args[1], args[3]);
writeln("\n - Internal buffer length set to ", bufferLength, " bytes.");
// here a keyFile is constructed, if needed
if (!args[3].exists || (args[3].isFile && args[3].getSize == 0))
{
write(" - Writing keyFile `", args[3], "', please wait... ");
stdout.flush;
auto keyFile = new BufferedFile(args[3], FileMode.Out);
auto prng = Random(unpredictableSeed);
auto remainingBytes = args[1].getSize;
auto buffer = new ubyte[remainingBytes % bufferLength];
do
{
foreach (ref r; buffer)
r = uniform!"[]"(ubyte.min, ubyte.max, prng);
keyFile.writeExact(buffer.ptr, buffer.length);
remainingBytes -= buffer.length;
buffer.length = bufferLength;
}
while (remainingBytes != 0);
keyFile.close;
writeln("keyFile ready.");
}
auto inputFile = new BufferedFile(args[1], FileMode.In);
auto outputFile = new BufferedFile(args[2], FileMode.OutNew);
auto keyFile = new BufferedFile(args[3], FileMode.In);
auto ioBuffer = new ubyte[inputFile.size % bufferLength];
auto keyBuffer = new ubyte[ioBuffer.length];
bool cycleKeyBuffer = false;
write(" - Writing outputFile `", args[2], "', please wait... ");
stdout.flush;
if (keyFile.size <= bufferLength)
{
keyBuffer.length = cast(uint)(keyFile.size);
keyFile.readExact(keyBuffer.ptr, keyBuffer.length);
cycleKeyBuffer = true;
}
uint k = 0; // for iterating the keyBuffer, if cycled
while (!inputFile.eof)
{
inputFile.readExact(ioBuffer.ptr, ioBuffer.length);
if (!cycleKeyBuffer)
{
auto keyBytesRead = keyFile.read(keyBuffer);
while (keyBytesRead != keyBuffer.length)
{
if (keyFile.eof)
keyFile.seekSet(0);
keyBytesRead += keyFile.read(keyBuffer[keyBytesRead .. $]);
}
foreach (i, ref b; ioBuffer)
b ^= keyBuffer[i];
keyBuffer.length = bufferLength;
}
else
foreach (ref b; ioBuffer)
{
b ^= keyBuffer[k++];
if (k == keyBuffer.length)
k = 0;
}
outputFile.writeExact(ioBuffer.ptr, ioBuffer.length);
ioBuffer.length = bufferLength;
}
outputFile.close;
writeln("outputFile ready.\n");
return 0;
}
|