| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- local Array = require("lockbox.util.array");
- local Stream = require("lockbox.util.stream");
- local Queue = require("lockbox.util.queue");
- local Bit = require("lockbox.util.bit");
- local AND = Bit.band;
- local CTR = {};
- CTR.Cipher = function()
- local public = {};
- local key;
- local blockCipher;
- local padding;
- local inputQueue;
- local outputQueue;
- local iv;
- public.setKey = function(keyBytes)
- key = keyBytes;
- return public;
- end
- public.setBlockCipher = function(cipher)
- blockCipher = cipher;
- return public;
- end
- public.setPadding = function(paddingMode)
- padding = paddingMode;
- return public;
- end
- public.init = function()
- inputQueue = Queue();
- outputQueue = Queue();
- iv = nil;
- return public;
- end
- local updateIV = function()
- iv[16] = iv[16] + 1;
- if iv[16] <= 0xFF then return; end
- iv[16] = AND(iv[16], 0xFF);
- iv[15] = iv[15] + 1;
- if iv[15] <= 0xFF then return; end
- iv[15] = AND(iv[15], 0xFF);
- iv[14] = iv[14] + 1;
- if iv[14] <= 0xFF then return; end
- iv[14] = AND(iv[14], 0xFF);
- iv[13] = iv[13] + 1;
- if iv[13] <= 0xFF then return; end
- iv[13] = AND(iv[13], 0xFF);
- iv[12] = iv[12] + 1;
- if iv[12] <= 0xFF then return; end
- iv[12] = AND(iv[12], 0xFF);
- iv[11] = iv[11] + 1;
- if iv[11] <= 0xFF then return; end
- iv[11] = AND(iv[11], 0xFF);
- iv[10] = iv[10] + 1;
- if iv[10] <= 0xFF then return; end
- iv[10] = AND(iv[10], 0xFF);
- iv[9] = iv[9] + 1;
- if iv[9] <= 0xFF then return; end
- iv[9] = AND(iv[9], 0xFF);
- return;
- end
- public.update = function(messageStream)
- local byte = messageStream();
- while (byte ~= nil) do
- inputQueue.push(byte);
- if(inputQueue.size() >= blockCipher.blockSize) then
- local block = Array.readFromQueue(inputQueue, blockCipher.blockSize);
- if(iv == nil) then
- iv = block;
- else
- local out = iv;
- out = blockCipher.encrypt(key, out);
- out = Array.XOR(out, block);
- Array.writeToQueue(outputQueue, out);
- updateIV();
- end
- end
- byte = messageStream();
- end
- return public;
- end
- public.finish = function()
- local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead());
- public.update(paddingStream);
- return public;
- end
- public.getOutputQueue = function()
- return outputQueue;
- end
- public.asHex = function()
- return Stream.toHex(outputQueue.pop);
- end
- public.asBytes = function()
- return Stream.toArray(outputQueue.pop);
- end
- public.asString = function()
- return Stream.toString(outputQueue.pop);
- end
- return public;
- end
- CTR.Decipher = function()
- local public = {};
- local key;
- local blockCipher;
- local padding;
- local inputQueue;
- local outputQueue;
- local iv;
- public.setKey = function(keyBytes)
- key = keyBytes;
- return public;
- end
- public.setBlockCipher = function(cipher)
- blockCipher = cipher;
- return public;
- end
- public.setPadding = function(paddingMode)
- padding = paddingMode;
- return public;
- end
- public.init = function()
- inputQueue = Queue();
- outputQueue = Queue();
- iv = nil;
- return public;
- end
- local updateIV = function()
- iv[16] = iv[16] + 1;
- if iv[16] <= 0xFF then return; end
- iv[16] = AND(iv[16], 0xFF);
- iv[15] = iv[15] + 1;
- if iv[15] <= 0xFF then return; end
- iv[15] = AND(iv[15], 0xFF);
- iv[14] = iv[14] + 1;
- if iv[14] <= 0xFF then return; end
- iv[14] = AND(iv[14], 0xFF);
- iv[13] = iv[13] + 1;
- if iv[13] <= 0xFF then return; end
- iv[13] = AND(iv[13], 0xFF);
- iv[12] = iv[12] + 1;
- if iv[12] <= 0xFF then return; end
- iv[12] = AND(iv[12], 0xFF);
- iv[11] = iv[11] + 1;
- if iv[11] <= 0xFF then return; end
- iv[11] = AND(iv[11], 0xFF);
- iv[10] = iv[10] + 1;
- if iv[10] <= 0xFF then return; end
- iv[10] = AND(iv[10], 0xFF);
- iv[9] = iv[9] + 1;
- if iv[9] <= 0xFF then return; end
- iv[9] = AND(iv[9], 0xFF);
- return;
- end
- public.update = function(messageStream)
- local byte = messageStream();
- while (byte ~= nil) do
- inputQueue.push(byte);
- if(inputQueue.size() >= blockCipher.blockSize) then
- local block = Array.readFromQueue(inputQueue, blockCipher.blockSize);
- if(iv == nil) then
- iv = block;
- else
- local out = iv;
- out = blockCipher.encrypt(key, out);
- out = Array.XOR(out, block);
- Array.writeToQueue(outputQueue, out);
- updateIV();
- end
- end
- byte = messageStream();
- end
- return public;
- end
- public.finish = function()
- local paddingStream = padding(blockCipher.blockSize, inputQueue.getHead());
- public.update(paddingStream);
- return public;
- end
- public.getOutputQueue = function()
- return outputQueue;
- end
- public.asHex = function()
- return Stream.toHex(outputQueue.pop);
- end
- public.asBytes = function()
- return Stream.toArray(outputQueue.pop);
- end
- public.asString = function()
- return Stream.toString(outputQueue.pop);
- end
- return public;
- end
- return CTR;
|