Merge pull request #1370 from coffeedogs/final_code_quality_12

Changes based on style and lint checks. Some empty docstrings remain …
This commit is contained in:
coffeedogs 2018-10-31 17:03:59 +00:00 committed by GitHub
commit 283154e508
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 216 additions and 122 deletions

View File

@ -1,21 +1,29 @@
"""
src/addresses.py
================
"""
# pylint: disable=redefined-outer-name,inconsistent-return-statements
from __future__ import print_function
import hashlib import hashlib
from struct import pack, unpack
from pyelliptic import arithmetic
from binascii import hexlify, unhexlify from binascii import hexlify, unhexlify
from struct import pack, unpack
from debug import logger from debug import logger
from pyelliptic import arithmetic
# There is another copy of this function in Bitmessagemain.py
def convertIntToString(n): def convertIntToString(n):
""".. todo:: There is another copy of this function in Bitmessagemain.py"""
a = __builtins__.hex(n) a = __builtins__.hex(n)
if a[-1:] == 'L': if a[-1:] == 'L':
a = a[:-1] a = a[:-1]
if (len(a) % 2) == 0: if len(a) % 2 == 0:
return unhexlify(a[2:]) return unhexlify(a[2:])
else:
return unhexlify('0' + a[2:]) return unhexlify('0' + a[2:])
ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
@ -25,7 +33,7 @@ def encodeBase58(num, alphabet=ALPHABET):
`num`: The number to encode `num`: The number to encode
`alphabet`: The alphabet to use for encoding `alphabet`: The alphabet to use for encoding
""" """
if (num == 0): if num == 0:
return alphabet[0] return alphabet[0]
arr = [] arr = []
base = len(alphabet) base = len(alphabet)
@ -59,6 +67,7 @@ def decodeBase58(string, alphabet=ALPHABET):
def encodeVarint(integer): def encodeVarint(integer):
"""Convert integer into varint bytes"""
if integer < 0: if integer < 0:
logger.error('varint cannot be < 0') logger.error('varint cannot be < 0')
raise SystemExit raise SystemExit
@ -76,6 +85,7 @@ def encodeVarint(integer):
class varintDecodeError(Exception): class varintDecodeError(Exception):
"""Exception class for decoding varint data"""
pass pass
@ -87,7 +97,7 @@ def decodeVarint(data):
Returns a tuple: (theEncodedValue, theSizeOfTheVarintInBytes) Returns a tuple: (theEncodedValue, theSizeOfTheVarintInBytes)
""" """
if len(data) == 0: if not data:
return (0, 0) return (0, 0)
firstByte, = unpack('>B', data[0:1]) firstByte, = unpack('>B', data[0:1])
if firstByte < 253: if firstByte < 253:
@ -135,6 +145,7 @@ def decodeVarint(data):
def calculateInventoryHash(data): def calculateInventoryHash(data):
"""Calculate inventory hash from object data"""
sha = hashlib.new('sha512') sha = hashlib.new('sha512')
sha2 = hashlib.new('sha512') sha2 = hashlib.new('sha512')
sha.update(data) sha.update(data)
@ -143,6 +154,7 @@ def calculateInventoryHash(data):
def encodeAddress(version, stream, ripe): def encodeAddress(version, stream, ripe):
"""Convert ripe to address"""
if version >= 2 and version < 4: if version >= 2 and version < 4:
if len(ripe) != 20: if len(ripe) != 20:
raise Exception( raise Exception(
@ -175,8 +187,11 @@ def encodeAddress(version, stream, ripe):
def decodeAddress(address): def decodeAddress(address):
# returns (status, address version number, stream number, """
# data (almost certainly a ripe hash)) returns (status, address version number, stream number,
data (almost certainly a ripe hash))
"""
# pylint: disable=too-many-return-statements,too-many-statements,too-many-return-statements,too-many-branches
address = str(address).strip() address = str(address).strip()
@ -194,24 +209,18 @@ def decodeAddress(address):
if len(hexdata) % 2 != 0: if len(hexdata) % 2 != 0:
hexdata = '0' + hexdata hexdata = '0' + hexdata
# print 'hexdata', hexdata
data = unhexlify(hexdata) data = unhexlify(hexdata)
checksum = data[-4:] checksum = data[-4:]
sha = hashlib.new('sha512') sha = hashlib.new('sha512')
sha.update(data[:-4]) sha.update(data[:-4])
currentHash = sha.digest() currentHash = sha.digest()
# print 'sha after first hashing: ', sha.hexdigest()
sha = hashlib.new('sha512') sha = hashlib.new('sha512')
sha.update(currentHash) sha.update(currentHash)
# print 'sha after second hashing: ', sha.hexdigest()
if checksum != sha.digest()[0:4]: if checksum != sha.digest()[0:4]:
status = 'checksumfailed' status = 'checksumfailed'
return status, 0, 0, '' return status, 0, 0, ''
# else:
# print 'checksum PASSED'
try: try:
addressVersionNumber, bytesUsedByVersionNumber = decodeVarint(data[:9]) addressVersionNumber, bytesUsedByVersionNumber = decodeVarint(data[:9])
@ -219,8 +228,6 @@ def decodeAddress(address):
logger.error(str(e)) logger.error(str(e))
status = 'varintmalformed' status = 'varintmalformed'
return status, 0, 0, '' return status, 0, 0, ''
# print 'addressVersionNumber', addressVersionNumber
# print 'bytesUsedByVersionNumber', bytesUsedByVersionNumber
if addressVersionNumber > 4: if addressVersionNumber > 4:
logger.error('cannot decode address version numbers this high') logger.error('cannot decode address version numbers this high')
@ -238,7 +245,7 @@ def decodeAddress(address):
logger.error(str(e)) logger.error(str(e))
status = 'varintmalformed' status = 'varintmalformed'
return status, 0, 0, '' return status, 0, 0, ''
# print streamNumber
status = 'success' status = 'success'
if addressVersionNumber == 1: if addressVersionNumber == 1:
return status, addressVersionNumber, streamNumber, data[-24:-4] return status, addressVersionNumber, streamNumber, data[-24:-4]
@ -258,7 +265,6 @@ def decodeAddress(address):
return 'ripetooshort', 0, 0, '' return 'ripetooshort', 0, 0, ''
elif len(embeddedRipeData) > 20: elif len(embeddedRipeData) > 20:
return 'ripetoolong', 0, 0, '' return 'ripetoolong', 0, 0, ''
else:
return 'otherproblem', 0, 0, '' return 'otherproblem', 0, 0, ''
elif addressVersionNumber == 4: elif addressVersionNumber == 4:
embeddedRipeData = \ embeddedRipeData = \
@ -271,13 +277,13 @@ def decodeAddress(address):
return 'ripetoolong', 0, 0, '' return 'ripetoolong', 0, 0, ''
elif len(embeddedRipeData) < 4: elif len(embeddedRipeData) < 4:
return 'ripetooshort', 0, 0, '' return 'ripetooshort', 0, 0, ''
else:
x00string = '\x00' * (20 - len(embeddedRipeData)) x00string = '\x00' * (20 - len(embeddedRipeData))
return status, addressVersionNumber, streamNumber, \ return status, addressVersionNumber, streamNumber, \
x00string + embeddedRipeData x00string + embeddedRipeData
def addBMIfNotPresent(address): def addBMIfNotPresent(address):
"""Prepend BM- to an address if it doesn't already have it"""
address = str(address).strip() address = str(address).strip()
return address if address[:3] == 'BM-' else 'BM-' + address return address if address[:3] == 'BM-' else 'BM-' + address

View File

@ -1,29 +1,39 @@
"""
src/bitmessageqt/address_dialogs.py
===================================
"""
# pylint: disable=attribute-defined-outside-init
import hashlib
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
from addresses import decodeAddress, encodeVarint, addBMIfNotPresent
from account import (
GatewayAccount, MailchuckAccount, AccountMixin, accountClass,
getSortedAccounts
)
from tr import _translate
from retranslateui import RetranslateMixin
import widgets
import queues import queues
import hashlib import widgets
from account import AccountMixin, GatewayAccount, MailchuckAccount, accountClass, getSortedAccounts
from addresses import addBMIfNotPresent, decodeAddress, encodeVarint
from inventory import Inventory from inventory import Inventory
from retranslateui import RetranslateMixin
from tr import _translate
class AddressCheckMixin(object): class AddressCheckMixin(object):
"""Base address validation class for QT UI"""
# pylint: disable=too-few-public-methods
def __init__(self): def __init__(self):
self.valid = False self.valid = False
QtCore.QObject.connect(self.lineEditAddress, QtCore.SIGNAL( QtCore.QObject.connect( # pylint: disable=no-member
"textChanged(QString)"), self.addressChanged) self.lineEditAddress,
QtCore.SIGNAL("textChanged(QString)"),
self.addressChanged)
def _onSuccess(self, addressVersion, streamNumber, ripe): def _onSuccess(self, addressVersion, streamNumber, ripe):
pass pass
def addressChanged(self, QString): def addressChanged(self, QString):
"""Address validation callback, performs validation and gives feedback"""
status, addressVersion, streamNumber, ripe = decodeAddress( status, addressVersion, streamNumber, ripe = decodeAddress(
str(QString)) str(QString))
self.valid = status == 'success' self.valid = status == 'success'
@ -71,11 +81,14 @@ class AddressCheckMixin(object):
class AddressDataDialog(QtGui.QDialog, AddressCheckMixin): class AddressDataDialog(QtGui.QDialog, AddressCheckMixin):
"""QDialog with Bitmessage address validation"""
def __init__(self, parent): def __init__(self, parent):
super(AddressDataDialog, self).__init__(parent) super(AddressDataDialog, self).__init__(parent)
self.parent = parent self.parent = parent
def accept(self): def accept(self):
"""Callback for QDIalog accepting value"""
if self.valid: if self.valid:
self.data = ( self.data = (
addBMIfNotPresent(str(self.lineEditAddress.text())), addBMIfNotPresent(str(self.lineEditAddress.text())),
@ -90,6 +103,7 @@ class AddressDataDialog(QtGui.QDialog, AddressCheckMixin):
class AddAddressDialog(AddressDataDialog, RetranslateMixin): class AddAddressDialog(AddressDataDialog, RetranslateMixin):
"""QDialog for adding a new address, with validation and translation"""
def __init__(self, parent=None, address=None): def __init__(self, parent=None, address=None):
super(AddAddressDialog, self).__init__(parent) super(AddAddressDialog, self).__init__(parent)
@ -100,6 +114,7 @@ class AddAddressDialog(AddressDataDialog, RetranslateMixin):
class NewAddressDialog(QtGui.QDialog, RetranslateMixin): class NewAddressDialog(QtGui.QDialog, RetranslateMixin):
"""QDialog for generating a new address, with translation"""
def __init__(self, parent=None): def __init__(self, parent=None):
super(NewAddressDialog, self).__init__(parent) super(NewAddressDialog, self).__init__(parent)
@ -115,6 +130,7 @@ class NewAddressDialog(QtGui.QDialog, RetranslateMixin):
self.show() self.show()
def accept(self): def accept(self):
"""accept callback"""
self.hide() self.hide()
# self.buttonBox.enabled = False # self.buttonBox.enabled = False
if self.radioButtonRandomAddress.isChecked(): if self.radioButtonRandomAddress.isChecked():
@ -160,6 +176,7 @@ class NewAddressDialog(QtGui.QDialog, RetranslateMixin):
class NewSubscriptionDialog(AddressDataDialog, RetranslateMixin): class NewSubscriptionDialog(AddressDataDialog, RetranslateMixin):
"""QDialog for subscribing to an address, with validation and translation"""
def __init__(self, parent=None): def __init__(self, parent=None):
super(NewSubscriptionDialog, self).__init__(parent) super(NewSubscriptionDialog, self).__init__(parent)
@ -202,6 +219,7 @@ class NewSubscriptionDialog(AddressDataDialog, RetranslateMixin):
class RegenerateAddressesDialog(QtGui.QDialog, RetranslateMixin): class RegenerateAddressesDialog(QtGui.QDialog, RetranslateMixin):
"""QDialog for regenerating deterministic addresses, with translation"""
def __init__(self, parent=None): def __init__(self, parent=None):
super(RegenerateAddressesDialog, self).__init__(parent) super(RegenerateAddressesDialog, self).__init__(parent)
widgets.load('regenerateaddresses.ui', self) widgets.load('regenerateaddresses.ui', self)
@ -210,6 +228,7 @@ class RegenerateAddressesDialog(QtGui.QDialog, RetranslateMixin):
class SpecialAddressBehaviorDialog(QtGui.QDialog, RetranslateMixin): class SpecialAddressBehaviorDialog(QtGui.QDialog, RetranslateMixin):
"""QDialog for special address behaviour (e.g. mailing list functionality), with translation"""
def __init__(self, parent=None, config=None): def __init__(self, parent=None, config=None):
super(SpecialAddressBehaviorDialog, self).__init__(parent) super(SpecialAddressBehaviorDialog, self).__init__(parent)
@ -250,6 +269,7 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog, RetranslateMixin):
self.show() self.show()
def accept(self): def accept(self):
"""Accept callback"""
self.hide() self.hide()
if self.address_is_chan: if self.address_is_chan:
return return
@ -267,7 +287,7 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog, RetranslateMixin):
self.config.set(str(self.address), 'mailinglistname', str( self.config.set(str(self.address), 'mailinglistname', str(
self.lineEditMailingListName.text().toUtf8())) self.lineEditMailingListName.text().toUtf8()))
self.parent.setCurrentItemColor( self.parent.setCurrentItemColor(
QtGui.QColor(137, 04, 177)) # magenta QtGui.QColor(137, 4, 177)) # magenta
self.parent.rerenderComboBoxSendFrom() self.parent.rerenderComboBoxSendFrom()
self.parent.rerenderComboBoxSendFromBroadcast() self.parent.rerenderComboBoxSendFromBroadcast()
self.config.save() self.config.save()
@ -275,6 +295,7 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog, RetranslateMixin):
class EmailGatewayDialog(QtGui.QDialog, RetranslateMixin): class EmailGatewayDialog(QtGui.QDialog, RetranslateMixin):
"""QDialog for email gateway control, with translation"""
def __init__(self, parent, config=None, account=None): def __init__(self, parent, config=None, account=None):
super(EmailGatewayDialog, self).__init__(parent) super(EmailGatewayDialog, self).__init__(parent)
widgets.load('emailgateway.ui', self) widgets.load('emailgateway.ui', self)
@ -315,6 +336,7 @@ class EmailGatewayDialog(QtGui.QDialog, RetranslateMixin):
QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self))
def accept(self): def accept(self):
"""Accept callback"""
self.hide() self.hide()
# no chans / mailinglists # no chans / mailinglists
if self.acct.type != AccountMixin.NORMAL: if self.acct.type != AccountMixin.NORMAL:

