From 7b210429b50e48de509ef00399604b338789c468 Mon Sep 17 00:00:00 2001 From: shortcutme Date: Mon, 25 Nov 2019 14:37:55 +0100 Subject: [PATCH] Multi threaded eciesDecrypt --- plugins/CryptMessage/CryptMessage.py | 15 +++++++++ plugins/CryptMessage/CryptMessagePlugin.py | 31 ++++++++++++++----- .../UiConfig/media/js/ConfigStorage.coffee | 14 +++++++++ plugins/UiConfig/media/js/all.js | 31 ++++++++++++++++++- src/Config.py | 5 +-- src/Crypt/Crypt.py | 4 +++ 6 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 src/Crypt/Crypt.py diff --git a/plugins/CryptMessage/CryptMessage.py b/plugins/CryptMessage/CryptMessage.py index 6f2cbdc2..b7286e2e 100644 --- a/plugins/CryptMessage/CryptMessage.py +++ b/plugins/CryptMessage/CryptMessage.py @@ -2,6 +2,7 @@ import hashlib import base64 import lib.pybitcointools as btctools +from Crypt import Crypt ecc_cache = {} @@ -22,10 +23,24 @@ def eciesEncrypt(data, pubkey, ephemcurve=None, ciphername='aes-256-cbc'): mac = pyelliptic.hmac_sha256(key_m, ciphertext) return key_e, ciphertext + mac + +@Crypt.thread_pool_crypt.wrap +def eciesDecryptMulti(encrypted_datas, privatekey): + texts = [] # Decoded texts + for encrypted_data in encrypted_datas: + try: + text = eciesDecrypt(encrypted_data, privatekey).decode("utf8") + texts.append(text) + except: + texts.append(None) + return texts + + def eciesDecrypt(encrypted_data, privatekey): ecc_key = getEcc(privatekey) return ecc_key.decrypt(base64.b64decode(encrypted_data)) + def split(encrypted): iv = encrypted[0:16] ciphertext = encrypted[16 + 70:-32] diff --git a/plugins/CryptMessage/CryptMessagePlugin.py b/plugins/CryptMessage/CryptMessagePlugin.py index c3907669..45afe184 100644 --- a/plugins/CryptMessage/CryptMessagePlugin.py +++ b/plugins/CryptMessage/CryptMessagePlugin.py @@ -1,10 +1,12 @@ import base64 import os +import gevent + from Plugin import PluginManager from Crypt import CryptBitcoin, CryptHash import lib.pybitcointools as btctools - +from Config import config from . import CryptMessage @@ -44,13 +46,7 @@ class UiWebsocketPlugin(object): else: encrypted_texts = [param] - texts = [] # Decoded texts - for encrypted_text in encrypted_texts: - try: - text = CryptMessage.eciesDecrypt(encrypted_text, privatekey).decode("utf8") - texts.append(text) - except Exception as err: - texts.append(None) + texts = CryptMessage.eciesDecryptMulti(encrypted_texts, privatekey) if type(param) == list: self.response(to, texts) @@ -188,6 +184,7 @@ class ActionsPlugin: tests.extend([ {"func": self.testCryptEciesEncrypt, "kwargs": {}, "num": 100, "time_standard": 1.2}, {"func": self.testCryptEciesDecrypt, "kwargs": {}, "num": 500, "time_standard": 1.3}, + {"func": self.testCryptEciesDecryptMulti, "kwargs": {}, "num": 5, "time_standard": 0.68}, {"func": self.testCryptAesEncrypt, "kwargs": {}, "num": 10000, "time_standard": 0.27}, {"func": self.testCryptAesDecrypt, "kwargs": {}, "num": 10000, "time_standard": 0.25} ]) @@ -207,6 +204,24 @@ class ActionsPlugin: assert ecc.decrypt(encrypted) == self.utf8_text.encode("utf8"), "%s != %s" % (ecc.decrypt(encrypted), self.utf8_text.encode("utf8")) yield "." + def testCryptEciesDecryptMulti(self, num_run=1): + yield "x 100 (%s threads) " % config.threads_crypt + aes_key, encrypted = CryptMessage.eciesEncrypt(self.utf8_text.encode("utf8"), self.publickey) + + threads = [] + for i in range(num_run): + assert len(aes_key) == 32 + threads.append(gevent.spawn( + CryptMessage.eciesDecryptMulti, [base64.b64encode(encrypted)] * 100, self.privatekey + )) + + for thread in threads: + res = thread.get() + assert res[0] == self.utf8_text, "%s != %s" % (res[0], self.utf8_text) + assert res[0] == res[-1], "%s != %s" % (res[0], res[-1]) + yield "." + gevent.joinall(threads) + def testCryptAesEncrypt(self, num_run=1): from lib import pyelliptic diff --git a/plugins/UiConfig/media/js/ConfigStorage.coffee b/plugins/UiConfig/media/js/ConfigStorage.coffee index 4d9684cc..642bae45 100644 --- a/plugins/UiConfig/media/js/ConfigStorage.coffee +++ b/plugins/UiConfig/media/js/ConfigStorage.coffee @@ -177,6 +177,20 @@ class ConfigStorage extends Class {title: "10 threads", value: 10} ] + section.items.push + key: "threads_crypt" + title: "Threads for cryptographic functions" + type: "select" + options: [ + {title: "Sync execution", value: 0} + {title: "1 thread", value: 1} + {title: "2 threads", value: 2} + {title: "3 threads", value: 3} + {title: "4 threads", value: 4} + {title: "5 threads", value: 5} + {title: "10 threads", value: 10} + ] + createSection: (title) => section = {} section.title = title diff --git a/plugins/UiConfig/media/js/all.js b/plugins/UiConfig/media/js/all.js index 68fe5268..b2c09e39 100644 --- a/plugins/UiConfig/media/js/all.js +++ b/plugins/UiConfig/media/js/all.js @@ -1510,7 +1510,7 @@ } ] }); - return section.items.push({ + section.items.push({ key: "threads_fs_write", title: "Threads for async file system writes", type: "select", @@ -1539,6 +1539,35 @@ } ] }); + return section.items.push({ + key: "threads_crypt", + title: "Threads for cryptographic functions", + type: "select", + options: [ + { + title: "Sync execution", + value: 0 + }, { + title: "1 thread", + value: 1 + }, { + title: "2 threads", + value: 2 + }, { + title: "3 threads", + value: 3 + }, { + title: "4 threads", + value: 4 + }, { + title: "5 threads", + value: 5 + }, { + title: "10 threads", + value: 10 + } + ] + }); }; ConfigStorage.prototype.createSection = function(title) { diff --git a/src/Config.py b/src/Config.py index 2d51fe52..4c2373bd 100644 --- a/src/Config.py +++ b/src/Config.py @@ -22,9 +22,9 @@ class Config(object): self.keys_api_change_allowed = set([ "tor", "fileserver_port", "language", "tor_use_bridges", "trackers_proxy", "trackers", "trackers_file", "open_browser", "log_level", "fileserver_ip_type", "ip_external", "offline", - "threads_fs_read", "threads_fs_write" + "threads_fs_read", "threads_fs_write", "threads_crypt" ]) - self.keys_restart_need = set(["tor", "fileserver_port", "fileserver_ip_type", "threads_fs_read", "threads_fs_write"]) + self.keys_restart_need = set(["tor", "fileserver_port", "fileserver_ip_type", "threads_fs_read", "threads_fs_write", "threads_crypt"]) self.start_dir = self.getStartDir() self.config_file = self.start_dir + "/zeronet.conf" @@ -283,6 +283,7 @@ class Config(object): self.parser.add_argument("--db_mode", choices=["speed", "security"], default="speed") self.parser.add_argument('--threads_fs_read', help='Number of threads for file read operations', default=1, type=int) self.parser.add_argument('--threads_fs_write', help='Number of threads for file write operations', default=1, type=int) + self.parser.add_argument('--threads_crypt', help='Number of threads for cryptographic operations', default=2, type=int) self.parser.add_argument("--download_optional", choices=["manual", "auto"], default="manual") self.parser.add_argument('--coffeescript_compiler', help='Coffeescript compiler for developing', default=coffeescript, diff --git a/src/Crypt/Crypt.py b/src/Crypt/Crypt.py new file mode 100644 index 00000000..7d7d3659 --- /dev/null +++ b/src/Crypt/Crypt.py @@ -0,0 +1,4 @@ +from Config import config +from util import ThreadPool + +thread_pool_crypt = ThreadPool.ThreadPool(config.threads_crypt) \ No newline at end of file