· 6 years ago · Sep 17, 2019, 01:44 PM
1-- CryptoNet Networking Framework by SiliconSloth
2-- Licensed under the MIT license.
3--
4-- Copyright (c) 2019 SiliconSloth
5--
6-- Permission is hereby granted, free of charge, to any person obtaining a copy
7-- of this software and associated documentation files (the "Software"), to deal
8-- in the Software without restriction, including without limitation the rights
9-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10-- copies of the Software, and to permit persons to whom the Software is
11-- furnished to do so, subject to the following conditions:
12--
13-- The above copyright notice and this permission notice shall be included in all
14-- copies or substantial portions of the Software.
15--
16-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22-- SOFTWARE.
23
24
25-- CryptoNet is a simple and secure framework for encrypted networking
26-- between ComputerCraft computers, intended to be used as an alternative to Rednet.
27-- For more information, see CryptoNet's GitHub repo at https://github.com/SiliconSloth/CryptoNet
28
29-- Line numbers:
30-- 48 Third Party
31-- 53 - SHA-256, HMAC and PBKDF2 functions in ComputerCraft by Anavrins
32-- 287 - Simple RSA Library by 1lann
33-- 1255 - RSA Key Generator by 1lann
34-- 1467 - Mersenne Twister RNG and ISAAC algorithm by KillaVanilla
35-- 1724 - AES implementation by KillaVanilla
36-- 2691 - Simple thread API by immibis
37-- 2771 CryptoNet
38-- 2800 - Accessors
39-- 2847 - Validity Checks
40-- 2952 - Helpers
41-- 3276 - Send Functions
42-- 3352 - Login System
43-- 3904 - Core Networking
44-- 4973 - Event Loop
45-- 5081 - Certificate Authority
46
47
48------- THRID PARTY -------
49-- The following code was written by thrid parties and modified by me (SiliconSloth)
50-- to integrate it into CryptoNet. (I shoved everything into tables.)
51
52
53-- SHA-256, HMAC and PBKDF2 functions in ComputerCraft
54-- By Anavrins
55-- For help and details, you can PM me on the CC forums
56-- You may use this code in your projects without asking me, as long as credit is given and this header is kept intact
57-- http://www.computercraft.info/forums2/index.php?/user/12870-anavrins
58-- http://pastebin.com/6UV4qfNF
59-- Last update: October 10, 2017
60
61-- Usage
62---- Data format
63------ Almost all arguments passed in these functions can take both a string or a special table containing a byte array.
64------ This byte array format is simply a table containing a list of each character's byte values.
65------ The phrase "hello world" will become {104,101,108,108,111, 32,119,111,114,108,100}.
66------ Any strings can be converted into it with {str:byte(1,-1)}, and back into string with string.char(unpack(arr))
67------
68------ The data returned by all functions are also in this byte array format.
69------ They are paired with a metatable containing metamethods like
70------ :toHex() to convert into the traditional hexadecimal representation.
71------ :isEqual(arr) to compare the hash with another byte array "arr" in constant time.
72------ __tostring to convert into a raw string (Might crash window api on old CC versions).
73------ This output can also be fed into my base64 function (TEtna4tX) to get a shorter hash representation.
74
75---- digest(data)
76------ The digest function is the core of this API, it simply hashes your data with the SHA256 algorithm, period.
77------ It's the function everybody is familiar with, and most likely what you're looking for.
78------ This function is mainly used for file integrity, however it is not suited for password storage by itself, use PBKDF2 instead.
79
80---- hmac(data, key)
81------ The HMAC function is used for message authentication, it's primary use is in networking apis
82------ to authenticate an encrypted message and ensuring that the data was not tempered with.
83------ The key may be a string or a byte array, with a size between 0 and 32 bytes (256-bits), having a key larger than 32 bytes will not increase security.
84------ This function *may* be used for password storage, if you choose to do so, you must pass the password as the key argument, and the salt as the data argument.
85
86---- PBKDF2(pass, salt, iter, dklen)
87------ Password-based key derivation function, returns a "dklen" bytes long array for use in various networking protocol to generate secure cryptographic keys.
88------ This is the preferred choice for password storage, it uses individual argument for password and salt, do not concatenate beforehand.
89------ This algorithm is designed to inherently slow down hashing by repeating the process many times to slow down cracking attempts.
90------ You can adjust the number of "iter" to control the speed of the algorithm, higher "iter" means slower hashing, as well as slower to crack.
91------ DO NOT TOUCH "dklen" if you're using it for passwords, simply pass nil or nothing at all (defaults to 32).
92------ Passing a dklen higher than 32 will multiply the number of iterations with no additional security whatsoever.
93
94sha256 = {}
95
96sha256.mod32 = 2^32
97sha256.band = bit32 and bit32.band or bit.band
98sha256.bnot = bit32 and bit32.bnot or bit.bnot
99sha256.bxor = bit32 and bit32.bxor or bit.bxor
100sha256.blshift = bit32 and bit32.lshift or bit.blshift
101sha256.upack = unpack
102
103sha256.rrotate = function (n, b)
104 local s = n/(2^b)
105 local f = s%1
106 return (s-f) + f*sha256.mod32
107end
108sha256.brshift = function (int, by) -- Thanks bit32 for bad rshift
109 local s = int / (2^by)
110 return s - s%1
111end
112
113sha256.H = {
114 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
115 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
116}
117
118sha256.K = {
119 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
120 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
121 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
122 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
123 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
124 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
125 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
126 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
127}
128
129sha256.counter = function (incr)
130 local t1, t2 = 0, 0
131 if 0xFFFFFFFF - t1 < incr then
132 t2 = t2 + 1
133 t1 = incr - (0xFFFFFFFF - t1) - 1
134 else t1 = t1 + incr
135 end
136 return t2, t1
137end
138
139sha256.BE_toInt = function (bs, i)
140 return sha256.blshift((bs[i] or 0), 24) + sha256.blshift((bs[i+1] or 0), 16) + sha256.blshift((bs[i+2] or 0), 8) + (bs[i+3] or 0)
141end
142
143sha256.preprocess = function (data)
144 local len = #data
145 local proc = {}
146 data[#data+1] = 0x80
147 while #data%64~=56 do data[#data+1] = 0 end
148 local blocks = math.ceil(#data/64)
149 for i = 1, blocks do
150 proc[i] = {}
151 for j = 1, 16 do
152 proc[i][j] = sha256.BE_toInt(data, 1+((i-1)*64)+((j-1)*4))
153 end
154 end
155 proc[blocks][15], proc[blocks][16] = sha256.counter(len*8)
156 return proc
157end
158
159sha256.digestblock = function (w, C)
160 for j = 17, 64 do
161 local v = w[j-15]
162 local s0 = sha256.bxor(sha256.bxor(sha256.rrotate(w[j-15], 7), sha256.rrotate(w[j-15], 18)), sha256.brshift(w[j-15], 3))
163 local s1 = sha256.bxor(sha256.bxor(sha256.rrotate(w[j-2], 17), sha256.rrotate(w[j-2], 19)), sha256.brshift(w[j-2], 10))
164 w[j] = (w[j-16] + s0 + w[j-7] + s1)%sha256.mod32
165 end
166 local a, b, c, d, e, f, g, h = sha256.upack(C)
167 for j = 1, 64 do
168 local S1 = sha256.bxor(sha256.bxor(sha256.rrotate(e, 6), sha256.rrotate(e, 11)), sha256.rrotate(e, 25))
169 local ch = sha256.bxor(sha256.band(e, f), sha256.band(sha256.bnot(e), g))
170 local temp1 = (h + S1 + ch + sha256.K[j] + w[j])%sha256.mod32
171 local S0 = sha256.bxor(sha256.bxor(sha256.rrotate(a, 2), sha256.rrotate(a, 13)), sha256.rrotate(a, 22))
172 local maj = sha256.bxor(sha256.bxor(sha256.band(a, b), sha256.band(a, c)), sha256.band(b, c))
173 local temp2 = (S0 + maj)%sha256.mod32
174 h, g, f, e, d, c, b, a = g, f, e, (d+temp1)%sha256.mod32, c, b, a, (temp1+temp2)%sha256.mod32
175 end
176 C[1] = (C[1] + a)%sha256.mod32
177 C[2] = (C[2] + b)%sha256.mod32
178 C[3] = (C[3] + c)%sha256.mod32
179 C[4] = (C[4] + d)%sha256.mod32
180 C[5] = (C[5] + e)%sha256.mod32
181 C[6] = (C[6] + f)%sha256.mod32
182 C[7] = (C[7] + g)%sha256.mod32
183 C[8] = (C[8] + h)%sha256.mod32
184 return C
185end
186
187sha256.mt = {
188 __tostring = function(a) return string.char(unpack(a)) end,
189 __index = {
190 toHex = function(self, s) return ("%02x"):rep(#self):format(unpack(self)) end,
191 isEqual = function(self, t)
192 if type(t) ~= "table" then return false end
193 if #self ~= #t then return false end
194 local ret = 0
195 for i = 1, #self do
196 ret = bit32.bor(ret, sha256.bxor(self[i], t[i]))
197 end
198 return ret == 0
199 end
200 }
201}
202
203sha256.toBytes = function (t, n)
204 local b = {}
205 for i = 1, n do
206 b[(i-1)*4+1] = sha256.band(sha256.brshift(t[i], 24), 0xFF)
207 b[(i-1)*4+2] = sha256.band(sha256.brshift(t[i], 16), 0xFF)
208 b[(i-1)*4+3] = sha256.band(sha256.brshift(t[i], 8), 0xFF)
209 b[(i-1)*4+4] = sha256.band(t[i], 0xFF)
210 end
211 return setmetatable(b, sha256.mt)
212end
213
214sha256.digest = function (data)
215 data = data or ""
216 data = type(data) == "string" and {data:byte(1,-1)} or data
217
218 data = sha256.preprocess(data)
219 local C = {sha256.upack(sha256.H)}
220 for i = 1, #data do C = sha256.digestblock(data[i], C) end
221 return sha256.toBytes(C, 8)
222end
223
224sha256.hmac = function (data, key)
225 local data = type(data) == "table" and {sha256.upack(data)} or {tostring(data):byte(1,-1)}
226 local key = type(key) == "table" and {sha256.upack(key)} or {tostring(key):byte(1,-1)}
227
228 local blocksize = 64
229
230 key = #key > blocksize and sha256.digest(key) or key
231
232 local ipad = {}
233 local opad = {}
234 local padded_key = {}
235
236 for i = 1, blocksize do
237 ipad[i] = sha256.bxor(0x36, key[i] or 0)
238 opad[i] = sha256.bxor(0x5C, key[i] or 0)
239 end
240
241 for i = 1, #data do
242 ipad[blocksize+i] = data[i]
243 end
244
245 ipad = sha256.digest(ipad)
246
247 for i = 1, blocksize do
248 padded_key[i] = opad[i]
249 padded_key[blocksize+i] = ipad[i]
250 end
251
252 return sha256.digest(padded_key)
253end
254
255sha256.pbkdf2 = function (pass, salt, iter, dklen)
256 local salt = type(salt) == "table" and salt or {tostring(salt):byte(1,-1)}
257 local hashlen = 32
258 local dklen = dklen or 32
259 local block = 1
260 local out = {}
261
262 while dklen > 0 do
263 local ikey = {}
264 local isalt = {sha256.upack(salt)}
265 local clen = dklen > hashlen and hashlen or dklen
266
267 isalt[#isalt+1] = sha256.band(sha256.brshift(block, 24), 0xFF)
268 isalt[#isalt+1] = sha256.band(sha256.brshift(block, 16), 0xFF)
269 isalt[#isalt+1] = sha256.band(sha256.brshift(block, 8), 0xFF)
270 isalt[#isalt+1] = sha256.band(block, 0xFF)
271
272 for j = 1, iter do
273 isalt = sha256.hmac(isalt, pass)
274 for k = 1, clen do ikey[k] = sha256.bxor(isalt[k], ikey[k] or 0) end
275 if j % 200 == 0 then os.queueEvent("PBKDF2", j) coroutine.yield("PBKDF2") end
276 end
277 dklen = dklen - clen
278 block = block+1
279 for k = 1, clen do out[#out+1] = ikey[k] end
280 end
281
282 return setmetatable(out, sha256.mt)
283end
284
285
286--
287-- Licenses for Simple RSA Library by 1lann
288--
289-- This RSA library should not be used for real-life purposes.
290-- It is here to demonstrate a pure Lua implementation of RSA
291-- for educational purposes. This RSA library is in no way
292-- secure and does not endorse use of this library for any
293-- actual security purposes.
294--
295-- Copyright (c) 2015 Jason Chu (1lann)
296--
297-- Permission to use, copy, modify, and distribute this software for any
298-- purpose with or without fee is hereby granted, provided that the above
299-- copyright notice and this permission notice appear in all copies.
300--
301-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
302-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
303-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
304-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
305-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
306-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
307-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
308--
309
310--
311-- Big Integer Library, copyright as follows.
312--
313-- Copyright (c) 2010 Ted Unangst <ted.unangst@gmail.com>
314--
315-- Permission to use, copy, modify, and distribute this software for any
316-- purpose with or without fee is hereby granted, provided that the above
317-- copyright notice and this permission notice appear in all copies.
318--
319-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
320-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
321-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
322-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
323-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
324-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
325-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
326--
327
328--
329-- Lua version ported/copied from the C version of the Big Integer Library, copyright as follows.
330--
331-- Copyright (c) 2000 by Jef Poskanzer <jef@mail.acme.com>.
332-- All rights reserved.
333--
334-- Redistribution and use in source and binary forms, with or without
335-- modification, are permitted provided that the following conditions
336-- are met:
337-- 1. Redistributions of source code must retain the above copyright
338-- notice, this list of conditions and the following disclaimer.
339-- 2. Redistributions in binary form must reproduce the above copyright
340-- notice, this list of conditions and the following disclaimer in the
341-- documentation and/or other materials provided with the distribution.
342--
343-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
344-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
345-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
346-- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
347-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
348-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
349-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
350-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
351-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
352-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
353-- SUCH DAMAGE.
354--
355
356
357--
358-- RSA Encryption/Decryption Library
359-- By 1lann
360--
361-- Refer to license: http://pastebin.com/9gWSyqQt
362--
363
364rsaCrypt = {}
365
366--
367-- Start of third-party libraries/helpers
368--
369
370-- two functions to help make Lua act more like C
371rsaCrypt.fl = function (x)
372 if x < 0 then
373 return math.ceil(x) + 0 -- make -0 go away
374 else
375 return math.floor(x)
376 end
377end
378
379rsaCrypt.cmod = function (a, b)
380 local x = a % b
381 if a < 0 and x > 0 then
382 x = x - b
383 end
384 return x
385end
386
387
388rsaCrypt.radix = 2^24 -- maybe up to 2^26 is safe?
389rsaCrypt.radix_sqrt = rsaCrypt.fl(math.sqrt(rsaCrypt.radix))
390
391rsaCrypt.alloc = function ()
392 local bi = {}
393 setmetatable(bi, rsaCrypt.bigintmt)
394 bi.comps = {}
395 bi.sign = 1;
396 return bi
397end
398
399rsaCrypt.clone = function (a)
400 local bi = rsaCrypt.alloc()
401 bi.sign = a.sign
402 local c = bi.comps
403 local ac = a.comps
404 for i = 1, #ac do
405 c[i] = ac[i]
406 end
407 return bi
408end
409
410rsaCrypt.normalize = function (bi, notrunc)
411 local c = bi.comps
412 local v
413 -- borrow for negative components
414 for i = 1, #c - 1 do
415 v = c[i]
416 if v < 0 then
417 c[i+1] = c[i+1] + rsaCrypt.fl(v / rsaCrypt.radix) - 1
418 v = rsaCrypt.cmod(v, rsaCrypt.radix)
419 if v ~= 0 then
420 c[i] = v + rsaCrypt.radix
421 else
422 c[i] = v
423 c[i+1] = c[i+1] + 1
424 end
425 end
426 end
427 -- is top component negative?
428 if c[#c] < 0 then
429 -- switch the sign and fix components
430 bi.sign = -bi.sign
431 for i = 1, #c - 1 do
432 v = c[i]
433 c[i] = rsaCrypt.radix - v
434 c[i+1] = c[i+1] + 1
435 end
436 c[#c] = -c[#c]
437 end
438 -- carry for components larger than radix
439 for i = 1, #c do
440 v = c[i]
441 if v > rsaCrypt.radix then
442 c[i+1] = (c[i+1] or 0) + rsaCrypt.fl(v / rsaCrypt.radix)
443 c[i] = rsaCrypt.cmod(v, rsaCrypt.radix)
444 end
445 end
446 -- trim off leading zeros
447 if not notrunc then
448 for i = #c, 2, -1 do
449 if c[i] == 0 then
450 c[i] = nil
451 else
452 break
453 end
454 end
455 end
456 -- check for -0
457 if #c == 1 and c[1] == 0 and bi.sign == -1 then
458 bi.sign = 1
459 end
460end
461
462rsaCrypt.negate = function (a)
463 local bi = rsaCrypt.clone(a)
464 bi.sign = -bi.sign
465 return bi
466end
467
468rsaCrypt.compare = function (a, b)
469 local ac, bc = a.comps, b.comps
470 local as, bs = a.sign, b.sign
471 if ac == bc then
472 return 0
473 elseif as > bs then
474 return 1
475 elseif as < bs then
476 return -1
477 elseif #ac > #bc then
478 return as
479 elseif #ac < #bc then
480 return -as
481 end
482 for i = #ac, 1, -1 do
483 if ac[i] > bc[i] then
484 return as
485 elseif ac[i] < bc[i] then
486 return -as
487 end
488 end
489 return 0
490end
491
492rsaCrypt.lt = function (a, b)
493 return rsaCrypt.compare(a, b) < 0
494end
495
496rsaCrypt.eq = function (a, b)
497 return rsaCrypt.compare(a, b) == 0
498end
499
500rsaCrypt.le = function (a, b)
501 return rsaCrypt.compare(a, b) <= 0
502end
503
504rsaCrypt.addint = function (a, n)
505 local bi = rsaCrypt.clone(a)
506 if bi.sign == 1 then
507 bi.comps[1] = bi.comps[1] + n
508 else
509 bi.comps[1] = bi.comps[1] - n
510 end
511 rsaCrypt.normalize(bi)
512 return bi
513end
514
515rsaCrypt.add = function (a, b)
516 if type(a) == "number" then
517 return rsaCrypt.addint(b, a)
518 elseif type(b) == "number" then
519 return rsaCrypt.addint(a, b)
520 end
521 local bi = rsaCrypt.clone(a)
522 local sign = bi.sign == b.sign
523 local c = bi.comps
524 for i = #c + 1, #b.comps do
525 c[i] = 0
526 end
527 local bc = b.comps
528 for i = 1, #bc do
529 local v = bc[i]
530 if sign then
531 c[i] = c[i] + v
532 else
533 c[i] = c[i] - v
534 end
535 end
536 rsaCrypt.normalize(bi)
537 return bi
538end
539
540rsaCrypt.sub = function (a, b)
541 if type(b) == "number" then
542 return rsaCrypt.addint(a, -b)
543 elseif type(a) == "number" then
544 a = rsaCrypt.bigint(a)
545 end
546 return rsaCrypt.add(a, rsaCrypt.negate(b))
547end
548
549rsaCrypt.mulint = function (a, b)
550 local bi = rsaCrypt.clone(a)
551 if b < 0 then
552 b = -b
553 bi.sign = -bi.sign
554 end
555 local bc = bi.comps
556 for i = 1, #bc do
557 bc[i] = bc[i] * b
558 end
559 rsaCrypt.normalize(bi)
560 return bi
561end
562
563rsaCrypt.multiply = function (a, b)
564 local bi = rsaCrypt.alloc()
565 local c = bi.comps
566 local ac, bc = a.comps, b.comps
567 for i = 1, #ac + #bc do
568 c[i] = 0
569 end
570 for i = 1, #ac do
571 for j = 1, #bc do
572 c[i+j-1] = c[i+j-1] + ac[i] * bc[j]
573 end
574 -- keep the zeroes
575 rsaCrypt.normalize(bi, true)
576 end
577 rsaCrypt.normalize(bi)
578 if bi ~= rsaCrypt.bigint(0) then
579 bi.sign = a.sign * b.sign
580 end
581 return bi
582end
583
584rsaCrypt.kmul = function (a, b)
585 local ac, bc = a.comps, b.comps
586 local an, bn = #a.comps, #b.comps
587 local bi, bj, bk, bl = rsaCrypt.alloc(), rsaCrypt.alloc(), rsaCrypt.alloc(), rsaCrypt.alloc()
588 local ic, jc, kc, lc = bi.comps, bj.comps, bk.comps, bl.comps
589
590 local n = rsaCrypt.fl((math.max(an, bn) + 1) / 2)
591 for i = 1, n do
592 ic[i] = (i + n <= an) and ac[i+n] or 0
593 jc[i] = (i <= an) and ac[i] or 0
594 kc[i] = (i + n <= bn) and bc[i+n] or 0
595 lc[i] = (i <= bn) and bc[i] or 0
596 end
597 rsaCrypt.normalize(bi)
598 rsaCrypt.normalize(bj)
599 rsaCrypt.normalize(bk)
600 rsaCrypt.normalize(bl)
601 local ik = bi * bk
602 local jl = bj * bl
603 local mid = (bi + bj) * (bk + bl) - ik - jl
604 local mc = mid.comps
605 local ikc = ik.comps
606 local jlc = jl.comps
607 for i = 1, #ikc + n*2 do -- fill it up
608 jlc[i] = jlc[i] or 0
609 end
610 for i = 1, #mc do
611 jlc[i+n] = jlc[i+n] + mc[i]
612 end
613 for i = 1, #ikc do
614 jlc[i+n*2] = jlc[i+n*2] + ikc[i]
615 end
616 jl.sign = a.sign * b.sign
617 rsaCrypt.normalize(jl)
618 return jl
619end
620
621rsaCrypt.kthresh = 12
622
623rsaCrypt.mul = function (a, b)
624 if type(a) == "number" then
625 return rsaCrypt.mulint(b, a)
626 elseif type(b) == "number" then
627 return rsaCrypt.mulint(a, b)
628 end
629 if #a.comps < rsaCrypt.kthresh or #b.comps < rsaCrypt.kthresh then
630 return rsaCrypt.multiply(a, b)
631 end
632 return rsaCrypt.kmul(a, b)
633end
634
635rsaCrypt.divint = function (numer, denom)
636 local bi = rsaCrypt.clone(numer)
637 if denom < 0 then
638 denom = -denom
639 bi.sign = -bi.sign
640 end
641 local r = 0
642 local c = bi.comps
643 for i = #c, 1, -1 do
644 r = r * rsaCrypt.radix + c[i]
645 c[i] = rsaCrypt.fl(r / denom)
646 r = rsaCrypt.cmod(r, denom)
647 end
648 rsaCrypt.normalize(bi)
649 return bi
650end
651
652rsaCrypt.multi_divide = function (numer, denom)
653 local n = #denom.comps
654 local approx = rsaCrypt.divint(numer, denom.comps[n])
655 for i = n, #approx.comps do
656 approx.comps[i - n + 1] = approx.comps[i]
657 end
658 for i = #approx.comps, #approx.comps - n + 2, -1 do
659 approx.comps[i] = nil
660 end
661 local rem = approx * denom - numer
662 if rem < denom then
663 quotient = approx
664 else
665 quotient = approx - rsaCrypt.multi_divide(rem, denom)
666 end
667 return quotient
668end
669
670rsaCrypt.multi_divide_wrap = function (numer, denom)
671 -- we use a successive approximation method, but it doesn't work
672 -- if the high order component is too small. adjust if needed.
673 if denom.comps[#denom.comps] < rsaCrypt.radix_sqrt then
674 numer = rsaCrypt.mulint(numer, rsaCrypt.radix_sqrt)
675 denom = rsaCrypt.mulint(denom, rsaCrypt.radix_sqrt)
676 end
677 return rsaCrypt.multi_divide(numer, denom)
678end
679
680rsaCrypt.div = function (numer, denom)
681 if type(denom) == "number" then
682 if denom == 0 then
683 error("divide by 0", 2)
684 end
685 return rsaCrypt.divint(numer, denom)
686 elseif type(numer) == "number" then
687 numer = rsaCrypt.bigint(numer)
688 end
689 -- check signs and trivial cases
690 local sign = 1
691 local cmp = rsaCrypt.compare(denom, rsaCrypt.bigint(0))
692 if cmp == 0 then
693 error("divide by 0", 2)
694 elseif cmp == -1 then
695 sign = -sign
696 denom = rsaCrypt.negate(denom)
697 end
698 cmp = rsaCrypt.compare(numer, rsaCrypt.bigint(0))
699 if cmp == 0 then
700 return rsaCrypt.bigint(0)
701 elseif cmp == -1 then
702 sign = -sign
703 numer = rsaCrypt.negate(numer)
704 end
705 cmp = rsaCrypt.compare(numer, denom)
706 if cmp == -1 then
707 return rsaCrypt.bigint(0)
708 elseif cmp == 0 then
709 return rsaCrypt.bigint(sign)
710 end
711 local bi
712 -- if small enough, do it the easy way
713 if #denom.comps == 1 then
714 bi = rsaCrypt.divint(numer, denom.comps[1])
715 else
716 bi = rsaCrypt.multi_divide_wrap(numer, denom)
717 end
718 if sign == -1 then
719 bi = rsaCrypt.negate(bi)
720 end
721 return bi
722end
723
724rsaCrypt.intrem = function (bi, m)
725 if m < 0 then
726 m = -m
727 end
728 local rad_r = 1
729 local r = 0
730 local bc = bi.comps
731 for i = 1, #bc do
732 local v = bc[i]
733 r = rsaCrypt.cmod(r + v * rad_r, m)
734 rad_r = rsaCrypt.cmod(rad_r * rsaCrypt.radix, m)
735 end
736 if bi.sign < 1 then
737 r = -r
738 end
739 return r
740end
741
742rsaCrypt.intmod = function (bi, m)
743 local r = rsaCrypt.intrem(bi, m)
744 if r < 0 then
745 r = r + m
746 end
747 return r
748end
749
750rsaCrypt.rem = function (bi, m)
751 if type(m) == "number" then
752 return rsaCrypt.bigint(rsaCrypt.intrem(bi, m))
753 elseif type(bi) == "number" then
754 bi = rsaCrypt.bigint(bi)
755 end
756
757 return bi - ((bi / m) * m)
758end
759
760rsaCrypt.mod = function (a, m)
761 local bi = rsaCrypt.rem(a, m)
762 if bi.sign == -1 then
763 bi = bi + m
764 end
765 return bi
766end
767
768rsaCrypt.printscale = 10000000
769rsaCrypt.printscalefmt = string.format("%%.%dd", math.log10(rsaCrypt.printscale))
770rsaCrypt.makestr = function (bi, s)
771 if bi >= rsaCrypt.bigint(rsaCrypt.printscale) then
772 rsaCrypt.makestr(rsaCrypt.divint(bi, rsaCrypt.printscale), s)
773 end
774 table.insert(s, string.format(rsaCrypt.printscalefmt, rsaCrypt.intmod(bi, rsaCrypt.printscale)))
775end
776
777rsaCrypt.biginttostring = function (bi)
778 local s = {}
779 if bi < rsaCrypt.bigint(0) then
780 bi = rsaCrypt.negate(bi)
781 table.insert(s, "-")
782 end
783 rsaCrypt.makestr(bi, s)
784 s = table.concat(s):gsub("^0*", "")
785 if s == "" then s = "0" end
786 return s
787end
788
789rsaCrypt.biginttonumber = function (bi)
790 return tonumber(rsaCrypt.biginttostring(bi))
791end
792
793rsaCrypt.bigintmt = {
794 __add = rsaCrypt.add,
795 __sub = rsaCrypt.sub,
796 __mul = rsaCrypt.mul,
797 __div = rsaCrypt.div,
798 __mod = rsaCrypt.mod,
799 __unm = rsaCrypt.negate,
800 __eq = rsaCrypt.eq,
801 __lt = rsaCrypt.lt,
802 __le = rsaCrypt.le,
803 __tostring = rsaCrypt.biginttostring,
804}
805
806rsaCrypt.cache = {}
807rsaCrypt.ncache = 0
808
809rsaCrypt.bigint = function (n)
810 if rsaCrypt.cache[n] then
811 return rsaCrypt.cache[n]
812 end
813 local bi
814 if type(n) == "string" then
815 local digits = { n:byte(1, -1) }
816 for i = 1, #digits do
817 digits[i] = string.char(digits[i])
818 end
819 local start = 1
820 local sign = 1
821 if digits[i] == '-' then
822 sign = -1
823 start = 2
824 end
825 bi = rsaCrypt.bigint(0)
826 for i = start, #digits do
827 bi = rsaCrypt.addint(rsaCrypt.mulint(bi, 10), tonumber(digits[i]))
828 end
829 bi = rsaCrypt.mulint(bi, sign)
830 else
831 bi = rsaCrypt.alloc()
832 bi.comps[1] = n
833 rsaCrypt.normalize(bi)
834 end
835 if rsaCrypt.ncache > 100 then
836 rsaCrypt.cache = {}
837 rsaCrypt.ncache = 0
838 end
839 rsaCrypt.cache[n] = bi
840 rsaCrypt.ncache = rsaCrypt.ncache + 1
841 return bi
842end
843
844--
845-- Start of my code
846--
847
848rsaCrypt.powersTwo = {
849rsaCrypt.bigint("2"),
850rsaCrypt.bigint("4"),
851rsaCrypt.bigint("8"),
852rsaCrypt.bigint("16"),
853rsaCrypt.bigint("32"),
854rsaCrypt.bigint("64"),
855rsaCrypt.bigint("128"),
856rsaCrypt.bigint("256"),
857rsaCrypt.bigint("512"),
858rsaCrypt.bigint("1024"),
859rsaCrypt.bigint("2048"),
860rsaCrypt.bigint("4096"),
861rsaCrypt.bigint("8192"),
862rsaCrypt.bigint("16384"),
863rsaCrypt.bigint("32768"),
864rsaCrypt.bigint("65536"),
865rsaCrypt.bigint("131072"),
866rsaCrypt.bigint("262144"),
867rsaCrypt.bigint("524288"),
868rsaCrypt.bigint("1048576"),
869rsaCrypt.bigint("2097152"),
870rsaCrypt.bigint("4194304"),
871rsaCrypt.bigint("8388608"),
872rsaCrypt.bigint("16777216"),
873rsaCrypt.bigint("33554432"),
874rsaCrypt.bigint("67108864"),
875rsaCrypt.bigint("134217728"),
876rsaCrypt.bigint("268435456"),
877rsaCrypt.bigint("536870912"),
878rsaCrypt.bigint("1073741824"),
879rsaCrypt.bigint("2147483648"),
880rsaCrypt.bigint("4294967296"),
881rsaCrypt.bigint("8589934592"),
882rsaCrypt.bigint("17179869184"),
883rsaCrypt.bigint("34359738368"),
884rsaCrypt.bigint("68719476736"),
885rsaCrypt.bigint("137438953472"),
886rsaCrypt.bigint("274877906944"),
887rsaCrypt.bigint("549755813888"),
888rsaCrypt.bigint("1099511627776"),
889rsaCrypt.bigint("2199023255552"),
890rsaCrypt.bigint("4398046511104"),
891rsaCrypt.bigint("8796093022208"),
892rsaCrypt.bigint("17592186044416"),
893rsaCrypt.bigint("35184372088832"),
894rsaCrypt.bigint("70368744177664"),
895rsaCrypt.bigint("140737488355328"),
896rsaCrypt.bigint("281474976710656"),
897rsaCrypt.bigint("562949953421312"),
898rsaCrypt.bigint("1125899906842624"),
899rsaCrypt.bigint("2251799813685248"),
900rsaCrypt.bigint("4503599627370496"),
901rsaCrypt.bigint("9007199254740992"),
902rsaCrypt.bigint("18014398509481984"),
903rsaCrypt.bigint("36028797018963968"),
904rsaCrypt.bigint("72057594037927936"),
905rsaCrypt.bigint("144115188075855872"),
906rsaCrypt.bigint("288230376151711744"),
907rsaCrypt.bigint("576460752303423488"),
908rsaCrypt.bigint("1152921504606846976"),
909rsaCrypt.bigint("2305843009213693952"),
910rsaCrypt.bigint("4611686018427387904"),
911rsaCrypt.bigint("9223372036854775808"),
912rsaCrypt.bigint("18446744073709551616"),
913rsaCrypt.bigint("36893488147419103232"),
914rsaCrypt.bigint("73786976294838206464"),
915rsaCrypt.bigint("147573952589676412928"),
916rsaCrypt.bigint("295147905179352825856"),
917rsaCrypt.bigint("590295810358705651712"),
918rsaCrypt.bigint("1180591620717411303424"),
919rsaCrypt.bigint("2361183241434822606848"),
920rsaCrypt.bigint("4722366482869645213696"),
921rsaCrypt.bigint("9444732965739290427392"),
922rsaCrypt.bigint("18889465931478580854784"),
923rsaCrypt.bigint("37778931862957161709568"),
924rsaCrypt.bigint("75557863725914323419136"),
925rsaCrypt.bigint("151115727451828646838272"),
926rsaCrypt.bigint("302231454903657293676544"),
927rsaCrypt.bigint("604462909807314587353088"),
928rsaCrypt.bigint("1208925819614629174706176"),
929rsaCrypt.bigint("2417851639229258349412352"),
930rsaCrypt.bigint("4835703278458516698824704"),
931rsaCrypt.bigint("9671406556917033397649408"),
932rsaCrypt.bigint("19342813113834066795298816"),
933rsaCrypt.bigint("38685626227668133590597632"),
934rsaCrypt.bigint("77371252455336267181195264"),
935rsaCrypt.bigint("154742504910672534362390528"),
936rsaCrypt.bigint("309485009821345068724781056"),
937rsaCrypt.bigint("618970019642690137449562112"),
938rsaCrypt.bigint("1237940039285380274899124224"),
939rsaCrypt.bigint("2475880078570760549798248448"),
940rsaCrypt.bigint("4951760157141521099596496896"),
941rsaCrypt.bigint("9903520314283042199192993792"),
942rsaCrypt.bigint("19807040628566084398385987584"),
943rsaCrypt.bigint("39614081257132168796771975168"),
944rsaCrypt.bigint("79228162514264337593543950336"),
945rsaCrypt.bigint("158456325028528675187087900672"),
946rsaCrypt.bigint("316912650057057350374175801344"),
947rsaCrypt.bigint("633825300114114700748351602688"),
948rsaCrypt.bigint("1267650600228229401496703205376"),
949rsaCrypt.bigint("2535301200456458802993406410752"),
950rsaCrypt.bigint("5070602400912917605986812821504"),
951rsaCrypt.bigint("10141204801825835211973625643008"),
952rsaCrypt.bigint("20282409603651670423947251286016"),
953rsaCrypt.bigint("40564819207303340847894502572032"),
954rsaCrypt.bigint("81129638414606681695789005144064"),
955rsaCrypt.bigint("162259276829213363391578010288128"),
956rsaCrypt.bigint("324518553658426726783156020576256"),
957rsaCrypt.bigint("649037107316853453566312041152512"),
958rsaCrypt.bigint("1298074214633706907132624082305024"),
959rsaCrypt.bigint("2596148429267413814265248164610048"),
960rsaCrypt.bigint("5192296858534827628530496329220096"),
961rsaCrypt.bigint("10384593717069655257060992658440192"),
962rsaCrypt.bigint("20769187434139310514121985316880384"),
963rsaCrypt.bigint("41538374868278621028243970633760768"),
964rsaCrypt.bigint("83076749736557242056487941267521536"),
965rsaCrypt.bigint("166153499473114484112975882535043072"),
966rsaCrypt.bigint("332306998946228968225951765070086144"),
967rsaCrypt.bigint("664613997892457936451903530140172288"),
968rsaCrypt.bigint("1329227995784915872903807060280344576"),
969rsaCrypt.bigint("2658455991569831745807614120560689152"),
970rsaCrypt.bigint("5316911983139663491615228241121378304"),
971rsaCrypt.bigint("10633823966279326983230456482242756608"),
972rsaCrypt.bigint("21267647932558653966460912964485513216"),
973rsaCrypt.bigint("42535295865117307932921825928971026432"),
974rsaCrypt.bigint("85070591730234615865843651857942052864"),
975rsaCrypt.bigint("170141183460469231731687303715884105728"),
976rsaCrypt.bigint("340282366920938463463374607431768211456"),
977rsaCrypt.bigint("680564733841876926926749214863536422912"),
978rsaCrypt.bigint("1361129467683753853853498429727072845824"),
979rsaCrypt.bigint("2722258935367507707706996859454145691648"),
980rsaCrypt.bigint("5444517870735015415413993718908291383296"),
981rsaCrypt.bigint("10889035741470030830827987437816582766592"),
982rsaCrypt.bigint("21778071482940061661655974875633165533184"),
983rsaCrypt.bigint("43556142965880123323311949751266331066368"),
984rsaCrypt.bigint("87112285931760246646623899502532662132736"),
985rsaCrypt.bigint("174224571863520493293247799005065324265472"),
986rsaCrypt.bigint("348449143727040986586495598010130648530944"),
987rsaCrypt.bigint("696898287454081973172991196020261297061888"),
988rsaCrypt.bigint("1393796574908163946345982392040522594123776"),
989rsaCrypt.bigint("2787593149816327892691964784081045188247552"),
990rsaCrypt.bigint("5575186299632655785383929568162090376495104"),
991rsaCrypt.bigint("11150372599265311570767859136324180752990208"),
992rsaCrypt.bigint("22300745198530623141535718272648361505980416"),
993rsaCrypt.bigint("44601490397061246283071436545296723011960832"),
994rsaCrypt.bigint("89202980794122492566142873090593446023921664"),
995rsaCrypt.bigint("178405961588244985132285746181186892047843328"),
996rsaCrypt.bigint("356811923176489970264571492362373784095686656"),
997rsaCrypt.bigint("713623846352979940529142984724747568191373312"),
998rsaCrypt.bigint("1427247692705959881058285969449495136382746624"),
999rsaCrypt.bigint("2854495385411919762116571938898990272765493248"),
1000rsaCrypt.bigint("5708990770823839524233143877797980545530986496"),
1001rsaCrypt.bigint("11417981541647679048466287755595961091061972992"),
1002rsaCrypt.bigint("22835963083295358096932575511191922182123945984"),
1003rsaCrypt.bigint("45671926166590716193865151022383844364247891968"),
1004rsaCrypt.bigint("91343852333181432387730302044767688728495783936"),
1005rsaCrypt.bigint("182687704666362864775460604089535377456991567872"),
1006rsaCrypt.bigint("365375409332725729550921208179070754913983135744"),
1007rsaCrypt.bigint("730750818665451459101842416358141509827966271488"),
1008rsaCrypt.bigint("1461501637330902918203684832716283019655932542976"),
1009rsaCrypt.bigint("2923003274661805836407369665432566039311865085952"),
1010rsaCrypt.bigint("5846006549323611672814739330865132078623730171904"),
1011rsaCrypt.bigint("11692013098647223345629478661730264157247460343808"),
1012rsaCrypt.bigint("23384026197294446691258957323460528314494920687616"),
1013rsaCrypt.bigint("46768052394588893382517914646921056628989841375232"),
1014rsaCrypt.bigint("93536104789177786765035829293842113257979682750464"),
1015rsaCrypt.bigint("187072209578355573530071658587684226515959365500928"),
1016rsaCrypt.bigint("374144419156711147060143317175368453031918731001856"),
1017rsaCrypt.bigint("748288838313422294120286634350736906063837462003712"),
1018rsaCrypt.bigint("1496577676626844588240573268701473812127674924007424"),
1019rsaCrypt.bigint("2993155353253689176481146537402947624255349848014848"),
1020rsaCrypt.bigint("5986310706507378352962293074805895248510699696029696"),
1021rsaCrypt.bigint("11972621413014756705924586149611790497021399392059392"),
1022rsaCrypt.bigint("23945242826029513411849172299223580994042798784118784"),
1023rsaCrypt.bigint("47890485652059026823698344598447161988085597568237568"),
1024rsaCrypt.bigint("95780971304118053647396689196894323976171195136475136"),
1025rsaCrypt.bigint("191561942608236107294793378393788647952342390272950272"),
1026rsaCrypt.bigint("383123885216472214589586756787577295904684780545900544"),
1027rsaCrypt.bigint("766247770432944429179173513575154591809369561091801088"),
1028rsaCrypt.bigint("1532495540865888858358347027150309183618739122183602176"),
1029rsaCrypt.bigint("3064991081731777716716694054300618367237478244367204352"),
1030rsaCrypt.bigint("6129982163463555433433388108601236734474956488734408704"),
1031rsaCrypt.bigint("12259964326927110866866776217202473468949912977468817408"),
1032rsaCrypt.bigint("24519928653854221733733552434404946937899825954937634816"),
1033rsaCrypt.bigint("49039857307708443467467104868809893875799651909875269632"),
1034rsaCrypt.bigint("98079714615416886934934209737619787751599303819750539264"),
1035rsaCrypt.bigint("196159429230833773869868419475239575503198607639501078528"),
1036rsaCrypt.bigint("392318858461667547739736838950479151006397215279002157056"),
1037rsaCrypt.bigint("784637716923335095479473677900958302012794430558004314112"),
1038rsaCrypt.bigint("1569275433846670190958947355801916604025588861116008628224"),
1039rsaCrypt.bigint("3138550867693340381917894711603833208051177722232017256448"),
1040rsaCrypt.bigint("6277101735386680763835789423207666416102355444464034512896"),
1041rsaCrypt.bigint("12554203470773361527671578846415332832204710888928069025792"),
1042rsaCrypt.bigint("25108406941546723055343157692830665664409421777856138051584"),
1043rsaCrypt.bigint("50216813883093446110686315385661331328818843555712276103168"),
1044rsaCrypt.bigint("100433627766186892221372630771322662657637687111424552206336"),
1045rsaCrypt.bigint("200867255532373784442745261542645325315275374222849104412672"),
1046rsaCrypt.bigint("401734511064747568885490523085290650630550748445698208825344"),
1047rsaCrypt.bigint("803469022129495137770981046170581301261101496891396417650688"),
1048rsaCrypt.bigint("1606938044258990275541962092341162602522202993782792835301376"),
1049rsaCrypt.bigint("3213876088517980551083924184682325205044405987565585670602752"),
1050rsaCrypt.bigint("6427752177035961102167848369364650410088811975131171341205504"),
1051rsaCrypt.bigint("12855504354071922204335696738729300820177623950262342682411008"),
1052rsaCrypt.bigint("25711008708143844408671393477458601640355247900524685364822016"),
1053rsaCrypt.bigint("51422017416287688817342786954917203280710495801049370729644032"),
1054rsaCrypt.bigint("102844034832575377634685573909834406561420991602098741459288064"),
1055rsaCrypt.bigint("205688069665150755269371147819668813122841983204197482918576128"),
1056rsaCrypt.bigint("411376139330301510538742295639337626245683966408394965837152256"),
1057rsaCrypt.bigint("822752278660603021077484591278675252491367932816789931674304512"),
1058rsaCrypt.bigint("1645504557321206042154969182557350504982735865633579863348609024"),
1059rsaCrypt.bigint("3291009114642412084309938365114701009965471731267159726697218048"),
1060rsaCrypt.bigint("6582018229284824168619876730229402019930943462534319453394436096"),
1061rsaCrypt.bigint("13164036458569648337239753460458804039861886925068638906788872192"),
1062rsaCrypt.bigint("26328072917139296674479506920917608079723773850137277813577744384"),
1063rsaCrypt.bigint("52656145834278593348959013841835216159447547700274555627155488768"),
1064rsaCrypt.bigint("105312291668557186697918027683670432318895095400549111254310977536"),
1065rsaCrypt.bigint("210624583337114373395836055367340864637790190801098222508621955072"),
1066rsaCrypt.bigint("421249166674228746791672110734681729275580381602196445017243910144"),
1067rsaCrypt.bigint("842498333348457493583344221469363458551160763204392890034487820288"),
1068rsaCrypt.bigint("1684996666696914987166688442938726917102321526408785780068975640576"),
1069rsaCrypt.bigint("3369993333393829974333376885877453834204643052817571560137951281152"),
1070rsaCrypt.bigint("6739986666787659948666753771754907668409286105635143120275902562304"),
1071rsaCrypt.bigint("13479973333575319897333507543509815336818572211270286240551805124608"),
1072rsaCrypt.bigint("26959946667150639794667015087019630673637144422540572481103610249216"),
1073rsaCrypt.bigint("53919893334301279589334030174039261347274288845081144962207220498432"),
1074rsaCrypt.bigint("107839786668602559178668060348078522694548577690162289924414440996864"),
1075rsaCrypt.bigint("215679573337205118357336120696157045389097155380324579848828881993728"),
1076rsaCrypt.bigint("431359146674410236714672241392314090778194310760649159697657763987456"),
1077rsaCrypt.bigint("862718293348820473429344482784628181556388621521298319395315527974912"),
1078rsaCrypt.bigint("1725436586697640946858688965569256363112777243042596638790631055949824"),
1079rsaCrypt.bigint("3450873173395281893717377931138512726225554486085193277581262111899648"),
1080rsaCrypt.bigint("6901746346790563787434755862277025452451108972170386555162524223799296"),
1081rsaCrypt.bigint("13803492693581127574869511724554050904902217944340773110325048447598592"),
1082rsaCrypt.bigint("27606985387162255149739023449108101809804435888681546220650096895197184"),
1083rsaCrypt.bigint("55213970774324510299478046898216203619608871777363092441300193790394368"),
1084rsaCrypt.bigint("110427941548649020598956093796432407239217743554726184882600387580788736"),
1085rsaCrypt.bigint("220855883097298041197912187592864814478435487109452369765200775161577472"),
1086rsaCrypt.bigint("441711766194596082395824375185729628956870974218904739530401550323154944"),
1087rsaCrypt.bigint("883423532389192164791648750371459257913741948437809479060803100646309888"),
1088rsaCrypt.bigint("1766847064778384329583297500742918515827483896875618958121606201292619776"),
1089rsaCrypt.bigint("3533694129556768659166595001485837031654967793751237916243212402585239552"),
1090rsaCrypt.bigint("7067388259113537318333190002971674063309935587502475832486424805170479104"),
1091rsaCrypt.bigint("14134776518227074636666380005943348126619871175004951664972849610340958208"),
1092rsaCrypt.bigint("28269553036454149273332760011886696253239742350009903329945699220681916416"),
1093rsaCrypt.bigint("56539106072908298546665520023773392506479484700019806659891398441363832832"),
1094rsaCrypt.bigint("113078212145816597093331040047546785012958969400039613319782796882727665664"),
1095rsaCrypt.bigint("226156424291633194186662080095093570025917938800079226639565593765455331328"),
1096rsaCrypt.bigint("452312848583266388373324160190187140051835877600158453279131187530910662656"),
1097rsaCrypt.bigint("904625697166532776746648320380374280103671755200316906558262375061821325312"),
1098rsaCrypt.bigint("1809251394333065553493296640760748560207343510400633813116524750123642650624"),
1099rsaCrypt.bigint("3618502788666131106986593281521497120414687020801267626233049500247285301248"),
1100rsaCrypt.bigint("7237005577332262213973186563042994240829374041602535252466099000494570602496"),
1101rsaCrypt.bigint("14474011154664524427946373126085988481658748083205070504932198000989141204992"),
1102rsaCrypt.bigint("28948022309329048855892746252171976963317496166410141009864396001978282409984"),
1103rsaCrypt.bigint("57896044618658097711785492504343953926634992332820282019728792003956564819968"),
1104rsaCrypt.bigint("115792089237316195423570985008687907853269984665640564039457584007913129639936"),
1105}
1106
1107rsaCrypt.powersTwo[0] = rsaCrypt.bigint("1")
1108
1109rsaCrypt.bigZero = rsaCrypt.bigint(0)
1110rsaCrypt.bigOne = rsaCrypt.bigint(1)
1111
1112rsaCrypt.numberToBytes = function (num, bits, byteSize)
1113 if bits > #rsaCrypt.powersTwo then
1114 error("Too many bits. Must be <= " .. #rsaCrypt.powersTwo .. ".")
1115 end
1116
1117 num = rsaCrypt.bigint(num)
1118
1119 local resultBits = {}
1120 resultBits[1] = {}
1121 for i = bits - 1, 0, -1 do
1122 local expVal = rsaCrypt.powersTwo[i]
1123 local resultant = num - expVal
1124 if expVal <= resultant then
1125 -- Invalid data!
1126 return nil
1127 end
1128
1129 if resultant < rsaCrypt.bigZero then
1130 -- A zero bit
1131 if #(resultBits[#resultBits]) >= byteSize then
1132 table.insert(resultBits, {0})
1133 else
1134 table.insert(resultBits[#resultBits], 0)
1135 end
1136 else
1137 -- A one bit
1138 num = resultant
1139 if #(resultBits[#resultBits]) >= byteSize then
1140 table.insert(resultBits, {1})
1141 else
1142 table.insert(resultBits[#resultBits], 1)
1143 end
1144 end
1145
1146 if num == rsaCrypt.bigint(0) then
1147 break
1148 end
1149 end
1150
1151 local results = {}
1152 for _, binarySeq in pairs(resultBits) do
1153 local thisResult = 0
1154 for k, bin in pairs(binarySeq) do
1155 if bin == 1 then
1156 thisResult = thisResult + 2^(byteSize - k)
1157 end
1158 end
1159 table.insert(results, thisResult)
1160 end
1161
1162 return results
1163end
1164
1165rsaCrypt.bytesToNumber = function (bytes, bits, byteSize)
1166 if bits > #rsaCrypt.powersTwo then
1167 error("Too many bits. Must be <= " .. #rsaCrypt.powersTwo .. ".")
1168 end
1169
1170 if #bytes > bits/byteSize then
1171 error("Too many bytes to store into the number of bits available. Must be <= " ..
1172 bits/byteSize .. ".")
1173 end
1174
1175 local binary = {}
1176 for _, byte in pairs(bytes) do
1177 for i = byteSize - 1, 0, -1 do
1178 if byte - (2 ^ i) < 0 then
1179 table.insert(binary, 0)
1180 else
1181 table.insert(binary, 1)
1182 byte = byte - (2 ^ i)
1183 end
1184 end
1185 end
1186
1187 local num = rsaCrypt.bigint(0)
1188 for i = 1, #binary do
1189 if binary[i] == 1 then
1190 num = num + rsaCrypt.powersTwo[bits - i]
1191 end
1192 end
1193
1194 return tostring(num)
1195end
1196
1197rsaCrypt.encodeBigNumbers = function (numbers)
1198 for k, v in pairs(numbers) do
1199 numbers[k] = tostring(v)
1200 end
1201 return numbers
1202end
1203
1204rsaCrypt.stringToBytes = function (str)
1205 local result = {}
1206 for i = 1, #str do
1207 table.insert(result, string.byte(str, i))
1208 end
1209 return result
1210end
1211
1212rsaCrypt.bytesToString = function (bytes)
1213 local str = ""
1214 for _, v in pairs(bytes) do
1215 str = str .. string.char(v)
1216 end
1217 return str
1218end
1219
1220rsaCrypt.modexp = function (base, exponent, modulus)
1221 local r = 1
1222
1223 while true do
1224 if exponent % 2 == rsaCrypt.bigOne then
1225 r = r * base % modulus
1226 end
1227 exponent = exponent / 2
1228
1229 if exponent == rsaCrypt.bigZero then
1230 break
1231 end
1232 base = base * base % modulus
1233 end
1234
1235 return r
1236end
1237
1238rsaCrypt.crypt = function (key, number)
1239 local exp
1240 if key.public then
1241 exp = rsaCrypt.bigint(key.public)
1242 else
1243 exp = rsaCrypt.bigint(key.private)
1244 end
1245
1246 return tostring(rsaCrypt.modexp(rsaCrypt.bigint(number), exp, rsaCrypt.bigint(key.shared)))
1247end
1248
1249--
1250-- END OF LIBRARY
1251--
1252
1253
1254--
1255-- RSA Key Generator
1256-- By 1lann
1257--
1258-- Refer to license: http://pastebin.com/9gWSyqQt
1259--
1260
1261rsaKeygen = {}
1262
1263--
1264-- Start of my (1lann's) code
1265--
1266
1267rsaKeygen.bigZero = rsaCrypt.bigint(0)
1268rsaKeygen.bigOne = rsaCrypt.bigint(1)
1269
1270rsaKeygen.gcd = function (a, b)
1271 if b ~= rsaKeygen.bigZero then
1272 return rsaKeygen.gcd(b, a % b)
1273 else
1274 return a
1275 end
1276end
1277
1278rsaKeygen.modexp = function (base, exponent, modulus)
1279 local r = 1
1280
1281 while true do
1282 if exponent % 2 == rsaKeygen.bigOne then
1283 r = r * base % modulus
1284 end
1285 exponent = exponent / 2
1286
1287 if exponent == rsaKeygen.bigZero then
1288 break
1289 end
1290 base = base * base % modulus
1291 end
1292
1293 return r
1294end
1295
1296rsaKeygen.bigRandomWithLength = function (length, cap)
1297 if not cap then
1298 cap = 999999999
1299 end
1300
1301 local randomString = tostring(math.random(100000000, cap))
1302
1303 while true do
1304 randomString = randomString ..
1305 tostring(math.random(100000000, cap))
1306 if #randomString >= length then
1307 local finalRandom = randomString:sub(1, length)
1308 if finalRandom:sub(-1, -1) == "2" then
1309 return rsaCrypt.bigint(finalRandom:sub(1, -2) .. "3")
1310 elseif finalRandom:sub(-1, -1) == "4" then
1311 return rsaCrypt.bigint(finalRandom:sub(1, -2) .. "5")
1312 elseif finalRandom:sub(-1, -1) == "6" then
1313 return rsaCrypt.bigint(finalRandom:sub(1, -2) .. "7")
1314 elseif finalRandom:sub(-1, -1) == "8" then
1315 return rsaCrypt.bigint(finalRandom:sub(1, -2) .. "9")
1316 elseif finalRandom:sub(-1, -1) == "0" then
1317 return rsaCrypt.bigint(finalRandom:sub(1, -2) .. "1")
1318 else
1319 return rsaCrypt.bigint(finalRandom)
1320 end
1321 end
1322 end
1323end
1324
1325rsaKeygen.bigRandom = function (minNum, maxNum)
1326 if maxNum < rsaCrypt.bigint(1000000000) then
1327 return rsaCrypt.bigint(math.random(rsaCrypt.biginttonumber(minNum),
1328 rsaCrypt.biginttonumber(maxNum)))
1329 end
1330
1331 local maxString = tostring(maxNum)
1332 local cap = tonumber(tostring(maxNum):sub(1, 9))
1333 local range = #maxString - #tostring(minNum)
1334
1335 if range == 0 then
1336 return rsaKeygen.bigRandomWithLength(#maxString, cap)
1337 end
1338
1339 if #maxString > 30 then
1340 return rsaKeygen.bigRandomWithLength(#maxString - 1)
1341 end
1342
1343 local randomLength = math.random(1, 2^(#maxString - 1))
1344 for i = 1, #maxString - 1 do
1345 if randomLength <= (2^i) then
1346 return rsaKeygen.bigRandomWithLength(i)
1347 end
1348 end
1349end
1350
1351rsaKeygen.isPrime = function (n)
1352 if type(n) == "number" then
1353 n = rsaCrypt.bigint(n)
1354 end
1355
1356 if n % 2 == rsaKeygen.bigZero then
1357 return false
1358 end
1359
1360 local s, d = 0, n - rsaKeygen.bigOne
1361 while d % 2 == rsaKeygen.bigZero do
1362 s, d = s + 1, d / 2
1363 end
1364
1365 for i = 1, 3 do
1366 local a = rsaKeygen.bigRandom(rsaCrypt.bigint(2), n - 2)
1367 local x = rsaKeygen.modexp(a, d, n)
1368 if x ~= rsaKeygen.bigOne and x + 1 ~= n then
1369 for j = 1, s do
1370 x = rsaKeygen.modexp(x, rsaCrypt.bigint(2), n)
1371 if x == rsaKeygen.bigOne then
1372 return false
1373 elseif x == n - 1 then
1374 a = rsaKeygen.bigZero
1375 break
1376 end
1377 end
1378 if a ~= rsaKeygen.bigZero then
1379 return false
1380 end
1381 end
1382 end
1383
1384 return true
1385end
1386
1387rsaKeygen.generateLargePrime = function ()
1388 local i = 0
1389 while true do
1390 write(".")
1391 os.sleep(0.1)
1392 local randomNumber = rsaKeygen.bigRandomWithLength(39)
1393
1394 if rsaKeygen.isPrime(randomNumber) then
1395 return randomNumber
1396 end
1397 end
1398end
1399
1400rsaKeygen.generatePQ = function (e)
1401 local randomPrime
1402 while true do
1403 randomPrime = rsaKeygen.generateLargePrime()
1404 if rsaKeygen.gcd(e, randomPrime - 1) == rsaKeygen.bigOne then
1405 return randomPrime
1406 end
1407 end
1408end
1409
1410rsaKeygen.euclidean = function (a, b)
1411 local x, y, u, v = rsaKeygen.bigZero, rsaKeygen.bigOne, rsaKeygen.bigOne, rsaKeygen.bigZero
1412 while a ~= rsaKeygen.bigZero do
1413 local q, r = b / a, b % a
1414 local m, n = x - u * q, y - v * q
1415 b, a, x, y, u, v = a, r, u, v, m, n
1416 end
1417 return b, x, y
1418end
1419
1420rsaKeygen.modinv = function (a, m)
1421 local gcdnum, x, y = rsaKeygen.euclidean(a, m)
1422 if gcdnum ~= rsaKeygen.bigOne then
1423 return nil
1424 else
1425 return x % m
1426 end
1427end
1428
1429rsaKeygen.generateKeyPair = function ()
1430 while true do
1431 local e = rsaKeygen.generateLargePrime()
1432 write("-")
1433 sleep(0.1)
1434 local p = rsaKeygen.generatePQ(e)
1435 write("-")
1436 sleep(0.1)
1437 local q = rsaKeygen.generatePQ(e)
1438 write("-")
1439 sleep(0.1)
1440
1441 local n = p * q
1442 local phi = (p - 1) * (q - 1)
1443 local d = rsaKeygen.modinv(e, phi)
1444
1445 -- 104328 is just a magic number (can be any semi-unique number)
1446 local encrypted = rsaKeygen.modexp(rsaCrypt.bigint(104328), e, n)
1447 local decrypted = rsaKeygen.modexp(encrypted, d, n)
1448
1449 write("+")
1450 sleep(0.1)
1451 counter = 0
1452
1453 if decrypted == rsaCrypt.bigint(104328) then
1454 counter = 0
1455 return {
1456 shared = tostring(n),
1457 public = tostring(e),
1458 }, {
1459 shared = tostring(n),
1460 private = tostring(d),
1461 }
1462 end
1463 end
1464end
1465
1466
1467-- KillaVanilla's RNG('s), composed of the Mersenne Twister RNG and the ISAAC algorithm.
1468
1469-- Exposed functions:
1470-- initalize_mt_generator(seed) - Seed the Mersenne Twister RNG.
1471-- extract_mt() - Get a number from the Mersenne Twister RNG.
1472-- seed_from_mt(seed) - Seed the ISAAC RNG, optionally seeding the Mersenne Twister RNG beforehand.
1473-- generate_isaac() - Force a reseed.
1474-- random(min, max) - Get a random number between min and max.
1475
1476isaac = {}
1477
1478-- Helper functions:
1479isaac.toBinary = function (a) -- Convert from an integer to an arbitrary-length table of bits
1480 local b = {}
1481 local copy = a
1482 while true do
1483 table.insert(b, copy % 2)
1484 copy = math.floor(copy / 2)
1485 if copy == 0 then
1486 break
1487 end
1488 end
1489 return b
1490end
1491
1492isaac.fromBinary = function (a) -- Convert from an arbitrary-length table of bits (from toBinary) to an integer
1493 local dec = 0
1494 for i=#a, 1, -1 do
1495 dec = dec * 2 + a[i]
1496 end
1497 return dec
1498end
1499
1500-- ISAAC internal state:
1501isaac.aa = 0
1502isaac.bb = 0
1503isaac.cc = 0
1504isaac.randrsl = {} -- Acts as entropy/seed-in. Fill to randrsl[256].
1505isaac.mm = {} -- Fill to mm[256]. Acts as output.
1506
1507-- Mersenne Twister State:
1508isaac.MT = {} -- Twister state
1509isaac.index = 0
1510
1511-- Other variables for the seeding mechanism
1512isaac.mtSeeded = false
1513isaac.mtSeed = math.random(1, 2^31-1)
1514
1515-- The Mersenne Twister can be used as an RNG for non-cryptographic purposes.
1516-- Here, we're using it to seed the ISAAC algorithm, which *can* be used for cryptographic purposes.
1517
1518isaac.initalize_mt_generator = function (seed)
1519 isaac.index = 0
1520 isaac.MT[0] = seed
1521 for i=1, 623 do
1522 local full = ( (1812433253 * bit.bxor(isaac.MT[i-1], bit.brshift(isaac.MT[i-1], 30) ) )+i)
1523 local b = isaac.toBinary(full)
1524 while #b > 32 do
1525 table.remove(b, 1)
1526 end
1527 isaac.MT[i] = isaac.fromBinary(b)
1528 end
1529end
1530
1531isaac.generate_mt = function () -- Restock the MT with new random numbers.
1532 for i=0, 623 do
1533 local y = bit.band(isaac.MT[i], 0x80000000)
1534 y = y + bit.band(isaac.MT[(i+1)%624], 0x7FFFFFFF)
1535 isaac.MT[i] = bit.bxor(isaac.MT[(i+397)%624], bit.brshift(y, 1))
1536 if y % 2 == 1 then
1537 isaac.MT[i] = bit.bxor(isaac.MT[i], 0x9908B0DF)
1538 end
1539 end
1540end
1541
1542isaac.extract_mt = function (min, max) -- Get one number from the Mersenne Twister.
1543 if isaac.index == 0 then
1544 isaac.generate_mt()
1545 end
1546 local y = isaac.MT[isaac.index]
1547 min = min or 0
1548 max = max or 2^32-1
1549 --print("Accessing: isaac.MT["..isaac.index.."]...")
1550 y = bit.bxor(y, bit.brshift(y, 11) )
1551 y = bit.bxor(y, bit.band(bit.blshift(y, 7), 0x9D2C5680) )
1552 y = bit.bxor(y, bit.band(bit.blshift(y, 15), 0xEFC60000) )
1553 y = bit.bxor(y, bit.brshift(y, 18) )
1554 isaac.index = (isaac.index+1) % 624
1555 return (y % max)+min
1556end
1557
1558isaac.seed_from_mt = function (seed) -- seed ISAAC with numbers from the MT:
1559 if seed then
1560 isaac.mtSeeded = false
1561 isaac.mtSeed = seed
1562 end
1563 if not isaac.mtSeeded or (math.random(1, 100) == 50) then -- Always seed the first time around. Otherwise, seed approximately once per 100 times.
1564 isaac.initalize_mt_generator(isaac.mtSeed)
1565 isaac.mtSeeded = true
1566 isaac.mtSeed = isaac.extract_mt()
1567 end
1568 for i=1, 256 do
1569 isaac.randrsl[i] = isaac.extract_mt()
1570 end
1571end
1572
1573isaac.mix = function (a,b,c,d,e,f,g,h)
1574 a = a % (2^32-1)
1575 b = b % (2^32-1)
1576 c = c % (2^32-1)
1577 d = d % (2^32-1)
1578 e = e % (2^32-1)
1579 f = f % (2^32-1)
1580 g = g % (2^32-1)
1581 h = h % (2^32-1)
1582 a = bit.bxor(a, bit.blshift(b, 11))
1583 d = (d + a) % (2^32-1)
1584 b = (b + c) % (2^32-1)
1585 b = bit.bxor(b, bit.brshift(c, 2) )
1586 e = (e + b) % (2^32-1)
1587 c = (c + d) % (2^32-1)
1588 c = bit.bxor(c, bit.blshift(d, 8) )
1589 f = (f + c) % (2^32-1)
1590 d = (d + e) % (2^32-1)
1591 d = bit.bxor(d, bit.brshift(e, 16) )
1592 g = (g + d) % (2^32-1)
1593 e = (e + f) % (2^32-1)
1594 e = bit.bxor(e, bit.blshift(f, 10) )
1595 h = (h + e) % (2^32-1)
1596 f = (f + g) % (2^32-1)
1597 f = bit.bxor(f, bit.brshift(g, 4) )
1598 a = (a + f) % (2^32-1)
1599 g = (g + h) % (2^32-1)
1600 g = bit.bxor(g, bit.blshift(h, 8) )
1601 b = (b + g) % (2^32-1)
1602 h = (h + a) % (2^32-1)
1603 h = bit.bxor(h, bit.brshift(a, 9) )
1604 c = (c + h) % (2^32-1)
1605 a = (a + b) % (2^32-1)
1606 return a,b,c,d,e,f,g,h
1607end
1608
1609isaac.isaac = function ()
1610 local x, y = 0, 0
1611 for i=1, 256 do
1612 x = isaac.mm[i]
1613 if (i % 4) == 0 then
1614 isaac.aa = bit.bxor(isaac.aa, bit.blshift(isaac.aa, 13))
1615 elseif (i % 4) == 1 then
1616 isaac.aa = bit.bxor(isaac.aa, bit.brshift(isaac.aa, 6))
1617 elseif (i % 4) == 2 then
1618 isaac.aa = bit.bxor(isaac.aa, bit.blshift(isaac.aa, 2))
1619 elseif (i % 4) == 3 then
1620 isaac.aa = bit.bxor(isaac.aa, bit.brshift(isaac.aa, 16))
1621 end
1622 isaac.aa = (isaac.mm[ ((i+128) % 256)+1 ] + isaac.aa) % (2^32-1)
1623 y = (isaac.mm[ (bit.brshift(x, 2) % 256)+1 ] + isaac.aa + isaac.bb) % (2^32-1)
1624 isaac.mm[i] = y
1625 isaac.bb = (isaac.mm[ (bit.brshift(y,10) % 256)+1 ] + x) % (2^32-1)
1626 isaac.randrsl[i] = isaac.bb
1627 end
1628end
1629
1630isaac.randinit = function (flag)
1631 local a,b,c,d,e,f,g,h = 0x9e3779b9,0x9e3779b9,0x9e3779b9,0x9e3779b9,0x9e3779b9,0x9e3779b9,0x9e3779b9,0x9e3779b9-- 0x9e3779b9 is the golden ratio
1632 isaac.aa = 0
1633 isaac.bb = 0
1634 isaac.cc = 0
1635 for i=1,4 do
1636 a,b,c,d,e,f,g,h = isaac.mix(a,b,c,d,e,f,g,h)
1637 end
1638 for i=1, 256, 8 do
1639 if flag then
1640 a = (a + isaac.randrsl[i]) % (2^32-1)
1641 b = (b + isaac.randrsl[i+1]) % (2^32-1)
1642 c = (c + isaac.randrsl[i+2]) % (2^32-1)
1643 d = (b + isaac.randrsl[i+3]) % (2^32-1)
1644 e = (e + isaac.randrsl[i+4]) % (2^32-1)
1645 f = (f + isaac.randrsl[i+5]) % (2^32-1)
1646 g = (g + isaac.randrsl[i+6]) % (2^32-1)
1647 h = (h + isaac.randrsl[i+7]) % (2^32-1)
1648 end
1649 a,b,c,d,e,f,g,h = isaac.mix(a,b,c,d,e,f,g,h)
1650 isaac.mm[i] = a
1651 isaac.mm[i+1] = b
1652 isaac.mm[i+2] = c
1653 isaac.mm[i+3] = d
1654 isaac.mm[i+4] = e
1655 isaac.mm[i+5] = f
1656 isaac.mm[i+6] = g
1657 isaac.mm[i+7] = h
1658 end
1659
1660 if flag then
1661 for i=1, 256, 8 do
1662 a = (a + isaac.randrsl[i]) % (2^32-1)
1663 b = (b + isaac.randrsl[i+1]) % (2^32-1)
1664 c = (c + isaac.randrsl[i+2]) % (2^32-1)
1665 d = (b + isaac.randrsl[i+3]) % (2^32-1)
1666 e = (e + isaac.randrsl[i+4]) % (2^32-1)
1667 f = (f + isaac.randrsl[i+5]) % (2^32-1)
1668 g = (g + isaac.randrsl[i+6]) % (2^32-1)
1669 h = (h + isaac.randrsl[i+7]) % (2^32-1)
1670 a,b,c,d,e,f,g,h = isaac.mix(a,b,c,d,e,f,g,h)
1671 isaac.mm[i] = a
1672 isaac.mm[i+1] = b
1673 isaac.mm[i+2] = c
1674 isaac.mm[i+3] = d
1675 isaac.mm[i+4] = e
1676 isaac.mm[i+5] = f
1677 isaac.mm[i+6] = g
1678 isaac.mm[i+7] = h
1679 end
1680 end
1681 isaac.isaac()
1682 randcnt = 256
1683end
1684
1685isaac.generate_isaac = function (entropy)
1686 isaac.aa = 0
1687 isaac.bb = 0
1688 isaac.cc = 0
1689 if entropy and #entropy >= 256 then
1690 for i=1, 256 do
1691 isaac.randrsl[i] = entropy[i]
1692 end
1693 else
1694 isaac.seed_from_mt()
1695 end
1696 for i=1, 256 do
1697 isaac.mm[i] = 0
1698 end
1699 isaac.randinit(true)
1700 isaac.isaac()
1701 isaac.isaac() -- run isaac twice
1702end
1703
1704isaac.getRandom = function ()
1705 if #isaac.mm > 0 then
1706 return table.remove(isaac.mm, 1)
1707 else
1708 isaac.generate_isaac()
1709 return table.remove(isaac.mm, 1)
1710 end
1711end
1712
1713isaac.random = function (min, max)
1714 if not max then
1715 max = 2^32-1
1716 end
1717 if not min then
1718 min = 0
1719 end
1720 return (isaac.getRandom() % max) + min
1721end
1722
1723
1724-- AES implementation
1725-- By KillaVanilla
1726
1727aes = {}
1728
1729aes.sbox = {
1730[0]=0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
17310xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
17320xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
17330x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
17340x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
17350x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
17360xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
17370x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
17380xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
17390x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
17400xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
17410xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
17420xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
17430x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
17440xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
17450x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16}
1746
1747aes.inv_sbox = {
1748[0]=0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
17490x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
17500x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
17510x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
17520x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
17530x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
17540x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
17550xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
17560x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
17570x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
17580x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
17590xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
17600x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
17610x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
17620xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
17630x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D}
1764
1765aes.Rcon = {
1766[0]=0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
17670x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
17680x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
17690x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
17700xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
17710xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
17720x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
17730x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
17740x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
17750x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
17760x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
17770x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
17780x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
17790x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
17800xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
17810x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d}
1782
1783-- Finite-field multiplication lookup tables:
1784
1785aes.mul_2 = {
1786[0]=0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e,0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e,
17870x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e,0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e,
17880x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,
17890x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e,0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e,
17900x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e,0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e,
17910xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae,0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe,
17920xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce,0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde,
17930xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee,0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe,
17940x1b,0x19,0x1f,0x1d,0x13,0x11,0x17,0x15,0x0b,0x09,0x0f,0x0d,0x03,0x01,0x07,0x05,
17950x3b,0x39,0x3f,0x3d,0x33,0x31,0x37,0x35,0x2b,0x29,0x2f,0x2d,0x23,0x21,0x27,0x25,
17960x5b,0x59,0x5f,0x5d,0x53,0x51,0x57,0x55,0x4b,0x49,0x4f,0x4d,0x43,0x41,0x47,0x45,
17970x7b,0x79,0x7f,0x7d,0x73,0x71,0x77,0x75,0x6b,0x69,0x6f,0x6d,0x63,0x61,0x67,0x65,
17980x9b,0x99,0x9f,0x9d,0x93,0x91,0x97,0x95,0x8b,0x89,0x8f,0x8d,0x83,0x81,0x87,0x85,
17990xbb,0xb9,0xbf,0xbd,0xb3,0xb1,0xb7,0xb5,0xab,0xa9,0xaf,0xad,0xa3,0xa1,0xa7,0xa5,
18000xdb,0xd9,0xdf,0xdd,0xd3,0xd1,0xd7,0xd5,0xcb,0xc9,0xcf,0xcd,0xc3,0xc1,0xc7,0xc5,
18010xfb,0xf9,0xff,0xfd,0xf3,0xf1,0xf7,0xf5,0xeb,0xe9,0xef,0xed,0xe3,0xe1,0xe7,0xe5,
1802}
1803
1804aes.mul_3 = {
1805[0]=0x00,0x03,0x06,0x05,0x0c,0x0f,0x0a,0x09,0x18,0x1b,0x1e,0x1d,0x14,0x17,0x12,0x11,
18060x30,0x33,0x36,0x35,0x3c,0x3f,0x3a,0x39,0x28,0x2b,0x2e,0x2d,0x24,0x27,0x22,0x21,
18070x60,0x63,0x66,0x65,0x6c,0x6f,0x6a,0x69,0x78,0x7b,0x7e,0x7d,0x74,0x77,0x72,0x71,
18080x50,0x53,0x56,0x55,0x5c,0x5f,0x5a,0x59,0x48,0x4b,0x4e,0x4d,0x44,0x47,0x42,0x41,
18090xc0,0xc3,0xc6,0xc5,0xcc,0xcf,0xca,0xc9,0xd8,0xdb,0xde,0xdd,0xd4,0xd7,0xd2,0xd1,
18100xf0,0xf3,0xf6,0xf5,0xfc,0xff,0xfa,0xf9,0xe8,0xeb,0xee,0xed,0xe4,0xe7,0xe2,0xe1,
18110xa0,0xa3,0xa6,0xa5,0xac,0xaf,0xaa,0xa9,0xb8,0xbb,0xbe,0xbd,0xb4,0xb7,0xb2,0xb1,
18120x90,0x93,0x96,0x95,0x9c,0x9f,0x9a,0x99,0x88,0x8b,0x8e,0x8d,0x84,0x87,0x82,0x81,
18130x9b,0x98,0x9d,0x9e,0x97,0x94,0x91,0x92,0x83,0x80,0x85,0x86,0x8f,0x8c,0x89,0x8a,
18140xab,0xa8,0xad,0xae,0xa7,0xa4,0xa1,0xa2,0xb3,0xb0,0xb5,0xb6,0xbf,0xbc,0xb9,0xba,
18150xfb,0xf8,0xfd,0xfe,0xf7,0xf4,0xf1,0xf2,0xe3,0xe0,0xe5,0xe6,0xef,0xec,0xe9,0xea,
18160xcb,0xc8,0xcd,0xce,0xc7,0xc4,0xc1,0xc2,0xd3,0xd0,0xd5,0xd6,0xdf,0xdc,0xd9,0xda,
18170x5b,0x58,0x5d,0x5e,0x57,0x54,0x51,0x52,0x43,0x40,0x45,0x46,0x4f,0x4c,0x49,0x4a,
18180x6b,0x68,0x6d,0x6e,0x67,0x64,0x61,0x62,0x73,0x70,0x75,0x76,0x7f,0x7c,0x79,0x7a,
18190x3b,0x38,0x3d,0x3e,0x37,0x34,0x31,0x32,0x23,0x20,0x25,0x26,0x2f,0x2c,0x29,0x2a,
18200x0b,0x08,0x0d,0x0e,0x07,0x04,0x01,0x02,0x13,0x10,0x15,0x16,0x1f,0x1c,0x19,0x1a,
1821}
1822
1823aes.mul_9 = {
1824[0]=0x00,0x09,0x12,0x1b,0x24,0x2d,0x36,0x3f,0x48,0x41,0x5a,0x53,0x6c,0x65,0x7e,0x77,
18250x90,0x99,0x82,0x8b,0xb4,0xbd,0xa6,0xaf,0xd8,0xd1,0xca,0xc3,0xfc,0xf5,0xee,0xe7,
18260x3b,0x32,0x29,0x20,0x1f,0x16,0x0d,0x04,0x73,0x7a,0x61,0x68,0x57,0x5e,0x45,0x4c,
18270xab,0xa2,0xb9,0xb0,0x8f,0x86,0x9d,0x94,0xe3,0xea,0xf1,0xf8,0xc7,0xce,0xd5,0xdc,
18280x76,0x7f,0x64,0x6d,0x52,0x5b,0x40,0x49,0x3e,0x37,0x2c,0x25,0x1a,0x13,0x08,0x01,
18290xe6,0xef,0xf4,0xfd,0xc2,0xcb,0xd0,0xd9,0xae,0xa7,0xbc,0xb5,0x8a,0x83,0x98,0x91,
18300x4d,0x44,0x5f,0x56,0x69,0x60,0x7b,0x72,0x05,0x0c,0x17,0x1e,0x21,0x28,0x33,0x3a,
18310xdd,0xd4,0xcf,0xc6,0xf9,0xf0,0xeb,0xe2,0x95,0x9c,0x87,0x8e,0xb1,0xb8,0xa3,0xaa,
18320xec,0xe5,0xfe,0xf7,0xc8,0xc1,0xda,0xd3,0xa4,0xad,0xb6,0xbf,0x80,0x89,0x92,0x9b,
18330x7c,0x75,0x6e,0x67,0x58,0x51,0x4a,0x43,0x34,0x3d,0x26,0x2f,0x10,0x19,0x02,0x0b,
18340xd7,0xde,0xc5,0xcc,0xf3,0xfa,0xe1,0xe8,0x9f,0x96,0x8d,0x84,0xbb,0xb2,0xa9,0xa0,
18350x47,0x4e,0x55,0x5c,0x63,0x6a,0x71,0x78,0x0f,0x06,0x1d,0x14,0x2b,0x22,0x39,0x30,
18360x9a,0x93,0x88,0x81,0xbe,0xb7,0xac,0xa5,0xd2,0xdb,0xc0,0xc9,0xf6,0xff,0xe4,0xed,
18370x0a,0x03,0x18,0x11,0x2e,0x27,0x3c,0x35,0x42,0x4b,0x50,0x59,0x66,0x6f,0x74,0x7d,
18380xa1,0xa8,0xb3,0xba,0x85,0x8c,0x97,0x9e,0xe9,0xe0,0xfb,0xf2,0xcd,0xc4,0xdf,0xd6,
18390x31,0x38,0x23,0x2a,0x15,0x1c,0x07,0x0e,0x79,0x70,0x6b,0x62,0x5d,0x54,0x4f,0x46,
1840}
1841
1842aes.mul_11 = {
1843[0]=0x00,0x0b,0x16,0x1d,0x2c,0x27,0x3a,0x31,0x58,0x53,0x4e,0x45,0x74,0x7f,0x62,0x69,
18440xb0,0xbb,0xa6,0xad,0x9c,0x97,0x8a,0x81,0xe8,0xe3,0xfe,0xf5,0xc4,0xcf,0xd2,0xd9,
18450x7b,0x70,0x6d,0x66,0x57,0x5c,0x41,0x4a,0x23,0x28,0x35,0x3e,0x0f,0x04,0x19,0x12,
18460xcb,0xc0,0xdd,0xd6,0xe7,0xec,0xf1,0xfa,0x93,0x98,0x85,0x8e,0xbf,0xb4,0xa9,0xa2,
18470xf6,0xfd,0xe0,0xeb,0xda,0xd1,0xcc,0xc7,0xae,0xa5,0xb8,0xb3,0x82,0x89,0x94,0x9f,
18480x46,0x4d,0x50,0x5b,0x6a,0x61,0x7c,0x77,0x1e,0x15,0x08,0x03,0x32,0x39,0x24,0x2f,
18490x8d,0x86,0x9b,0x90,0xa1,0xaa,0xb7,0xbc,0xd5,0xde,0xc3,0xc8,0xf9,0xf2,0xef,0xe4,
18500x3d,0x36,0x2b,0x20,0x11,0x1a,0x07,0x0c,0x65,0x6e,0x73,0x78,0x49,0x42,0x5f,0x54,
18510xf7,0xfc,0xe1,0xea,0xdb,0xd0,0xcd,0xc6,0xaf,0xa4,0xb9,0xb2,0x83,0x88,0x95,0x9e,
18520x47,0x4c,0x51,0x5a,0x6b,0x60,0x7d,0x76,0x1f,0x14,0x09,0x02,0x33,0x38,0x25,0x2e,
18530x8c,0x87,0x9a,0x91,0xa0,0xab,0xb6,0xbd,0xd4,0xdf,0xc2,0xc9,0xf8,0xf3,0xee,0xe5,
18540x3c,0x37,0x2a,0x21,0x10,0x1b,0x06,0x0d,0x64,0x6f,0x72,0x79,0x48,0x43,0x5e,0x55,
18550x01,0x0a,0x17,0x1c,0x2d,0x26,0x3b,0x30,0x59,0x52,0x4f,0x44,0x75,0x7e,0x63,0x68,
18560xb1,0xba,0xa7,0xac,0x9d,0x96,0x8b,0x80,0xe9,0xe2,0xff,0xf4,0xc5,0xce,0xd3,0xd8,
18570x7a,0x71,0x6c,0x67,0x56,0x5d,0x40,0x4b,0x22,0x29,0x34,0x3f,0x0e,0x05,0x18,0x13,
18580xca,0xc1,0xdc,0xd7,0xe6,0xed,0xf0,0xfb,0x92,0x99,0x84,0x8f,0xbe,0xb5,0xa8,0xa3,
1859}
1860
1861aes.mul_13 = {
1862[0]=0x00,0x0d,0x1a,0x17,0x34,0x39,0x2e,0x23,0x68,0x65,0x72,0x7f,0x5c,0x51,0x46,0x4b,
18630xd0,0xdd,0xca,0xc7,0xe4,0xe9,0xfe,0xf3,0xb8,0xb5,0xa2,0xaf,0x8c,0x81,0x96,0x9b,
18640xbb,0xb6,0xa1,0xac,0x8f,0x82,0x95,0x98,0xd3,0xde,0xc9,0xc4,0xe7,0xea,0xfd,0xf0,
18650x6b,0x66,0x71,0x7c,0x5f,0x52,0x45,0x48,0x03,0x0e,0x19,0x14,0x37,0x3a,0x2d,0x20,
18660x6d,0x60,0x77,0x7a,0x59,0x54,0x43,0x4e,0x05,0x08,0x1f,0x12,0x31,0x3c,0x2b,0x26,
18670xbd,0xb0,0xa7,0xaa,0x89,0x84,0x93,0x9e,0xd5,0xd8,0xcf,0xc2,0xe1,0xec,0xfb,0xf6,
18680xd6,0xdb,0xcc,0xc1,0xe2,0xef,0xf8,0xf5,0xbe,0xb3,0xa4,0xa9,0x8a,0x87,0x90,0x9d,
18690x06,0x0b,0x1c,0x11,0x32,0x3f,0x28,0x25,0x6e,0x63,0x74,0x79,0x5a,0x57,0x40,0x4d,
18700xda,0xd7,0xc0,0xcd,0xee,0xe3,0xf4,0xf9,0xb2,0xbf,0xa8,0xa5,0x86,0x8b,0x9c,0x91,
18710x0a,0x07,0x10,0x1d,0x3e,0x33,0x24,0x29,0x62,0x6f,0x78,0x75,0x56,0x5b,0x4c,0x41,
18720x61,0x6c,0x7b,0x76,0x55,0x58,0x4f,0x42,0x09,0x04,0x13,0x1e,0x3d,0x30,0x27,0x2a,
18730xb1,0xbc,0xab,0xa6,0x85,0x88,0x9f,0x92,0xd9,0xd4,0xc3,0xce,0xed,0xe0,0xf7,0xfa,
18740xb7,0xba,0xad,0xa0,0x83,0x8e,0x99,0x94,0xdf,0xd2,0xc5,0xc8,0xeb,0xe6,0xf1,0xfc,
18750x67,0x6a,0x7d,0x70,0x53,0x5e,0x49,0x44,0x0f,0x02,0x15,0x18,0x3b,0x36,0x21,0x2c,
18760x0c,0x01,0x16,0x1b,0x38,0x35,0x22,0x2f,0x64,0x69,0x7e,0x73,0x50,0x5d,0x4a,0x47,
18770xdc,0xd1,0xc6,0xcb,0xe8,0xe5,0xf2,0xff,0xb4,0xb9,0xae,0xa3,0x80,0x8d,0x9a,0x97,
1878}
1879
1880aes.mul_14 = {
1881[0]=0x00,0x0e,0x1c,0x12,0x38,0x36,0x24,0x2a,0x70,0x7e,0x6c,0x62,0x48,0x46,0x54,0x5a,
18820xe0,0xee,0xfc,0xf2,0xd8,0xd6,0xc4,0xca,0x90,0x9e,0x8c,0x82,0xa8,0xa6,0xb4,0xba,
18830xdb,0xd5,0xc7,0xc9,0xe3,0xed,0xff,0xf1,0xab,0xa5,0xb7,0xb9,0x93,0x9d,0x8f,0x81,
18840x3b,0x35,0x27,0x29,0x03,0x0d,0x1f,0x11,0x4b,0x45,0x57,0x59,0x73,0x7d,0x6f,0x61,
18850xad,0xa3,0xb1,0xbf,0x95,0x9b,0x89,0x87,0xdd,0xd3,0xc1,0xcf,0xe5,0xeb,0xf9,0xf7,
18860x4d,0x43,0x51,0x5f,0x75,0x7b,0x69,0x67,0x3d,0x33,0x21,0x2f,0x05,0x0b,0x19,0x17,
18870x76,0x78,0x6a,0x64,0x4e,0x40,0x52,0x5c,0x06,0x08,0x1a,0x14,0x3e,0x30,0x22,0x2c,
18880x96,0x98,0x8a,0x84,0xae,0xa0,0xb2,0xbc,0xe6,0xe8,0xfa,0xf4,0xde,0xd0,0xc2,0xcc,
18890x41,0x4f,0x5d,0x53,0x79,0x77,0x65,0x6b,0x31,0x3f,0x2d,0x23,0x09,0x07,0x15,0x1b,
18900xa1,0xaf,0xbd,0xb3,0x99,0x97,0x85,0x8b,0xd1,0xdf,0xcd,0xc3,0xe9,0xe7,0xf5,0xfb,
18910x9a,0x94,0x86,0x88,0xa2,0xac,0xbe,0xb0,0xea,0xe4,0xf6,0xf8,0xd2,0xdc,0xce,0xc0,
18920x7a,0x74,0x66,0x68,0x42,0x4c,0x5e,0x50,0x0a,0x04,0x16,0x18,0x32,0x3c,0x2e,0x20,
18930xec,0xe2,0xf0,0xfe,0xd4,0xda,0xc8,0xc6,0x9c,0x92,0x80,0x8e,0xa4,0xaa,0xb8,0xb6,
18940x0c,0x02,0x10,0x1e,0x34,0x3a,0x28,0x26,0x7c,0x72,0x60,0x6e,0x44,0x4a,0x58,0x56,
18950x37,0x39,0x2b,0x25,0x0f,0x01,0x13,0x1d,0x47,0x49,0x5b,0x55,0x7f,0x71,0x63,0x6d,
18960xd7,0xd9,0xcb,0xc5,0xef,0xe1,0xf3,0xfd,0xa7,0xa9,0xbb,0xb5,0x9f,0x91,0x83,0x8d,
1897}
1898
1899aes.bxor = bit.bxor
1900aes.insert = table.insert
1901
1902aes.copy = function (input)
1903 local c = {}
1904 for i, v in pairs(input) do
1905 c[i] = v
1906 end
1907 return c
1908end
1909
1910aes.subBytes = function (input, invert)
1911 for i=1, #input do
1912 if not (aes.sbox[input[i]] and aes.inv_sbox[input[i]]) then
1913 error("subBytes: input["..i.."] > 0xFF")
1914 end
1915 if invert then
1916 input[i] = aes.inv_sbox[input[i]]
1917 else
1918 input[i] = aes.sbox[input[i]]
1919 end
1920 end
1921 return input
1922end
1923
1924aes.shiftRows = function (input)
1925 local copy = {}
1926 -- Row 1: No change
1927 copy[1] = input[1]
1928 copy[2] = input[2]
1929 copy[3] = input[3]
1930 copy[4] = input[4]
1931 -- Row 2: Offset 1
1932 copy[5] = input[6]
1933 copy[6] = input[7]
1934 copy[7] = input[8]
1935 copy[8] = input[5]
1936 -- Row 3: Offset 2
1937 copy[9] = input[11]
1938 copy[10] = input[12]
1939 copy[11] = input[9]
1940 copy[12] = input[10]
1941 -- Row 4: Offset 3
1942 copy[13] = input[16]
1943 copy[14] = input[13]
1944 copy[15] = input[14]
1945 copy[16] = input[15]
1946 return copy
1947end
1948
1949aes.invShiftRows = function (input)
1950 local copy = {}
1951 -- Row 1: No change
1952 copy[1] = input[1]
1953 copy[2] = input[2]
1954 copy[3] = input[3]
1955 copy[4] = input[4]
1956 -- Row 2: Offset 1
1957 copy[5] = input[8]
1958 copy[6] = input[5]
1959 copy[7] = input[6]
1960 copy[8] = input[7]
1961 -- Row 3: Offset 2
1962 copy[9] = input[11]
1963 copy[10] = input[12]
1964 copy[11] = input[9]
1965 copy[12] = input[10]
1966 -- Row 4: Offset 3
1967 copy[13] = input[14]
1968 copy[14] = input[15]
1969 copy[15] = input[16]
1970 copy[16] = input[13]
1971 return copy
1972end
1973
1974aes.finite_field_mul = function (a,b) -- Multiply two numbers in GF(256), assuming that polynomials are 8 bits wide
1975 local product = 0
1976 local mulA, mulB = a,b
1977 for i=1, 8 do
1978 --print("FFMul: MulA: "..mulA.." MulB: "..mulB)
1979 if mulA == 0 or mulB == 0 then
1980 break
1981 end
1982 if bit.band(1, mulB) > 0 then
1983 product = aes.bxor(product, mulA)
1984 end
1985 mulB = bit.brshift(mulB, 1)
1986 local carry = bit.band(0x80, mulA)
1987 mulA = bit.band(0xFF, bit.blshift(mulA, 1))
1988 if carry > 0 then
1989 mulA = aes.bxor( mulA, 0x1B )
1990 end
1991 end
1992 return product
1993end
1994
1995aes.mixColumn = function (column)
1996 local output = {}
1997 --print("MixColumn: #column: "..#column)
1998 output[1] = aes.bxor( aes.mul_2[column[1]], aes.bxor( aes.mul_3[column[2]], aes.bxor( column[3], column[4] ) ) )
1999 output[2] = aes.bxor( column[1], aes.bxor( aes.mul_2[column[2]], aes.bxor( aes.mul_3[column[3]], column[4] ) ) )
2000 output[3] = aes.bxor( column[1], aes.bxor( column[2], aes.bxor( aes.mul_2[column[3]], aes.mul_3[column[4]] ) ) )
2001 output[4] = aes.bxor( aes.mul_3[column[1]], aes.bxor( column[2], aes.bxor( column[3], aes.mul_2[column[4]] ) ) )
2002 return output
2003end
2004
2005aes.invMixColumn = function (column)
2006 local output = {}
2007 --print("InvMixColumn: #column: "..#column)
2008 output[1] = aes.bxor( aes.mul_14[column[1]], aes.bxor( aes.mul_11[column[2]], aes.bxor( aes.mul_13[column[3]], aes.mul_9[column[4]] ) ) )
2009 output[2] = aes.bxor( aes.mul_9[column[1]], aes.bxor( aes.mul_14[column[2]], aes.bxor( aes.mul_11[column[3]], aes.mul_13[column[4]] ) ) )
2010 output[3] = aes.bxor( aes.mul_13[column[1]], aes.bxor( aes.mul_9[column[2]], aes.bxor( aes.mul_14[column[3]], aes.mul_11[column[4]] ) ) )
2011 output[4] = aes.bxor( aes.mul_11[column[1]], aes.bxor( aes.mul_13[column[2]], aes.bxor( aes.mul_9[column[3]], aes.mul_14[column[4]] ) ) )
2012 return output
2013end
2014
2015aes.mixColumns = function (input, invert)
2016 --print("MixColumns: #input: "..#input)
2017 -- Ooops. I mixed the ROWS instead of the COLUMNS on accident.
2018 local output = {}
2019 --[[
2020 local c1 = { input[1], input[2], input[3], input[4] }
2021 local c2 = { input[5], input[6], input[7], input[8] }
2022 local c3 = { input[9], input[10], input[11], input[12] }
2023 local c4 = { input[13], input[14], input[15], input[16] }
2024 ]]
2025 local c1 = { input[1], input[5], input[9], input[13] }
2026 local c2 = { input[2], input[6], input[10], input[14] }
2027 local c3 = { input[3], input[7], input[11], input[15] }
2028 local c4 = { input[4], input[8], input[12], input[16] }
2029 if invert then
2030 c1 = aes.invMixColumn(c1)
2031 c2 = aes.invMixColumn(c2)
2032 c3 = aes.invMixColumn(c3)
2033 c4 = aes.invMixColumn(c4)
2034 else
2035 c1 = aes.mixColumn(c1)
2036 c2 = aes.mixColumn(c2)
2037 c3 = aes.mixColumn(c3)
2038 c4 = aes.mixColumn(c4)
2039 end
2040 --[[
2041 output[1] = c1[1]
2042 output[2] = c1[2]
2043 output[3] = c1[3]
2044 output[4] = c1[4]
2045
2046 output[5] = c2[1]
2047 output[6] = c2[2]
2048 output[7] = c2[3]
2049 output[8] = c2[4]
2050
2051 output[9] = c3[1]
2052 output[10] = c3[2]
2053 output[11] = c3[3]
2054 output[12] = c3[4]
2055
2056 output[13] = c4[1]
2057 output[14] = c4[2]
2058 output[15] = c4[3]
2059 output[16] = c4[4]
2060 ]]
2061
2062 output[1] = c1[1]
2063 output[5] = c1[2]
2064 output[9] = c1[3]
2065 output[13] = c1[4]
2066
2067 output[2] = c2[1]
2068 output[6] = c2[2]
2069 output[10] = c2[3]
2070 output[14] = c2[4]
2071
2072 output[3] = c3[1]
2073 output[7] = c3[2]
2074 output[11] = c3[3]
2075 output[15] = c3[4]
2076
2077 output[4] = c4[1]
2078 output[8] = c4[2]
2079 output[12] = c4[3]
2080 output[16] = c4[4]
2081
2082 return output
2083end
2084
2085aes.addRoundKey = function (input, exp_key, round)
2086 local output = {}
2087 for i=1, 16 do
2088 assert(input[i], "input["..i.."]=nil!")
2089 assert(exp_key[ ((round-1)*16)+i ], "round_key["..(((round-1)*16)+i).."]=nil!")
2090 output[i] = aes.bxor( input[i], exp_key[ ((round-1)*16)+i ] )
2091 end
2092 return output
2093end
2094
2095aes.key_schedule = function (enc_key)
2096 local function core(in1, in2, in3, in4, i)
2097 local s1 = in2
2098 local s2 = in3
2099 local s3 = in4
2100 local s4 = in1
2101 s1 = aes.bxor(aes.sbox[s1], aes.Rcon[i])
2102 s2 = aes.sbox[s2]
2103 s3 = aes.sbox[s3]
2104 s4 = aes.sbox[s4]
2105 return s1, s2, s3, s4
2106 end
2107
2108 local n, b, key_type = 0, 0, 0
2109
2110 -- Len | n | b |
2111 -- 128 |16 |176|
2112 -- 192 |24 |208|
2113 -- 256 |32 |240|
2114
2115 -- Determine keysize:
2116
2117 if #enc_key < 16 then
2118 error("Encryption key is too small; key size must be more than 16 bytes.")
2119 elseif #enc_key >= 16 and #enc_key < 24 then
2120 n = 16
2121 b = 176
2122 --key_type = 1
2123 elseif #enc_key >= 24 and #enc_key < 32 then
2124 n = 24
2125 b = 208
2126 --key_type = 2
2127 else
2128 n = 32
2129 b = 240
2130 --key_type = 3
2131 end
2132
2133 local exp_key = {}
2134 local rcon_iter = 1
2135 for i=1, n do
2136 exp_key[i] = enc_key[i]
2137 end
2138 while #exp_key < b do
2139 local t1 = exp_key[#exp_key]
2140 local t2 = exp_key[#exp_key-1]
2141 local t3 = exp_key[#exp_key-2]
2142 local t4 = exp_key[#exp_key-3]
2143 t1, t2, t3, t4 = core(t1, t2, t3, t4, rcon_iter)
2144 rcon_iter = rcon_iter+1
2145 t1 = aes.bxor(t1, exp_key[#exp_key-(n-1)])
2146 t2 = aes.bxor(t2, exp_key[#exp_key-(n-2)])
2147 t3 = aes.bxor(t3, exp_key[#exp_key-(n-3)])
2148 t4 = aes.bxor(t4, exp_key[#exp_key-(n-4)])
2149 aes.insert(exp_key, t1)
2150 aes.insert(exp_key, t2)
2151 aes.insert(exp_key, t3)
2152 aes.insert(exp_key, t4)
2153 for i=1, 3 do
2154 t1 = aes.bxor(exp_key[#exp_key], exp_key[#exp_key-(n-1)])
2155 t2 = aes.bxor(exp_key[#exp_key-1], exp_key[#exp_key-(n-2)])
2156 t3 = aes.bxor(exp_key[#exp_key-2], exp_key[#exp_key-(n-3)])
2157 t4 = aes.bxor(exp_key[#exp_key-3], exp_key[#exp_key-(n-4)])
2158 aes.insert(exp_key, t1)
2159 aes.insert(exp_key, t2)
2160 aes.insert(exp_key, t3)
2161 aes.insert(exp_key, t4)
2162 end
2163 if key_type == 3 then -- If we're processing a 256 bit key...
2164 -- Take the previous 4 bytes of the expanded key, run them through the sbox,
2165 -- then XOR them with the previous n bytes of the expanded key, then output them
2166 -- as the next 4 bytes of expanded key.
2167 t1 = aes.bxor(aes.sbox[exp_key[#exp_key]], exp_key[#exp_key-(n-1)])
2168 t2 = aes.bxor(aes.sbox[exp_key[#exp_key-1]], exp_key[#exp_key-(n-2)])
2169 t3 = aes.bxor(aes.sbox[exp_key[#exp_key-2]], exp_key[#exp_key-(n-3)])
2170 t4 = aes.bxor(aes.sbox[exp_key[#exp_key-3]], exp_key[#exp_key-(n-4)])
2171 aes.insert(exp_key, t1)
2172 aes.insert(exp_key, t2)
2173 aes.insert(exp_key, t3)
2174 aes.insert(exp_key, t4)
2175 end
2176 if key_type == 2 or key_type == 3 then -- If we're processing a 192-bit or 256-bit key..
2177 local i = 2
2178 if key_type == 3 then
2179 i = 3
2180 end
2181 for j=1, i do
2182 t1 = aes.bxor(exp_key[#exp_key], exp_key[#exp_key-(n-1)])
2183 t2 = aes.bxor(exp_key[#exp_key-1], exp_key[#exp_key-(n-2)])
2184 t3 = aes.bxor(exp_key[#exp_key-2], exp_key[#exp_key-(n-3)])
2185 t4 = aes.bxor(exp_key[#exp_key-3], exp_key[#exp_key-(n-4)])
2186 aes.insert(exp_key, t1)
2187 aes.insert(exp_key, t2)
2188 aes.insert(exp_key, t3)
2189 aes.insert(exp_key, t4)
2190 end
2191 end
2192 end
2193 return exp_key
2194end
2195
2196-- Transform a string of bytes into 16 byte blocks, adding padding to ensure that each block contains 16 bytes.
2197-- For example:
2198-- "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" (contains 28 0xFF bytes)
2199-- Is transformed into this:
2200-- {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}, {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0,0,0,0} (16 0xFF bytes, followed by 12 0xFF bytes and 4 0x00 bytes for padding)
2201
2202aes.breakIntoBlocks = function (data)
2203 if type(data) ~= "string" then
2204 error("breakIntoBlocks: data is not a string", 2)
2205 end
2206 while (#data % 16) ~= 0 do
2207 data = data.."\0"
2208 end
2209 local blocks = {}
2210 local blockNum = 1
2211 local output = {}
2212 for i=1, #data, 16 do
2213 blocks[blockNum] = {}
2214 for j=1, 16 do
2215 blocks[blockNum][j] = string.byte(data, ((blockNum-1)*16)+j, ((blockNum-1)*16)+j)
2216 end
2217 blockNum = blockNum+1
2218 end
2219 return blocks
2220end
2221
2222-- Transform a string into a series of blocks.
2223
2224-- For example, to get a key from a string:
2225-- local key = strToBlocks(keyStr)
2226-- key = key[1]
2227
2228aes.strToBlocks = function (str)
2229 local rawBytestream = {}
2230 local blocks = {}
2231 for i=1, #str do
2232 rawBytestream[i] = string.byte(str, i, i)
2233 end
2234 for i=1, math.ceil(#rawBytestream / 16) do
2235 blocks[i] = {}
2236 for j=1, 16 do
2237 blocks[i][j] = rawBytestream[ ((i-1)*16)+j ] or 0
2238 end
2239 end
2240 return blocks
2241end
2242
2243-- Encrypt / Decrypt individual blocks:
2244
2245aes.encrypt_block = function (data, key)
2246 local exp_key = aes.key_schedule(key)
2247 local state = data
2248 local nr = 0
2249
2250 if #exp_key == 176 then -- Key type 1 (128-bits)
2251 nr = 10
2252 elseif #exp_key == 208 then -- Key type 2 (192-bits)
2253 nr = 12
2254 elseif #exp_key == 240 then -- Key type 3 (256-bits)
2255 nr = 14
2256 else
2257 error("encrypt_block: Unknown key size?", 2)
2258 end
2259
2260 -- Inital round:
2261 state = aes.addRoundKey(state, exp_key, 1)
2262
2263 -- Repeat (Nr-1) times:
2264 for round_num = 2, nr-1 do
2265 state = aes.subBytes(state)
2266 state = aes.shiftRows(state)
2267 state = aes.mixColumns(state)
2268 state = aes.addRoundKey(state, exp_key, round_num)
2269 end
2270
2271 -- Final round (No mixColumns()):
2272 state = aes.subBytes(state)
2273 state = aes.shiftRows(state)
2274 state = aes.addRoundKey(state, exp_key, nr)
2275 return state
2276end
2277
2278aes.decrypt_block = function (data, key)
2279 local exp_key = aes.key_schedule(key)
2280 local state = data
2281 local nr = 0
2282
2283 if #exp_key == 176 then -- Key type 1 (128-bits)
2284 nr = 10
2285 elseif #exp_key == 208 then -- Key type 2 (192-bits)
2286 nr = 12
2287 elseif #exp_key == 240 then -- Key type 3 (256-bits)
2288 nr = 14
2289 else
2290 error("decrypt_block: Unknown key size?", 2)
2291 end
2292
2293 -- Inital round:
2294 state = aes.addRoundKey(state, exp_key, nr)
2295
2296 -- Repeat (Nr-1) times:
2297 for round_num = nr-1, 2, -1 do
2298 state = aes.invShiftRows(state)
2299 state = aes.subBytes(state, true)
2300 state = aes.addRoundKey(state, exp_key, round_num)
2301 state = aes.mixColumns(state, true)
2302 end
2303
2304 -- Final round (No mixColumns()):
2305 state = aes.invShiftRows(state)
2306 state = aes.subBytes(state, true)
2307 state = aes.addRoundKey(state, exp_key, 1)
2308 return state
2309end
2310
2311aes.encrypt_block_customExpKey = function (data, exp_key--[[, key_type]]) -- Encrypt blocks, but using a precalculated expanded key instead of performing the key expansion on every step like with the normal encrypt_block(2) call
2312 local state = data
2313 local nr = 0
2314 if #exp_key == 176 then -- Key type 1 (128-bits)
2315 nr = 10
2316 elseif #exp_key == 208 then -- Key type 2 (192-bits)
2317 nr = 12
2318 elseif #exp_key == 240 then -- Key type 3 (256-bits)
2319 nr = 14
2320 else
2321 error("encrypt_block: Unknown key size?", 2)
2322 end
2323
2324 -- Inital round:
2325 state = aes.addRoundKey(state, exp_key, 1)
2326
2327 -- Repeat (Nr-1) times:
2328 for round_num = 2, nr-1 do
2329 state = aes.subBytes(state)
2330 state = aes.shiftRows(state)
2331 state = aes.mixColumns(state)
2332 state = aes.addRoundKey(state, exp_key, round_num)
2333 end
2334
2335 -- Final round (No mixColumns()):
2336 state = aes.subBytes(state)
2337 state = aes.shiftRows(state)
2338 state = aes.addRoundKey(state, exp_key, nr)
2339 return state
2340end
2341
2342aes.decrypt_block_customExpKey = function (data, exp_key--[[, key_type]])
2343 local state = data
2344 local nr = 0
2345 if #exp_key == 176 then -- Key type 1 (128-bits)
2346 nr = 10
2347 elseif #exp_key == 208 then -- Key type 2 (192-bits)
2348 nr = 12
2349 elseif #exp_key == 240 then -- Key type 3 (256-bits)
2350 nr = 14
2351 else
2352 error("decrypt_block: Unknown key size?", 2)
2353 end
2354
2355 -- Inital round:
2356 state = aes.addRoundKey(state, exp_key, nr)
2357
2358 -- Repeat (Nr-1) times:
2359 for round_num = nr-1, 2, -1 do
2360 state = aes.invShiftRows(state)
2361 state = aes.subBytes(state, true)
2362 state = aes.addRoundKey(state, exp_key, round_num)
2363 state = aes.mixColumns(state, true)
2364 end
2365
2366 -- Final round (No mixColumns()):
2367 state = aes.invShiftRows(state)
2368 state = aes.subBytes(state, true)
2369 state = aes.addRoundKey(state, exp_key, 1)
2370 return state
2371end
2372
2373-- Encrypt / Decrypt bytestreams (tables of bytes):
2374
2375-- ECB (electronic codebook) Mode (not secure, do not use):
2376
2377aes.encrypt_bytestream_ecb = function (data, key)
2378 local blocks = {}
2379 local outputBytestream = {}
2380 local exp_key = aes.key_schedule(key)
2381 for i=1, #data, 16 do
2382 local block = {}
2383 for j=1, 16 do
2384 block[j] = data[i+(j-1)] or 0
2385 end
2386 block = aes.encrypt_block_customExpKey(block, exp_key)
2387 for j=1, 16 do
2388 table.insert(outputBytestream, block[j])
2389 end
2390 os.queueEvent("")
2391 os.pullEvent("")
2392 end
2393 return outputBytestream
2394end
2395
2396aes.decrypt_bytestream_ecb = function (data, key)
2397 local outputBytestream = {}
2398 local exp_key = aes.key_schedule(key)
2399 for i=1, #data, 16 do
2400 local block = {}
2401 for j=1, 16 do
2402 block[j] = data[i+(j-1)] or 0
2403 end
2404 block = aes.decrypt_block_customExpKey(block, exp_key)
2405 for j=1, 16 do
2406 table.insert(outputBytestream, block[j])
2407 end
2408 os.queueEvent("")
2409 os.pullEvent("")
2410 end
2411 for i=#outputBytestream, 1, -1 do
2412 if outputBytestream[i] ~= 0 then
2413 break
2414 else
2415 outputBytestream[i] = nil
2416 end
2417 end
2418 return outputBytestream
2419end
2420
2421-- CBC (cipher-block chaining) mode:
2422
2423aes.encrypt_bytestream = function (data, key, init_vector)
2424 local blocks = { init_vector }
2425 local outputBytestream = {}
2426 local exp_key = aes.key_schedule(key)
2427 if not init_vector then
2428 error("encrypt_bytestream: No initalization vector was passed.", 2)
2429 end
2430 for i=1, #data do
2431 if data[i] == nil or data[i] >= 256 then
2432 if type(data[i]) == "number" then
2433 error("encrypt_bytestream: Invalid data at i="..i.." data[i]="..data[i], 2)
2434 else
2435 error("encrypt_bytestream: Invalid data at i="..i.." data[i]="..type(data[i]), 2)
2436 end
2437 end
2438 end
2439 local s = os.clock()
2440 for i=1, math.ceil(#data/16) do
2441 local block = {}
2442 if not blocks[i] then
2443 error("encrypt_bytestream: blocks["..i.."] is nil! Input size: "..#data, 2)
2444 end
2445 for j=1, 16 do
2446 block[j] = data[((i-1)*16)+j] or 0
2447 block[j] = aes.bxor(block[j], blocks[i][j]) -- XOR this block with the previous one
2448 end
2449 --print("#bytes: "..#block)
2450 block = aes.encrypt_block_customExpKey(block, exp_key)
2451 table.insert(blocks, block)
2452 for j=1, 16 do
2453 aes.insert(outputBytestream, block[j])
2454 end
2455 if os.clock() - s >= 2.5 then
2456 os.queueEvent("")
2457 os.pullEvent("")
2458 s = os.clock()
2459 end
2460 end
2461 return outputBytestream
2462end
2463
2464aes.decrypt_bytestream = function (data, key, init_vector)
2465 local blocks = { init_vector }
2466 local outputBytestream = {}
2467 local exp_key = aes.key_schedule(key)
2468 if not init_vector then
2469 error("decrypt_bytestream: No initalization vector was passed.", 2)
2470 end
2471 local s = os.clock()
2472 for i=1, math.ceil(#data/16) do
2473 local block = {}
2474 if not blocks[i] then
2475 error("decrypt_bytestream: blocks["..i.."] is nil! Input size: "..#data, 2)
2476 end
2477 for j=1, 16 do
2478 block[j] = data[((i-1)*16)+j] or 0
2479 end
2480 table.insert(blocks, block)
2481 local dec_block = aes.decrypt_block_customExpKey(block, exp_key)
2482 for j=1, 16 do
2483 dec_block[j] = aes.bxor(dec_block[j], blocks[i][j]) -- We use XOR on the plaintext, not the ciphertext
2484 table.insert(outputBytestream, dec_block[j])
2485 end
2486 if os.clock() - s >= 2.5 then
2487 os.queueEvent("")
2488 os.pullEvent("")
2489 s = os.clock()
2490 end
2491 end
2492 -- Remove padding:
2493 for i=#outputBytestream, #outputBytestream-15, -1 do
2494 if outputBytestream[i] ~= 0 then
2495 break
2496 else
2497 outputBytestream[i] = nil
2498 end
2499 end
2500 return outputBytestream
2501end
2502
2503-- Encrypt / Decrypt strings:
2504
2505aes.encrypt_str = function (data, key, iv)
2506 local byteStream = {}
2507 for i=1, #data do
2508 table.insert(byteStream, string.byte(data, i, i))
2509 end
2510 local output_bytestream = {}
2511 if iv then
2512 output_bytestream = aes.encrypt_bytestream(byteStream, key, iv)
2513 else
2514 output_bytestream = aes.encrypt_bytestream_ecb(byteStream, key)
2515 end
2516 local output = ""
2517 for i=1, #output_bytestream do
2518 output = output..string.char(output_bytestream[i])
2519 end
2520 return output
2521end
2522
2523aes.decrypt_str = function (data, key, iv)
2524 local byteStream = {}
2525 for i=1, #data do
2526 table.insert(byteStream, string.byte(data, i, i))
2527 end
2528 local output_bytestream = {}
2529 if iv then
2530 output_bytestream = aes.decrypt_bytestream(byteStream, key, iv)
2531 else
2532 output_bytestream = aes.decrypt_bytestream_ecb(byteStream, key)
2533 end
2534 local output = ""
2535 for i=1, #output_bytestream do
2536 output = output..string.char(output_bytestream[i])
2537 end
2538 return output
2539end
2540
2541aes.davies_meyer = function (data, h0)
2542 local last_h = h0
2543 for dm_iter=1, 16 do
2544 for i=1, math.ceil(#data/16) do
2545 local block = {}
2546 for j=1, 16 do
2547 block[j] = data[((i-1)*16)+j] or 0
2548 end
2549 local block = aes.encrypt_block(last_h, block)
2550 for j=1, 16 do
2551 block[j] = aes.bxor(block[j], last_h[j]) -- XOR h[i-1] with h[i].
2552 end
2553 last_h = block
2554 os.queueEvent("")
2555 os.pullEvent("")
2556 end
2557 end
2558 return last_h
2559end
2560
2561aes.increment_ctr = function (blk)
2562 local cpy = {}
2563 for i=1, 16 do
2564 cpy[i] = blk[i] or 0
2565 end
2566 cpy[1] = cpy[1] + incAmt
2567 for i=2, 16 do
2568 if cpy[i-1] <= 255 then
2569 break
2570 end
2571 local carry = cpy[i-1] - 255
2572 cpy[i] = cpy[i]+carry
2573 end
2574 return cpy
2575end
2576
2577aes.counter_mode_context = {
2578 key = {},
2579 ctr = {},
2580 stream_cache = {}, -- Use "leftover" bytes from generate() here.
2581 set_key = function(self, key)
2582 if type(key) == "string" then
2583 if #key < 16 then
2584 error("set_key: Key length ("..#key..") must be at least 16 characters!", 2)
2585 end
2586 for i=1, 16 do
2587 self.key[i] = string.byte(key, i, i)
2588 end
2589 elseif type(key) == "table" then
2590 if #key < 16 then
2591 error("set_key: Key length ("..#key..") must be at least 16 bytes!", 2)
2592 end
2593 for i=1, 16 do
2594 if type(key[i]) ~= "number" or key[i] > 255 or key[i] < 0 then
2595 if type(key[i]) == "nil" then
2596 error("set_key: Value key["..i.."] is invalid: nil", 2)
2597 else
2598 error("set_key: Value key["..i.."] is invalid: "..key[i], 2)
2599 end
2600 end
2601 self.key[i] = key[i]
2602 end
2603 else
2604 error("set_key: Key type is not supported: "..type(key), 2)
2605 end
2606 end,
2607 set_ctr = function(self, ctr)
2608 if type(ctr) == "string" then
2609 if #ctr < 16 then
2610 error("set_ctr: Counter length ("..#ctr..") must be at least 16 characters!", 2)
2611 end
2612 for i=1, 16 do
2613 self.ctr[i] = string.byte(ctr, i, i)
2614 end
2615 elseif type(ctr) == "table" then
2616 if #ctr < 16 then
2617 error("set_ctr: Counter length ("..#ctr..") must be at least 16 bytes!", 2)
2618 end
2619 for i=1, 16 do
2620 if type(ctr[i]) ~= "number" or ctr[i] > 255 or ctr[i] < 0 then
2621 if type(ctr[i]) == "nil" then
2622 error("set_ctr: Value ctr["..i.."] is invalid: nil", 2)
2623 else
2624 error("set_ctr: Value ctr["..i.."] is invalid: "..ctr[i], 2)
2625 end
2626 end
2627 self.ctr[i] = ctr[i]
2628 end
2629 elseif type(ctr) == "number" then
2630 local b1 = bit.band( ctr, 0xFF )
2631 local b2 = bit.band( bit.brshift(bit.band( ctr, 0xFF00 ), 8), 0xFF )
2632 local b3 = bit.band( bit.brshift(bit.band( ctr, 0xFF0000 ), 16), 0xFF )
2633 local b4 = bit.band( bit.brshift(bit.band( ctr, 0xFF000000 ), 24), 0xFF )
2634 self.ctr = {}
2635 for i=1, 16 do
2636 self.ctr[i] = 0
2637 end
2638 self.ctr[1] = b1
2639 self.ctr[2] = b2
2640 self.ctr[3] = b3
2641 self.ctr[4] = b4
2642 else
2643 error("set_ctr: Counter type is not supported: "..type(ctr), 2)
2644 end
2645 end,
2646 generate = function(self, bytes)
2647 local genBytes = {}
2648 if #self.stream_cache >= bytes then
2649 for i=1, bytes do
2650 table.insert(genBytes, table.remove(self.stream_cache))
2651 end
2652 else
2653 for i=1, #self.stream_cache do
2654 table.insert(genBytes, table.remove(self.stream_cache))
2655 end
2656 local blocksToGenerate = math.ceil((bytes - #genBytes) / 16)
2657 for i=1, blocksToGenerate-1 do
2658 self.ctr = aes.increment_ctr(self.ctr)
2659 local block = aes.encrypt_block(self.ctr, self.key)
2660 for i=1, 16 do
2661 table.insert(genBytes, block[i])
2662 end
2663 end
2664 self.ctr = aes.increment_ctr(self.ctr)
2665 local block = aes.encrypt_block(self.ctr, self.key)
2666 for i=1, (bytes - #genBytes) do
2667 table.insert(genBytes, table.remove(block))
2668 end
2669 for i=1, #block do
2670 table.insert(self.stream_cache, table.remove(block))
2671 end
2672 end
2673 return genBytes
2674 end,
2675}
2676
2677aes.new_ctrMode = function (key, iv)
2678 local context = {
2679 stream_cache = {},
2680 key = {},
2681 iv = {},
2682 __index = aes.counter_mode_context,
2683 }
2684 setmetatable(context, context)
2685 context:set_key(key)
2686 context:set_ctr(iv)
2687 return context
2688end
2689
2690
2691-- Simple thread API by immibis
2692
2693threadAPI = {}
2694
2695threadAPI.threads = {}
2696threadAPI.starting = {}
2697threadAPI.eventFilter = nil
2698
2699rawset(os, "startThread", function(fn, blockTerminate)
2700 table.insert(threadAPI.starting, {
2701 cr = coroutine.create(fn),
2702 blockTerminate = blockTerminate or false,
2703 error = nil,
2704 dead = false,
2705 filter = nil
2706 })
2707end)
2708
2709threadAPI.tick = function (t, evt, ...)
2710 if t.dead then return end
2711 if t.filter ~= nil and evt ~= t.filter then return end
2712 if evt == "terminate" and t.blockTerminate then return end
2713
2714 coroutine.resume(t.cr, evt, ...)
2715 t.dead = (coroutine.status(t.cr) == "dead")
2716end
2717
2718threadAPI.tickAll = function ()
2719 if #threadAPI.starting > 0 then
2720 local clone = threadAPI.starting
2721 threadAPI.starting = {}
2722 for _,v in ipairs(clone) do
2723 threadAPI.tick(v)
2724 table.insert(threadAPI.threads, v)
2725 end
2726 end
2727 local e
2728 if threadAPI.eventFilter then
2729 e = {threadAPI.eventFilter(coroutine.yield())}
2730 else
2731 e = {coroutine.yield()}
2732 end
2733 local dead = nil
2734 for k,v in ipairs(threadAPI.threads) do
2735 threadAPI.tick(v, unpack(e))
2736 if v.dead then
2737 if dead == nil then dead = {} end
2738 table.insert(dead, k - #dead)
2739 end
2740 end
2741 if dead ~= nil then
2742 for _,v in ipairs(dead) do
2743 table.remove(threadAPI.threads, v)
2744 end
2745 end
2746end
2747
2748rawset(os, "setGlobalEventFilter", function(fn)
2749 if threadAPI.eventFilter ~= nil then error("This can only be set once!") end
2750 threadAPI.eventFilter = fn
2751 rawset(os, "setGlobalEventFilter", nil)
2752end)
2753
2754threadAPI.startThreading = function (mainThread)
2755 if type(mainThread) == "function" then
2756 os.startThread(mainThread)
2757 else
2758 os.startThread(function() shell.run("shell") end)
2759 end
2760
2761 while #threadAPI.threads > 0 or #threadAPI.starting > 0 do
2762 threadAPI.tickAll()
2763 end
2764
2765 print("All threads terminated!")
2766 print("Exiting thread manager")
2767end
2768
2769------- END THRID PARTY -------
2770
2771------- BEGIN CRYPTONET -------
2772-- The following code was written by me (SiliconSloth).
2773
2774
2775-- Channel used to send discovery requests and responses.
2776DISCOVERY_CHANNEL = 65531
2777-- If set to true CryptoNet will also broadcast all messages over the Rednet
2778-- reapter channel, which allows CryptoNet messages to be repeated by the built-in
2779-- program repeat. Disabling this is a little more secure as an attacker won't know
2780-- which channel you are communicating over.
2781local repeatMessages = true
2782-- Whether to print log messages or not.
2783local loggingEnabled = true
2784-- Directory CryptoNet looks for files in.
2785local workingDir = ""
2786-- All servers currently open on this computer.
2787local allServers = {}
2788-- All client sockets (opened with connect()) open on this computer.
2789local allClientSockets = {}
2790
2791
2792local function log(message)
2793 if loggingEnabled then
2794 print("[CryptoNet] "..message)
2795 end
2796end
2797
2798
2799--
2800-- ACCESSORS
2801--
2802
2803function getLoggingEnabled()
2804 return loggingEnabled
2805end
2806
2807
2808function setLoggingEnabled(enabled)
2809 loggingEnabled = enabled
2810end
2811
2812
2813function getRepeatMessages()
2814 return repeatMessages
2815end
2816
2817
2818function setRepeatMessages(repMsgs)
2819 repeatMessages = repMsgs
2820end
2821
2822
2823function getWorkingDirectory()
2824 return workingDir
2825end
2826
2827
2828function setWorkingDirectory(dir)
2829 if type(dir) ~= "string" then
2830 error("Directory must be a string.", 2)
2831 end
2832 workingDir = dir
2833end
2834
2835
2836function getAllServers()
2837 return allServers
2838end
2839
2840
2841function getAllClientSockets()
2842 return allClientSockets
2843end
2844
2845
2846--
2847-- VALIDITY CHECKS
2848--
2849
2850-- Check that the key is a 16 element table of numbers.
2851function keyValid(key)
2852 if not (type(key) == "table" and #key == 16) then
2853 return false
2854 end
2855 -- Make sure all elements are numbers.
2856 for _,v in pairs(key) do
2857 if type(v) ~= "number" then
2858 return false
2859 end
2860 end
2861 return true
2862end
2863
2864
2865-- Check that a table has all the parts required to be a valid private key.
2866function privateKeyValid(key)
2867 return type(key) == "table" and type(key.private) == "string" and type(key.shared) == "string"
2868end
2869
2870
2871-- Check that a table has all the parts required to be a valid public key.
2872function publicKeyValid(key)
2873 return type(key) == "table" and type(key.public) == "string" and type(key.shared) == "string"
2874end
2875
2876
2877-- Check that a table has all the parts required to be a valid server certificate.
2878-- If ignoreKey is true it is acceptable for a server to have no key,
2879-- but if present it must be valid.
2880-- The signature is always optional but must be valid (syntactically,
2881-- it isn't actually verified here) if present.
2882function certificateValid(certificate, ignoreKey)
2883 -- All certificates must contain the server name.
2884 if type(certificate) ~= "table" or type(certificate.name) ~= "string" then
2885 return false
2886 end
2887
2888 -- A certificate must contain the server's public key, unless ignoreKey is true.
2889 if certificate.key == nil and not ignoreKey then
2890 return false
2891 end
2892 -- Ensure that the public key is valid, if present.
2893 if certificate.key ~= nil and not publicKeyValid(certificate.key) then
2894 return false
2895 end
2896
2897 -- A certificate should only have a signature if it also contains a key.
2898 if certificate.key == nil and certificate.signature ~= nil then
2899 return false
2900 end
2901 -- If a signature is present (which it doesn't need to be), it must be a string.
2902 if certificate.signature ~= nil and type(certificate.signature) ~= "string" then
2903 return false
2904 end
2905
2906 return true
2907end
2908
2909
2910-- Check that a table has everything it needs to be a valid server.
2911function serverValid(server)
2912 return type(server) == "table"
2913 and type(server.name) == "string"
2914 and certificateValid(server.certificate)
2915 and privateKeyValid(server.privateKey)
2916 and type(server.modemSide) == "string"
2917 and type(server.channel) == "number"
2918 and type(server.userTable) == "table"
2919 and type(server.userTablePath) == "string"
2920 and type(server.sockets) == "table"
2921end
2922
2923
2924-- Check that a table has everything it needs to be a valid socket.
2925function socketValid(socket)
2926 return type(socket) == "table"
2927 and type(socket.sender) == "string"
2928 and type(socket.target) == "string"
2929 and keyValid(socket.key)
2930 and type(socket.modemSide) == "string"
2931 and type(socket.channel) == "number"
2932 and type(socket.permissionLevel) == "number"
2933 and type(socket.receivedMessages) == "table"
2934end
2935
2936
2937-- Check that all the entries in a user table are valid.
2938function userTableValid(userTable)
2939 if type(userTable) ~= "table" then
2940 return false
2941 end
2942 for username,entry in pairs(userTable) do
2943 if type(username) ~= "string" or type(entry[1]) ~= "table" or type(entry[2]) ~= "number" then
2944 return false
2945 end
2946 end
2947 return true
2948end
2949
2950
2951--
2952-- HELPERS
2953--
2954
2955-- Used to process modem side arguments passed to functions.
2956function resolveModemSide(modemSide)
2957 -- If no modem side argument is provided, search for a modem and use that side.
2958 if modemSide == nil then
2959 for _,side in pairs(peripheral.getNames()) do
2960 if peripheral.getType(side) == "modem" then
2961 modemSide = side
2962 break
2963 end
2964 end
2965 if modemSide == nil then
2966 error("Could not find a modem.", 3)
2967 end
2968 else
2969 -- If an argument was provided, check that it is a valid side.
2970 local found = false
2971 for _,side in pairs(redstone.getSides()) do
2972 if side == modemSide then
2973 found = true
2974 break
2975 end
2976 end
2977 if not found then
2978 error(tostring(modemSide).." is not a valid side.", 3)
2979 end
2980 end
2981 if peripheral.getType(modemSide) ~= "modem" then
2982 error("No modem on side "..modemSide..".", 3)
2983 end
2984
2985 log("Using modem "..modemSide..".")
2986 return modemSide
2987end
2988
2989
2990-- Decides which channel a server should communicate on, based on its name.
2991-- This function will always return the same channel for a given server name,
2992-- allowing clients to find out the channel of a server without any prior
2993-- communications with it.
2994function getChannel(serverName)
2995 local nameHash = sha256.digest(serverName)
2996 -- Use the first two bytes of the hash as the channel number, so that the full range
2997 -- of acceptable channels can be used.
2998 local channel = nameHash[1] + nameHash[2]*2^8
2999 -- Avoid clashing with the lower channels, which are likely being used by
3000 -- standard Rednet users.
3001 if channel < 100 then
3002 channel = channel + 100
3003 -- Reserve the highest channels for Rednet and CryptoNet's internal use.
3004 elseif channel > 65530 then
3005 channel = channel - 5
3006 end
3007
3008 return channel
3009end
3010
3011
3012-- Check if any servers or sockets on this machine are using the specified channel
3013-- on the specified modem.
3014function channelInUse(channel, modemSide)
3015 -- Check the client sockets.
3016 for _,socket in pairs(allClientSockets) do
3017 if socket.channel == channel and socket.modemSide == modemSide then
3018 return true
3019 end
3020 end
3021 -- Check the server channels.
3022 for _,server in pairs(allServers) do
3023 if server.channel == channel and server.modemSide == modemSide then
3024 return true
3025 end
3026 end
3027
3028 return false
3029end
3030
3031
3032-- Convert a table of bytes into a string.
3033local function bytesToString(bytes)
3034 local str = ""
3035 for _,byte in pairs(bytes) do
3036 local ok, char = pcall(string.char, byte)
3037 -- If there are invalid bytes in the string, return nil without raising an error.
3038 -- This is to prevent attackers from crashing the system by sending invalid characters
3039 -- in encrypted messages.
3040 if not ok then
3041 return nil
3042 end
3043 str = str..char
3044 end
3045 return str
3046end
3047
3048
3049-- Serialize pretty much any Lua data type as a string so that it can be encrypted
3050-- and sent over CryptoNet. The resulting string starts with a characer
3051-- identifying the type of the data, followed by a string representation of the data.
3052local function serializeAny(value)
3053 if type(value) == "nil" then
3054 return "x"
3055 elseif type(value) == "boolean" then
3056 return value and "b1" or "b0"
3057 elseif type(value) == "number" then
3058 return "n"..tostring(value)
3059 elseif type(value) == "string" then
3060 return "s"..value
3061 elseif type(value) == "table" then
3062 return "t"..textutils.serialize(value)
3063 else
3064 error("Can't serialize "..type(value).."s.", 2)
3065 end
3066end
3067
3068
3069-- Deserialize data serialized by serializeAny.
3070local function deserializeAny(str)
3071 local typeChar = str:sub(1,1)
3072 local valueStr = str:sub(2)
3073 if typeChar == "x" then
3074 return nil
3075 elseif typeChar == "b" then
3076 return valueStr == "1"
3077 elseif typeChar == "n" then
3078 return tonumber(valueStr)
3079 elseif typeChar == "s" then
3080 return valueStr
3081 elseif typeChar == "t" then
3082 return textutils.unserialize(valueStr)
3083 else
3084 error("Invalid type character: "..typeChar, 2)
3085 end
3086end
3087
3088
3089-- Serialize a certificate or RSA key into a string, for saving to a file.
3090-- The textutils functions don't seem to like the huge strings of numbers in
3091-- the keys, so quotation marks must be added to them before serialization,
3092-- which is what this function does.
3093function serializeCertOrKey(obj)
3094 if type(obj) ~= "table" then
3095 error("Can only serialize tables.", 2)
3096 end
3097 -- Add the certificate name, if it exists.
3098 local output = {name=obj.name}
3099
3100 -- If this is a key, add its number string parts with quotes around them
3101 -- to keep textutils happy.
3102 if type(obj.public) == "string" then
3103 output.public = "\""..obj.public.."\""
3104 end
3105 if type(obj.private) == "string" then
3106 output.private = "\""..obj.private.."\""
3107 end
3108 if type(obj.shared) == "string" then
3109 output.shared = "\""..obj.shared.."\""
3110 end
3111
3112 -- If this is a certificate with a key, do the above for the key.
3113 if type(obj.key) == "table" then
3114 output.key = {}
3115 if type(obj.key.public) == "string" then
3116 output.key.public = "\""..obj.key.public.."\""
3117 end
3118 if type(obj.key.private) == "string" then
3119 output.key.private = "\""..obj.key.private.."\""
3120 end
3121 if type(obj.key.shared) == "string" then
3122 output.key.shared = "\""..obj.key.shared.."\""
3123 end
3124 end
3125
3126 -- If the certificate has a signature, that must have quotes as well.
3127 if type(obj.signature) == "string" then
3128 output.signature = "\""..obj.signature.."\""
3129 end
3130
3131 -- Serialize the table as normal.
3132 return textutils.serialize(output)
3133end
3134
3135
3136-- Deserialize certificates or RSA keys serialized by serializeCertOrKey().
3137-- This involves deserializing as normal and removing the quotation marks added
3138-- during serialization.
3139function deserializeCertOrKey(str)
3140 if str == nil then return nil end
3141 -- Deserialize as normal.
3142 local output = textutils.unserialize(str)
3143 if type(output) ~= "table" then
3144 return output
3145 end
3146
3147 -- If this is a key, remove the quotes from the number string parts.
3148 if type(output.public) == "string" then
3149 output.public = string.gsub(output.public, "\"", "")
3150 end
3151 if type(output.private) == "string" then
3152 output.private = string.gsub(output.private, "\"", "")
3153 end
3154 if type(output.shared) == "string" then
3155 output.shared = string.gsub(output.shared, "\"", "")
3156 end
3157
3158 -- If this is a certificate with a key, do the above for the key.
3159 if output.key ~= nil then
3160 if type(output.key.public) == "string" then
3161 output.key.public = string.gsub(output.key.public, "\"", "")
3162 end
3163 if type(output.key.private) == "string" then
3164 output.key.private = string.gsub(output.key.private, "\"", "")
3165 end
3166 if type(output.key.shared) == "string" then
3167 output.key.shared = string.gsub(output.key.shared, "\"", "")
3168 end
3169 end
3170
3171 if type(output.signature) == "string" then
3172 output.signature = string.gsub(output.signature, "\"", "")
3173 end
3174
3175 return output
3176end
3177
3178
3179-- Generate random 16 byte sequence that can be used as a key or
3180-- initialization vector for AES encryption.
3181function generateKey()
3182 local iv = {}
3183 -- Convert four 4-byte integers into 16 bytes.
3184 for j=1,4 do
3185 local num = isaac.random()
3186 for i=0,3 do
3187 -- Extract 8 bits at a time, by shifting right and applying a mask.
3188 table.insert(iv, bit.band(bit.brshift(num, 8*i), 2^8-1))
3189 end
3190 end
3191 return iv
3192end
3193
3194
3195-- Generate an unsigned certificate and corresponding private key for a server
3196-- with the given name. The certificate is distributed to clients, who can use
3197-- the public key it contains to encrypt messages using RSA such that only
3198-- this server can read them, using the private key.
3199function generateCertificate(name)
3200 log("Generating keys... (may take some time)")
3201 publicKey, privateKey = rsaKeygen.generateKeyPair()
3202 print("")
3203 log("Done!")
3204 -- The certificate contains the name and public key of the server.
3205 return {name=name, key=publicKey}, privateKey
3206end
3207
3208
3209-- Load a certificate authority public key from the specified file and validate it,
3210-- or just validate the key itself if passed directly as the argument.
3211-- If key is left nil, a default filename of "certAuth.key" is used.
3212--
3213-- key (string or key table, default: "certAuth.key"):
3214-- The file to load the key from, or the key itself to validate.
3215--
3216-- Returns the loaded key, or nil if not found or invalid.
3217function loadCertAuthKey(key)
3218 if key == nil then
3219 -- Default value.
3220 key = "certAuth.key"
3221 end
3222 -- If key is a file path...
3223 if type(key) == "string" then
3224 local keyFilename = key
3225 -- Make paths relative to the current CryptoNet working directory.
3226 local keyPath = workingDir == "" and keyFilename or workingDir.."/"..keyFilename
3227 log("Checking "..keyPath.." for cert auth key...")
3228 if fs.isDir(keyPath) or not fs.exists(keyPath) then
3229 if fs.isDir(keyPath) then
3230 log(keyFilename.." is not a file, will not be able to verify signatures.")
3231 else
3232 log(keyFilename.." does not exist, will not be able to verify signatures.")
3233 end
3234 return nil
3235 else
3236 local file = fs.open(keyPath, "r")
3237 key = deserializeCertOrKey(file.readAll())
3238 file.close()
3239
3240 if not publicKeyValid(key) then
3241 log(keyFilename.." does not contain a valid cert auth key, will not be able to verify signatures.")
3242 return nil
3243 else
3244 log("Loaded cert auth key from "..keyFilename..".")
3245 return key
3246 end
3247 end
3248 -- If the argument is not a string it should be the key table itself,
3249 -- so just validate it and return unchanged if valid.
3250 elseif publicKeyValid(key) then
3251 return key
3252 else
3253 log("Invalid cert auth key, won't be able to verify signatures.")
3254 return nil
3255 end
3256end
3257
3258
3259-- Verify that the signature on a certificate is valid, using the public key
3260-- of the trusted certificate authority.
3261function verifyCertificate(certificate, key)
3262 -- Signatures are made by encrypting the certificate's hash using the cert auth's private key.
3263 -- If the signature was generated by the certificate authority that uses the provided public key,
3264 -- decrypting the signature with this key should yield the certificate's hash.
3265
3266 -- Find the hash of the certificate.
3267 local hash = sha256.digest(certificate.name..certificate.key.public..certificate.key.shared)
3268 -- Decrypt the signature using the provided public key.
3269 local sigHash = rsaCrypt.bytesToString(rsaCrypt.numberToBytes(rsaCrypt.crypt(key, certificate.signature), 32*8, 8))
3270 -- See whether the decrypted signature matches the expected hash.
3271 return tostring(hash) == sigHash
3272end
3273
3274
3275--
3276-- SEND FUNCTIONS
3277--
3278
3279-- Send an unencrypted message in the Rednet format using the cryptoNet protocol.
3280-- CryptoNet uses this internally for sending various message types.
3281-- If enabled, this function will also send every message it sends on the Rednet
3282-- repeat channel, allowing the Rednet repeat command to repeat CryptoNet messages.
3283-- Since these messages are in the format Rednet uses, CryptoNet should be fully
3284-- compatible with any networking systems designed for Rednet.
3285local function sendInternal(modemSide, channel, target, message, msgType, sender)
3286 -- Generate the message in exactly the same format as Rednet.
3287 local nMessageID = math.random(1, 2147483647)
3288 local tMessage = {
3289 nMessageID = nMessageID,
3290 nRecipient = channel,
3291 message = {message=message, msgType=msgType, target=target, sender=sender},
3292 sProtocol = "cryptoNet",
3293 }
3294
3295 local modem = peripheral.wrap(modemSide)
3296 modem.transmit(channel, channel, tMessage)
3297 -- Allow Rednet repeaters to repeat the message if enabled.
3298 if repeatMessages then
3299 modem.transmit(rednet.CHANNEL_REPEAT, channel, tMessage)
3300 end
3301end
3302
3303
3304-- Send an encrypted internal message. Unlike the user-facing send() function,
3305-- this one only allows strings to be sent.
3306local function sendEncryptedInternal(socket, message)
3307 if type(message) ~= "string" then
3308 error("Message must be a string.", 2)
3309 end
3310 if not socketValid(socket) then
3311 error("Invalid socket.", 2)
3312 end
3313 -- Use unique IVs for every message.
3314 local iv = generateKey()
3315 local ok, encrypted = pcall(aes.encrypt_str, message, socket.key, iv)
3316 if ok then
3317 -- Send the encrypted message and the IVs used to generate it.
3318 -- We have to send the encrypted string as a table of bytes, because some of
3319 -- the special characters in the string seem to get lost in transmission otherwise.
3320 sendInternal(socket.modemSide, socket.channel, socket.target, {{string.byte(encrypted, 1, encrypted:len())}, iv}, "encrypted_message", socket.sender)
3321 else
3322 error("Encryption failed: "..encrypted:sub(8), 2)
3323 end
3324end
3325
3326
3327-- Send an encrypted message over the given socket. The message can be pretty much
3328-- any Lua data type.
3329function send(socket, message)
3330 if not socketValid(socket) then
3331 error("Invalid socket.", 2)
3332 end
3333 -- Convert the message to a string before sending, so it can be encrypted.
3334 -- It will be deserialized at the other end.
3335 sendEncryptedInternal(socket, serializeAny(message))
3336end
3337
3338
3339-- Send an unencrypted message over CryptoNet. Useful for streams of high speed,
3340-- non-sensitive data. Unencrypted messages have no security features applied,
3341-- so can be easily exploited by attackers. Only use for non-critical messages.
3342function sendUnencrypted(socket, message)
3343 if not socketValid(socket) then
3344 error("Invalid socket.", 2)
3345 end
3346 -- Just send the message as-is.
3347 sendInternal(socket.modemSide, socket.channel, socket.target, message, "plain_message", socket.sender)
3348end
3349
3350
3351--
3352-- LOGIN SYSTEM
3353--
3354
3355-- Hash a password using the username and server name as a salt.
3356-- Used to secure passwords before they are sent over CryptoNet to a server.
3357-- Technically this is unnecessary as the connection is encrypted anyway,
3358-- but it means that even if this is somehow compromised (e.g. with a spoof attack)
3359-- the attacker won't know the actual password and be able to use it on the user's
3360-- other accounts, if they use the same password for multiple things.
3361function hashPassword(username, password, serverName)
3362 if type(username) ~= "string" then
3363 error("Username must be a string.", 2)
3364 end
3365 if type(password) ~= "string" then
3366 error("Password must be a string.", 2)
3367 end
3368 if type(serverName) ~= "string" then
3369 error("Server name must be a string.", 2)
3370 end
3371
3372 return tostring(sha256.digest(serverName..username..password))
3373end
3374
3375
3376-- Load the user table stored at the given path, defaulting to an empty table
3377-- if the file does not exist.
3378function loadUserTable(path)
3379 if type(path) ~= "string" then
3380 error("Path must be a string.", 2)
3381 end
3382 if not fs.exists(path) then
3383 log(path.." does not exist, creating empty user table.")
3384 return {}
3385 end
3386 if fs.isDir(path) then
3387 error(path.." is not a file, could not load user table.", 2)
3388 end
3389
3390 local file = fs.open(path, "r")
3391 local userTable = textutils.unserialize(file.readAll())
3392 file.close()
3393
3394 if not userTableValid(userTable) then
3395 error(path.." does not contain a valid user table, user table could not be loaded.", 2)
3396 end
3397
3398 log("Loaded user table from "..path..".")
3399 return userTable
3400end
3401
3402
3403-- Save the given user table to the given file.
3404function saveUserTable(userTable, path)
3405 if type(path) ~= "string" then
3406 error("Path must be a string.", 2)
3407 end
3408 if not userTableValid(userTable) then
3409 error("Not a valid user table", 2)
3410 end
3411
3412 if fs.isDir(path) then
3413 error(path.." already exists and is a directory.", 2)
3414 end
3415
3416 local file = fs.open(path, "w")
3417 file.write(textutils.serialize(userTable))
3418 file.close()
3419 log("Saved user table to "..path..".")
3420end
3421
3422
3423-- Add a user to the given server with the provided details.
3424-- The provided password should already have been hashed by hashPassword().
3425-- Default permission level is 1. If there is only one server running,
3426-- that server will be used by default.
3427function addUserHashed(username, passHash, permissionLevel, server)
3428 if type(username) ~= "string" then
3429 error("Username must be a string.", 2)
3430 end
3431 if type(passHash) ~= "string" then
3432 error("Password hash must be a string.", 2)
3433 end
3434 if permissionLevel == nil then
3435 permissionLevel = 1
3436 elseif type(permissionLevel) ~= "number" then
3437 error("Permission level must be a number", 2)
3438 end
3439
3440 -- If there is exactly one server running, default to it.
3441 if server == nil then
3442 if #allServers == 0 then
3443 error("No servers running.", 2)
3444 elseif #allServers == 1 then
3445 server = allServers[1]
3446 else
3447 error("Please specify a server.", 2)
3448 end
3449 elseif not serverValid(server) then
3450 error("Invalid server.", 2)
3451 end
3452
3453 if server.userTable[username] ~= nil then
3454 error("User "..username.." already exists.", 2)
3455 end
3456
3457 -- The password is hashed again before going in the database, so that even if
3458 -- an attacker has access to this file they do not have the original password
3459 -- required to log into the server from the outside.
3460 -- PBKDF2 is used over the standard SHA256 digest as it is theoretically harder
3461 -- to crack.
3462 server.userTable[username] = {sha256.pbkdf2(passHash, server.name..username, 8), permissionLevel}
3463 log("Added user "..username..".")
3464 saveUserTable(server.userTable, server.userTablePath)
3465end
3466
3467
3468-- Add a user to the given (local) server's user table with the provided details.
3469-- The user table is saved to disk, so is non volatile.
3470-- The server parameter can be left blank if exactly one server is running.
3471function addUser(username, password, permissionLevel, server)
3472 if type(username) ~= "string" then
3473 error("Username must be a string.", 2)
3474 end
3475 if type(password) ~= "string" then
3476 error("Password must be a string.", 2)
3477 end
3478 if permissionLevel == nil then
3479 permissionLevel = 1
3480 elseif type(permissionLevel) ~= "number" then
3481 error("Permission level must be a number", 2)
3482 end
3483
3484 -- If there is exactly one server running, default to it.
3485 if server == nil then
3486 if #allServers == 0 then
3487 error("No servers running.", 2)
3488 elseif #allServers == 1 then
3489 server = allServers[1]
3490 else
3491 error("Please specify a server.", 2)
3492 end
3493 elseif not serverValid(server) then
3494 error("Invalid server.", 2)
3495 end
3496
3497 if server.userTable[username] ~= nil then
3498 error("User "..username.." already exists.", 2)
3499 end
3500
3501 -- When users log into the server remotely their passwords will be hashed
3502 -- before being sent, so we must perform the same process here before
3503 -- adding it to the table.
3504 addUserHashed(username, hashPassword(username, password, server.name), permissionLevel, server)
3505end
3506
3507
3508-- Remove a user from a server.
3509-- The server parameter can be left blank if exactly one server is running.
3510function deleteUser(username, server)
3511 if type(username) ~= "string" then
3512 error("Username must be a string.", 2)
3513 end
3514
3515 -- If there is exactly one server running, default to it.
3516 if server == nil then
3517 if #allServers == 0 then
3518 error("No servers running.", 2)
3519 elseif #allServers == 1 then
3520 server = allServers[1]
3521 else
3522 error("Please specify a server.", 2)
3523 end
3524 elseif not serverValid(server) then
3525 error("Invalid server.", 2)
3526 end
3527
3528 if server.userTable[username] == nil then
3529 error("No user called "..username..".", 2)
3530 else
3531 server.userTable[username] = nil
3532 log("Deleted user "..username..".")
3533 saveUserTable(server.userTable, server.userTablePath)
3534 end
3535end
3536
3537
3538-- Check if a user exists on the server.
3539-- The server parameter can be left blank if exactly one server is running.
3540function userExists(username, server)
3541 if type(username) ~= "string" then
3542 error("Username must be a string.", 2)
3543 end
3544
3545 -- If there is exactly one server running, default to it.
3546 if server == nil then
3547 if #allServers == 0 then
3548 error("No servers running.", 2)
3549 elseif #allServers == 1 then
3550 server = allServers[1]
3551 else
3552 error("Please specify a server.", 2)
3553 end
3554 elseif not serverValid(server) then
3555 error("Invalid server.", 2)
3556 end
3557
3558 return server.userTable[username] ~= nil
3559end
3560
3561
3562-- Get the hashed password of a user from the users table.
3563-- The original password cannot be (easily) retrieved from this hash.
3564-- Returns nil if the user does not exist.
3565-- The server parameter can be left blank if exactly one server is running.
3566function getPasswordHash(username, server)
3567 if type(username) ~= "string" then
3568 error("Username must be a string.", 2)
3569 end
3570
3571 -- If there is exactly one server running, default to it.
3572 if server == nil then
3573 if #allServers == 0 then
3574 error("No servers running.", 2)
3575 elseif #allServers == 1 then
3576 server = allServers[1]
3577 else
3578 error("Please specify a server.", 2)
3579 end
3580 elseif not serverValid(server) then
3581 error("Invalid server.", 2)
3582 end
3583
3584 if server.userTable[username] == nil then
3585 return nil
3586 end
3587 return server.userTable[username][1]
3588end
3589
3590
3591-- Get the permission level of a user.
3592-- Returns nil if the user does not exist.
3593-- The server parameter can be left blank if exactly one server is running.
3594function getPermissionLevel(username, server)
3595 if type(username) ~= "string" then
3596 error("Username must be a string.", 2)
3597 end
3598
3599 -- If there is exactly one server running, default to it.
3600 if server == nil then
3601 if #allServers == 0 then
3602 error("No servers running.", 2)
3603 elseif #allServers == 1 then
3604 server = allServers[1]
3605 else
3606 error("Please specify a server.", 2)
3607 end
3608 elseif not serverValid(server) then
3609 error("Invalid server.", 2)
3610 end
3611
3612 if server.userTable[username] == nil then
3613 return nil
3614 end
3615 return server.userTable[username][2]
3616end
3617
3618
3619-- Set the hashed password of a user in the table.
3620-- Assumes the provided passowrd has already been hashed with hashPassword().
3621-- The server parameter can be left blank if exactly one server is running.
3622function setPasswordHashed(username, passHash, server)
3623 if type(username) ~= "string" then
3624 error("Username must be a string.", 2)
3625 end
3626 if type(passHash) ~= "string" then
3627 error("Password hash must be a string.", 2)
3628 end
3629
3630 -- If there is exactly one server running, default to it.
3631 if server == nil then
3632 if #allServers == 0 then
3633 error("No servers running.", 2)
3634 elseif #allServers == 1 then
3635 server = allServers[1]
3636 else
3637 error("Please specify a server.", 2)
3638 end
3639 elseif not serverValid(server) then
3640 error("Invalid server.", 2)
3641 end
3642
3643 if server.userTable[username] == nil then
3644 error("No user called "..username..".", 2)
3645 end
3646
3647 -- Hash the password again before storing.
3648 server.userTable[username][1] = sha256.pbkdf2(passHash, server.name..username, 8)
3649 log("Updated password for "..username..".")
3650 saveUserTable(server.userTable, server.userTablePath)
3651end
3652
3653
3654-- Sets the password of a user in the table.
3655-- The server parameter can be left blank if exactly one server is running.
3656function setPassword(username, password, server)
3657 if type(username) ~= "string" then
3658 error("Username must be a string.", 2)
3659 end
3660 if type(password) ~= "string" then
3661 error("Password must be a string.", 2)
3662 end
3663
3664 -- If there is exactly one server running, default to it.
3665 if server == nil then
3666 if #allServers == 0 then
3667 error("No servers running.", 2)
3668 elseif #allServers == 1 then
3669 server = allServers[1]
3670 else
3671 error("Please specify a server.", 2)
3672 end
3673 elseif not serverValid(server) then
3674 error("Invalid server.", 2)
3675 end
3676
3677 if server.userTable[username] == nil then
3678 error("No user called "..username..".", 2)
3679 end
3680
3681 -- Hash the password before adding, to mimic the hashing performed by clients
3682 -- logging in remotely.
3683 setPasswordHashed(username, hashPassword(username, password, server.name), server)
3684end
3685
3686
3687-- Set the permission level of a user in the table.
3688-- The server parameter can be left blank if exactly one server is running.
3689function setPermissionLevel(username, permissionLevel, server)
3690 if type(username) ~= "string" then
3691 error("Username must be a string.", 2)
3692 end
3693 if type(permissionLevel) ~= "number" then
3694 error("Permission level must be a number.", 2)
3695 end
3696
3697 -- If there is exactly one server running, default to it.
3698 if server == nil then
3699 if #allServers == 0 then
3700 error("No servers running.", 2)
3701 elseif #allServers == 1 then
3702 server = allServers[1]
3703 else
3704 error("Please specify a server.", 2)
3705 end
3706 elseif not serverValid(server) then
3707 error("Invalid server.", 2)
3708 end
3709
3710 if server.userTable[username] == nil then
3711 error("No user called "..username..".", 2)
3712 end
3713
3714 server.userTable[username][2] = permissionLevel
3715 log("Updated permission level for "..username..".")
3716 saveUserTable(server.userTable, server.userTablePath)
3717end
3718
3719
3720-- Check that the given password matches the one in the table.
3721-- Assumes the password has already been hashed by hashPassword().
3722-- The server parameter can be left blank if exactly one server is running.
3723function checkPasswordHashed(username, passHash, server)
3724 if type(username) ~= "string" then
3725 error("Username must be a string.", 2)
3726 end
3727 if type(passHash) ~= "string" then
3728 error("Password hash must be a string.", 2)
3729 end
3730
3731 -- If there is exactly one server running, default to it.
3732 if server == nil then
3733 if #allServers == 0 then
3734 error("No servers running.", 2)
3735 elseif #allServers == 1 then
3736 server = allServers[1]
3737 else
3738 error("Please specify a server.", 2)
3739 end
3740 elseif not serverValid(server) then
3741 error("Invalid server.", 2)
3742 end
3743
3744 if server.userTable[username] == nil then
3745 return nil
3746 end
3747
3748 -- Since we can't unhash the passwords in the table, we must instead
3749 -- hash the query password and compare it to the hash in the table.
3750 -- If they are the same, then the original passwords were the same.
3751 local hash = sha256.pbkdf2(passHash, server.name..username, 8)
3752 -- Check if all the bytes of the hashes are equal.
3753 for i=1,#hash do
3754 if hash[i] ~= server.userTable[username][1][i] then
3755 return false
3756 end
3757 end
3758 return true
3759end
3760
3761
3762-- Check that the given password matches the one in the table.
3763-- The server parameter can be left blank if exactly one server is running.
3764function checkPassword(username, password, server)
3765 if type(username) ~= "string" then
3766 error("Username must be a string.", 2)
3767 end
3768 if type(password) ~= "string" then
3769 error("Password must be a string.", 2)
3770 end
3771
3772 -- If there is exactly one server running, default to it.
3773 if server == nil then
3774 if #allServers == 0 then
3775 error("No servers running.", 2)
3776 elseif #allServers == 1 then
3777 server = allServers[1]
3778 else
3779 error("Please specify a server.", 2)
3780 end
3781 elseif not serverValid(server) then
3782 error("Invalid server.", 2)
3783 end
3784
3785 -- Mimic the client-side hashing before checking.
3786 return checkPasswordHashed(username, hashPassword(username, password, server.name), server)
3787end
3788
3789
3790-- Log into the server connected to this socket, remote or local,
3791-- with the specified username and password.
3792-- Assumes the password has already been hashed by hashPassword().
3793-- If executed on a server socket, the event details of the attempt are returned.
3794--
3795-- If successful, the user's details will be stored in the socket.
3796-- If the socket is already logged in, the username will be overwritten
3797-- but the permission level will be set to the highest of the old and new one.
3798-- This allows an admin account to log in then log in as a normal user
3799-- to temporarily gain elevated privileges as that account.
3800function loginHashed(socket, username, passHash)
3801 if not socketValid(socket) then
3802 error("Invalid socket.", 2)
3803 end
3804 if type(username) ~= "string" then
3805 error("Username must be a string.", 2)
3806 end
3807 if type(passHash) ~= "string" then
3808 error("Password hash must be a string.", 2)
3809 end
3810
3811 if socket.server == nil then
3812 -- If this is a client socket, send a login request to the server.
3813 sendEncryptedInternal(socket, "lr"..textutils.serialize({username, passHash}))
3814 log("Sent login request for "..username.." to "..socket.target..".")
3815 else
3816 -- If this is a server socket, try to log in as the user
3817 -- and send the result to the client.
3818 if socket.server.userTable[username] == nil then
3819 log("Failed login attempt for "..username..".")
3820 sendEncryptedInternal(socket, "lf"..username)
3821 return "login_failed", username, socket, socket.server
3822 else
3823 if checkPasswordHashed(username, passHash, socket.server) then
3824 -- If the password was correct, log the user into the socket.
3825 socket.username = username
3826 -- Set the permission level to the greatest of the socket's original
3827 -- permission level and the new one, so admins can temporarily transfer
3828 -- their elevated rights to normal accounts.
3829 socket.permissionLevel = math.max(socket.permissionLevel, getPermissionLevel(username, socket.server))
3830 -- Tell the client-side socket that the attempt was successful, so it can
3831 -- change its details as well.
3832 sendEncryptedInternal(socket, "ls"..textutils.serialize({username, socket.permissionLevel}))
3833 log(username.." logged in successfully.")
3834 return "login", username, socket, socket.server
3835 else
3836 log("Failed login attempt for "..username..".")
3837 sendEncryptedInternal(socket, "lf"..username)
3838 return "login_failed", username, socket, socket.server
3839 end
3840 end
3841 end
3842end
3843
3844
3845-- Log into the server connected to this socket, remote or local,
3846-- with the specified username and password.
3847-- The password will be hashed before sending for extra security.
3848-- If executed on a server socket, the event details of the attempt are returned.
3849--
3850-- If successful, the user's details will be stored in the socket.
3851-- If the socket is already logged in, the username will be overwritten
3852-- but the permission level will be set to the highest of the old and new one.
3853-- This allows an admin account to log in then log in as a normal user
3854-- to temporarily gain elevated privileges as that account.
3855function login(socket, username, password)
3856 if not socketValid(socket) then
3857 error("Invalid socket.", 2)
3858 end
3859 if type(username) ~= "string" then
3860 error("Username must be a string.", 2)
3861 end
3862 if type(password) ~= "string" then
3863 error("Password must be a string.", 2)
3864 end
3865
3866 -- Get the server name based on whether this is a client or server socket.
3867 local serverName = socket.server == nil and socket.target or socket.sender
3868 -- Hash the password before sending.
3869 return loginHashed(socket, username, hashPassword(username, password, serverName))
3870end
3871
3872
3873-- Log out of the user account currently logged in on this socket.
3874-- If executed on a server socket, the event details are returned.
3875function logout(socket)
3876 if not socketValid(socket) then
3877 error("Invalid socket.", 2)
3878 end
3879
3880 -- Tell the other end to log out as well.
3881 sendEncryptedInternal(socket, "lo")
3882 if socket.server == nil then
3883 -- If this is a client socket, all we can do is ask the server to log out.
3884 -- The actual logging out is only performed once a response is received
3885 -- from the server.
3886 log("Sent logout request to "..socket.target..".")
3887 else
3888 -- If this is a server socket, we can actually logout.
3889 local username = socket.username
3890 socket.username = nil
3891 socket.permissionLevel = 0
3892
3893 if username == nil then
3894 log("Already logged out.")
3895 else
3896 log(username.." logged out.")
3897 end
3898 return "logout", username, socket, server
3899 end
3900end
3901
3902
3903--
3904-- CORE NETWORKING
3905--
3906
3907-- Check if a Rednet-format message is a CryptoNet one, and return its contents
3908-- if so. If it is invalid or has been processed before nil is returned.
3909local function extractMessage(message, receivedIDs)
3910 -- Check the list of alrady received message IDs to see if any of them are
3911 -- more than 5 seconds old and can be deleted. The purpose of this list is
3912 -- to avoid processing messages processed by Rednet's repeat program
3913 -- more than once, but repeat is unlikely to take 5 seconds to repeat a message.
3914 -- Since the message IDs are randomly generated, it is good to remove them
3915 -- from the list as soon as possible to reduce the chance of a future message
3916 -- with same ID from being blocked.
3917 -- Note that CryptoNet has a seperate more advanced system for preventing
3918 -- attackers from sending the same encrypted message twice, handled elsewhere.
3919 local toDelete = {}
3920 for id, time in pairs(receivedIDs) do
3921 -- List the ID for deletion if it is more than 5 seconds old.
3922 if os.clock() - time > 5 then
3923 table.insert(toDelete, id)
3924 end
3925 end
3926 -- Remove all the deleted IDs.
3927 for _,id in pairs(toDelete) do
3928 receivedIDs[id] = nil
3929 end
3930
3931 -- Check that the message follows the Rednet format and is using the cryptoNet protocol.
3932 if type(message) == "table" and message.sProtocol == "cryptoNet" and type(message.message) == "table" and type(message.nMessageID) == "number" then
3933 -- If this message ID has not been received already recently,
3934 -- return the message contents.
3935 if not receivedIDs[message.nMessageID] then
3936 receivedIDs[message.nMessageID] = os.clock()
3937 return message.message
3938 end
3939 -- Always keep the latest timestamp of the ID.
3940 receivedIDs[message.nMessageID] = os.clock()
3941 end
3942 return
3943end
3944
3945
3946-- Create and host a CryptoNet server, which other machines can remotely connect
3947-- to. This function will load the certificate and private key of the server
3948-- from the specified files, or generate new ones if no existing files are found.
3949-- Note that serverName is the only required parameter; all the others have
3950-- sensible defaults.
3951--
3952-- serverName (string, required):
3953-- The name of the server, which clients will use to connect to it.
3954-- Also determines the channel that the server communicates on.
3955--
3956-- discoverable (boolean, default: true):
3957-- Whether this server responds to discover() requests.
3958-- Disabling this is more secure as it means clients can't connect unless
3959-- they already know the name of the server.
3960--
3961-- hideCertificate (boolean, default: false):
3962-- If true the server will not distribute its certificate to clients,
3963-- either in discover() or connect() requests, meaning clients can only
3964-- connect if they have already been given the certificate manually.
3965-- Useful if you only want certain manually authorised clients to be able to connect.
3966--
3967-- modemSide (string, default: a side that has a modem):
3968-- The modem the server should use.
3969--
3970-- certificate (table or string, default: "<serverName>.crt"):
3971-- The certificate of the server. This can either be the certificate table itself,
3972-- or the name of a file that contains it. If the certicate and key files do not
3973-- exist, new ones will be generated and saved to the specified files.
3974--
3975-- privateKey (table or string, default: "<serverName>_private.key"):
3976-- The private key of the server. This can either be the key table itself,
3977-- or the name of a file that contains it. If the certicate and key files do not
3978-- exist, new ones will be generated and saved to the specified files.
3979--
3980-- userTablePath (string, default: "<serverName>_users.tbl"):
3981-- Path at which to store the user login details table,
3982-- if/when users are added to the server.
3983--
3984-- Returns: The server table, containing the following information:
3985-- name: The server name
3986-- certificate: The server's certificate
3987-- privateKey: The server's private key
3988-- modemSide: The modem used by the server
3989-- channel: The channel number the server communicates on
3990-- hideCertificate: Whether the server distributes its certificate to clients
3991-- discoverable: Whether the server responds to discover() requests
3992-- userTable: The table of user login details for the server,
3993-- loaded from file or empty by default
3994-- userTablePath: The name of the user table file
3995-- sockets: The table of the server's sockets, used to communicate with clients.
3996-- Starts empty and is populated as clients connect.
3997function host(serverName, discoverable, hideCertificate, modemSide, certificate, privateKey, userTablePath)
3998 if type(serverName) ~= "string" then
3999 error("Server name must be a string.", 2)
4000 end
4001 -- Don't allow duplicate server names.
4002 for _,server in pairs(allServers) do
4003 if server.name == serverName then
4004 error("Server called "..serverName.." already exists.", 2)
4005 end
4006 end
4007
4008 modemSide = resolveModemSide(modemSide)
4009 local modem = peripheral.wrap(modemSide)
4010
4011 -- Generate default file names if none were provided, then get the paths
4012 -- relative to the current working directory.
4013 local certFilename = type(certificate) == "string" and certificate or serverName..".crt"
4014 local keyFilename = type(privateKey) == "string" and privateKey or serverName.."_private.key"
4015 local certificatePath = workingDir == "" and certFilename or workingDir.."/"..certFilename
4016 local keyPath = workingDir == "" and keyFilename or workingDir.."/"..keyFilename
4017
4018 -- Now that we've extracted the filenames above, only store the actual certificate
4019 -- and key in these variables.
4020 if type(certificate) == "string" then certificate = nil end
4021 if type(privateKey) == "string" then privateKey = nil end
4022
4023 if certificate ~= nil and not certificateValid(certificate) then
4024 error("Invalid certificate.", 2)
4025 end
4026 if privateKey ~= nil and not privateKeyValid(privateKey) then
4027 error("Invalid private key.", 2)
4028 end
4029
4030 -- Try loading the certificate from file.
4031 if certificate == nil then
4032 log("Checking "..certificatePath.." for certificate...")
4033 if fs.isDir(certificatePath) then
4034 error(certFilename.." already exists and is a directory, not a certificate.", 2)
4035 elseif fs.exists(certificatePath) then
4036 local file = fs.open(certificatePath, "r")
4037 certificate = deserializeCertOrKey(file.readAll())
4038 file.close()
4039
4040 if not certificateValid(certificate) then
4041 error(certFilename.." already exists and is not a valid certificate.", 2)
4042 else
4043 log("Loaded certificate from "..certFilename..".")
4044 end
4045 else
4046 log("Certificate file not found, will need to generate a new one.")
4047 end
4048 end
4049
4050 -- Try loading the private key from file.
4051 if privateKey == nil then
4052 log("Checking "..keyPath.." for private key...")
4053 if fs.isDir(keyPath) then
4054 error(keyFilename.." already exists and is a directory, not a keyfile.", 2)
4055 elseif fs.exists(keyFilename) then
4056 local file = fs.open(keyFilename, "r")
4057 privateKey = deserializeCertOrKey(file.readAll())
4058 file.close()
4059
4060 if not privateKeyValid(privateKey) then
4061 error(keyFilename.." already exists and is not a valid keyfile.", 2)
4062 else
4063 log("Loaded private key from "..keyFilename..".")
4064 end
4065 else
4066 log("Private keyfile not found, will need to generate a new one.")
4067 end
4068 end
4069
4070 -- If we have no certificate or private key yet, generate them.
4071 -- You can't just provide one and not the other, as the public and private
4072 -- keys must be generated as a pair.
4073 if certificate == nil and privateKey == nil then
4074 log("No certificate or private key found, generating new ones.")
4075 certificate, privateKey = generateCertificate(serverName)
4076
4077 local file = fs.open(certificatePath, "w")
4078 file.write(serializeCertOrKey(certificate))
4079 file.close()
4080 log("Saved certificate to "..certificatePath..".")
4081
4082 file = fs.open(keyPath, "w")
4083 file.write(serializeCertOrKey(privateKey))
4084 file.close()
4085 log("Saved private key to "..keyPath..". Do not share this with anyone!")
4086 elseif certificate ~= nil and privateKey == nil then
4087 error("Have a certificate but not a private key, need both or neither.", 2)
4088 elseif certificate == nil and privateKey ~= nil then
4089 error("Have a private key but not a certificate, need both or neither.", 2)
4090 end
4091
4092 -- It is possible for an attacker to host a server with the same name as yours,
4093 -- confusing and tricking clients. Having a certifiate authority sign
4094 -- the certificates of trusted servers prevents this.
4095 if certificate.signature == nil then
4096 log("Warning: Your certificate does not have a signature.")
4097 else
4098 log("Certificate is signed.")
4099 end
4100
4101 -- Open the server's channel (derived from the server name) so it can be used
4102 -- for communication.
4103 local channel = getChannel(serverName)
4104 modem.open(channel)
4105 log("Hosting on channel "..channel..".")
4106
4107 if hideCertificate then
4108 log("Your server is set to require clients to already have its certificate in order to connect to it.")
4109 end
4110
4111 -- Allow clients to use discover() to get the name and certificate
4112 -- of this server without prior knowledge of it.
4113 if discoverable or discoverable == nil then
4114 modem.open(DISCOVERY_CHANNEL)
4115 log("Your server is discoverable.")
4116 else
4117 log("Your server is not discoverable.")
4118 end
4119
4120 -- Load the server's user table from file, or create a new one if none was found.
4121 if userTablePath == nil then
4122 userTablePath = serverName.."_users.tbl"
4123 end
4124 local userTable
4125 if type(userTablePath) == "string" then
4126 -- Append the current working directory to the table path.
4127 userTablePath = workingDir == "" and userTablePath or workingDir.."/"..userTablePath
4128 userTable = loadUserTable(userTablePath)
4129 else
4130 error("userTablePath must be a string.", 2)
4131 end
4132
4133 -- Create the server table.
4134 local server = {
4135 name = serverName,
4136 certificate = certificate,
4137 privateKey = privateKey,
4138 modemSide = modemSide,
4139 channel = channel,
4140 hideCertificate = hideCertificate,
4141 discoverable = discoverable or discoverable == nil, -- Default to true
4142 userTable = userTable,
4143 userTablePath = userTablePath,
4144 sockets = {} -- New servers have no connections yet.
4145 }
4146
4147 table.insert(allServers, server)
4148 log("Server ready.")
4149 return server
4150end
4151
4152
4153-- Close a socket or server, such that it will not listen for messages anymore.
4154-- Closing a server closes all its sockets.
4155function close(socket)
4156 if socketValid(socket) then
4157 -- Let the other end of the socket know it has been closed.
4158 -- Don't send if this one was closed remotely, since the other end clearly
4159 -- already knows.
4160 if not socket.closedRemotely then
4161 sendEncryptedInternal(socket, "c")
4162 end
4163 if socket.server == nil then
4164 -- If this is a client socket, remove it from the list of client sockets.
4165 -- This will stop handleModemEvent() from processing messages for it.
4166 for i=1,#allClientSockets do
4167 if allClientSockets[i] == socket then
4168 table.remove(allClientSockets, i)
4169 break
4170 end
4171 end
4172 else
4173 -- If this is a server socket, remove it from the server's socket list.
4174 -- This will stop handleModemEvent() from processing messages for it.
4175 socket.server.sockets[socket.target] = nil
4176 end
4177
4178 -- If this was the only socket communicating on its channel, close the channel
4179 -- on the modem. Don't close the channel if another socket is still using it.
4180 if not channelInUse(socket.channel, socket.modemSide) then
4181 peripheral.wrap(socket.modemSide).close(socket.channel)
4182 log("Closed socket channel "..socket.channel.." on modem "..socket.modemSide..".")
4183 end
4184 log("Closed socket.")
4185
4186 elseif serverValid(socket) then
4187 -- If this is a server being closed...
4188 local server = socket
4189 -- Create a copy of the server's socket list and close them all.
4190 -- Closing a socket will remove it from the server's socket list,
4191 -- so we make a copy so it doesn't change while we're trying to iterate
4192 -- over it.
4193 local socketsCopy = {}
4194 for _,soc in pairs(server.sockets) do
4195 table.insert(socketsCopy, soc)
4196 end
4197 for _,soc in pairs(socketsCopy) do
4198 close(soc)
4199 end
4200
4201 -- Remove the closed server from the server list.
4202 -- This will stop handleModemEvent() from processing messages for it.
4203 for i=1,#allServers do
4204 if allServers[i] == server then
4205 table.remove(allServers, i)
4206 break
4207 end
4208 end
4209
4210 -- If this was the only server/socket communicating on its channel, close the channel
4211 -- on the modem. Don't close the channel if another socket is still using it.
4212 if not channelInUse(server.channel, server.modemSide) then
4213 peripheral.wrap(server.modemSide).close(server.channel)
4214 log("Closed server channel "..server.channel.." on modem "..server.modemSide..".")
4215 end
4216
4217 -- If this was the only server using the discovery channel, close it.
4218 if server.discoverable then
4219 found = false
4220 for _,srvr in pairs(allServers) do
4221 if srvr.discoverable and srvr.modemSide == server.modemSide then
4222 found = true
4223 break
4224 end
4225 end
4226 if not found then
4227 peripheral.wrap(server.modemSide).close(DISCOVERY_CHANNEL)
4228 log("Closed discovery channel.")
4229 end
4230 end
4231 else
4232 error("Must be a valid socket or server.", 2)
4233 end
4234end
4235
4236
4237-- Close all sockets and servers on this machine.
4238function closeAll()
4239 -- Iteratve backwards so the list isn't chaning in front of us.
4240 for i=#allClientSockets,1,-1 do
4241 close(allClientSockets[i])
4242 end
4243 for i=#allServers,1,-1 do
4244 close(allServers[i])
4245 end
4246 log("Closed all sockets and servers.")
4247end
4248
4249
4250-- Process an encrypted message sent over CryptoNet to a socket,
4251-- that has already been decrypted.
4252-- Decrypted messages start with one or two characters that specify the type
4253-- of the message, which may either be an internal message (e.g. login requests)
4254-- or an encrypted message sent by a user using the send() function.
4255--
4256-- May return the details of a CryptoNet event caused by the message,
4257-- or nil if none occurs. Also returns a status boolean to say whether the
4258-- message turned out to have a valid format.
4259local function handleDecryptedMessage(socket, message)
4260 local ok = true
4261 local result = nil
4262 if message == "c" then
4263 log("Connection closed by other end.")
4264 socket.closedRemotely = true
4265 -- Close our end of the socket too.
4266 close(socket)
4267 socket.closedRemotely = nil
4268 result = {"connection_closed", socket, socket.server}
4269 elseif message:sub(1,2) == "lr" then
4270 -- Login requests have the format lr{username,password}
4271 -- Note that the password will have already been hashed using hashPassword()
4272 -- by the client before sending.
4273 local request = textutils.unserialize(message:sub(3))
4274 if type(request) == "table" and type(request[1]) == "string" and type(request[2]) == "string" then
4275 result = {loginHashed(socket, request[1], request[2])}
4276 else
4277 ok = false
4278 end
4279 elseif message:sub(1,2) == "lf" then
4280 -- Runs on client when server says the login failed. Format: lfusername
4281 log("Failed login attempt for "..message:sub(3)..".")
4282 result = {"login_failed", message:sub(3), socket, socket.server}
4283 elseif message:sub(1,2) == "ls" then
4284 -- Runs on client when server says the login was successful.
4285 -- Format: ls{username,permissionLevel}
4286 local details = textutils.unserialize(message:sub(3))
4287 if type(details) == "table" and type(details[1]) == "string" and type(details[2]) == "number" then
4288 socket.username = details[1]
4289 socket.permissionLevel = details[2]
4290 log(socket.username.." logged in successfully.")
4291 result = {"login", socket.username, socket, socket.server}
4292 else
4293 -- Response was invalid.
4294 ok = false
4295 end
4296 elseif message == "lo" then
4297 -- Logout.
4298 if socket.server == nil then
4299 -- On client side just reset the user details, the server will already
4300 -- have logged out its socket.
4301 local username = socket.username
4302 socket.username = nil
4303 socket.permissionLevel = 0
4304
4305 if username == nil then
4306 log("Already logged out.")
4307 else
4308 log(username.." logged out.")
4309 end
4310 result = {"logout", username, socket, nil}
4311 else
4312 -- On server side call logout() to also send a message to the client
4313 -- to tell it to log out.
4314 result = {logout(socket)}
4315 end
4316 else
4317 -- If the message had none of the above internal message types,
4318 -- it must be a user-generated encrypted message, which will start with
4319 -- a data type character. Attempt to deserialize the message as such.
4320 ok, message = pcall(deserializeAny, message)
4321 if ok then
4322 result = {"encrypted_message", message, socket, socket.server}
4323 end
4324 end
4325 return ok, result
4326end
4327
4328
4329-- See if the given CryptoNet message is relevant to this server, and act upon
4330-- it as needed. May return the details of a CryptoNet event caused by the message,
4331-- or nil if none occurs.
4332local function handleServerMessage(server, message, messageChannel)
4333 -- Check if this message is a discovery request,
4334 -- and respond to it if and only if the server is discoverable.
4335 if messageChannel == DISCOVERY_CHANNEL and message.msgType == "discovery_request" and server.discoverable then
4336 -- Remove the public key and signature from the certificate if needed.
4337 local certificate = server.hideCertificate and {name=server.name} or server.certificate
4338 sendInternal(server.modemSide, DISCOVERY_CHANNEL, nil, certificate, "discovery_response")
4339 log("Responded to discovery request.")
4340 -- If this is a message directed at this server...
4341 elseif messageChannel == server.channel and message.target == server.name then
4342 if message.msgType == "certificate_request" and not server.hideCertificate then
4343 sendInternal(server.modemSide, server.channel, nil, server.certificate, "certificate_response")
4344 log("Responded to certificate request.")
4345 elseif message.msgType == "connection_request" and type(message.message) == "string" then
4346 -- The client will have sent a session key, encryped using the server's public key.
4347 -- We need to use the private key to decrypt it and use the session key to send
4348 -- an acknowledgement to the client.
4349 local encryptedKey = message.message
4350 if server.sockets[encryptedKey] ~= nil then
4351 -- This is probably a repeated message, as we have already processed it before.
4352 log("Received duplicate connection request, ignoring it.")
4353 else
4354 -- Try to decrypt the session key using the server's private key.
4355 local ok, numKey = pcall(rsaCrypt.crypt, server.privateKey, encryptedKey)
4356 ok, sessKey = pcall(rsaCrypt.numberToBytes, numKey, 16*8, 8)
4357 -- Validate the key, which should be a table of 16 bytes.
4358 if ok and (sessKey == nil or #sessKey ~= 16) then
4359 ok = false
4360 end
4361 if not ok then
4362 log("Received invalid session key.")
4363 else
4364 -- Send a message back to the client encrypted with the session key
4365 -- to prove that we have received it correctly.
4366 -- The client knows what the message is supposed to be,
4367 -- allowing it to validate it.
4368 local response = tostring(sha256.digest(server.name..server.certificate.key.public..server.certificate.key.shared..numKey))
4369 -- Encrypt the message.
4370 local iv = generateKey()
4371 response = aes.encrypt_str(response, sessKey, iv)
4372 -- From now on the client will be identified by it's encrypted session key.
4373 sendInternal(server.modemSide, server.channel, encryptedKey, {{string.byte(response, 1, response:len())}, iv}, "connection_response")
4374 log("Responded to connection request.")
4375
4376 -- Create the socket object pointing to the client.
4377 local socket = {sender=server.name, target=encryptedKey, key=sessKey, modemSide=server.modemSide,
4378 channel=server.channel, server=server, permissionLevel=0, receivedMessages={}}
4379 server.sockets[encryptedKey] = socket
4380 return {"connection_opened", socket, server}
4381 end
4382 end
4383 elseif message.msgType == "encrypted_message" and type(message.message) == "table" and #message.message == 2
4384 and type(message.message[1]) == "table" and type(message.message[2]) == "table" then
4385 -- If this is an encrypted message, try decrypting it with the session key
4386 -- and handle the decrypted message as needed.
4387 local socket = server.sockets[message.sender]
4388 local encrypted = bytesToString(message.message[1])
4389 local iv = message.message[2]
4390 if socket == nil then
4391 log("Received a message from a sender who has yet to open a connection.")
4392 elseif encrypted == nil then
4393 log("Received invalid message.")
4394 elseif socket.receivedMessages[encrypted] then
4395 -- The encryption algorithm adds random numbers to each message before
4396 -- encrypting it, so even if two messages are identical their encrypted
4397 -- versions will probably be different. Therefore if we receive the exact
4398 -- same encrypted message twice it is most likely a malicious duplicate
4399 -- made by someone without the session key, and so should be ignored.
4400 log("Received duplicate message, ignoring it.")
4401 else
4402 -- Remember we have received this message so we don't accept it again
4403 -- (see above).
4404 socket.receivedMessages[encrypted] = true
4405 local ok, decrypted = pcall(aes.decrypt_str, encrypted, socket.key, iv)
4406 if ok then
4407 local ok, result = handleDecryptedMessage(socket, decrypted)
4408 if ok and result ~= null then
4409 return result
4410 end
4411 end
4412 if not ok then
4413 log("Received invalid message.")
4414 end
4415 end
4416 elseif message.msgType == "plain_message" then
4417 local socket = server.sockets[message.sender]
4418 if socket ~= nil then
4419 return {"plain_message", message.message, socket, server}
4420 else
4421 log("Received a message from a sender who has yet to open a connection.")
4422 end
4423 end
4424 end
4425end
4426
4427
4428-- See if the given CryptoNet message is relevant to this client socket, and act upon
4429-- it as needed.
4430--
4431-- May return the details of a CryptoNet event caused by the message,
4432-- or nil if none occurs.
4433local function handleClientMessage(socket, message, messageChannel)
4434 -- If this is a message directed at this socket...
4435 if messageChannel == socket.channel and message.sender == socket.target and message.target == socket.sender then
4436 if message.msgType == "encrypted_message" and type(message.message) == "table" and #message.message == 2
4437 and type(message.message[1]) == "table" and type(message.message[2]) == "table" then
4438 local encrypted = bytesToString(message.message[1])
4439 local iv = message.message[2]
4440 if encrypted == nil then
4441 log("Received invalid message.")
4442 elseif socket.receivedMessages[encrypted] then
4443 -- The encryption algorithm adds random numbers to each message before
4444 -- encrypting it, so even if two messages are identical their encrypted
4445 -- versions will probably be different. Therefore if we receive the exact
4446 -- same encrypted message twice it is most likely a malicious duplicate
4447 -- made by someone without the session key, and so should be ignored.
4448 log("Received duplicate message, ignoring it.")
4449 else
4450 socket.receivedMessages[encrypted] = true
4451 -- Decrypt the message with the session key and handle as needed.
4452 local ok, decrypted = pcall(aes.decrypt_str, encrypted, socket.key, iv)
4453 if ok then
4454 local ok, result = handleDecryptedMessage(socket, decrypted)
4455 if ok then
4456 return result
4457 end
4458 end
4459 if not ok then
4460 log("Received invalid message.")
4461 end
4462 end
4463 elseif message.msgType == "plain_message" then
4464 return {"plain_message", message.message, socket, nil}
4465 end
4466 end
4467end
4468
4469
4470-- Check if the given modem_message event is a CryptoNet message, and if so
4471-- decrypt and act upon it as needed.
4472--
4473-- receivedIDs: A table of recently received message IDs, used to block any
4474-- more messages with the same ID within a cooldown period, on the basis that they
4475-- are probably the same message repeated.
4476--
4477-- May return the details of a CryptoNet event caused by the message,
4478-- or nil if none occurs.
4479local function handleModemEvent(event, receivedIDs)
4480 -- Check if the modem message was a CryptoNet-formatted message, and extract
4481 -- the message contents.
4482 local message = extractMessage(event[5], receivedIDs)
4483 if message ~= nil then
4484 -- Try passing the message to all servers on this machine.
4485 for _,server in pairs(allServers) do
4486 local result = handleServerMessage(server, message, event[3])
4487 if result ~= nil then
4488 return result
4489 end
4490 end
4491
4492 -- Try passing the message to all client sockets on this machine.
4493 for _,socket in pairs(allClientSockets) do
4494 local result = handleClientMessage(socket, message, event[3])
4495 if result ~= nil then
4496 return result
4497 end
4498 end
4499 end
4500
4501 return nil
4502end
4503
4504
4505-- Listens for and handles CryptoNet messages for all sockets and servers
4506-- on this machine. Returns when a message is received that invokes a
4507-- user-facing CryptoNet event, with the details of said event.
4508-- Should ideally be executed inside a while loop alongside event handling logic.
4509--
4510-- It is recommended that users use startEventLoop() over a listen() loop,
4511-- as it creates a new thread for each event received, allowing for calls to sleep()
4512-- and pullEvent() in event handling code without freezing the rest of the server.
4513function listen()
4514 -- Message IDs recently received by this machine that we don't want to
4515 -- process repeat copies of.
4516 local receivedIDs = {}
4517 -- Keep listening for and handling modem_messages until
4518 -- a CryptoNet event is raised.
4519 while true do
4520 local event = {os.pullEvent("modem_message")}
4521 local newEvent = handleModemEvent(event, receivedIDs)
4522 if newEvent ~= nil then
4523 return table.unpack(newEvent)
4524 end
4525 end
4526end
4527
4528
4529-- Request the certificates of all online CryptoNet servers on the network.
4530-- Some servers may have been set to not respond to discovery requests,
4531-- and some will only contain the server name in the certificate, excluding
4532-- the public key required to connect to the server.
4533--
4534-- This function can optionally use a certificate authority public key
4535-- to verify the signatures of certificates, only returning certificates
4536-- with valid signatures. By default discover() looks for the public key
4537-- in "certAuth.key".
4538--
4539-- timeout (number, default: 1):
4540-- The time in seconds to spend listening for responses.
4541--
4542-- certAuthKey (table or string, default: "certAuth.key"):
4543-- The certificate authority public key used to verify signatures,
4544-- or the path of the file to load it from. If no valid key is found
4545-- the discovery will still go ahead, but signatures will not be checked.
4546--
4547-- allowUnsigned (boolean, default: false):
4548-- Whether to include certificates with no valid signature in the results.
4549-- If no valid cert auth key is provided this is ignored, as the certificates
4550-- cannot be checked without a key.
4551--
4552-- modemSide (string, default: a side with a modem):
4553-- The modem to use to send and receive messages.
4554--
4555-- Returns a table of the certificates received, all of which will include
4556-- the name of server and possibly also the public key and signature.
4557function discover(timeout, certAuthKey, allowUnsigned, modemSide)
4558 -- Load and validate the key.
4559 certAuthKey = loadCertAuthKey(certAuthKey)
4560
4561 modemSide = resolveModemSide(modemSide)
4562 local modem = peripheral.wrap(modemSide)
4563 -- Remember if the modem was already open so we can
4564 -- close it afterwards if it wasn't.
4565 local wasOpen = modem.isOpen(DISCOVERY_CHANNEL)
4566 modem.open(DISCOVERY_CHANNEL)
4567
4568 log("Discovering...")
4569 sendInternal(modemSide, DISCOVERY_CHANNEL, nil, nil, "discovery_request")
4570
4571 -- List of response message IDs we've already received
4572 -- so we can ignore duplicates.
4573 local receivedIDs = {}
4574 -- The received certificates.
4575 local certificates = {}
4576 -- Set a timer for when the timeout expires.
4577 local timer = os.startTimer((type(timeout) == "number") and timeout or 1)
4578 while true do
4579 -- Wait for either a modem_message or timer event.
4580 local event = {os.pullEvent()}
4581 if event[1] == "modem_message" and event[3] == DISCOVERY_CHANNEL then
4582 -- See if this is a CryptoNet-formatted message and exract its contents.
4583 local message = extractMessage(event[5], receivedIDs)
4584 -- If this is a discovery_response with a correctly formatted certifiate...
4585 if message ~= nil and message.msgType == "discovery_response" and certificateValid(message.message, true) then
4586 local certificate = message.message
4587 local found = false
4588 -- If we have already received an identical certificate don't add this one.
4589 for _,cert in pairs(certificates) do
4590 if certificate.name == cert.name and ((certificate.key == nil and cert.key == nil) or (certificate.key ~= nil and cert.key ~= nil
4591 and certificate.key.public == cert.key.public and certificate.key.shared == cert.key.shared)) and certificate.signature == cert.signature then
4592 found = true
4593 break
4594 end
4595 end
4596
4597 if not found then
4598 table.insert(certificates, certificate)
4599 end
4600 end
4601 elseif event[1] == "timer" and event[2] == timer then
4602 -- Stop listening for events once the time is up.
4603 break
4604 end
4605 end
4606
4607 -- Close the discovery channel if it wasn't open before we started.
4608 if not wasOpen then
4609 modem.close(DISCOVERY_CHANNEL)
4610 end
4611
4612 -- If we have a valid cert auth key to use,
4613 -- verify the signatures of the received certificates.
4614 -- If allowUnsigned is false any certificates without valid signatures
4615 -- will be removed.
4616 if certAuthKey ~= nil and #certificates > 0 then
4617 log("Checking signatures...")
4618 -- Iterate backwards as we will be deleting from the list.
4619 for i=#certificates,1,-1 do
4620 local certificate = certificates[i]
4621 if certificate.signature == nil then
4622 if not allowUnsigned then
4623 log("Discarding "..certificate.name.." as it has no signature.")
4624 table.remove(certificates, i)
4625 end
4626 else
4627 local ok, valid = pcall(verifyCertificate, certificate, certAuthKey)
4628 if ok and valid then
4629 -- Keep the certificate.
4630 log(certificate.name.." has a valid signature.")
4631 else
4632 log("Discarding "..certificate.name.." as it has an invalid signature.")
4633 table.remove(certificates, i)
4634 end
4635 end
4636 end
4637 end
4638
4639 return certificates
4640end
4641
4642
4643-- Request the certificate of a server with the given name.
4644-- Note that some servers may not respond to these requests,
4645-- expecting trusted clients to have been given the certificate manually.
4646-- All the certificates returned will contain the public key of their server.
4647--
4648-- If multiple certificates are received with the same server name,
4649-- there is no way to tell which one is the real server (the others are probably
4650-- malicious fakes), so none of them are returned. To avoid this situation,
4651-- this function can optionally use a certificate authority public key to
4652-- verify the signatures of received certificates, ignoring any with invalid
4653-- signatures. By default requestCertificate() looks in "certAuth.key"
4654-- for the key.
4655-- If multiple signed certificates are received, this implies that
4656-- the certificate authority has authorized an impersonator, so none of them
4657-- are returned as we don't know which is the real one.
4658--
4659-- serverName (string, required):
4660-- The name of the server to request the certificate of.
4661--
4662-- timeout (number, default: 1):
4663-- The length of time in seconds to wait for responses.
4664-- The function will always wait the full time, to allow for duplicates.
4665--
4666-- certAuthKey (table or string, default: "certAuth.key"):
4667-- The certificate authority public key used to verify signatures,
4668-- or the path of the file to load it from. If no valid key is found
4669-- the request will still go ahead, but signatures will not be checked.
4670--
4671-- allowUnsigned (boolean, default: false):
4672-- Whether to accept certificates with no valid signature.
4673-- If no valid cert auth key is provided this is ignored, as the certificates
4674-- cannot be checked without a key.
4675--
4676-- modemSide (string, default: a side with a modem):
4677-- The modem to use to send and receive messages.
4678--
4679-- Returns the certificate of the server if exactly one is received, or nil
4680-- if zero or more than one acceptable certificates are found.
4681-- Also returns a table of all acceptable certificates received.
4682function requestCertificate(serverName, timeout, certAuthKey, allowUnsigned, modemSide)
4683 if type(serverName) ~= "string" then
4684 error("Server name must be a string.", 2)
4685 end
4686 certAuthKey = loadCertAuthKey(certAuthKey)
4687
4688 modemSide = resolveModemSide(modemSide)
4689 local modem = peripheral.wrap(modemSide)
4690 local channel = getChannel(serverName)
4691 -- Remember if the modem was already open so we can
4692 -- close it afterwards if it wasn't.
4693 local wasOpen = modem.isOpen(channel)
4694 modem.open(channel)
4695
4696 log("Requesting certificate...")
4697 sendInternal(modemSide, channel, serverName, nil, "certificate_request")
4698
4699 -- List of response message IDs we've already received
4700 -- so we can ignore duplicates.
4701 local receivedIDs = {}
4702 -- The received certificates.
4703 local certificates = {}
4704 -- Set a timer for when the timeout expires.
4705 local timer = os.startTimer((type(timeout) == "number") and timeout or 1)
4706 while true do
4707 -- Wait for either a modem_message or timer event.
4708 local event = {os.pullEvent()}
4709 if event[1] == "modem_message" and event[3] == channel then
4710 -- See if this is a CryptoNet-formatted message and exract its contents.
4711 local message = extractMessage(event[5], receivedIDs)
4712 -- If this is a certificate_response with a correctly formatted certifiate,
4713 -- for the correct server...
4714 if message ~= nil and message.msgType == "certificate_response" and certificateValid(message.message) and message.message.name == serverName then
4715 local certificate = message.message
4716 local found = false
4717 -- If we have already received an identical certificate don't add this one.
4718 for _,cert in pairs(certificates) do
4719 if certificate.key.public == cert.key.public and certificate.key.shared == cert.key.shared and certificate.signature == cert.signature then
4720 found = true
4721 break
4722 end
4723 end
4724
4725 if not found then
4726 table.insert(certificates, certificate)
4727 end
4728 end
4729 elseif event[1] == "timer" and event[2] == timer then
4730 -- Stop listening for events once the time is up.
4731 break
4732 end
4733 end
4734
4735 -- Close the channel if it wasn't open before we started.
4736 if not wasOpen then
4737 modem.close(channel)
4738 end
4739
4740 -- If we have a valid cert auth key to use,
4741 -- verify the signatures of the received certificates.
4742 -- If allowUnsigned is false any certificates without valid signatures
4743 -- will be removed.
4744 local signedCount = 0
4745 if certAuthKey ~= nil and #certificates > 0 then
4746 log("Checking signatures...")
4747 -- Iterate backwards as we will be deleting from the list.
4748 for i=#certificates,1,-1 do
4749 local certificate = certificates[i]
4750 if certificate.signature == nil then
4751 if not allowUnsigned then
4752 log("Discarding a certificate as it has no signature.")
4753 table.remove(certificates, i)
4754 end
4755 else
4756 local ok, valid = pcall(verifyCertificate, certificate, certAuthKey)
4757 if ok and valid then
4758 -- Keep the certificate.
4759 log("This certificate has a valid signature.")
4760 signedCount = signedCount + 1
4761 else
4762 log("Discarding a certificate as it has an invalid signature.")
4763 table.remove(certificates, i)
4764 end
4765 end
4766 end
4767 end
4768
4769 if #certificates == 1 then
4770 log("One certificate found, good.")
4771 return certificates[1], certificates
4772 else
4773 if #certificates == 0 then
4774 log("No certificates found.")
4775 elseif signedCount > 1 then
4776 log("Multiple ("..signedCount..") certificates had valid signatures, has the certificate authority authorized impersonators?")
4777 else
4778 log("Multiple ("..#certificates..") certificates found, some may be malicious.")
4779 end
4780 -- Don't return any certificate as the chosen one, but still return the whole list.
4781 return nil, certificates
4782 end
4783end
4784
4785
4786-- Open an encrypted connection to a CryptoNet server, returning a socket object
4787-- that can be used to send and receive messages from the server.
4788--
4789-- serverName (string, default: inferred from certificate):
4790-- The name of the server to connect to.
4791--
4792-- timeout (number, default: 5):
4793-- The number of seconds to wait for a response to the connection request.
4794-- Will terminate early if a response is received.
4795--
4796-- certTimeout (number, default: 1):
4797-- The number of seconds to wait for certificate responses,
4798-- if no certificate was provided.
4799--
4800-- certificate (table or string, default: "<serverName>.crt"):
4801-- The certificate of the server. Can either be the certificate of
4802-- the server itself, or the name of a file that contains it.
4803-- If no valid certificate is found a certificate request
4804-- will be sent to the server.
4805--
4806-- modemSide (string, default: a side with a modem):
4807-- The modem to use to send and receive messages.
4808--
4809-- certAuthKey (table or string, default: "certAuth.key"):
4810-- The certificate authority public key used to verify signatures,
4811-- or the path of the file to load it from. If no valid key is found
4812-- the connection will still go ahead, but signatures will not be checked.
4813--
4814-- allowUnsigned (boolean, default: false):
4815-- Whether to accept certificates with no valid signature.
4816-- If no valid cert auth key is provided this is ignored, as the certificates
4817-- cannot be checked without a key.
4818-- This does not apply to the certificate provided by the user (if present),
4819-- which is never verified (we trust them to get their own certificate right),
4820-- only to certificates received through a certificate request.
4821--
4822-- Returns a socket object that can be used to communicate with the server,
4823-- with the following attributes:
4824-- sender: The encrypted session key of this socket, which acts as the client's
4825-- temporary identity to the server
4826-- target: The name of the server
4827-- key: The session key for this socket's session
4828-- modemSide: The modem used by the socket
4829-- channel: The channel the server (and this socket) use to communicate
4830-- permissionLevel: The permission level of the user logged into the socket,
4831-- initialized to 0.
4832-- receivedMessages: The encrypted messages received by this socket,
4833-- used to prevent replay attacks using duplicate messages.
4834-- Every time a message is encrypted the encrypted version will be different
4835-- due to randomness in the algorithm, so if we get the exact same message
4836-- twice it is probably a malicious duplicate.
4837function connect(serverName, timeout, certTimeout, certificate, modemSide, certAuthKey, allowUnsigned)
4838 if serverName ~= nil and type(serverName) ~= "string" then
4839 error("Server name must be a string or nil.", 2)
4840 end
4841 if certificate == nil then
4842 if type(serverName) == "string" then
4843 -- If a server name was given but not a certificate,
4844 -- try to load a corresponding certificate from file.
4845 certificate = serverName..".crt"
4846 else
4847 -- Need a way to identify the server.
4848 error("Server name and certificate can't both be nil.", 2)
4849 end
4850 end
4851
4852 -- If the certificate is a file path...
4853 if type(certificate) == "string" then
4854 local certFilename = certificate
4855 -- Make paths relative to the current CryptoNet working directory.
4856 local certPath = workingDir == "" and certFilename or workingDir.."/"..certFilename
4857 log("Checking "..certPath.." for certificate...")
4858 if fs.isDir(certPath) or not fs.exists(certPath) then
4859 if fs.isDir(certPath) then
4860 log(certFilename.." is not a file, will need to request certificate.")
4861 else
4862 log(certFilename.." does not exist, will need to request certificate.")
4863 end
4864 certificate = nil
4865 else
4866 local file = fs.open(certPath, "r")
4867 certificate = deserializeCertOrKey(file.readAll())
4868 file.close()
4869
4870 if not certificateValid(certificate) then
4871 log(certFilename.." does not contain a valid certificate, will need to request certificate.")
4872 certificate = nil
4873 else
4874 log("Loaded certificate from "..certFilename..".")
4875 end
4876 end
4877 elseif not certificateValid(certificate) then
4878 -- If certificate was not a string, it should be a valid certificate.
4879 error("Invalid certificate.", 2)
4880 end
4881
4882 -- Infer serverName from the certificate.
4883 if serverName == nil then
4884 if certificate ~= nil then
4885 serverName = certificate.name
4886 else
4887 error("Failed to load name from certificate, and no name was provided.", 2)
4888 end
4889 end
4890
4891 modemSide = resolveModemSide(modemSide)
4892 local modem = peripheral.wrap(modemSide)
4893 local channel = getChannel(serverName)
4894 -- Remember if the modem was already open so we can
4895 -- close it afterwards if it wasn't.
4896 local wasOpen = modem.isOpen(channel)
4897 modem.open(channel)
4898
4899 -- If we have no certificate yet, request it from the server.
4900 if certificate == nil then
4901 certificate = requestCertificate(serverName, certTimeout, certAuthKey, allowUnsigned, modemSide)
4902 if certificate == nil then
4903 -- Close the modem channel if it wasn't open before we started.
4904 if not wasOpen then
4905 modem.close(channel)
4906 end
4907 error("Failed to request certificate from server.", 2)
4908 end
4909 end
4910
4911 -- An AES session key is used to encrypt the messages sent and received over
4912 -- this socket. Before sending messages we need to generate a session key
4913 -- and send it to the server. RSA encryption using the server's public key
4914 -- (contained in its certificate) is used to send the session key;
4915 -- the server will use its private key to decrypt the message.
4916 log("Generating session key...")
4917 local sessKey = generateKey()
4918 local numKey = rsaCrypt.bytesToNumber(sessKey, 16*8, 8)
4919 local encryptedKey = rsaCrypt.crypt(certificate.key, numKey)
4920 -- The server will send a response encrypted with the session key to prove
4921 -- that it has received is successfully. We know what the response content
4922 -- is supposed to be, allowing us to verify the response.
4923 local expectedResponse = tostring(sha256.digest(serverName..certificate.key.public..certificate.key.shared..numKey))
4924 sendInternal(modemSide, channel, serverName, encryptedKey, "connection_request")
4925
4926 log("Awaiting response...")
4927 -- List of response message IDs we've already received
4928 -- so we can ignore duplicates.
4929 local receivedIDs = {}
4930 -- Set a timer for when the timeout expires.
4931 local timer = os.startTimer((type(timeout) == "number") and timeout or 5)
4932 while true do
4933 -- Wait for either a modem_message or timer event.
4934 local event = {os.pullEvent()}
4935 if event[1] == "modem_message" and event[3] == channel then
4936 -- See if this is a CryptoNet-formatted message and exract its contents.
4937 local message = extractMessage(event[5], receivedIDs)
4938 -- If the message is a valid connection_response directed at this socket,
4939 -- containing a valid encrypted message...
4940 if message ~= nil and message.msgType == "connection_response" and message.target == encryptedKey and type(message.message) == "table"
4941 and #message.message == 2 and type(message.message[1]) == "table" and type(message.message[2]) == "table" then
4942 -- Decrypt using the session key.
4943 local ok, actualResponse = pcall(aes.decrypt_str, bytesToString(message.message[1]), sessKey, message.message[2])
4944 -- Compare the response to what we know the response content is supposed
4945 -- to be, to see if the session key was received correctly.
4946 if ok and actualResponse == expectedResponse then
4947 log("Connection successful.")
4948 -- Once we have received a valid response we know the connection has
4949 -- been opened on the server, so we can stop listening.
4950 os.cancelTimer(timer)
4951 break
4952 else
4953 log("Received an invalid response.")
4954 end
4955 end
4956 elseif event[1] == "timer" and event[2] == timer then
4957 -- If the timeout expires abort the connection attempt.
4958 -- Close the modem channel if it wasn't open before we started.
4959 if not wasOpen then
4960 modem.close(channel)
4961 end
4962 error("Did not receive a response before timeout.", 2)
4963 end
4964 end
4965
4966 -- Create and return the socket object.
4967 local socket = {sender=encryptedKey, target=serverName, key=sessKey, modemSide=modemSide, channel=channel, permissionLevel=0, receivedMessages={}}
4968 table.insert(allClientSockets, socket)
4969 return socket
4970end
4971
4972
4973--
4974-- EVENT LOOP
4975--
4976
4977-- Run a background loop that listens for events of any kind, and calls
4978-- an optional event handler on every event.
4979-- The event handler is always called in a new thread, so it is okay to use
4980-- blocking functions such as sleep() and pullEvent() within onEvent
4981-- without freezing the whole program. Errors raised during event handling
4982-- are printed without terminating the whole program, so errors processing one
4983-- event won't bring down the entire system.
4984--
4985-- Any modem_message events are also sent to CryptoNet for handling,
4986-- allowing all sockets and servers on this machine to listen for messages
4987-- in the background. Both the modem_message itself and any CryptoNet events invoked
4988-- by it are sent to the event handler, on seperate iterations of the event loop.
4989local function eventLoop(onEvent)
4990 -- List of response message IDs we've already received
4991 -- so we can ignore duplicates.
4992 local receivedIDs = {}
4993 while true do
4994 -- Wrap everything in pcall so any errors won't exit the entire program,
4995 -- only this iteration of the loop.
4996 local ok, msg = pcall(function()
4997 -- Listen for all event types.
4998 local event = {os.pullEvent()}
4999 if event[1] == "modem_message" then
5000 local newEvent = handleModemEvent(event, receivedIDs)
5001 if newEvent ~= nil then
5002 -- This event will be processed on a later iteration of the loop.
5003 os.queueEvent(table.unpack(newEvent))
5004 end
5005 end
5006 -- Call the event handler in a new thread.
5007 if onEvent ~= nil then
5008 os.startThread(function ()
5009 -- We need another pcall here since this is in a different thread
5010 -- to the outer pcall, so that one won't be able to catch errors
5011 -- from the handler.
5012 local ok, msg = pcall(onEvent, event)
5013 if not ok then
5014 -- Make sure pressing Ctrl+T can still terminate the program.
5015 if msg == "Terminated" then
5016 error("Terminated", 0)
5017 else
5018 -- Print the error without crashing.
5019 print(msg)
5020 end
5021 end
5022 end)
5023 end
5024 end)
5025 if not ok then
5026 -- Make sure pressing Ctrl+T can still terminate the program.
5027 if msg == "Terminated" then
5028 error("Terminated", 0)
5029 else
5030 -- Print the error without crashing.
5031 print(msg)
5032 end
5033 end
5034 end
5035end
5036
5037
5038-- Run a background loop that listens for events of any kind, and calls
5039-- the given event handler (which should take one argument) on them.
5040-- The event handler is always called in a new thread, so it is okay to use
5041-- blocking functions such as sleep() and pullEvent() within onEvent
5042-- without freezing the whole program. Errors raised during event handling
5043-- are printed without terminating the whole program, so errors processing one
5044-- event won't bring down the entire system.
5045--
5046-- Any modem_message events are also sent to CryptoNet for handling,
5047-- allowing all sockets and servers on this machine to listen for messages
5048-- in the background. Both the modem_message itself and any CryptoNet events invoked
5049-- by it are sent to the event handler, on separate iterations of the event loop.
5050--
5051-- The onStart function is called once after the loop starts,
5052-- after the threading system has been started.
5053-- onStart and onEvent are both optional.
5054-- os.startThread() can be called from within onStart and onEvent
5055-- (and any functions called by them) to start new threads without blocking
5056-- the current one.
5057function startEventLoop(onStart, onEvent)
5058 if onStart ~= nil and type(onStart) ~= "function" then
5059 error("onStart is not a function.", 2)
5060 end
5061 if onEvent ~= nil and type(onEvent) ~= "function" then
5062 error("onEvent is not a function.", 2)
5063 end
5064
5065 -- Start the threading system so os.startThread() can be used.
5066 threadAPI.startThreading(function ()
5067 -- Start the actual event loop in a different thread.
5068 os.startThread(function () eventLoop(onEvent) end)
5069 -- Call onStart in this thread.
5070 if onStart ~= nil then
5071 local ok, msg = pcall(onStart)
5072 if not ok then
5073 -- Print the error without crashing.
5074 print(msg)
5075 end
5076 end
5077 end)
5078end
5079
5080
5081--
5082-- CERTIFICATE AUTHORITY
5083--
5084
5085-- Generate the public and private keys used by a certificate authority
5086-- to sign certificates. The keys will be written to the specified files,
5087-- which both have sensible default names.
5088function initCertificateAuthority(publicFilename, privateFilename)
5089 if publicFilename == nil then
5090 publicFilename = "certAuth.key"
5091 end
5092 if privateFilename == nil then
5093 privateFilename = "certAuth_private.key"
5094 end
5095 -- Math paths relative to the current CryptoNet working directory.
5096 local publicPath = workingDir == "" and publicFilename or workingDir.."/"..publicFilename
5097 local privatePath = workingDir == "" and privateFilename or workingDir.."/"..privateFilename
5098
5099 if fs.exists(publicPath) then
5100 error(publicPath.." already exists, please delete both your existing keyfiles in order to generate new ones.", 2)
5101 end
5102 if fs.exists(privatePath) then
5103 error(privatePath.." already exists, please delete both your existing keyfiles in order to generate new ones.", 2)
5104 end
5105
5106 log("Generating key pair... (may take some time)")
5107 publicKey, privateKey = rsaKeygen.generateKeyPair()
5108 print("")
5109 log("Done!")
5110
5111 local file = fs.open(publicPath, "w")
5112 file.write(serializeCertOrKey(publicKey))
5113 file.close()
5114 log("Saved public key to "..publicPath..". Give this to client users.")
5115
5116 file = fs.open(privatePath, "w")
5117 file.write(serializeCertOrKey(privateKey))
5118 file.close()
5119 log("Saved private key to "..privatePath..". Do not share this with anyone!")
5120
5121 log("Initialization successful.")
5122end
5123
5124
5125-- Sign a certificate using the certificate authority's private key.
5126-- Both arguments can either be the certificate/key itself, or a path to
5127-- a file that contains it. The signed certificate is returned, and written
5128-- to the path the certificate was stored in, if it was loaded from file.
5129function signCertificate(certificate, privateKey)
5130 local certPath = nil
5131 if type(certificate) == "string" then
5132 -- Make paths relative to the current CryptoNet working directory.
5133 certPath = workingDir == "" and certificate or workingDir.."/"..certificate
5134 if not fs.exists(certPath) then
5135 error(certPath.." does not exist.", 2)
5136 end
5137 if fs.isDir(certPath) then
5138 error(certPath.." is not a file.", 2)
5139 end
5140
5141 local file = fs.open(certPath, "r")
5142 certificate = deserializeCertOrKey(file.readAll())
5143 file.close()
5144
5145 if not certificateValid(certificate) then
5146 error(certPath.." does not contain a valid certificate.", 2)
5147 end
5148 log("Loaded certificate from "..certPath..".")
5149 elseif not certificateValid(certificate) then
5150 -- If certificate is not a file path it should be a valid certificate.
5151 error("Not a valid certificate or file.", 2)
5152 end
5153
5154 -- Default value.
5155 if privateKey == nil then
5156 privateKey = "certAuth_private.key"
5157 end
5158 if type(privateKey) == "string" then
5159 -- Make paths relative to the current CryptoNet working directory.
5160 local keyPath = workingDir == "" and privateKey or workingDir.."/"..privateKey
5161 if not fs.exists(keyPath) then
5162 error(keyPath.." does not exist.", 2)
5163 end
5164 if fs.isDir(keyPath) then
5165 error(keyPath.." is not a file.", 2)
5166 end
5167
5168 local file = fs.open(keyPath, "r")
5169 privateKey = deserializeCertOrKey(file.readAll())
5170 file.close()
5171
5172 if not privateKeyValid(privateKey) then
5173 error(keyPath.." does not contain a valid private key.", 2)
5174 end
5175 log("Loaded private key from "..keyPath..".")
5176 elseif not privateKeyValid(privateKey) then
5177 -- If privateKey is not a file path it should be a valid private key.
5178 error("Not a valid private key or file.", 2)
5179 end
5180
5181 -- The signature is just the contents of the certificate hashed and encrypted.
5182 -- Clients can verify the signature by decrypting it with the cert auth public key
5183 -- and seeing if it matches the contents of the certificate.
5184 log("Generating signature...")
5185 local hash = sha256.digest(certificate.name..certificate.key.public..certificate.key.shared)
5186 certificate.signature = rsaCrypt.crypt(privateKey, rsaCrypt.bytesToNumber(hash, 32*8, 8))
5187
5188 -- If the certificate was loaded from a file, save it back there.
5189 if certPath ~= nil then
5190 local file = fs.open(certPath, "w")
5191 file.write(serializeCertOrKey(certificate))
5192 file.close()
5193 log("Saved certificate to "..certPath..".")
5194 end
5195 return certificate
5196end
5197
5198-- CryptoNet's command line interface, used by a certificate authority
5199-- to sign certificates.
5200-- Supports two commands: initCertAuth and signCert.
5201--
5202-- initCertAuth is used to generate the keys used to sign and verify certificates.
5203-- The public key should be distributed to all clients using the certificate
5204-- authority, while the private key should be kept secure on the cert auth's
5205-- machine.
5206--
5207-- Certificates to be signed should be copied to the cert auth machine,
5208-- e.g. using floppy disks. signCert is then used to sign the certificate,
5209-- which can then be transferred back to the server machine.
5210-- Only sign the certificates of trusted servers, and don't sign two certificates
5211-- with the same name and different public keys.
5212
5213-- Only run if executed on the command line, not when imported with os.loadAPI().
5214if shell ~= nil then
5215 setLoggingEnabled(true)
5216 -- Set the CryptoNet working directory to match the system one.
5217 setWorkingDirectory(shell.dir())
5218
5219 local args = {...}
5220 if args[1] == "signCert" then
5221 -- Sign a certificate loaded from a file.
5222 local certPath = args[2]
5223 if certPath == nil then
5224 log("Usage: cryptoNet signCert <file>")
5225 return
5226 end
5227
5228 -- Make paths relative to the working directory.
5229 certPath = workingDir == "" and certPath or workingDir.."/"..certPath
5230 -- Optional private key file argument, can be omitted to use default.
5231 local keyPath = args[3]
5232 local ok, msg = pcall(signCertificate, certPath, keyPath)
5233
5234 if not ok then
5235 log("Error: "..msg:sub(8))
5236 end
5237 elseif args[1] == "initCertAuth" then
5238 -- Generate the cert auth key pair and save them to the specified files.
5239 -- The file arguments can be omitted to use the default values.
5240 local ok, msg = pcall(initCertificateAuthority, args[2], args[3])
5241 if not ok then
5242 log("Error: "..msg:sub(8))
5243 end
5244 else
5245 log("Invalid command.")
5246 end
5247end