View File

@ -1,52 +1,59 @@
from email.mime.text import MIMEText """
from email.header import Header src/class_smtpDeliver.py
========================
"""
# pylint: disable=unused-variable
import smtplib import smtplib
import sys import sys
import threading import threading
import urlparse import urlparse
from email.header import Header
from email.mime.text import MIMEText
from bmconfigparser import BMConfigParser
from debug import logger
from helper_threading import *
import queues import queues
import state import state
from bmconfigparser import BMConfigParser
from debug import logger
from helper_threading import StoppableThread
SMTPDOMAIN = "bmaddr.lan" SMTPDOMAIN = "bmaddr.lan"
class smtpDeliver(threading.Thread, StoppableThread): class smtpDeliver(threading.Thread, StoppableThread):
"""SMTP client thread for delivery"""
_instance = None _instance = None
def __init__(self, parent=None): def __init__(self):
threading.Thread.__init__(self, name="smtpDeliver") threading.Thread.__init__(self, name="smtpDeliver")
self.initStop() self.initStop()
def stopThread(self): def stopThread(self):
try: try:
queues.UISignallerQueue.put(("stopThread", "data")) queues.UISignallerQueue.put(("stopThread", "data")) # pylint: disable=no-member
except: except:
pass pass
super(smtpDeliver, self).stopThread() super(smtpDeliver, self).stopThread()
@classmethod @classmethod
def get(cls): def get(cls):
"""(probably) Singleton functionality"""
if not cls._instance: if not cls._instance:
cls._instance = smtpDeliver() cls._instance = smtpDeliver()
return cls._instance return cls._instance
def run(self): def run(self):
# pylint: disable=too-many-branches,too-many-statements,too-many-locals
while state.shutdown == 0: while state.shutdown == 0:
command, data = queues.UISignalQueue.get() command, data = queues.UISignalQueue.get()
if command == 'writeNewAddressToTable': if command == 'writeNewAddressToTable':
label, address, streamNumber = data label, address, streamNumber = data
pass
elif command == 'updateStatusBar': elif command == 'updateStatusBar':
pass pass
elif command == 'updateSentItemStatusByToAddress': elif command == 'updateSentItemStatusByToAddress':
toAddress, message = data toAddress, message = data
pass
elif command == 'updateSentItemStatusByAckdata': elif command == 'updateSentItemStatusByAckdata':
ackData, message = data ackData, message = data
pass
elif command == 'displayNewInboxMessage': elif command == 'displayNewInboxMessage':
inventoryHash, toAddress, fromAddress, subject, body = data inventoryHash, toAddress, fromAddress, subject, body = data
dest = BMConfigParser().safeGet("bitmessagesettings", "smtpdeliver", '') dest = BMConfigParser().safeGet("bitmessagesettings", "smtpdeliver", '')
@ -59,8 +66,12 @@ class smtpDeliver(threading.Thread, StoppableThread):
msg = MIMEText(body, 'plain', 'utf-8') msg = MIMEText(body, 'plain', 'utf-8')
msg['Subject'] = Header(subject, 'utf-8') msg['Subject'] = Header(subject, 'utf-8')
msg['From'] = fromAddress + '@' + SMTPDOMAIN msg['From'] = fromAddress + '@' + SMTPDOMAIN
toLabel = map (lambda y: BMConfigParser().safeGet(y, "label"), filter(lambda x: x == toAddress, BMConfigParser().addresses())) toLabel = map( # pylint: disable=deprecated-lambda
if len(toLabel) > 0: lambda y: BMConfigParser().safeGet(y, "label"),
filter( # pylint: disable=deprecated-lambda
lambda x: x == toAddress, BMConfigParser().addresses())
)
if toLabel:
msg['To'] = "\"%s\" <%s>" % (Header(toLabel[0], 'utf-8'), toAddress + '@' + SMTPDOMAIN) msg['To'] = "\"%s\" <%s>" % (Header(toLabel[0], 'utf-8'), toAddress + '@' + SMTPDOMAIN)
else: else:
msg['To'] = toAddress + '@' + SMTPDOMAIN msg['To'] = toAddress + '@' + SMTPDOMAIN
@ -74,7 +85,6 @@ class smtpDeliver(threading.Thread, StoppableThread):
logger.error("smtp delivery error", exc_info=True) logger.error("smtp delivery error", exc_info=True)
elif command == 'displayNewSentMessage': elif command == 'displayNewSentMessage':
toAddress, fromLabel, fromAddress, subject, message, ackdata = data toAddress, fromLabel, fromAddress, subject, message, ackdata = data
pass
elif command == 'updateNetworkStatusTab': elif command == 'updateNetworkStatusTab':
pass pass
elif command == 'updateNumberOfMessagesProcessed': elif command == 'updateNumberOfMessagesProcessed':
@ -103,7 +113,6 @@ class smtpDeliver(threading.Thread, StoppableThread):
pass pass
elif command == 'alert': elif command == 'alert':
title, text, exitAfterUserClicksOk = data title, text, exitAfterUserClicksOk = data
pass
elif command == 'stopThread': elif command == 'stopThread':
break break
else: else:

