· 6 years ago · Jan 12, 2020, 11:26 AM
1--[[
2 ------------------------------------------------------------------------------------------------------------------
3 ------------------------------------------------------------------------------------------------------------------
4 ------------------------------------------------------------------------------------------------------------------
5 Daft Encrypted-Frequency Transmission (DEFT) Protocol
6
7 Somewhat speedy secure transmission. Not guranteed to be secure, but sure-as-hell more secure than
8 transmit-over-wire!
9
10 Remarks:
11
12 I currently do not have an implementation of a cryptographically secure random number generator. That is the
13 next task, although I do not believe it is neccessary for the time being.
14
15 ------------------------------------------------------------------------------------------------------------------
16 ------------------------------------------------------------------------------------------------------------------
17 ------------------------------------------------------------------------------------------------------------------
18--]]
19
20-- Download dependency from pastebin if not present.
21local aesLoaded = os.loadAPI("aeslua")
22if not aesLoaded then
23 print("AES Lib not found, downloading from pastebin!")
24 shell.run("pastebin","run","LYAxmSby", "get", "86925e07cbabd70773e53d781bd8b2fe/aeslua.min.lua", "aeslua")
25 os.loadAPI("aeslua")
26end
27
28local PROTOCOL_VERSION = "1.0"
29
30--[[
31 ------------------------------------------------------------------------------------------------------------------
32 Embedded Dependency: Base64 Encoder
33
34 Lua for Java has a bug where characters with a byte code of above 127 will be corrupted or lost. This is bad when you
35 are working with AES, which generates such characters. This library
36 ------------------------------------------------------------------------------------------------------------------
37--]]
38
39-- character table string
40local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
41
42-- encoding
43function enc(data)
44 return ((data:gsub('.', function(x)
45 local r,b='',x:byte()
46 for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
47 return r;
48 end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
49 if (#x < 6) then return '' end
50 local c=0
51 for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
52 return b:sub(c+1,c+1)
53 end)..({ '', '==', '=' })[#data%3+1])
54end
55
56-- decoding
57function dec(data)
58 data = string.gsub(data, '[^'..b..'=]', '')
59 return (data:gsub('.', function(x)
60 if (x == '=') then return '' end
61 local r,f='',(b:find(x)-1)
62 for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
63 return r;
64 end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
65 if (#x ~= 8) then return '' end
66 local c=0
67 for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
68 return string.char(c)
69 end))
70end
71
72--[[
73 ------------------------------------------------------------------------------------------------------------------
74 Queue
75
76 Represents a simple FIFO (first-in first-out) queue
77 ------------------------------------------------------------------------------------------------------------------
78--]]
79Queue = {}
80Queue.__index = Queue
81
82--[[
83 Constructor
84--]]
85function Queue:new()
86 local queue = {}
87 setmetatable(queue, Queue)
88
89 -- initialize values here!
90 queue.table = {}
91
92 return queue
93end
94
95--[[
96 Queue:Enqueue
97
98 Enqueues the item into the queue.
99--]]
100function Queue:enqueue(item)
101 table.insert(self.table, item)
102end
103
104--[[
105 Queue:getCount
106
107 Returns the amount of elements in the queue.
108--]]
109function Queue:getCount()
110 return #(self.table)
111end
112
113--[[
114 Queue:GetElementTable
115
116 Returns a copy of the internal table
117--]]
118function Queue:toTable()
119 local copy = {}
120 for i, v in ipairs(self.table) do
121 copy[i] = v
122 end
123
124 return copy
125end
126
127--[[
128 Queue:Dequeue
129
130 Returns the next item in the queue and removes it from the queue. Returns nil if the queue is empty.
131--]]
132function Queue:dequeue()
133 if self:getCount() == 0 then return nil end
134
135 -- Get and remove
136 local returnedValue = self.table[1]
137 table.remove(self.table, 1)
138 return returnedValue
139end
140
141--[[
142 Queue:Peek
143
144 Returns the next item in the queue without removing it from the queue. Returns nil if the queue is empty.
145--]]
146function Queue:peek()
147 if self:getCount() == 0 then return nil end
148 return self.table[1] -- Zeroth element in other languages
149end
150
151--[[
152 ------------------------------------------------------------------------------------------------------------------
153 DaftCryptoUtils
154
155 DaftCrypto contains many useful functions for encryption, shared secret exchanges, and generating prime numbers.
156
157 TODO: Implement a better way to find primitive roots for the Diffie-Hellman stage. Right now, we use any old parameter
158 for generator g. This provides soundness (message integrity) but not security (gives a few bits of the exponent away
159 to a potential attacker.)
160 ------------------------------------------------------------------------------------------------------------------
161--]]
162
163DaftCryptoUtils = {}
164
165-- Exponent-mod composite function to prevent overflows when calculating base^exponent mod m
166-- Implementation of Bruce Schneier's pseudocode for the right-to-left method on Wikipedia.
167function DaftCryptoUtils.modExponent(base, exponent, mod)
168 if mod == 1 then
169 return 0
170 else
171 local returnValue = 1
172 base = base % mod
173 while exponent > 0 do
174 if exponent % 2 == 1 then
175 returnValue = (returnValue*base) % mod
176 end
177 exponent = bit.brshift(exponent, 1)
178 base = (base^2) % mod
179 end
180 return returnValue
181 end
182end
183
184-- Calculates a random prime
185function DaftCryptoUtils.calculateRandomPrime(min, max)
186 while true do
187 local randNumb = math.random(min, max)
188
189 if (randNumb % 2) == 0 then randNumb = randNumb - 1 end
190
191 --print("attempting "..randNumb)
192 if DaftCryptoUtils.fermatsLittleTheorem(randNumb, 20) then
193 return randNumb
194 end
195 end
196end
197
198--[[
199 An implementation of Fermat's little theorem for verifying a prime.
200--]]
201function DaftCryptoUtils.fermatsLittleTheorem(number, iterations)
202
203 -- With 20 iterations there is a one in a million chance of a false positive.
204 for i=1, iterations do
205 local a = math.random(1, number-1)
206 local e = DaftCryptoUtils.modExponent(a, number-1, number)
207
208 -- Theorem says composite numbers will most likely return ~= -1.
209 if e ~= 1 then
210 return false
211 end
212 end
213
214 return true
215end
216
217--[[
218 Calculates whether root is a primitive root of number. True if primitive root, false otherwise.
219 Assumes number is prime.
220
221 Remarks: Inefficient but it will do.
222--]]
223function DaftCryptoUtils.isPrimitiveRoot(root, number)
224
225 -- Create list of numbers required in order to fit definition
226 local moduloOutcomesToFind = number-1
227 local modsFound = {}
228
229 for i=1, number-1 do
230 modsFound[i] = false
231 end
232
233 -- Run through each number option
234 for i=0, number-1 do
235 local mod = DaftCryptoUtils.modExponent(root, i, number)
236
237 --print("iteration "..i)
238
239 if (i%10000) == 0 then
240 os.sleep()
241 end
242
243 -- If such a mod was not already found, add it to the list of ones we found.
244 if modsFound[mod] == false then
245 moduloOutcomesToFind = moduloOutcomesToFind - 1
246 modsFound[mod] = true
247
248 -- If we have no more to find, we are done! Return true!
249 if moduloOutcomesToFind == 0 then
250 return true
251 end
252 end
253 end
254
255 return moduloOutcomesToFind == 0
256end
257
258--[[
259 Implements Euclid's Algorithm for finding the Greatest Common Factor
260 returns the greatest common factor.
261--]]
262function DaftCryptoUtils.greatestCommonDenominator(a, b)
263 while b > 0 do
264 local c = a % b
265 a = b
266 b = c
267 end
268
269 return a
270end
271
272--[[
273
274 prime: The prime base
275 generator: A prime exponent (DOES NOT HAVE TO BE A GENERATOR; BUT IT IS MORE SECURE THAT WAY)
276 privateKey: Any number that represents the private key.
277--]]
278function DaftCryptoUtils.dhCalculatePublicKey(prime, generator, privateKey)
279 return DaftCryptoUtils.modExponent(generator, privateKey, prime)
280end
281
282--[[
283 prime: The prime base
284 generator: A prime exponent (DOES NOT HAVE TO BE A GENERATOR; BUT IT IS MORE SECURE THAT WAY)
285 remotePublicKey: The remote public key calculated by the person we want to talk to.
286--]]
287function DaftCryptoUtils.dhCalculateSharedSecret(prime, localPrivateKey, remotePublicKey)
288 return DaftCryptoUtils.modExponent(remotePublicKey, localPrivateKey, prime)
289end
290
291
292--[[
293 ------------------------------------------------------------------------------------------------------------------
294 DeftCommunicator
295
296 DeftCommunicator is used to send and receive messages using the DEFT security protocol.
297 The DeftCommunicator will setup encrypted connections before any messages are sent.
298
299 ------------------------------------------------------------------------------------------------------------------
300
301 {{ PROTOCOL PACKET STRUCTURE }}
302
303 {
304 [1] = packetId,
305 [2] = packet
306
307 }
308
309 {{ PROTOCOL PACKET TYPES }}
310
311 ID: 0
312 TYPE: CONNECTION_ESTABLISH
313 ENCRYPTED: NO
314 PAYLOAD:
315 {
316 0: string version: The version of the protocol being used.
317 }
318 DESCRIPTION: Sent by a client to a server to make a new connection.
319
320 ID: 1
321 TYPE: HANDSHAKE_SERVERHANDSHAKE
322 ENCRYPTED: NO
323 PAYLOAD:
324 {
325 0: int prime: The random DH prime
326 1: int generator: The random DH generator
327 2: int serverPublicKey: The server's exchanged public key.
328 }
329 DESCRIPTION: After receiving a CONNECTION_ESTABLISH packet, the server will send
330 this packet to the client. The client can calculate their private key and the shared
331 secret from this information.
332
333 ID: 2
334 TYPE: HANDSHAKE_CLIENTHANDSHAKE
335 ENCRYPTED: NO
336 PAYLOAD:
337 {
338 0: int clientPublicKey
339 }
340 DESCRIPTION: Once the client calculates their public key, they send it back. Then, both parties calculate
341 the shared secret.
342
343 ID: 3
344 TYPE: HANDSHAKE_SERVERVERIFY
345 ENCRYPTED: YES
346 PAYLOAD:
347 {
348 0: string "The quick brown fox jumps over the lazy dog"
349 }
350 DESCRIPTION: After both parties have the shared secret calculated, the server sends an encrypted verification
351 message to the client to verify the integrity of the shared secret. If the client can decrypt the packet, they
352 send a HANDSHAKE_CLIENTVERIFY packet.
353
354 ID: 4
355 TYPE: HANDSHAKE_CLIENTVERIFY
356 ENCRYPTED: NO
357 PAYLOAD:
358 {
359 }
360 DESCRIPTION: Once the server receives this packet, the connection is considered established.
361
362 ID: 5
363 TYPE: ACK
364 ENCRYPTED: NO
365 PAYLOAD:
366 {
367 }
368 DESCRIPTION: A dummy packet sent by either party to prevent a network connection timeout.
369
370 ID: 6
371 TYPE: DISCONNECT
372 ENCRYPTED: NO
373 PAYLOAD:
374 {
375 }
376 DESCRIPTION: A dummy packet sent by either party to close the connection.
377
378 ID: 255
379 TYPE: MESSAGE
380 ENCRYPTED: YES
381 PAYLOAD:
382 {
383 string encryptedMessage: The encrypted message. Uses textutils.serialize() and then the given encryption cipher to encrypt.
384 }
385 DESCRIPTION:
386
387 ------------------------------------------------------------------------------------------------------------------
388--]]
389
390--[[
391 ------------------------------------------------------------------------------------------------------------------
392 DeftConnection
393
394 Represents a single connection using the DEFT security protocol.
395 ------------------------------------------------------------------------------------------------------------------
396--]]
397
398
399DeftCommunicator = {}
400DeftCommunicator.__index = DeftCommunicator
401
402--[[
403 Constructor
404--]]
405function DeftCommunicator:new(side)
406 local deftCommunicator = {}
407 setmetatable(deftCommunicator, DeftCommunicator)
408
409 -- Open rednet channel
410 rednet.open(side)
411
412 -- Initialize values here!
413 deftCommunicator.protocolVersion = PROTOCOL_VERSION
414 deftCommunicator.isDebug = false
415 deftCommunicator.connections = {} -- Key: senderId. Value: deftConnection
416
417 -- Connection ids added to this table will be closed when the current process loop is done.
418 deftCommunicator.connectionsToClose = {}
419
420 return deftCommunicator
421end
422
423--[[
424 Processes the next receive and next send commands.
425--]]
426function DeftCommunicator:process()
427 while true do
428
429 -- Get the next received message
430 local remoteId, packet, protocol = rednet.receive(.5)
431 if remoteId ~= nil and protocol == "DEFT" then -- Received message AND is of DEFT protocol.
432 -- Only process correctly-formatted packets.
433 if packet[1] ~= nil and packet[2] ~= nil then
434 -- Extract packed id and payload
435 local packetId = packet[1]
436 local packetPayload = packet[2]
437
438 -- Connection exists
439 if self:hasCommunicatorForId(remoteId) then -- Sent to a connection
440 self.connections[remoteId]:passReceivedPacket(packet)
441 elseif packetId == 0 then -- Is a CONNECTION_ESTABLISH packet
442 self:accept(remoteId)
443 end
444 end
445 end
446
447 -- After yielding to receive messages, process individual communicators and send their packets.
448 for _, connection in pairs(self.connections) do
449
450 -- Send messages in queue.
451 while connection.sendQueue:peek() ~= nil do
452
453 local packet = connection.sendQueue:dequeue()
454 rednet.send(connection.remoteId, packet, "DEFT")
455
456 end
457
458 connection:process() -- Process their received messages
459 end
460
461 -- Close any connections that need to be closed.
462 for _, connection in ipairs(self.connectionsToClose) do
463 self.connections[connection] = nil
464 end
465 while #self.connectionsToClose > 0 do
466 table.remove(self.connectionsToClose, 1)
467 end
468 end
469end
470
471--[[
472 Accepts an incoming connection and creates a connection object for them.
473--]]
474function DeftCommunicator:accept(remoteId)
475 local acceptedConnection = DeftConnection:new(self, remoteId, true)
476 self.connections[remoteId] = acceptedConnection
477 print("Accepted new connection to "..remoteId)
478 acceptedConnection:enqueueServerHandshake()
479end
480
481--[[
482 Returns true if a communicator exists for the given remote id.
483--]]
484function DeftCommunicator:hasCommunicatorForId(remoteId)
485 return self.connections[remoteId] ~= nil
486end
487
488--[[
489 Attempts to connect to the given id.
490--]]
491function DeftCommunicator:connect(computerId)
492 local newConnection = DeftConnection:new(self, computerId, false)
493 self.connections[computerId] = newConnection
494 print("Connecting...")
495 newConnection:enqueueConnectionEstablishPacket()
496end
497
498--[[
499 Reports the connection as dead and removes it from the communicator's table.
500--]]
501function DeftCommunicator:finishDisconnect(remoteId)
502 if self:hasCommunicatorForId(remoteId) then
503 table.insert(self.connectionsToClose, remoteId)
504 end
505end
506
507--[[
508 ------------------------------------------------------------------------------------------------------------------
509 DeftConnection
510
511 Represents a single connection
512
513 ------------------------------------------------------------------------------------------------------------------
514]]
515
516DeftConnection = {}
517DeftConnection.__index = DeftConnection
518
519--[[
520 Constructor
521--]]
522function DeftConnection:new(deftCommunicator, remoteId, isServer)
523 -- Create Object
524 local deftConnection = {}
525 setmetatable(deftConnection, DeftConnection)
526
527 -- Parent deftCommunicator
528 deftConnection.communicator = deftCommunicator
529
530 -- Inner Connection Info
531 deftConnection.protocolVersion = PROTOCOL_VERSION -- The version of the protocol.
532 deftConnection.remoteId = remoteId -- Who we are communicating with.
533 deftConnection.isDebug = false
534 deftConnection.connectionState = 0 -- 0: Connecting, 1: Handshake, 2: Verifying, 3: Connected, 4: Disconnected
535 deftConnection.isServer = isServer
536
537 -- Cryptographic handshake
538 deftConnection.dhPrime = -1
539 deftConnection.dhGenerator = -1
540 deftConnection.dhLocalPrivateKey = math.random(1000000)
541 deftConnection.dhLocalPublicKey = -1
542 deftConnection.dhRemotePublicKey = -1
543 deftConnection.dhSharedSecret = -1
544
545 if isServer then
546 deftConnection.connectionState = 1
547
548 -- Server always picks prime / generator combo.
549 deftConnection.dhPrime = DaftCryptoUtils.calculateRandomPrime(1000000, 9999999)
550 local generatorPick = math.random(0,2)
551 if generatorPick == 0 then
552 deftConnection.dhGenerator = 5
553 elseif generatorPick == 1 then
554 deftConnection.dhGenerator = 7
555 elseif generatorPick == 2 then
556 deftConnection.dhGenerator = 11
557 end
558
559 -- Server can also calculate public key at this point
560 deftConnection.dhLocalPublicKey = DaftCryptoUtils.dhCalculatePublicKey(deftConnection.dhPrime, deftConnection.dhGenerator, deftConnection.dhLocalPrivateKey)
561 end
562
563 -- Timers
564 deftConnection.connectionTimeOut = 10
565 deftConnection.lastMessageReceived = os.clock()
566
567 deftConnection.ackInterval = 2
568 deftConnection.lastAckSent = os.clock()
569
570 -- Queues
571 deftConnection.sendQueue = Queue:new() -- Queue for sending off new messages
572 deftConnection.receiveQueue = Queue:new() -- When messages are received, the decrypted payload will be added into here.
573
574 return deftConnection
575end
576
577
578--[[
579 checkTimeOut
580
581 Operates the network timeout. If a DeftConnection does not receive a packet
582 bool resetToCurrentTime: If true, resets the timer even if the timeout was exceeded.
583 Always returns true in this case.
584--]]
585function DeftConnection:checkTimeOut(resetToCurrentTime)
586 if resetToCurrentTime then
587 self.lastMessageReceived = os.clock()
588 return true
589 end
590
591 return (os.clock() - self.lastMessageReceived) > self.connectionTimeOut
592end
593
594-- Returns true if enough time has elapsed to send an ACK packet, false otherwise.
595function DeftConnection:shouldSendAckPacket()
596 if self.connectionState == 4 then
597 return false
598 end
599
600 return (os.clock() - self.lastAckSent) > self.ackInterval
601end
602
603--[[
604 Forcefully closes a DeftConnection.
605--]]
606function DeftConnection:disconnect()
607 self:enqueueDisconnect()
608 self.communicator:finishDisconnect(self.remoteId)
609end
610
611--[[
612 Fired by the DeftCommunicator on a set time interval. Processes the current state of
613 the handshake, sending ack/alive packets, and more.
614--]]
615function DeftConnection:process()
616 -- Send Queue is fired by the DeftCommunicator.
617
618 --self:debugLog("Output: "..textutils.serialize(self))
619
620 -- Process received messages. A shitty state machine.
621 while self.receiveQueue:peek() ~= nil do
622 self:checkTimeOut(true) -- As long as we receive SOMETHING, we cannot time out.
623
624 -- Capture packet contents.
625 local packet = self.receiveQueue:dequeue()
626 local packetId = packet[1]
627 local payload = packet[2]
628
629 -- If it is a disconnect packet, we will disconnect.
630 if packetId == 6 then
631 self:debugLog("Disconnecting due to remote host shutting down.")
632 self.deftCommunicator:finishDisconnect(self.remoteId)
633 connectionState = 4
634 end
635
636 if packetId == 5 then
637 self:debugLog("Ack Received!")
638 end
639
640 -- Connection State 0 is handled by the communicator for both client and server connections.
641
642 -- Shitty State Machine that controls the communication of the handshake.
643 if self.connectionState == 1 and self.isServer then
644
645 -- HANDSHAKE_CLIENTHANDSHAKE
646 if packetId == 2 then
647
648 if payload[1] ~= nil and type(payload[1]) == "number" then -- Defensive coding.
649
650 self:debugLog("HANDSHAKE_CLIENTHANDSHAKE, Remote Public Key: "..self.dhRemotePublicKey)
651
652 self.dhRemotePublicKey = payload[1]
653 self.dhSharedSecret = DaftCryptoUtils.dhCalculateSharedSecret(self.dhPrime, self.dhLocalPrivateKey, self.dhRemotePublicKey)
654
655 self:debugLog("Calculated shared secret as "..self.dhSharedSecret)
656
657 self:enqueueServerVerify()
658
659 self.connectionState = 2
660 end
661 end
662
663 elseif self.connectionState == 0 and not self.isServer then
664
665 -- HANDSHAKE_SERVERHANDSHAKE
666 if packetId == 1 then
667
668 if payload[1] ~= nil and type(payload[1]) == "number" and
669 payload[2] ~= nil and type(payload[2]) == "number" and
670 payload[3] ~= nil and type(payload[3]) == "number" then -- Defensive coding.
671
672 self.connectionState = 1
673
674 self:debugLog("HANDSHAKE_SERVERHANDSHAKE, prime: "..payload[1]..", gen: "..payload[2]..", remotePublicKey: "..payload[3])
675
676 -- Store DH exchange values
677 self.dhPrime = payload[1]
678 self.dhGenerator = payload[2]
679 self.dhRemotePublicKey = payload[3]
680
681 -- Calculate our public key, shared secret, and then transmit the public key.
682 self.dhLocalPublicKey = DaftCryptoUtils.dhCalculatePublicKey(self.dhPrime, self.dhGenerator, self.dhLocalPrivateKey)
683 self.dhSharedSecret = DaftCryptoUtils.dhCalculateSharedSecret(self.dhPrime, self.dhLocalPrivateKey, self.dhRemotePublicKey)
684
685 self:debugLog("Calculated shared secret as "..self.dhSharedSecret)
686
687 self:enqueueClientHandshake()
688
689 self.connectionState = 2
690 end
691 end
692
693 elseif self.connectionState == 2 and self.isServer then
694
695 if packetId == 4 then -- HANDSHAKE_CLIENTVERIFY
696 self:debugLog("HANDSHAKE_CLIENTVERIFY")
697 self.connectionState = 3
698 self:debugLog("Connected!")
699 end
700
701 elseif self.connectionState == 2 and not self.isServer then
702
703 if packetId == 3 then -- HANDSHAKE_SERVERVERIFY
704
705 if payload[1] ~= nil and type(payload[1]) == "string" then
706
707 payload[1] = dec(payload[1])
708
709 self:debugLog("HANDSHAKE_SERVERVERIFY: Checking "..payload[1])
710
711 local decryptedText = aeslua.decrypt(tostring(self.dhSharedSecret), payload[1])
712
713 self:debugLog("HANDSHAKE_SERVERVERIFY: Decrypted as "..tostring(decryptedText))
714
715 if decryptedText == "The quick brown fox jumped over the lazy dog." then -- This is the test to verify whether the secret is synchronized.
716 self:enqueueClientVerify()
717 self.connectionState = 3
718 self:debugLog("HANDSHAKE_SERVERVERIFY: Verify Success!")
719 else
720 self:debugLog("HANDSHAKE_SERVERVERIFY: Verify Failure!")
721 self:disconnect() -- Failed.
722 end
723 end
724
725 end
726
727 elseif self.connectionState == 3 then
728
729 end
730 end
731
732 -- Is it time to send ACK packets? Then we will send ACK packets.
733 if self:shouldSendAckPacket() then
734 self:enqueueAck()
735 end
736
737 -- If we are going to timeout, please do.
738 if self:checkTimeOut(false) then
739 self.connectionState = 4
740 self:debugLog("Disconnecting due to timeout.")
741 self:disconnect()
742 end
743end
744
745--[[
746 enqueueConnectionEstablishPacket
747
748 Enqueues the protocol-specific CONNECTION_ESTABLISH to the send queue.
749--]]
750function DeftConnection:enqueueConnectionEstablishPacket()
751 self.sendQueue:enqueue(
752 {
753 0, -- ID
754 {
755 self.protocolVersion
756 }
757 }
758 )
759end
760
761--[[
762 enqueueServerHandshake
763
764 Enqueues the protocol-specific HANDSHAKE_SERVERHANDSHAKE to the send queue.
765--]]
766function DeftConnection:enqueueServerHandshake()
767 self.sendQueue:enqueue(
768 {
769 1, -- ID
770 {
771 self.dhPrime,
772 self.dhGenerator,
773 self.dhLocalPublicKey
774 }
775 }
776 )
777end
778
779--[[
780 enqueueClientHandshake
781
782 Enqueues the protocol-specific HANDSHAKE_CLIENTHANDSHAKE to the send queue.
783--]]
784function DeftConnection:enqueueClientHandshake()
785 self.sendQueue:enqueue(
786 {
787 2, -- ID
788 {
789 self.dhLocalPublicKey
790 }
791 }
792 )
793end
794
795--[[
796 enqueueServerVerify
797
798 Enqueues the protocol-specific HANDSHAKE_SERVERVERIFY to the send queue.
799--]]
800function DeftConnection:enqueueServerVerify()
801 self.sendQueue:enqueue(
802 {
803 3, -- ID
804 {
805 enc(aeslua.encrypt(tostring(self.dhSharedSecret), "The quick brown fox jumped over the lazy dog."))
806 }
807 }
808 )
809end
810
811--[[
812 enqueueClientVerify
813
814 Enquerues the protocol-specific HANDSHAKE_CLIENTVERIFY to the send queue.
815--]]
816function DeftConnection:enqueueClientVerify()
817 self.sendQueue:enqueue(
818 {
819 4, -- ID
820 {
821 }
822 }
823 )
824end
825
826--[[
827 enqueueAck
828
829 Enqueues the protocol-specific ACK to the send queue.
830--]]
831function DeftConnection:enqueueAck()
832 self.lastAckSent = os.clock()
833 self.sendQueue:enqueue(
834 {
835 5, -- ID
836 {
837 }
838 }
839 )
840end
841
842--[[
843 Sent by either party to close the connection. You can include an optional reason
844 for the logs.
845--]]
846function DeftConnection:enqueueDisconnect(reason)
847 self.sendQueue:enqueue(
848 {
849 6, -- ID
850 {
851 }
852 }
853 )
854end
855
856--[[
857 Returns the connection state as a string.
858
859--]]
860function DeftConnection:getConnectionStateAsString()
861 if self.connectionState == 0 then
862 return "Connecting"
863 elseif self.connectionState == 1 then
864 return "Handshake"
865 elseif self.connectionState == 2 then
866 return "Verify"
867 elseif self.connectionState == 3 then
868 return "Connected"
869 elseif self.connectionState == 4 then
870 return "Disconnected"
871 end
872end
873
874--[[
875 Passes the received packet from the DeftCommunicator to the specific connection.
876 Resets the timeout timer.
877--]]
878function DeftConnection:passReceivedPacket(packet)
879 self.receiveQueue:enqueue(packet)
880 self.lastMessageReceived = os.clock()
881end
882
883function DeftConnection:debugLog(msg)
884 if self.isDebug then print("CONNECTION w/"..self.remoteId..": "..msg.." ("..self:getConnectionStateAsString()..")") end
885end
886
887
888
889--local prime = 1000003
890--print(DaftCryptoUtils.fermatsLittleTheorem(prime, 20))
891
892--os.sleep(5)
893--[[
894print("Selecting prime and generator...")
895local sharedPrime = DaftCryptoUtils.calculateRandomPrime(100000,999999)
896local sharedGenerator = DaftCryptoUtils.calculateRandomPrime(1000,math.floor(sharedPrime/2))
897
898local bobKey = math.random(100000,999999)
899local aliceKey = math.random(100000,999999)
900
901print("Shared prime: "..tostring(sharedPrime))
902print("Shared generator: "..tostring(sharedGenerator))
903
904print("bobPrivateKey: "..bobKey)
905print("alicePrivateKey: "..aliceKey)
906
907local bobPublicKey = DaftCryptoUtils.dhCalculatePublicKey(sharedPrime, sharedGenerator, bobKey)
908local alicePublicKey = DaftCryptoUtils.dhCalculatePublicKey(sharedPrime, sharedGenerator, aliceKey)
909
910print("bobPublicKey:"..bobPublicKey)
911print("alicePublicKey: "..alicePublicKey)
912
913print("Sharing keys...")
914
915print("Using public keys to find shared secret...")
916local bobSharedSecret = DaftCryptoUtils.dhCalculateSharedSecret(sharedPrime, bobKey, alicePublicKey)
917local aliceSharedSecret = DaftCryptoUtils.dhCalculateSharedSecret(sharedPrime, aliceKey, bobPublicKey)
918
919print("bobSharedSecret: "..bobSharedSecret)
920print("aliceSharedSecret: "..aliceSharedSecret)
921]]
922
923
924local deftComm = DeftCommunicator:new("back")
925
926if os.getComputerID() == 0 then
927 deftComm:process()
928else
929 deftComm:connect(0)
930 deftComm:process()
931end