· 6 years ago · Mar 13, 2020, 09:10 PM
1--[[ LanteaCraft ]]--
2--[[ and SGCraft ]]--
3--[[ Gate Buddy ]]--
4--[[ by Dog ]]--
5--[[ aka HydrantHunter ]]--
6--[[ pastebin B81kt39c ]]--
7local gbVer = "2.0.00"
8--[[
9Tested with/requires:
10 - Minecraft 1.7.10+ AND ComputerCraft 1.75+ || LanteaCraft LC2-16+ | OR | SGCraft1.11.x-mc1.7.10+
11 For setup and usage instructions, please visit http://tinyurl.com/jf3rjr7
12
13Special thanks to: SquidDev (AES encryption/decryption)
14 Alex Kloss (base64 encoder/decoder)
15
16IMPORTANT NOTE:
17 - all of the following variables are set by the program as necessary
18 - editing any of them below will most likely cause unexpected results
19]]--
20local tArgs, clients = { ... }, { }
21local gate, thisGate, dialAddress, pingTimer
22local chevronNumber, clientCount, thisCC = 0, 0, tostring(os.getComputerID())
23local modemSide, callDirection, gateStatus, remoteIrisStatus = "none", "none", "QRY", "unk"
24local lcGate, continueDialing, spinTime, irisState, allowIrisClose, logging = false, false, false, false, false, false
25local sgStates = {
26 Idle = "Idle";
27 Dialing = "Dialing";
28 Dialling = "Dialing";
29 Opening = "Dialing";
30 Connected = "Connected";
31 Closing = "Disconnecting";
32 Offline = "Offline";
33}
34
35-- Lua 5.1+ base64 v3.0 (c) 2009 by Alex Kloss <alexthkloss@web.de>
36-- licensed under the terms of the LGPL2
37-- http://lua-users.org/wiki/BaseSixtyFour
38-- character table string
39local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
40-- encoding
41local function encode(data)
42 return ((data:gsub('.', function(x)
43 local r,b='',x:byte()
44 for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
45 return r;
46 end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
47 if (#x < 6) then return '' end
48 local c=0
49 for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
50 return b:sub(c+1,c+1)
51 end)..({ '', '==', '=' })[#data%3+1])
52end
53-- decoding
54local function decode(data)
55 data = string.gsub(data, '[^'..b..'=]', '')
56 return (data:gsub('.', function(x)
57 if (x == '=') then return '' end
58 local r,f='',(b:find(x)-1)
59 for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
60 return r;
61 end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
62 if (#x ~= 8) then return '' end
63 local c=0
64 for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
65 return string.char(c)
66 end))
67end
68
69-- AES Lua implementation by SquidDev
70-- https://gist.github.com/SquidDev/86925e07cbabd70773e53d781bd8b2fe
71-- http://pastebin.com/DMx8M0LP
72local encrypt, decrypt
73do
74 local function _W(f) local e=setmetatable({}, {__index = _ENV or getfenv()}) if setfenv then setfenv(f, e) end return f(e) or e end
75 local bit=_W(function(_ENV, ...)
76 --[[
77 This bit API is designed to cope with unsigned integers instead of normal integers
78 To do this we add checks for overflows: (x > 2^31 ? x - 2 ^ 32 : x)
79 These are written in long form because no constant folding.
80 ]]
81 local floor = math.floor
82 local lshift, rshift
83
84 rshift = function(a,disp)
85 return floor(a % 4294967296 / 2^disp)
86 end
87
88 lshift = function(a,disp)
89 return (a * 2^disp) % 4294967296
90 end
91
92 return {
93 -- bit operations
94 bnot = bit32 and bit32.bnot or bit.bnot,
95 band = bit32 and bit32.band or bit.band,
96 bor = bit32 and bit32.bor or bit.bor,
97 bxor = bit32 and bit32.bxor or bit.bxor,
98 rshift = rshift,
99 lshift = lshift,
100 }
101 end)
102
103 local gf=_W(function(_ENV, ...)
104 -- finite field with base 2 and modulo irreducible polynom x^8+x^4+x^3+x+1 = 0x11d
105 local bxor = bit32 and bit32.bxor or bit.bxor
106 local lshift = bit.lshift
107 -- private data of gf
108 local n = 0x100
109 local ord = 0xff
110 local irrPolynom = 0x11b
111 local exp, log = {}, {}
112 --
113 -- add two polynoms (its simply xor)
114 --
115 local function add(operand1, operand2)
116 return bxor(operand1,operand2)
117 end
118 --
119 -- subtract two polynoms (same as addition)
120 --
121 local function sub(operand1, operand2)
122 return bxor(operand1,operand2)
123 end
124 --
125 -- inverts element
126 -- a^(-1) = g^(order - log(a))
127 --
128 local function invert(operand)
129 -- special case for 1 or normal invert
130 return operand == 1 and 1 or exp[ord - log[operand]]
131 end
132 --
133 -- multiply two elements using a logarithm table
134 -- a*b = g^(log(a)+log(b))
135 --
136 local function mul(operand1, operand2)
137 if (operand1 == 0 or operand2 == 0) then
138 return 0
139 end
140 local exponent = log[operand1] + log[operand2]
141 if (exponent >= ord) then
142 exponent = exponent - ord
143 end
144 return exp[exponent]
145 end
146 --
147 -- divide two elements
148 -- a/b = g^(log(a)-log(b))
149 --
150 local function div(operand1, operand2)
151 if (operand1 == 0) then
152 return 0
153 end
154 -- TODO: exception if operand2 == 0
155 local exponent = log[operand1] - log[operand2]
156 if (exponent < 0) then
157 exponent = exponent + ord
158 end
159 return exp[exponent]
160 end
161 --
162 -- print logarithmic table
163 --
164 local function printLog()
165 for i = 1, n do
166 print("log(", i-1, ")=", log[i-1])
167 end
168 end
169 --
170 -- print exponentiation table
171 --
172 local function printExp()
173 for i = 1, n do
174 print("exp(", i-1, ")=", exp[i-1])
175 end
176 end
177 --
178 -- calculate logarithmic and exponentiation table
179 --
180 local function initMulTable()
181 local a = 1
182 for i = 0,ord-1 do
183 exp[i] = a
184 log[a] = i
185 -- multiply with generator x+1 -> left shift + 1
186 a = bxor(lshift(a, 1), a)
187 -- if a gets larger than order, reduce modulo irreducible polynom
188 if a > ord then
189 a = sub(a, irrPolynom)
190 end
191 end
192 end
193
194 initMulTable()
195
196 return {
197 add = add,
198 sub = sub,
199 invert = invert,
200 mul = mul,
201 div = div,
202 printLog = printLog,
203 printExp = printExp,
204 }
205 end)
206
207 util=_W(function(_ENV, ...)
208 -- Cache some bit operators
209 local bxor = bit.bxor
210 local rshift = bit.rshift
211 local band = bit.band
212 local lshift = bit.lshift
213 local sleepCheckIn
214 --
215 -- calculate the parity of one byte
216 --
217 local function byteParity(byte)
218 byte = bxor(byte, rshift(byte, 4))
219 byte = bxor(byte, rshift(byte, 2))
220 byte = bxor(byte, rshift(byte, 1))
221 return band(byte, 1)
222 end
223 --
224 -- get byte at position index
225 --
226 local function getByte(number, index)
227 return index == 0 and band(number,0xff) or band(rshift(number, index*8),0xff)
228 end
229 --
230 -- put number into int at position index
231 --
232 local function putByte(number, index)
233 return index == 0 and band(number,0xff) or lshift(band(number,0xff),index*8)
234 end
235 --
236 -- convert byte array to int array
237 --
238 local function bytesToInts(bytes, start, n)
239 local ints = {}
240 for i = 0, n - 1 do
241 ints[i + 1] =
242 putByte(bytes[start + (i*4)], 3) +
243 putByte(bytes[start + (i*4) + 1], 2) +
244 putByte(bytes[start + (i*4) + 2], 1) +
245 putByte(bytes[start + (i*4) + 3], 0)
246 if n % 10000 == 0 then sleepCheckIn() end
247 end
248 return ints
249 end
250 --
251 -- convert int array to byte array
252 --
253 local function intsToBytes(ints, output, outputOffset, n)
254 n = n or #ints
255 for i = 0, n - 1 do
256 for j = 0,3 do
257 output[outputOffset + i*4 + (3 - j)] = getByte(ints[i + 1], j)
258 end
259 if n % 10000 == 0 then sleepCheckIn() end
260 end
261 return output
262 end
263 --
264 -- convert bytes to hexString
265 --
266 local function bytesToHex(bytes)
267 local hexBytes = ""
268 for i,byte in ipairs(bytes) do
269 hexBytes = hexBytes .. string.format("%02x ", byte)
270 end
271 return hexBytes
272 end
273
274 local function hexToBytes(bytes)
275 local out = {}
276 for i = 1, #bytes, 2 do
277 out[#out + 1] = tonumber(bytes:sub(i, i + 1), 16)
278 end
279 return out
280 end
281 --
282 -- convert data to hex string
283 --
284 local function toHexString(data)
285 local type = type(data)
286 if (type == "number") then
287 return string.format("%08x",data)
288 elseif (type == "table") then
289 return bytesToHex(data)
290 elseif (type == "string") then
291 local bytes = {string.byte(data, 1, #data)}
292 return bytesToHex(bytes)
293 else
294 return data
295 end
296 end
297
298 local function padByteString(data)
299 local dataLength = #data
300 local random1 = math.random(0,255)
301 local random2 = math.random(0,255)
302 local prefix = string.char(random1,
303 random2,
304 random1,
305 random2,
306 getByte(dataLength, 3),
307 getByte(dataLength, 2),
308 getByte(dataLength, 1),
309 getByte(dataLength, 0)
310 )
311 data = prefix .. data
312 local padding, paddingLength = "", math.ceil(#data/16)*16 - #data
313 for i=1,paddingLength do
314 padding = padding .. string.char(math.random(0,255))
315 end
316 return data .. padding
317 end
318
319 local function properlyDecrypted(data)
320 local random = {string.byte(data,1,4)}
321 if (random[1] == random[3] and random[2] == random[4]) then
322 return true
323 end
324 return false
325 end
326
327 local function unpadByteString(data)
328 if (not properlyDecrypted(data)) then
329 return nil
330 end
331 local dataLength = putByte(string.byte(data,5), 3)
332 + putByte(string.byte(data,6), 2)
333 + putByte(string.byte(data,7), 1)
334 + putByte(string.byte(data,8), 0)
335 return string.sub(data,9,8+dataLength)
336 end
337
338 local function xorIV(data, iv)
339 for i = 1,16 do
340 data[i] = bxor(data[i], iv[i])
341 end
342 end
343
344 local function increment(data)
345 local i = 16
346 while true do
347 local value = data[i] + 1
348 if value >= 256 then
349 data[i] = value - 256
350 i = (i - 2) % 16 + 1
351 else
352 data[i] = value
353 break
354 end
355 end
356 end
357
358 -- Called every encryption cycle
359 local push, pull, time = os.queueEvent, coroutine.yield, os.time
360 local oldTime = time()
361 local function sleepCheckIn()
362 local newTime = time()
363 if newTime - oldTime >= 0.03 then -- (0.020 * 1.5)
364 oldTime = newTime
365 push("sleep")
366 pull("sleep")
367 end
368 end
369
370 local function getRandomData(bytes)
371 local char, random, sleep, insert = string.char, math.random, sleepCheckIn, table.insert
372 local result = {}
373 for i=1,bytes do
374 insert(result, random(0,255))
375 if i % 10240 == 0 then sleep() end
376 end
377 return result
378 end
379
380 local function getRandomString(bytes)
381 local char, random, sleep, insert = string.char, math.random, sleepCheckIn, table.insert
382 local result = {}
383 for i=1,bytes do
384 insert(result, char(random(0,255)))
385 if i % 10240 == 0 then sleep() end
386 end
387 return table.concat(result)
388 end
389
390 return {
391 byteParity = byteParity,
392 getByte = getByte,
393 putByte = putByte,
394 bytesToInts = bytesToInts,
395 intsToBytes = intsToBytes,
396 bytesToHex = bytesToHex,
397 hexToBytes = hexToBytes,
398 toHexString = toHexString,
399 padByteString = padByteString,
400 properlyDecrypted = properlyDecrypted,
401 unpadByteString = unpadByteString,
402 xorIV = xorIV,
403 increment = increment,
404 sleepCheckIn = sleepCheckIn,
405 getRandomData = getRandomData,
406 getRandomString = getRandomString,
407 }
408 end)
409
410 aes=_W(function(_ENV, ...)
411 -- Implementation of AES with nearly pure lua
412 -- AES with lua is slow, really slow :-)
413 local putByte = util.putByte
414 local getByte = util.getByte
415 -- some constants
416 local ROUNDS = 'rounds'
417 local KEY_TYPE = "type"
418 local ENCRYPTION_KEY=1
419 local DECRYPTION_KEY=2
420 -- aes SBOX
421 local SBox = {}
422 local iSBox = {}
423 -- aes tables
424 local table0 = {}
425 local table1 = {}
426 local table2 = {}
427 local table3 = {}
428 local tableInv0 = {}
429 local tableInv1 = {}
430 local tableInv2 = {}
431 local tableInv3 = {}
432 -- round constants
433 local rCon = {
434 0x01000000,
435 0x02000000,
436 0x04000000,
437 0x08000000,
438 0x10000000,
439 0x20000000,
440 0x40000000,
441 0x80000000,
442 0x1b000000,
443 0x36000000,
444 0x6c000000,
445 0xd8000000,
446 0xab000000,
447 0x4d000000,
448 0x9a000000,
449 0x2f000000,
450 }
451 --
452 -- affine transformation for calculating the S-Box of AES
453 --
454 local function affinMap(byte)
455 mask = 0xf8
456 result = 0
457 for i = 1,8 do
458 result = bit.lshift(result,1)
459 parity = util.byteParity(bit.band(byte,mask))
460 result = result + parity
461 -- simulate roll
462 lastbit = bit.band(mask, 1)
463 mask = bit.band(bit.rshift(mask, 1),0xff)
464 mask = lastbit ~= 0 and bit.bor(mask, 0x80) or bit.band(mask, 0x7f)
465 end
466 return bit.bxor(result, 0x63)
467 end
468 --
469 -- calculate S-Box and inverse S-Box of AES
470 -- apply affine transformation to inverse in finite field 2^8
471 --
472 local function calcSBox()
473 for i = 0, 255 do
474 inverse = i ~= 0 and gf.invert(i) or 0
475 mapped = affinMap(inverse)
476 SBox[i] = mapped
477 iSBox[mapped] = i
478 end
479 end
480 --
481 -- Calculate round tables
482 -- round tables are used to calculate shiftRow, MixColumn and SubBytes
483 -- with 4 table lookups and 4 xor operations.
484 --
485 local function calcRoundTables()
486 for x = 0,255 do
487 byte = SBox[x]
488 table0[x] = putByte(gf.mul(0x03, byte), 0)
489 + putByte( byte , 1)
490 + putByte( byte , 2)
491 + putByte(gf.mul(0x02, byte), 3)
492 table1[x] = putByte( byte , 0)
493 + putByte( byte , 1)
494 + putByte(gf.mul(0x02, byte), 2)
495 + putByte(gf.mul(0x03, byte), 3)
496 table2[x] = putByte( byte , 0)
497 + putByte(gf.mul(0x02, byte), 1)
498 + putByte(gf.mul(0x03, byte), 2)
499 + putByte( byte , 3)
500 table3[x] = putByte(gf.mul(0x02, byte), 0)
501 + putByte(gf.mul(0x03, byte), 1)
502 + putByte( byte , 2)
503 + putByte( byte , 3)
504 end
505 end
506 --
507 -- Calculate inverse round tables
508 -- does the inverse of the normal roundtables for the equivalent
509 -- decryption algorithm.
510 --
511 local function calcInvRoundTables()
512 for x = 0,255 do
513 byte = iSBox[x]
514 tableInv0[x] = putByte(gf.mul(0x0b, byte), 0)
515 + putByte(gf.mul(0x0d, byte), 1)
516 + putByte(gf.mul(0x09, byte), 2)
517 + putByte(gf.mul(0x0e, byte), 3)
518 tableInv1[x] = putByte(gf.mul(0x0d, byte), 0)
519 + putByte(gf.mul(0x09, byte), 1)
520 + putByte(gf.mul(0x0e, byte), 2)
521 + putByte(gf.mul(0x0b, byte), 3)
522 tableInv2[x] = putByte(gf.mul(0x09, byte), 0)
523 + putByte(gf.mul(0x0e, byte), 1)
524 + putByte(gf.mul(0x0b, byte), 2)
525 + putByte(gf.mul(0x0d, byte), 3)
526 tableInv3[x] = putByte(gf.mul(0x0e, byte), 0)
527 + putByte(gf.mul(0x0b, byte), 1)
528 + putByte(gf.mul(0x0d, byte), 2)
529 + putByte(gf.mul(0x09, byte), 3)
530 end
531 end
532 --
533 -- rotate word: 0xaabbccdd gets 0xbbccddaa
534 -- used for key schedule
535 --
536 local function rotWord(word)
537 local tmp = bit.band(word,0xff000000)
538 return (bit.lshift(word,8) + bit.rshift(tmp,24))
539 end
540 --
541 -- replace all bytes in a word with the SBox.
542 -- used for key schedule
543 --
544 local function subWord(word)
545 return putByte(SBox[getByte(word,0)],0)
546 + putByte(SBox[getByte(word,1)],1)
547 + putByte(SBox[getByte(word,2)],2)
548 + putByte(SBox[getByte(word,3)],3)
549 end
550 --
551 -- generate key schedule for aes encryption
552 --
553 -- returns table with all round keys and
554 -- the necessary number of rounds saved in [ROUNDS]
555 --
556 local function expandEncryptionKey(key)
557 local keySchedule = {}
558 local keyWords = math.floor(#key / 4)
559 if ((keyWords ~= 4 and keyWords ~= 6 and keyWords ~= 8) or (keyWords * 4 ~= #key)) then
560 error("Invalid key size: " .. tostring(keyWords))
561 return nil
562 end
563 keySchedule[ROUNDS] = keyWords + 6
564 keySchedule[KEY_TYPE] = ENCRYPTION_KEY
565 for i = 0,keyWords - 1 do
566 keySchedule[i] = putByte(key[i*4+1], 3)
567 + putByte(key[i*4+2], 2)
568 + putByte(key[i*4+3], 1)
569 + putByte(key[i*4+4], 0)
570 end
571 for i = keyWords, (keySchedule[ROUNDS] + 1)*4 - 1 do
572 local tmp = keySchedule[i-1]
573 if ( i % keyWords == 0) then
574 tmp = rotWord(tmp)
575 tmp = subWord(tmp)
576 local index = math.floor(i/keyWords)
577 tmp = bit.bxor(tmp,rCon[index])
578 elseif (keyWords > 6 and i % keyWords == 4) then
579 tmp = subWord(tmp)
580 end
581 keySchedule[i] = bit.bxor(keySchedule[(i-keyWords)],tmp)
582 end
583 return keySchedule
584 end
585 --
586 -- Inverse mix column
587 -- used for key schedule of decryption key
588 --
589 local function invMixColumnOld(word)
590 local b0 = getByte(word,3)
591 local b1 = getByte(word,2)
592 local b2 = getByte(word,1)
593 local b3 = getByte(word,0)
594 return putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b1),
595 gf.mul(0x0d, b2)),
596 gf.mul(0x09, b3)),
597 gf.mul(0x0e, b0)),3)
598 + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b2),
599 gf.mul(0x0d, b3)),
600 gf.mul(0x09, b0)),
601 gf.mul(0x0e, b1)),2)
602 + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b3),
603 gf.mul(0x0d, b0)),
604 gf.mul(0x09, b1)),
605 gf.mul(0x0e, b2)),1)
606 + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b0),
607 gf.mul(0x0d, b1)),
608 gf.mul(0x09, b2)),
609 gf.mul(0x0e, b3)),0)
610 end
611 --
612 -- Optimized inverse mix column
613 -- look at http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf
614 -- TODO: make it work
615 --
616 local function invMixColumn(word)
617 local b0 = getByte(word,3)
618 local b1 = getByte(word,2)
619 local b2 = getByte(word,1)
620 local b3 = getByte(word,0)
621 local t = bit.bxor(b3,b2)
622 local u = bit.bxor(b1,b0)
623 local v = bit.bxor(t,u)
624 v = bit.bxor(v,gf.mul(0x08,v))
625 w = bit.bxor(v,gf.mul(0x04, bit.bxor(b2,b0)))
626 v = bit.bxor(v,gf.mul(0x04, bit.bxor(b3,b1)))
627 return putByte( bit.bxor(bit.bxor(b3,v), gf.mul(0x02, bit.bxor(b0,b3))), 0)
628 + putByte( bit.bxor(bit.bxor(b2,w), gf.mul(0x02, t )), 1)
629 + putByte( bit.bxor(bit.bxor(b1,v), gf.mul(0x02, bit.bxor(b0,b3))), 2)
630 + putByte( bit.bxor(bit.bxor(b0,w), gf.mul(0x02, u )), 3)
631 end
632 --
633 -- generate key schedule for aes decryption
634 --
635 -- uses key schedule for aes encryption and transforms each
636 -- key by inverse mix column.
637 --
638 local function expandDecryptionKey(key)
639 local keySchedule = expandEncryptionKey(key)
640 if (keySchedule == nil) then
641 return nil
642 end
643 keySchedule[KEY_TYPE] = DECRYPTION_KEY
644 for i = 4, (keySchedule[ROUNDS] + 1)*4 - 5 do
645 keySchedule[i] = invMixColumnOld(keySchedule[i])
646 end
647 return keySchedule
648 end
649 --
650 -- xor round key to state
651 --
652 local function addRoundKey(state, key, round)
653 for i = 0, 3 do
654 state[i + 1] = bit.bxor(state[i + 1], key[round*4+i])
655 end
656 end
657 --
658 -- do encryption round (ShiftRow, SubBytes, MixColumn together)
659 --
660 local function doRound(origState, dstState)
661 dstState[1] = bit.bxor(bit.bxor(bit.bxor(
662 table0[getByte(origState[1],3)],
663 table1[getByte(origState[2],2)]),
664 table2[getByte(origState[3],1)]),
665 table3[getByte(origState[4],0)])
666 dstState[2] = bit.bxor(bit.bxor(bit.bxor(
667 table0[getByte(origState[2],3)],
668 table1[getByte(origState[3],2)]),
669 table2[getByte(origState[4],1)]),
670 table3[getByte(origState[1],0)])
671 dstState[3] = bit.bxor(bit.bxor(bit.bxor(
672 table0[getByte(origState[3],3)],
673 table1[getByte(origState[4],2)]),
674 table2[getByte(origState[1],1)]),
675 table3[getByte(origState[2],0)])
676 dstState[4] = bit.bxor(bit.bxor(bit.bxor(
677 table0[getByte(origState[4],3)],
678 table1[getByte(origState[1],2)]),
679 table2[getByte(origState[2],1)]),
680 table3[getByte(origState[3],0)])
681 end
682 --
683 -- do last encryption round (ShiftRow and SubBytes)
684 --
685 local function doLastRound(origState, dstState)
686 dstState[1] = putByte(SBox[getByte(origState[1],3)], 3)
687 + putByte(SBox[getByte(origState[2],2)], 2)
688 + putByte(SBox[getByte(origState[3],1)], 1)
689 + putByte(SBox[getByte(origState[4],0)], 0)
690 dstState[2] = putByte(SBox[getByte(origState[2],3)], 3)
691 + putByte(SBox[getByte(origState[3],2)], 2)
692 + putByte(SBox[getByte(origState[4],1)], 1)
693 + putByte(SBox[getByte(origState[1],0)], 0)
694 dstState[3] = putByte(SBox[getByte(origState[3],3)], 3)
695 + putByte(SBox[getByte(origState[4],2)], 2)
696 + putByte(SBox[getByte(origState[1],1)], 1)
697 + putByte(SBox[getByte(origState[2],0)], 0)
698 dstState[4] = putByte(SBox[getByte(origState[4],3)], 3)
699 + putByte(SBox[getByte(origState[1],2)], 2)
700 + putByte(SBox[getByte(origState[2],1)], 1)
701 + putByte(SBox[getByte(origState[3],0)], 0)
702 end
703 --
704 -- do decryption round
705 --
706 local function doInvRound(origState, dstState)
707 dstState[1] = bit.bxor(bit.bxor(bit.bxor(
708 tableInv0[getByte(origState[1],3)],
709 tableInv1[getByte(origState[4],2)]),
710 tableInv2[getByte(origState[3],1)]),
711 tableInv3[getByte(origState[2],0)])
712 dstState[2] = bit.bxor(bit.bxor(bit.bxor(
713 tableInv0[getByte(origState[2],3)],
714 tableInv1[getByte(origState[1],2)]),
715 tableInv2[getByte(origState[4],1)]),
716 tableInv3[getByte(origState[3],0)])
717 dstState[3] = bit.bxor(bit.bxor(bit.bxor(
718 tableInv0[getByte(origState[3],3)],
719 tableInv1[getByte(origState[2],2)]),
720 tableInv2[getByte(origState[1],1)]),
721 tableInv3[getByte(origState[4],0)])
722 dstState[4] = bit.bxor(bit.bxor(bit.bxor(
723 tableInv0[getByte(origState[4],3)],
724 tableInv1[getByte(origState[3],2)]),
725 tableInv2[getByte(origState[2],1)]),
726 tableInv3[getByte(origState[1],0)])
727 end
728 --
729 -- do last decryption round
730 --
731 local function doInvLastRound(origState, dstState)
732 dstState[1] = putByte(iSBox[getByte(origState[1],3)], 3)
733 + putByte(iSBox[getByte(origState[4],2)], 2)
734 + putByte(iSBox[getByte(origState[3],1)], 1)
735 + putByte(iSBox[getByte(origState[2],0)], 0)
736 dstState[2] = putByte(iSBox[getByte(origState[2],3)], 3)
737 + putByte(iSBox[getByte(origState[1],2)], 2)
738 + putByte(iSBox[getByte(origState[4],1)], 1)
739 + putByte(iSBox[getByte(origState[3],0)], 0)
740 dstState[3] = putByte(iSBox[getByte(origState[3],3)], 3)
741 + putByte(iSBox[getByte(origState[2],2)], 2)
742 + putByte(iSBox[getByte(origState[1],1)], 1)
743 + putByte(iSBox[getByte(origState[4],0)], 0)
744 dstState[4] = putByte(iSBox[getByte(origState[4],3)], 3)
745 + putByte(iSBox[getByte(origState[3],2)], 2)
746 + putByte(iSBox[getByte(origState[2],1)], 1)
747 + putByte(iSBox[getByte(origState[1],0)], 0)
748 end
749 --
750 -- encrypts 16 Bytes
751 -- key encryption key schedule
752 -- input array with input data
753 -- inputOffset start index for input
754 -- output array for encrypted data
755 -- outputOffset start index for output
756 --
757 local function encrypt(key, input, inputOffset, output, outputOffset)
758 --default parameters
759 inputOffset = inputOffset or 1
760 output = output or {}
761 outputOffset = outputOffset or 1
762 local state, tmpState = {}, {}
763 if (key[KEY_TYPE] ~= ENCRYPTION_KEY) then
764 error("No encryption key: " .. tostring(key[KEY_TYPE]) .. ", expected " .. ENCRYPTION_KEY)
765 return
766 end
767 state = util.bytesToInts(input, inputOffset, 4)
768 addRoundKey(state, key, 0)
769 local round = 1
770 while (round < key[ROUNDS] - 1) do
771 -- do a double round to save temporary assignments
772 doRound(state, tmpState)
773 addRoundKey(tmpState, key, round)
774 round = round + 1
775 doRound(tmpState, state)
776 addRoundKey(state, key, round)
777 round = round + 1
778 end
779 doRound(state, tmpState)
780 addRoundKey(tmpState, key, round)
781 round = round +1
782 doLastRound(tmpState, state)
783 addRoundKey(state, key, round)
784 util.sleepCheckIn()
785 return util.intsToBytes(state, output, outputOffset)
786 end
787 --
788 -- decrypt 16 bytes
789 -- key decryption key schedule
790 -- input array with input data
791 -- inputOffset start index for input
792 -- output array for decrypted data
793 -- outputOffset start index for output
794 ---
795 local function decrypt(key, input, inputOffset, output, outputOffset)
796 -- default arguments
797 inputOffset = inputOffset or 1
798 output = output or {}
799 outputOffset = outputOffset or 1
800 local state, tmpState = {}, {}
801 if (key[KEY_TYPE] ~= DECRYPTION_KEY) then
802 error("No decryption key: " .. tostring(key[KEY_TYPE]))
803 return
804 end
805 state = util.bytesToInts(input, inputOffset, 4)
806 addRoundKey(state, key, key[ROUNDS])
807 local round = key[ROUNDS] - 1
808 while (round > 2) do
809 -- do a double round to save temporary assignments
810 doInvRound(state, tmpState)
811 addRoundKey(tmpState, key, round)
812 round = round - 1
813 doInvRound(tmpState, state)
814 addRoundKey(state, key, round)
815 round = round - 1
816 end
817 doInvRound(state, tmpState)
818 addRoundKey(tmpState, key, round)
819 round = round - 1
820 doInvLastRound(tmpState, state)
821 addRoundKey(state, key, round)
822 util.sleepCheckIn()
823 return util.intsToBytes(state, output, outputOffset)
824 end
825
826 -- calculate all tables when loading this file
827 calcSBox()
828 calcRoundTables()
829 calcInvRoundTables()
830
831 return {
832 ROUNDS = ROUNDS,
833 KEY_TYPE = KEY_TYPE,
834 ENCRYPTION_KEY = ENCRYPTION_KEY,
835 DECRYPTION_KEY = DECRYPTION_KEY,
836 expandEncryptionKey = expandEncryptionKey,
837 expandDecryptionKey = expandDecryptionKey,
838 encrypt = encrypt,
839 decrypt = decrypt,
840 }
841 end)
842
843 local buffer=_W(function(_ENV, ...)
844 local function new()
845 return {}
846 end
847
848 local function addString(stack, s)
849 table.insert(stack, s)
850 end
851
852 local function toString(stack)
853 return table.concat(stack)
854 end
855
856 return {
857 new = new,
858 addString = addString,
859 toString = toString,
860 }
861 end)
862
863 ciphermode=_W(function(_ENV, ...)
864 local public = {}
865 --
866 -- Encrypt strings
867 -- key - byte array with key
868 -- string - string to encrypt
869 -- modefunction - function for cipher mode to use
870 --
871 local random, unpack = math.random, unpack or table.unpack
872 function public.encryptString(key, data, modeFunction, iv)
873 if iv then
874 local ivCopy = {}
875 for i = 1, 16 do ivCopy[i] = iv[i] end
876 iv = ivCopy
877 else
878 iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
879 end
880 local keySched = aes.expandEncryptionKey(key)
881 local encryptedData = buffer.new()
882 for i = 1, #data/16 do
883 local offset = (i-1)*16 + 1
884 local byteData = {string.byte(data,offset,offset +15)}
885 iv = modeFunction(keySched, byteData, iv)
886 buffer.addString(encryptedData, string.char(unpack(byteData)))
887 end
888 return buffer.toString(encryptedData)
889 end
890 --
891 -- the following 4 functions can be used as
892 -- modefunction for encryptString
893 --
894 -- Electronic code book mode encrypt function
895 function public.encryptECB(keySched, byteData, iv)
896 aes.encrypt(keySched, byteData, 1, byteData, 1)
897 end
898
899 -- Cipher block chaining mode encrypt function
900 function public.encryptCBC(keySched, byteData, iv)
901 util.xorIV(byteData, iv)
902 aes.encrypt(keySched, byteData, 1, byteData, 1)
903 return byteData
904 end
905
906 -- Output feedback mode encrypt function
907 function public.encryptOFB(keySched, byteData, iv)
908 aes.encrypt(keySched, iv, 1, iv, 1)
909 util.xorIV(byteData, iv)
910 return iv
911 end
912
913 -- Cipher feedback mode encrypt function
914 function public.encryptCFB(keySched, byteData, iv)
915 aes.encrypt(keySched, iv, 1, iv, 1)
916 util.xorIV(byteData, iv)
917 return byteData
918 end
919
920 function public.encryptCTR(keySched, byteData, iv)
921 local nextIV = {}
922 for j = 1, 16 do nextIV[j] = iv[j] end
923 aes.encrypt(keySched, iv, 1, iv, 1)
924 util.xorIV(byteData, iv)
925 util.increment(nextIV)
926 return nextIV
927 end
928 --
929 -- Decrypt strings
930 -- key - byte array with key
931 -- string - string to decrypt
932 -- modefunction - function for cipher mode to use
933 --
934 function public.decryptString(key, data, modeFunction, iv)
935 if iv then
936 local ivCopy = {}
937 for i = 1, 16 do ivCopy[i] = iv[i] end
938 iv = ivCopy
939 else
940 iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
941 end
942 local keySched
943 if modeFunction == public.decryptOFB or modeFunction == public.decryptCFB or modeFunction == public.decryptCTR then
944 keySched = aes.expandEncryptionKey(key)
945 else
946 keySched = aes.expandDecryptionKey(key)
947 end
948 local decryptedData = buffer.new()
949 for i = 1, #data/16 do
950 local offset = (i-1)*16 + 1
951 local byteData = {string.byte(data,offset,offset +15)}
952 iv = modeFunction(keySched, byteData, iv)
953 buffer.addString(decryptedData, string.char(unpack(byteData)))
954 end
955 return buffer.toString(decryptedData)
956 end
957 --
958 -- the following 4 functions can be used as
959 -- modefunction for decryptString
960 --
961 -- Electronic code book mode decrypt function
962 function public.decryptECB(keySched, byteData, iv)
963 aes.decrypt(keySched, byteData, 1, byteData, 1)
964 return iv
965 end
966
967 -- Cipher block chaining mode decrypt function
968 function public.decryptCBC(keySched, byteData, iv)
969 local nextIV = {}
970 for j = 1, 16 do nextIV[j] = byteData[j] end
971 aes.decrypt(keySched, byteData, 1, byteData, 1)
972 util.xorIV(byteData, iv)
973 return nextIV
974 end
975
976 -- Output feedback mode decrypt function
977 function public.decryptOFB(keySched, byteData, iv)
978 aes.encrypt(keySched, iv, 1, iv, 1)
979 util.xorIV(byteData, iv)
980 return iv
981 end
982
983 -- Cipher feedback mode decrypt function
984 function public.decryptCFB(keySched, byteData, iv)
985 local nextIV = {}
986 for j = 1, 16 do nextIV[j] = byteData[j] end
987 aes.encrypt(keySched, iv, 1, iv, 1)
988 util.xorIV(byteData, iv)
989 return nextIV
990 end
991
992 public.decryptCTR = public.encryptCTR
993 return public
994 end)
995
996 -- Simple API for encrypting strings.
997 --
998 AES128 = 16
999 AES192 = 24
1000 AES256 = 32
1001 ECBMODE = 1
1002 CBCMODE = 2
1003 OFBMODE = 3
1004 CFBMODE = 4
1005 CTRMODE = 4
1006
1007 local function pwToKey(password, keyLength, iv)
1008 local padLength = keyLength
1009 if (keyLength == AES192) then
1010 padLength = 32
1011 end
1012 if (padLength > #password) then
1013 local postfix = ""
1014 for i = 1,padLength - #password do
1015 postfix = postfix .. string.char(0)
1016 end
1017 password = password .. postfix
1018 else
1019 password = string.sub(password, 1, padLength)
1020 end
1021 local pwBytes = {string.byte(password,1,#password)}
1022 password = ciphermode.encryptString(pwBytes, password, ciphermode.encryptCBC, iv)
1023 password = string.sub(password, 1, keyLength)
1024 return {string.byte(password,1,#password)}
1025 end
1026 --
1027 -- Encrypts string data with password password.
1028 -- password - the encryption key is generated from this string
1029 -- data - string to encrypt (must not be too large)
1030 -- keyLength - length of aes key: 128(default), 192 or 256 Bit
1031 -- mode - mode of encryption: ecb, cbc(default), ofb, cfb
1032 --
1033 -- mode and keyLength must be the same for encryption and decryption.
1034 --
1035 function encrypt(password, data, keyLength, mode, iv)
1036 assert(password ~= nil, "Empty password.")
1037 assert(data ~= nil, "Empty data.")
1038 local mode = mode or CBCMODE
1039 local keyLength = keyLength or AES128
1040 local key = pwToKey(password, keyLength, iv)
1041 local paddedData = util.padByteString(data)
1042 if mode == ECBMODE then
1043 return ciphermode.encryptString(key, paddedData, ciphermode.encryptECB, iv)
1044 elseif mode == CBCMODE then
1045 return ciphermode.encryptString(key, paddedData, ciphermode.encryptCBC, iv)
1046 elseif mode == OFBMODE then
1047 return ciphermode.encryptString(key, paddedData, ciphermode.encryptOFB, iv)
1048 elseif mode == CFBMODE then
1049 return ciphermode.encryptString(key, paddedData, ciphermode.encryptCFB, iv)
1050 elseif mode == CTRMODE then
1051 return ciphermode.encryptString(key, paddedData, ciphermode.encryptCTR, iv)
1052 else
1053 error("Unknown mode", 2)
1054 end
1055 end
1056 --
1057 -- Decrypts string data with password password.
1058 -- password - the decryption key is generated from this string
1059 -- data - string to encrypt
1060 -- keyLength - length of aes key: 128(default), 192 or 256 Bit
1061 -- mode - mode of decryption: ecb, cbc(default), ofb, cfb
1062 --
1063 -- mode and keyLength must be the same for encryption and decryption.
1064 --
1065 function decrypt(password, data, keyLength, mode, iv)
1066 local mode = mode or CBCMODE
1067 local keyLength = keyLength or AES128
1068 local key = pwToKey(password, keyLength, iv)
1069 local plain
1070 if mode == ECBMODE then
1071 plain = ciphermode.decryptString(key, data, ciphermode.decryptECB, iv)
1072 elseif mode == CBCMODE then
1073 plain = ciphermode.decryptString(key, data, ciphermode.decryptCBC, iv)
1074 elseif mode == OFBMODE then
1075 plain = ciphermode.decryptString(key, data, ciphermode.decryptOFB, iv)
1076 elseif mode == CFBMODE then
1077 plain = ciphermode.decryptString(key, data, ciphermode.decryptCFB, iv)
1078 elseif mode == CTRMODE then
1079 plain = ciphermode.decryptString(key, data, ciphermode.decryptCTR, iv)
1080 else
1081 error("Unknown mode", 2)
1082 end
1083 result = util.unpadByteString(plain)
1084 if (result == nil) then
1085 return nil
1086 end
1087 return result
1088 end
1089end
1090
1091local function netSend(id, data)
1092 local encKey, encryptedDataPack
1093 if not rednet.isOpen(modemSide) then rednet.open(modemSide) end
1094 if clients[id] then
1095 encKey = tostring(id) .. "ccDHD!General_Comms*Key" .. thisCC
1096 encryptedDataPack = encode(encrypt(encKey, textutils.serialize({ program = "ccDialer", data = data, ccDHD = false, gStatus = gateStatus, iris = remoteIrisStatus })))
1097 rednet.send(id, encryptedDataPack, "ccDialerWiFi")
1098 end
1099end
1100
1101local function netSendAll(data)
1102 if not rednet.isOpen(modemSide) then rednet.open(modemSide) end
1103 if clientCount < 1 then return end
1104 local encKey, encryptedDataPack
1105 for id in pairs(clients) do
1106 encKey = tostring(id) .. "ccDHD!General_Comms*Key" .. thisCC
1107 encryptedDataPack = encode(encrypt(encKey, textutils.serialize({ program = "ccDialer", data = data, ccDHD = false, gStatus = gateStatus, iris = remoteIrisStatus })))
1108 rednet.send(id, encryptedDataPack, "ccDialerWiFi")
1109 end
1110end
1111
1112local function recordSessionData() --# Human readable log files (last gate & history)
1113 local logAddress = dialAddress or "N/A" --# set logAddress
1114 if callDirection == "none" then callDirection = "Incoming" end
1115 local callTime = textutils.formatTime(os.time(), false) --# format the time
1116 if not fs.exists("/data") then fs.makeDir("/data") end
1117 local previousCall = fs.open("/data/lastCall", "w") --# record last call
1118 previousCall.writeLine(tostring(os.day()) .. " @ " .. callTime .. " <" .. callDirection .. "> " .. logAddress)
1119 previousCall.close()
1120end
1121
1122local function updateTerminal()
1123 term.setCursorPos(2, 5)
1124 term.write("Local / Target: " .. thisGate .. " / " .. (dialAddress or "none "))
1125 term.setCursorPos(14, 7)
1126 term.write(string.rep(" ", 20))
1127 term.setCursorPos(14, 7)
1128 term.write(gateStatus .. " " .. ((gateStatus == "Dialing" or gateStatus == "Connected") and callDirection or " "))
1129end
1130
1131local function hangUp() --# LanteaCraft & SGCraft
1132 if gateStatus == "Idle" or gateStatus == "Offline" then return end
1133 if lcGate then
1134 continueDialing = false
1135 while spinTime do
1136 os.queueEvent("spinWait")
1137 os.pullEvent("spinWait")
1138 end
1139 pcall(gate.disengageStargate)
1140 chevronNumber = gate.getActivatedChevrons()
1141 if chevronNumber > 0 then
1142 for i = 1, chevronNumber do
1143 --[[
1144 local onHook = pcall(gate.deactivateChevron)
1145 if onHook then
1146 chevronNumber = chevronNumber - 1
1147 else
1148 break
1149 end
1150 ]]--
1151 pcall(gate.deactivateChevron)
1152 chevronNumber = chevronNumber - 1
1153 end
1154 end
1155 if chevronNumber == 0 then
1156 dialAddress = nil
1157 gateStatus = "Idle"
1158 remoteIrisStatus = "unk"
1159 netSendAll("Idle")
1160 updateTerminal()
1161 end
1162 else
1163 gate.disconnect()
1164 end
1165end
1166
1167local function lockChevron(num) --# LanteaCraft
1168 if continueDialing then
1169 --[[
1170 local dialGate = pcall(gate.selectGlyph, dialAddress:sub(num, num))
1171 if not dialGate then return false end
1172 dialGate = pcall(gate.activateChevron)
1173 if not dialGate then return false end
1174 ]]--
1175 pcall(gate.selectGlyph, dialAddress:sub(num, num))
1176 pcall(gate.activateChevron)
1177 gateStatus = "Dialing"
1178 return true
1179 else
1180 gateStatus = "Paused"
1181 return false
1182 end
1183end
1184
1185local function lcIrisMonitor() --# LanteaCraft
1186 local event --, irisStatus, dataPack
1187 while true do
1188 event = os.pullEvent()
1189 if event == "irisOpened" or event == "irisDestroyed" or event == "irisClosed" then
1190 irisState = event == "irisClosed"
1191 term.setCursorPos(14, 9)
1192 term.write(irisState and "Closed" or "Open ")
1193 --if gateStatus == "Connected" then
1194 --irisStatus = irisState and "closed" or "open"
1195 --dataPack = textutils.serialize({ irisState = irisStatus })
1196 --pcall(gate.sendMessage, dataPack)
1197 --end
1198 end
1199 end
1200end
1201
1202local function lcGateMonitor() --# LanteaCraft
1203 local event --, irisStatus, dataPack, establishWormhole
1204 while true do
1205 event = os.pullEvent()
1206 if event == "spinToGlyph" or event == "engageGlyph" or event == "connect" or event == "disconnect" then
1207 if event == "spinToGlyph" then
1208 spinTime = true
1209 callDirection = dialAddress and "Outgoing" or "Incoming"
1210 elseif event == "engageGlyph" then
1211 spinTime = false
1212 if dialAddress then
1213 chevronNumber = chevronNumber + 1
1214 if chevronNumber == #dialAddress then
1215 continueDialing = false
1216 --establishWormhole = pcall(gate.engageStargate)
1217 --if not establishWormhole then hangUp() end
1218 pcall(gate.engageStargate)
1219 else
1220 if continueDialing and not lockChevron(chevronNumber + 1) then
1221 continueDialing = false
1222 gateStatus = "Paused"
1223 end
1224 end
1225 netSendAll(gateStatus == "Dialing" and "Dialing" or "Paused")
1226 end
1227 elseif event == "connect" then
1228 gateStatus = "Connected"
1229 spinTime = false
1230 if logging then recordSessionData() end
1231 --irisStatus = irisState and "closed" or "open"
1232 --dataPack = textutils.serialize({ irisState = irisStatus })
1233 --pcall(gate.sendMessage, dataPack)
1234 netSendAll("Connected")
1235 elseif event == "disconnect" then
1236 gateStatus = "Idle"
1237 remoteIrisStatus = "unk"
1238 spinTime = false
1239 dialAddress = nil
1240 callDirection = "none"
1241 chevronNumber = 0
1242 netSendAll("Idle")
1243 end
1244 updateTerminal()
1245 end
1246 end
1247end
1248
1249local function sgIrisMonitor() --# SGCraft
1250 local irisEvent, _, newState, oldState, irisStatus
1251 while true do
1252 irisEvent, _, newState, oldState = os.pullEvent("sgIrisStateChange")
1253 if newState == "Closed" or newState == "Open" or newState == "Offline" then
1254 irisState = newState == "Closed"
1255 term.setCursorPos(14, 9)
1256 term.write(irisState and "Closed" or "Open ")
1257 if gateStatus == "Connected" then
1258 irisStatus = irisState and "closed" or "open"
1259 gate.sendMessage(textutils.serialize({ irisState = irisStatus }))
1260 end
1261 end
1262 end
1263end
1264
1265local function sgGateMonitor() --# SGCraft
1266 local sgEvent, _, newState, oldState, irisStatus
1267 while true do
1268 sgEvent, _, newState, oldState = os.pullEvent("sgStargateStateChange")
1269 gateStatus = sgStates[newState] or "Unknown"
1270 if gateStatus == "Connected" then
1271 if not dialAddress then
1272 dialAddress = gate.remoteAddress()
1273 _, chevronNumber, callDirection = gate.stargateState()
1274 end
1275 if logging and newState ~= oldState then recordSessionData() end
1276 irisStatus = irisState and "closed" or "open"
1277 gate.sendMessage(textutils.serialize({ irisState = irisStatus }))
1278 netSendAll("Connected")
1279 elseif gateStatus == "Idle" or gateStatus == "Offline" then
1280 dialAddress = nil
1281 callDirection = "none"
1282 remoteIrisStatus = "unk"
1283 chevronNumber = 0
1284 netSendAll("Idle")
1285 end
1286 updateTerminal()
1287 end
1288end
1289
1290local function outgoingCall() --# LanteaCraft & SGCraft
1291 local _, sgEvent, outgoingAddress
1292 while true do
1293 if lcGate then
1294 sgEvent, chevronNumber = os.pullEvent("sgChevronEncode")
1295 else
1296 sgEvent, _, outgoingAddress = os.pullEvent("sgDialOut")
1297 end
1298 gateStatus = "Dialing"
1299 callDirection = "Outgoing"
1300 updateTerminal()
1301 netSendAll("Dialing")
1302 end
1303end
1304
1305local function incomingCall() --# LanteaCraft & SGCraft
1306 local _, incomingChevron, incomingAddress, sgEvent
1307 while true do
1308 if lcGate then
1309 _, incomingChevron = os.pullEvent("sgIncoming")
1310 else
1311 sgEvent, _, incomingAddress = os.pullEvent("sgDialIn")
1312 end
1313 gateStatus = "Dialing"
1314 callDirection = "Incoming"
1315 --if lcGate then incomingAddress = incomingAddress and incomingAddress .. incomingChevron or incomingChevron end
1316 dialAddress = lcGate and "N/A" or gate.remoteAddress()
1317 updateTerminal()
1318 netSendAll("Dialing")
1319 end
1320end
1321
1322local function gateReceive() --# LanteaCraft & SGCraft
1323 local _, src, message, success, data
1324 while true do
1325 if lcGate then
1326 _, message = os.pullEvent("receive")
1327 else
1328 _, src, message = os.pullEvent("sgMessageReceived")
1329 end
1330 success, data = pcall(textutils.unserialize, message)
1331 if success and type(data) == "table" then
1332 if data.password then
1333 if irisState then
1334 pcall(gate.openIris)
1335 elseif not irisState and allowIrisClose then
1336 pcall(gate.closeIris)
1337 end
1338 elseif data.irisState then
1339 remoteIrisStatus = data.irisState
1340 netSendAll(remoteIrisStatus)
1341 end
1342 end
1343 end
1344end
1345
1346local function netReceive()
1347 local id, encryptedMessage, decryptedMesesage, encodedMessage, message, success, mCommand, mcLen, dataPack
1348 while true do
1349 if not rednet.isOpen(modemSide) then rednet.open(modemSide) end
1350 id, encodedMessage = rednet.receive("ccDialerWiFi")
1351 if type(encodedMessage) == "string" then
1352 success, encryptedMessage = pcall(decode, encodedMessage)
1353 if success then
1354 encKey = thisCC .. "ccDHD!General_Comms*Key" .. tostring(id)
1355 success, decryptedMessage = pcall(decrypt, encKey, encryptedMessage)
1356 if success then
1357 success, message = pcall(textutils.unserialize, decryptedMessage)
1358 if success and type(message) == "table" and message.program and message.program == "ccDialer" and message.gate then
1359 if message.gate == "NO HOST" and message.command and message.command == "QRY" then
1360 if not clients[id] then clientCount = clientCount + 1 end
1361 clients[id] = 0
1362 netSend(id, thisGate)
1363 elseif message.gate == thisGate then
1364 if message.password and clients[id] and gateStatus == "Connected" then
1365 dataPack = textutils.serialize({ password = message.password })
1366 pcall(gate.sendMessage, dataPack)
1367 elseif message.command and clients[id] then
1368 mCommand = message.command
1369 if mCommand == "ping" then
1370 netSend(id, "pong")
1371 elseif mCommand == "pong" then
1372 clients[id] = 0
1373 elseif mCommand == "endCall" then
1374 hangUp()
1375 elseif mCommand == "logout" then
1376 clients[id] = nil
1377 clientCount = math.max(0, clientCount - 1)
1378 else
1379 mcLen = #tostring(mCommand)
1380 if (mcLen == 7 or mcLen == 9) and mCommand ~= thisGate then
1381 if lcGate then
1382 if gateStatus == "Dialing" and mCommand == dialAddress then
1383 continueDialing = false
1384 gateStatus = "Paused"
1385 elseif gateStatus == "Paused" and mCommand == dialAddress then
1386 continueDialing = true
1387 if not lockChevron(chevronNumber + 1) then
1388 continueDialing = false
1389 gateStatus = "Paused"
1390 end
1391 elseif gateStatus == "Idle" then
1392 if gate.getActivatedChevrons() > 0 then hangUp() end
1393 dialAddress = mCommand
1394 continueDialing = true
1395 if not lockChevron(1) then hangUp() end
1396 end
1397 else
1398 if gateStatus == "Idle" then
1399 dialAddress = mCommand
1400 if not gate.dial(dialAddress) then dialAddress = nil end
1401 end
1402 end
1403 end
1404 end
1405 end
1406 end
1407 end
1408 end
1409 end
1410 end
1411 end
1412end
1413
1414local function charInput()
1415 while true do
1416 local _, char = os.pullEvent("char")
1417 if string.lower(char) == "q" then
1418 netSendAll("Offline")
1419 rednet.unhost("ccDialerWiFi", thisGate)
1420 if rednet.isOpen(modemSide) then rednet.close(modemSide) end
1421 term.clear()
1422 term.setCursorPos(1, 1)
1423 term.write("gateBuddy is OFFLINE")
1424 term.setCursorPos(1, 3)
1425 return
1426 end
1427 end
1428end
1429
1430local function dataPoller()
1431 local _, timer
1432 while true do
1433 _, timer = os.pullEvent("timer")
1434 if timer == pingTimer then
1435 if clientCount > 0 then
1436 for id, timeout in pairs(clients) do
1437 clients[id] = timeout + 1
1438 if clients[id] > 2 then
1439 clients[id] = nil
1440 clientCount = math.max(0, clientCount - 1)
1441 else
1442 netSend(id, "ping")
1443 end
1444 end
1445 end
1446 pingTimer = os.startTimer(5)
1447 end
1448 end
1449end
1450
1451local function initError(device)
1452 term.clear()
1453 term.setCursorPos(1, 1)
1454 term.write("No " .. device .. " detected!")
1455 term.setCursorPos(1, 3)
1456 term.write("gateBuddy is OFFLINE")
1457 term.setCursorPos(1, 5)
1458end
1459
1460term.setBackgroundColor(colors.black)
1461term.setTextColor(colors.white)
1462term.clear()
1463term.setCursorPos(2, 2)
1464if pocket then error("Computer or turtle required.", 0) end
1465term.write("gateBuddy initializing...")
1466if not os.getComputerLabel() then os.setComputerLabel("gateBuddy.cc#" .. thisCC) end
1467gate = peripheral.find("stargate")
1468if not gate then
1469 lcGate = true
1470 gate = peripheral.find("StargateBase")
1471 if gate and not gate.isValid() then gate = nil end
1472end
1473if not gate then return initError("STARGATE") end
1474thisGate = lcGate and gate.getStargateAddressString() or gate.localAddress()
1475local irisStatus
1476if lcGate then
1477 local glyphs = gate.getActivatedGlyphs() --# returns a string
1478 local chevs = gate.getActivatedChevrons() --# returns a number
1479 if glyphs and chevs > 0 then --# this can be confused - if the gate is hanging up, there will be chevrons encoded, but the status is "Disconnecting" not "Dialing"
1480 dialAddress = chevs == 9 and glyphs or glyphs .. string.rep("?", 9 - chevs)
1481 gateStatus = chevs == 9 and "Connected" or "Dialing"
1482 chevronNumber = chevs
1483 callDirection = "Unknown"
1484 else
1485 gateStatus = "Idle"
1486 callDirection = "none"
1487 end
1488 irisStatus = gate.getIrisState()
1489 irisState = irisStatus == "CLOSED"
1490else
1491 local gateState
1492 gateState, chevronNumber, callDirection = gate.stargateState()
1493 if gateState == "Offline" then return initError("STARGATE") end
1494 gateStatus = sgStates[gateState] or "Unknown"
1495 if gateStatus ~= "Idle" then dialAddress = gate.remoteAddress() end
1496 irisStatus = gate.irisState()
1497 irisState = irisStatus == "Closed"
1498end
1499for _, side in pairs(rs.getSides()) do
1500 if peripheral.isPresent(side) and peripheral.getType(side) == "modem" and peripheral.call(side, "isWireless") then
1501 modemSide = side
1502 rednet.open(side)
1503 rednet.host("ccDialerWiFi", thisGate)
1504 break
1505 end
1506end
1507if modemSide == "none" then return initError("WIRELESS MODEM") end
1508if tArgs[1] then
1509 for i = 1, #tArgs do
1510 if tArgs[i] == "log" then
1511 logging = true
1512 elseif tArgs[i] == "iris" and irisStatus ~= "Offline" and irisStatus ~= "NONE" then
1513 allowIrisClose = true
1514 end
1515 end
1516end
1517pingTimer = os.startTimer(5)
1518term.clear()
1519term.setCursorPos(2, 2)
1520term.write("gateBuddy " .. gbVer .. " is ONLINE")
1521term.setCursorPos(2, 5)
1522term.write("Local / Target: " .. thisGate .. " / " .. (dialAddress or "none"))
1523term.setCursorPos(2, 7)
1524term.write("Gate State: ")
1525term.write(gateStatus .. " " .. ((gateStatus == "Dialing" or gateStatus == "Connected") and callDirection or " "))
1526term.setCursorPos(2, 9)
1527term.write("Iris State: " .. (irisState and "Closed" or "Open"))
1528term.setCursorPos(2, 12)
1529term.write("press 'q' to quit")
1530if lcGate then
1531 parallel.waitForAny(gateReceive, netReceive, lcGateMonitor, lcIrisMonitor, charInput, dataPoller) --incomingCall, outgoingCall,
1532else
1533 parallel.waitForAny(gateReceive, netReceive, sgGateMonitor, sgIrisMonitor, incomingCall, outgoingCall, charInput, dataPoller)
1534end