View File

@ -31,6 +31,9 @@
# THE SOFTWARE. # THE SOFTWARE.
# #
""" """
src/fallback/umsgpack/umsgpack.py
=================================
u-msgpack-python v2.4.1 - v at sergeev.io u-msgpack-python v2.4.1 - v at sergeev.io
https://github.com/vsergeev/u-msgpack-python https://github.com/vsergeev/u-msgpack-python
@ -43,10 +46,13 @@ types.
License: MIT License: MIT
""" """
import struct # pylint: disable=too-many-lines,too-many-branches,too-many-statements,global-statement,too-many-return-statements
# pylint: disable=unused-argument
import collections import collections
import sys
import io import io
import struct
import sys
__version__ = "2.4.1" __version__ = "2.4.1"
"Module version string" "Module version string"
@ -60,7 +66,7 @@ version = (2, 4, 1)
############################################################################## ##############################################################################
# Extension type for application-defined types and data # Extension type for application-defined types and data
class Ext: class Ext: # pylint: disable=old-style-class
""" """
The Ext class facilitates creating a serializable extension object to store The Ext class facilitates creating a serializable extension object to store
an application-defined type and data byte array. an application-defined type and data byte array.
@ -87,6 +93,8 @@ class Ext:
Ext Object (Type: 0x05, Data: 01 02 03) Ext Object (Type: 0x05, Data: 01 02 03)
>>> >>>
""" """
# pylint:disable=redefined-builtin
# Application ext type should be 0 <= type <= 127 # Application ext type should be 0 <= type <= 127
if not isinstance(type, int) or not (type >= 0 and type <= 127): if not isinstance(type, int) or not (type >= 0 and type <= 127):
raise TypeError("ext type out of range") raise TypeError("ext type out of range")
@ -412,7 +420,7 @@ def _pack2(obj, fp, **options):
_pack_ext(ext_handlers[obj.__class__](obj), fp, options) _pack_ext(ext_handlers[obj.__class__](obj), fp, options)
elif isinstance(obj, bool): elif isinstance(obj, bool):
_pack_boolean(obj, fp, options) _pack_boolean(obj, fp, options)
elif isinstance(obj, int) or isinstance(obj, long): elif isinstance(obj, (int, long)):
_pack_integer(obj, fp, options) _pack_integer(obj, fp, options)
elif isinstance(obj, float): elif isinstance(obj, float):
_pack_float(obj, fp, options) _pack_float(obj, fp, options)
@ -424,7 +432,7 @@ def _pack2(obj, fp, **options):
_pack_string(obj, fp, options) _pack_string(obj, fp, options)
elif isinstance(obj, str): elif isinstance(obj, str):
_pack_binary(obj, fp, options) _pack_binary(obj, fp, options)
elif isinstance(obj, list) or isinstance(obj, tuple): elif isinstance(obj, (list, tuple)):
_pack_array(obj, fp, options) _pack_array(obj, fp, options)
elif isinstance(obj, dict): elif isinstance(obj, dict):
_pack_map(obj, fp, options) _pack_map(obj, fp, options)
@ -494,7 +502,7 @@ def _pack3(obj, fp, **options):
_pack_string(obj, fp, options) _pack_string(obj, fp, options)
elif isinstance(obj, bytes): elif isinstance(obj, bytes):
_pack_binary(obj, fp, options) _pack_binary(obj, fp, options)
elif isinstance(obj, list) or isinstance(obj, tuple): elif isinstance(obj, (list, tuple)):
_pack_array(obj, fp, options) _pack_array(obj, fp, options)
elif isinstance(obj, dict): elif isinstance(obj, dict):
_pack_map(obj, fp, options) _pack_map(obj, fp, options)
@ -723,7 +731,7 @@ def _unpack_array(code, fp, options):
else: else:
raise Exception("logic error, not array: 0x%02x" % ord(code)) raise Exception("logic error, not array: 0x%02x" % ord(code))
return [_unpack(fp, options) for i in xrange(length)] return [_unpack(fp, options) for _ in xrange(length)]
def _deep_list_to_tuple(obj): def _deep_list_to_tuple(obj):
@ -957,6 +965,8 @@ def _unpackb3(s, **options):
def __init(): def __init():
# pylint: disable=global-variable-undefined
global pack global pack
global packb global packb
global unpack global unpack
@ -989,7 +999,7 @@ def __init():
unpackb = _unpackb3 unpackb = _unpackb3
load = _unpack3 load = _unpack3
loads = _unpackb3 loads = _unpackb3
xrange = range xrange = range # pylint: disable=redefined-builtin
else: else:
pack = _pack2 pack = _pack2
packb = _packb2 packb = _packb2

View File

@ -1,17 +1,23 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""
src/pyelliptic/ecc.py
=====================
"""
# pylint: disable=protected-access
# Copyright (C) 2011 Yann GUIBET <yannguibet@gmail.com> # Copyright (C) 2011 Yann GUIBET <yannguibet@gmail.com>
# See LICENSE for details. # See LICENSE for details.
from hashlib import sha512 from hashlib import sha512
from pyelliptic.openssl import OpenSSL
from pyelliptic.cipher import Cipher
from pyelliptic.hash import hmac_sha256, equals
from struct import pack, unpack from struct import pack, unpack
from pyelliptic.cipher import Cipher
from pyelliptic.hash import equals, hmac_sha256
from pyelliptic.openssl import OpenSSL
class ECC:
class ECC(object):
""" """
Asymmetric encryption with Elliptic Curve Cryptography (ECC) Asymmetric encryption with Elliptic Curve Cryptography (ECC)
ECDH, ECDSA and ECIES ECDH, ECDSA and ECIES
@ -40,13 +46,21 @@ class ECC:
>>> print bob.get_ecdh_key(alice.get_pubkey()).encode('hex') >>> print bob.get_ecdh_key(alice.get_pubkey()).encode('hex')
""" """
def __init__(self, pubkey=None, privkey=None, pubkey_x=None,
pubkey_y=None, raw_privkey=None, curve='sect283r1'): def __init__(
self,
pubkey=None,
privkey=None,
pubkey_x=None,
pubkey_y=None,
raw_privkey=None,
curve='sect283r1',
): # pylint: disable=too-many-arguments
""" """
For a normal and High level use, specifie pubkey, For a normal and High level use, specifie pubkey,
privkey (if you need) and the curve privkey (if you need) and the curve
""" """
if type(curve) == str: if isinstance(curve, str):
self.curve = OpenSSL.get_curve(curve) self.curve = OpenSSL.get_curve(curve)
else: else:
self.curve = curve self.curve = curve
@ -54,9 +68,9 @@ class ECC:
if pubkey_x is not None and pubkey_y is not None: if pubkey_x is not None and pubkey_y is not None:
self._set_keys(pubkey_x, pubkey_y, raw_privkey) self._set_keys(pubkey_x, pubkey_y, raw_privkey)
elif pubkey is not None: elif pubkey is not None:
curve, pubkey_x, pubkey_y, i = ECC._decode_pubkey(pubkey) curve, pubkey_x, pubkey_y, _ = ECC._decode_pubkey(pubkey)
if privkey is not None: if privkey is not None:
curve2, raw_privkey, i = ECC._decode_privkey(privkey) curve2, raw_privkey, _ = ECC._decode_privkey(privkey)
if curve != curve2: if curve != curve2:
raise Exception("Bad ECC keys ...") raise Exception("Bad ECC keys ...")
self.curve = curve self.curve = curve
@ -83,9 +97,11 @@ class ECC:
return OpenSSL.curves.keys() return OpenSSL.curves.keys()
def get_curve(self): def get_curve(self):
"""Encryption object from curve name"""
return OpenSSL.get_curve_by_id(self.curve) return OpenSSL.get_curve_by_id(self.curve)
def get_curve_id(self): def get_curve_id(self):
"""Currently used curve"""
return self.curve return self.curve
def get_pubkey(self): def get_pubkey(self):
@ -93,11 +109,12 @@ class ECC:
High level function which returns : High level function which returns :
curve(2) + len_of_pubkeyX(2) + pubkeyX + len_of_pubkeyY + pubkeyY curve(2) + len_of_pubkeyX(2) + pubkeyX + len_of_pubkeyY + pubkeyY
""" """
return b''.join((pack('!H', self.curve), return b''.join((
pack('!H', self.curve),
pack('!H', len(self.pubkey_x)), pack('!H', len(self.pubkey_x)),
self.pubkey_x, self.pubkey_x,
pack('!H', len(self.pubkey_y)), pack('!H', len(self.pubkey_y)),
self.pubkey_y self.pubkey_y,
)) ))
def get_privkey(self): def get_privkey(self):
@ -105,9 +122,10 @@ class ECC:
High level function which returns High level function which returns
curve(2) + len_of_privkey(2) + privkey curve(2) + len_of_privkey(2) + privkey
""" """
return b''.join((pack('!H', self.curve), return b''.join((
pack('!H', self.curve),
pack('!H', len(self.privkey)), pack('!H', len(self.privkey)),
self.privkey self.privkey,
)) ))
@staticmethod @staticmethod
@ -153,12 +171,9 @@ class ECC:
group = OpenSSL.EC_KEY_get0_group(key) group = OpenSSL.EC_KEY_get0_group(key)
pub_key = OpenSSL.EC_KEY_get0_public_key(key) pub_key = OpenSSL.EC_KEY_get0_public_key(key)
if (OpenSSL.EC_POINT_get_affine_coordinates_GFp(group, pub_key, if OpenSSL.EC_POINT_get_affine_coordinates_GFp(
pub_key_x, group, pub_key, pub_key_x, pub_key_y, 0) == 0:
pub_key_y, 0 raise Exception("[OpenSSL] EC_POINT_get_affine_coordinates_GFp FAIL ...")
)) == 0:
raise Exception(
"[OpenSSL] EC_POINT_get_affine_coordinates_GFp FAIL ...")
privkey = OpenSSL.malloc(0, OpenSSL.BN_num_bytes(priv_key)) privkey = OpenSSL.malloc(0, OpenSSL.BN_num_bytes(priv_key))
pubkeyx = OpenSSL.malloc(0, OpenSSL.BN_num_bytes(pub_key_x)) pubkeyx = OpenSSL.malloc(0, OpenSSL.BN_num_bytes(pub_key_x))
@ -183,12 +198,13 @@ class ECC:
High level function. Compute public key with the local private key High level function. Compute public key with the local private key
and returns a 512bits shared key and returns a 512bits shared key
""" """
curve, pubkey_x, pubkey_y, i = ECC._decode_pubkey(pubkey) curve, pubkey_x, pubkey_y, _ = ECC._decode_pubkey(pubkey)
if curve != self.curve: if curve != self.curve:
raise Exception("ECC keys must be from the same curve !") raise Exception("ECC keys must be from the same curve !")
return sha512(self.raw_get_ecdh_key(pubkey_x, pubkey_y)).digest() return sha512(self.raw_get_ecdh_key(pubkey_x, pubkey_y)).digest()
def raw_get_ecdh_key(self, pubkey_x, pubkey_y): def raw_get_ecdh_key(self, pubkey_x, pubkey_y):
"""ECDH key as binary data"""
try: try:
ecdh_keybuffer = OpenSSL.malloc(0, 32) ecdh_keybuffer = OpenSSL.malloc(0, 32)
@ -248,20 +264,22 @@ class ECC:
Check the public key and the private key. Check the public key and the private key.
The private key is optional (replace by None) The private key is optional (replace by None)
""" """
curve, pubkey_x, pubkey_y, i = ECC._decode_pubkey(pubkey) curve, pubkey_x, pubkey_y, _ = ECC._decode_pubkey(pubkey)
if privkey is None: if privkey is None:
raw_privkey = None raw_privkey = None
curve2 = curve curve2 = curve
else: else:
curve2, raw_privkey, i = ECC._decode_privkey(privkey) curve2, raw_privkey, _ = ECC._decode_privkey(privkey)
if curve != curve2: if curve != curve2:
raise Exception("Bad public and private key") raise Exception("Bad public and private key")
return self.raw_check_key(raw_privkey, pubkey_x, pubkey_y, curve) return self.raw_check_key(raw_privkey, pubkey_x, pubkey_y, curve)
def raw_check_key(self, privkey, pubkey_x, pubkey_y, curve=None): def raw_check_key(self, privkey, pubkey_x, pubkey_y, curve=None):
"""Check key validity, key is supplied as binary data"""
# pylint: disable=too-many-branches
if curve is None: if curve is None:
curve = self.curve curve = self.curve
elif type(curve) == str: elif isinstance(curve, str):
curve = OpenSSL.get_curve(curve) curve = OpenSSL.get_curve(curve)
else: else:
curve = curve curve = curve
@ -306,6 +324,7 @@ class ECC:
""" """
Sign the input with ECDSA method and returns the signature Sign the input with ECDSA method and returns the signature
""" """
# pylint: disable=too-many-branches,too-many-locals
try: try:
size = len(inputb) size = len(inputb)
buff = OpenSSL.malloc(inputb, size) buff = OpenSSL.malloc(inputb, size)
@ -369,13 +388,13 @@ class ECC:
OpenSSL.EVP_MD_CTX_free(md_ctx) OpenSSL.EVP_MD_CTX_free(md_ctx)
else: else:
OpenSSL.EVP_MD_CTX_destroy(md_ctx) OpenSSL.EVP_MD_CTX_destroy(md_ctx)
pass
def verify(self, sig, inputb, digest_alg=OpenSSL.digest_ecdsa_sha1): def verify(self, sig, inputb, digest_alg=OpenSSL.digest_ecdsa_sha1):
""" """
Verify the signature with the input and the local public key. Verify the signature with the input and the local public key.
Returns a boolean Returns a boolean
""" """
# pylint: disable=too-many-branches
try: try:
bsig = OpenSSL.malloc(sig, len(sig)) bsig = OpenSSL.malloc(sig, len(sig))
binputb = OpenSSL.malloc(inputb, len(inputb)) binputb = OpenSSL.malloc(inputb, len(inputb))
@ -419,12 +438,9 @@ class ECC:
if ret == -1: if ret == -1:
return False # Fail to Check return False # Fail to Check
else:
if ret == 0: if ret == 0:
return False # Bad signature ! return False # Bad signature !
else:
return True # Good return True # Good
return False
finally: finally:
OpenSSL.EC_KEY_free(key) OpenSSL.EC_KEY_free(key)
@ -441,13 +457,21 @@ class ECC:
""" """
Encrypt data with ECIES method using the public key of the recipient. Encrypt data with ECIES method using the public key of the recipient.
""" """
curve, pubkey_x, pubkey_y, i = ECC._decode_pubkey(pubkey) curve, pubkey_x, pubkey_y, _ = ECC._decode_pubkey(pubkey)
return ECC.raw_encrypt(data, pubkey_x, pubkey_y, curve=curve, return ECC.raw_encrypt(data, pubkey_x, pubkey_y, curve=curve,
ephemcurve=ephemcurve, ciphername=ciphername) ephemcurve=ephemcurve, ciphername=ciphername)
@staticmethod @staticmethod
def raw_encrypt(data, pubkey_x, pubkey_y, curve='sect283r1', def raw_encrypt(
ephemcurve=None, ciphername='aes-256-cbc'): data,
pubkey_x,
pubkey_y,
curve='sect283r1',
ephemcurve=None,
ciphername='aes-256-cbc',
): # pylint: disable=too-many-arguments
"""ECHD encryption, keys supplied in binary data format"""
if ephemcurve is None: if ephemcurve is None:
ephemcurve = curve ephemcurve = curve
ephem = ECC(curve=ephemcurve) ephem = ECC(curve=ephemcurve)
@ -464,10 +488,11 @@ class ECC:
""" """
Decrypt data with ECIES method using the local private key Decrypt data with ECIES method using the local private key
""" """
# pylint: disable=too-many-locals
blocksize = OpenSSL.get_cipher(ciphername).get_blocksize() blocksize = OpenSSL.get_cipher(ciphername).get_blocksize()
iv = data[:blocksize] iv = data[:blocksize]
i = blocksize i = blocksize
curve, pubkey_x, pubkey_y, i2 = ECC._decode_pubkey(data[i:]) _, pubkey_x, pubkey_y, i2 = ECC._decode_pubkey(data[i:])
i += i2 i += i2
ciphertext = data[i:len(data) - 32] ciphertext = data[i:len(data) - 32]
i += len(ciphertext) i += len(ciphertext)

View File

@ -1,12 +1,29 @@
"""
src/randomtrackingdict.py
=========================
"""
import random import random
from threading import RLock from threading import RLock
from time import time from time import time
import helper_random import helper_random
class RandomTrackingDict(object): class RandomTrackingDict(object):
"""
Dict with randomised order and tracking.
Keeps a track of how many items have been requested from the dict, and timeouts. Resets after all objects have been
retrieved and timed out. The main purpose of this isn't as much putting related code together as performance
optimisation and anonymisation of downloading of objects from other peers. If done using a standard dict or array,
it takes too much CPU (and looks convoluted). Randomisation helps with anonymity.
"""
# pylint: disable=too-many-instance-attributes
maxPending = 10 maxPending = 10
pendingTimeout = 60 pendingTimeout = 60
def __init__(self): # O(1)
def __init__(self):
self.dictionary = {} self.dictionary = {}
self.indexDict = [] self.indexDict = []
self.len = 0 self.len = 0
@ -46,7 +63,7 @@ class RandomTrackingDict(object):
self.len += 1 self.len += 1
def __delitem__(self, key): def __delitem__(self, key):
if not key in self.dictionary: if key not in self.dictionary:
raise KeyError raise KeyError
with self.lock: with self.lock:
index = self.dictionary[key][0] index = self.dictionary[key][0]
@ -67,9 +84,14 @@ class RandomTrackingDict(object):
self.len -= 1 self.len -= 1
def setMaxPending(self, maxPending): def setMaxPending(self, maxPending):
"""
Sets maximum number of objects that can be retrieved from the class simultaneously as long as there is no
timeout
"""
self.maxPending = maxPending self.maxPending = maxPending
def setPendingTimeout(self, pendingTimeout): def setPendingTimeout(self, pendingTimeout):
"""Sets how long to wait for a timeout if max pending is reached (or all objects have been retrieved)"""
self.pendingTimeout = pendingTimeout self.pendingTimeout = pendingTimeout
def setLastObject(self): def setLastObject(self):
@ -77,10 +99,13 @@ class RandomTrackingDict(object):
self.lastObject = time() self.lastObject = time()
def randomKeys(self, count=1): def randomKeys(self, count=1):
"""Retrieve count random keys from the dict that haven't already been retrieved"""
if self.len == 0 or ((self.pendingLen >= self.maxPending or if self.len == 0 or ((self.pendingLen >= self.maxPending or
self.pendingLen == self.len) and self.lastPoll + self.pendingLen == self.len) and self.lastPoll +
self.pendingTimeout > time()): self.pendingTimeout > time()):
raise KeyError raise KeyError
# pylint: disable=redefined-outer-name
with self.lock: with self.lock:
# reset if we've requested all # reset if we've requested all
# or if last object received too long time ago # or if last object received too long time ago
@ -99,8 +124,12 @@ class RandomTrackingDict(object):
self.lastPoll = time() self.lastPoll = time()
return retval return retval
if __name__ == '__main__': if __name__ == '__main__':
# pylint: disable=redefined-outer-name
def randString(): def randString():
"""helper function for tests, generates a random string"""
retval = b'' retval = b''
for _ in range(32): for _ in range(32):
retval += chr(random.randint(0, 255)) retval += chr(random.randint(0, 255))
@ -110,31 +139,24 @@ if __name__ == '__main__':
k = RandomTrackingDict() k = RandomTrackingDict()
d = {} d = {}
# print "populating normal dict"
# a.append(time())
# for i in range(50000):
# d[randString()] = True
# a.append(time())
print "populating random tracking dict" print "populating random tracking dict"
a.append(time()) a.append(time())
for i in range(50000): for i in range(50000):
k[randString()] = True k[randString()] = True
a.append(time()) a.append(time())
print "done" print "done"
while len(k) > 0:
while k:
retval = k.randomKeys(1000) retval = k.randomKeys(1000)
if not retval: if not retval:
print "error getting random keys" print "error getting random keys"
#a.append(time())
try: try:
k.randomKeys(100) k.randomKeys(100)
print "bad" print "bad"
except KeyError: except KeyError:
pass pass
#a.append(time())
for i in retval: for i in retval:
del k[i] del k[i]
#a.append(time())
a.append(time()) a.append(time())
for x in range(len(a) - 1): for x in range(len(a) - 1):