Revert "Switch to sslcrypto for cryptography tasks (#2338)"

This reverts commit fbc7b6fc4f.
This commit is contained in:
shortcutme 2019-12-15 18:30:42 +01:00
parent 2f7323043f
commit 958882c1c5
No known key found for this signature in database
GPG key ID: 5B63BAE6CB9613AE
55 changed files with 7287 additions and 3748 deletions

View file

@ -103,8 +103,8 @@ class ActionsPlugin:
tests.extend([
{"func": self.testHdPrivatekey, "num": 50, "time_standard": 0.57},
{"func": self.testSign, "num": 20, "time_standard": 0.46},
{"func": self.testVerify, "kwargs": {"lib_verify": "sslcrypto_fallback"}, "num": 20, "time_standard": 0.38},
{"func": self.testVerify, "kwargs": {"lib_verify": "sslcrypto"}, "num": 200, "time_standard": 0.30},
{"func": self.testVerify, "kwargs": {"lib_verify": "btctools"}, "num": 20, "time_standard": 0.38},
{"func": self.testVerify, "kwargs": {"lib_verify": "openssl"}, "num": 200, "time_standard": 0.30},
{"func": self.testVerify, "kwargs": {"lib_verify": "libsecp256k1"}, "num": 200, "time_standard": 0.10},
{"func": self.testPackMsgpack, "num": 100, "time_standard": 0.35},

View file

@ -1,21 +1,28 @@
import hashlib
import base64
import sslcrypto
import binascii
import lib.pybitcointools as btctools
from util import ThreadPool
from Crypt import Crypt
ecc_cache = {}
curve = sslcrypto.ecc.get_curve("secp256k1")
def eciesEncrypt(data, pubkey, ciphername="aes-256-cbc"):
ciphertext, key_e = curve.encrypt(
data,
base64.b64decode(pubkey),
algo=ciphername,
derivation="sha512",
return_aes_key=True
)
return key_e, ciphertext
def eciesEncrypt(data, pubkey, ephemcurve=None, ciphername='aes-256-cbc'):
from lib import pyelliptic
pubkey_openssl = toOpensslPublickey(base64.b64decode(pubkey))
curve, pubkey_x, pubkey_y, i = pyelliptic.ECC._decode_pubkey(pubkey_openssl)
if ephemcurve is None:
ephemcurve = curve
ephem = pyelliptic.ECC(curve=ephemcurve)
key = hashlib.sha512(ephem.raw_get_ecdh_key(pubkey_x, pubkey_y)).digest()
key_e, key_m = key[:32], key[32:]
pubkey = ephem.get_pubkey()
iv = pyelliptic.OpenSSL.rand(pyelliptic.OpenSSL.get_cipher(ciphername).get_blocksize())
ctx = pyelliptic.Cipher(key_e, iv, 1, ciphername)
ciphertext = iv + pubkey + ctx.ciphering(data)
mac = pyelliptic.hmac_sha256(key_m, ciphertext)
return key_e, ciphertext + mac
@Crypt.thread_pool_crypt.wrap
@ -30,12 +37,38 @@ def eciesDecryptMulti(encrypted_datas, privatekey):
return texts
def eciesDecrypt(ciphertext, privatekey):
return curve.decrypt(
base64.b64decode(ciphertext),
curve.wif_to_private(privatekey),
derivation="sha512"
)
def eciesDecrypt(encrypted_data, privatekey):
ecc_key = getEcc(privatekey)
return ecc_key.decrypt(base64.b64decode(encrypted_data))
def split(ciphertext):
return ciphertext[:16], ciphertext[86:-32]
def split(encrypted):
iv = encrypted[0:16]
ciphertext = encrypted[16 + 70:-32]
return iv, ciphertext
def getEcc(privatekey=None):
from lib import pyelliptic
global ecc_cache
if privatekey not in ecc_cache:
if privatekey:
publickey_bin = btctools.encode_pubkey(btctools.privtopub(privatekey), "bin")
publickey_openssl = toOpensslPublickey(publickey_bin)
privatekey_openssl = toOpensslPrivatekey(privatekey)
ecc_cache[privatekey] = pyelliptic.ECC(curve='secp256k1', privkey=privatekey_openssl, pubkey=publickey_openssl)
else:
ecc_cache[None] = pyelliptic.ECC()
return ecc_cache[privatekey]
def toOpensslPrivatekey(privatekey):
privatekey_bin = btctools.encode_privkey(privatekey, "bin")
return b'\x02\xca\x00\x20' + privatekey_bin
def toOpensslPublickey(publickey):
publickey_bin = btctools.encode_pubkey(publickey, "bin")
publickey_bin = publickey_bin[1:]
publickey_openssl = b'\x02\xca\x00 ' + publickey_bin[:32] + b'\x00 ' + publickey_bin[32:]
return publickey_openssl

View file

@ -5,22 +5,24 @@ import gevent
from Plugin import PluginManager
from Crypt import CryptBitcoin, CryptHash
import lib.pybitcointools as btctools
from Config import config
import sslcrypto
from . import CryptMessage
curve = sslcrypto.ecc.get_curve("secp256k1")
@PluginManager.registerTo("UiWebsocket")
class UiWebsocketPlugin(object):
def eciesDecrypt(self, encrypted, privatekey):
back = CryptMessage.getEcc(privatekey).decrypt(encrypted)
return back.decode("utf8")
# - Actions -
# Returns user's public key unique to site
# Return: Public key
def actionUserPublickey(self, to, index=0):
self.response(to, self.user.getEncryptPublickey(self.site.address, index))
publickey = self.user.getEncryptPublickey(self.site.address, index)
self.response(to, publickey)
# Encrypt a text using the publickey or user's sites unique publickey
# Return: Encrypted text using base64 encoding
@ -53,16 +55,23 @@ class UiWebsocketPlugin(object):
# Encrypt a text using AES
# Return: Iv, AES key, Encrypted text
def actionAesEncrypt(self, to, text, key=None):
def actionAesEncrypt(self, to, text, key=None, iv=None):
from lib import pyelliptic
if key:
key = base64.b64decode(key)
else:
key = sslcrypto.aes.new_key()
key = os.urandom(32)
if iv: # Generate new AES key if not definied
iv = base64.b64decode(iv)
else:
iv = pyelliptic.Cipher.gen_IV('aes-256-cbc')
if text:
encrypted, iv = sslcrypto.aes.encrypt(text.encode("utf8"), key)
encrypted = pyelliptic.Cipher(key, iv, 1, ciphername='aes-256-cbc').ciphering(text.encode("utf8"))
else:
encrypted, iv = b"", b""
encrypted = b""
res = [base64.b64encode(item).decode("utf8") for item in [key, iv, encrypted]]
self.response(to, res)
@ -70,6 +79,8 @@ class UiWebsocketPlugin(object):
# Decrypt a text using AES
# Return: Decrypted text
def actionAesDecrypt(self, to, *args):
from lib import pyelliptic
if len(args) == 3: # Single decrypt
encrypted_texts = [(args[0], args[1])]
keys = [args[2]]
@ -82,8 +93,9 @@ class UiWebsocketPlugin(object):
iv = base64.b64decode(iv)
text = None
for key in keys:
ctx = pyelliptic.Cipher(base64.b64decode(key), iv, 0, ciphername='aes-256-cbc')
try:
decrypted = sslcrypto.aes.decrypt(encrypted_text, iv, base64.b64decode(key))
decrypted = ctx.ciphering(encrypted_text)
if decrypted and decrypted.decode("utf8"): # Valid text decoded
text = decrypted.decode("utf8")
except Exception as err:
@ -110,11 +122,12 @@ class UiWebsocketPlugin(object):
# Gets the publickey of a given privatekey
def actionEccPrivToPub(self, to, privatekey):
self.response(to, curve.private_to_public(curve.wif_to_private(privatekey)))
self.response(to, btctools.privtopub(privatekey))
# Gets the address of a given publickey
def actionEccPubToAddr(self, to, publickey):
self.response(to, curve.public_to_address(bytes.fromhex(publickey)))
address = btctools.pubtoaddr(btctools.decode_pubkey(publickey))
self.response(to, address)
@PluginManager.registerTo("User")
@ -150,7 +163,7 @@ class UserPlugin(object):
if "encrypt_publickey_%s" % index not in site_data:
privatekey = self.getEncryptPrivatekey(address, param_index)
publickey = curve.private_to_public(curve.wif_to_private(privatekey))
publickey = btctools.encode_pubkey(btctools.privtopub(privatekey), "bin_compressed")
site_data["encrypt_publickey_%s" % index] = base64.b64encode(publickey).decode("utf8")
return site_data["encrypt_publickey_%s" % index]
@ -187,8 +200,8 @@ class ActionsPlugin:
aes_key, encrypted = CryptMessage.eciesEncrypt(self.utf8_text.encode("utf8"), self.publickey)
for i in range(num_run):
assert len(aes_key) == 32
decrypted = CryptMessage.eciesDecrypt(base64.b64encode(encrypted), self.privatekey)
assert decrypted == self.utf8_text.encode("utf8"), "%s != %s" % (decrypted, self.utf8_text.encode("utf8"))
ecc = CryptMessage.getEcc(self.privatekey)
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):
@ -210,16 +223,23 @@ class ActionsPlugin:
gevent.joinall(threads)
def testCryptAesEncrypt(self, num_run=1):
from lib import pyelliptic
for i in range(num_run):
key = os.urandom(32)
encrypted = sslcrypto.aes.encrypt(self.utf8_text.encode("utf8"), key)
iv = pyelliptic.Cipher.gen_IV('aes-256-cbc')
encrypted = pyelliptic.Cipher(key, iv, 1, ciphername='aes-256-cbc').ciphering(self.utf8_text.encode("utf8"))
yield "."
def testCryptAesDecrypt(self, num_run=1):
from lib import pyelliptic
key = os.urandom(32)
encrypted_text, iv = sslcrypto.aes.encrypt(self.utf8_text.encode("utf8"), key)
iv = pyelliptic.Cipher.gen_IV('aes-256-cbc')
encrypted_text = pyelliptic.Cipher(key, iv, 1, ciphername='aes-256-cbc').ciphering(self.utf8_text.encode("utf8"))
for i in range(num_run):
decrypted = sslcrypto.aes.decrypt(encrypted_text, iv, key).decode("utf8")
ctx = pyelliptic.Cipher(key, iv, 0, ciphername='aes-256-cbc')
decrypted = ctx.ciphering(encrypted_text).decode("utf8")
assert decrypted == self.utf8_text
yield "."

View file

@ -18,10 +18,13 @@ class TestCrypt:
assert len(aes_key) == 32
# assert len(encrypted) == 134 + int(len(text) / 16) * 16 # Not always true
assert CryptMessage.eciesDecrypt(base64.b64encode(encrypted), self.privatekey) == text_repeated
ecc = CryptMessage.getEcc(self.privatekey)
assert ecc.decrypt(encrypted) == text_repeated
def testDecryptEcies(self, user):
assert CryptMessage.eciesDecrypt(self.ecies_encrypted_text, self.privatekey) == b"hello"
encrypted = base64.b64decode(self.ecies_encrypted_text)
ecc = CryptMessage.getEcc(self.privatekey)
assert ecc.decrypt(encrypted) == b"hello"
def testPublickey(self, ui_websocket):
pub = ui_websocket.testAction("UserPublickey", 0)