Advertisement
Anavrins

ChaCha20-Lua

Dec 24th, 2015 (edited)
1,405
2
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.08 KB | None | 2 0
  1. -- Chacha20 cipher in ComputerCraft
  2. -- By Anavrins
  3. -- For help and details, you can DM me on Discord (Anavrins#4600)
  4. -- MIT License
  5. -- Pastebin: https://pastebin.com/GPzf9JSa
  6. -- Last updated: March 27 2020
  7.  
  8. local mod32 = 2^32
  9. local bor = bit32.bor
  10. local bxor = bit32.bxor
  11. local band = bit32.band
  12. local blshift = bit32.lshift
  13. local brshift = bit32.arshift
  14.  
  15. local tau = {("expand 16-byte k"):byte(1,-1)}
  16. local sigma = {("expand 32-byte k"):byte(1,-1)}
  17. local null32 = {("A"):rep(32):byte(1,-1)}
  18. local null12 = {("A"):rep(12):byte(1,-1)}
  19.  
  20. local function rotl(n, b)
  21.     local s = n/(2^(32-b))
  22.     local f = s%1
  23.     return (s-f) + f*mod32
  24. end
  25.  
  26. local function quarterRound(s, a, b, c, d)
  27.     s[a] = (s[a]+s[b])%mod32; s[d] = rotl(bxor(s[d], s[a]), 16)
  28.     s[c] = (s[c]+s[d])%mod32; s[b] = rotl(bxor(s[b], s[c]), 12)
  29.     s[a] = (s[a]+s[b])%mod32; s[d] = rotl(bxor(s[d], s[a]), 8)
  30.     s[c] = (s[c]+s[d])%mod32; s[b] = rotl(bxor(s[b], s[c]), 7)
  31.     return s
  32. end
  33.  
  34. local function hashBlock(state, rnd)
  35.     local s = {unpack(state)}
  36.     for i = 1, rnd do
  37.         local r = i%2==1
  38.         s = r and quarterRound(s, 1, 5,  9, 13) or quarterRound(s, 1, 6, 11, 16)
  39.         s = r and quarterRound(s, 2, 6, 10, 14) or quarterRound(s, 2, 7, 12, 13)
  40.         s = r and quarterRound(s, 3, 7, 11, 15) or quarterRound(s, 3, 8,  9, 14)
  41.         s = r and quarterRound(s, 4, 8, 12, 16) or quarterRound(s, 4, 5, 10, 15)
  42.     end
  43.     for i = 1, 16 do s[i] = (s[i]+state[i])%mod32 end
  44.     return s
  45. end
  46.  
  47. local function LE_toInt(bs, i)
  48.     return (bs[i+1] or 0)+
  49.     blshift((bs[i+2] or 0), 8)+
  50.     blshift((bs[i+3] or 0), 16)+
  51.     blshift((bs[i+4] or 0), 24)
  52. end
  53.  
  54. local function initState(key, nonce, counter)
  55.     local isKey256 = #key == 32
  56.     local const = isKey256 and sigma or tau
  57.     local state = {}
  58.  
  59.     state[ 1] = LE_toInt(const, 0)
  60.     state[ 2] = LE_toInt(const, 4)
  61.     state[ 3] = LE_toInt(const, 8)
  62.     state[ 4] = LE_toInt(const, 12)
  63.  
  64.     state[ 5] = LE_toInt(key, 0)
  65.     state[ 6] = LE_toInt(key, 4)
  66.     state[ 7] = LE_toInt(key, 8)
  67.     state[ 8] = LE_toInt(key, 12)
  68.     state[ 9] = LE_toInt(key, isKey256 and 16 or 0)
  69.     state[10] = LE_toInt(key, isKey256 and 20 or 4)
  70.     state[11] = LE_toInt(key, isKey256 and 24 or 8)
  71.     state[12] = LE_toInt(key, isKey256 and 28 or 12)
  72.  
  73.     state[13] = counter
  74.     state[14] = LE_toInt(nonce, 0)
  75.     state[15] = LE_toInt(nonce, 4)
  76.     state[16] = LE_toInt(nonce, 8)
  77.  
  78.     return state
  79. end
  80.  
  81. local function serialize(state)
  82.     local r = {}
  83.     for i = 1, 16 do
  84.         r[#r+1] = band(state[i], 0xFF)
  85.         r[#r+1] = band(brshift(state[i], 8), 0xFF)
  86.         r[#r+1] = band(brshift(state[i], 16), 0xFF)
  87.         r[#r+1] = band(brshift(state[i], 24), 0xFF)
  88.     end
  89.     return r
  90. end
  91.  
  92. local mt = {
  93.     __tostring = function(a) return string.char(unpack(a)) end,
  94.     __index = {
  95.         toHex = function(self) return ("%02x"):rep(#self):format(unpack(self)) end,
  96.         isEqual = function(self, t)
  97.             if type(t) ~= "table" then return false end
  98.             if #self ~= #t then return false end
  99.             local ret = 0
  100.             for i = 1, #self do
  101.                 ret = bor(ret, bxor(self[i], t[i]))
  102.             end
  103.             return ret == 0
  104.         end
  105.     }
  106. }
  107.  
  108. local function crypt(data, key, nonce, cntr, round)
  109.     assert(type(key) == "table", "ChaCha20: Invalid key format ("..type(key).."), must be table")
  110.     assert(type(nonce) == "table", "ChaCha20: Invalid nonce format ("..type(nonce).."), must be table")
  111.     assert(#key == 16 or #key == 32, "ChaCha20: Invalid key length ("..#key.."), must be 16 or 32")
  112.     assert(#nonce == 12, "ChaCha20: Invalid nonce length ("..#nonce.."), must be 12")
  113.  
  114.     local data = type(data) == "table" and {unpack(data)} or {tostring(data):byte(1,-1)}
  115.     cntr = tonumber(cntr) or 1
  116.     round = tonumber(round) or 20
  117.  
  118.     local out = {}
  119.     local state = initState(key, nonce, cntr)
  120.     local blockAmt = math.floor(#data/64)
  121.     for i = 0, blockAmt do
  122.         local ks = serialize(hashBlock(state, round))
  123.         state[13] = (state[13]+1) % mod32
  124.  
  125.         local block = {}
  126.         for j = 1, 64 do
  127.             block[j] = data[((i)*64)+j]
  128.         end
  129.         for j = 1, #block do
  130.             out[#out+1] = bxor(block[j], ks[j])
  131.         end
  132.  
  133.         if i % 1000 == 0 then
  134.             os.queueEvent("")
  135.             os.pullEvent("")
  136.         end
  137.     end
  138.     return setmetatable(out, mt)
  139. end
  140.  
  141. local function genNonce(len)
  142.     local nonce = {}
  143.     for i = 1, len do
  144.         nonce[i] = math.random(0, 0xFF)
  145.     end
  146.     return setmetatable(nonce, mt)
  147. end
  148.  
  149. local obj = {}
  150. local mtrng = {['__index'] = obj}
  151. local function newRNG(seed)
  152.   local objVars = {}
  153.   objVars.seed = seed
  154.   objVars.cnt = 0
  155.   objVars.block = {}
  156.   return setmetatable(objVars, mtrng)
  157. end
  158.  
  159. -- Specify how many bytes to return
  160. -- 1 Byte is 8 bits, returns int between 0 and 255
  161. -- 2 Bytes is 16 bits, returns int up to 65535
  162. -- 4 Bytes is 32 bits, returns int up to 4294967295
  163. -- Max of 6 Bytes is 48 bits, returns int up to 281474976710655
  164. function obj:nextInt(byte)
  165.   if not byte or byte < 1 or byte > 6 then error("Can only return 1-6 bytes", 2) end
  166.   local output = 0
  167.   for i = 0, byte-1 do
  168.     if #self.block == 0 then
  169.       self.cnt = self.cnt + 1
  170.       self.block = crypt(null32, self.seed, null12, self.cnt)
  171.     end
  172.     local newByte = table.remove(self.block)
  173.     output = output + (newByte * (2^(8*i)))
  174.   end
  175.   return output
  176. end
  177.  
  178. return {
  179.     crypt = crypt,
  180.     genNonce = genNonce,
  181.     newRNG = newRNG
  182. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement