1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
|
# -*- cosing: utf-8 -*-
import hmac
import hashlib
from .ciphertextmessage import CiphertextMessage
from ..util.byteutil import ByteUtil
from ..ecc.curve import Curve
from . import whisperprotos_pb2 as whisperprotos
from ..legacymessageexception import LegacyMessageException
from ..invalidmessageexception import InvalidMessageException
from ..invalidkeyexception import InvalidKeyException
class WhisperMessage(CiphertextMessage):
MAC_LENGTH = 8
def __init__(self, messageVersion=None, macKey=None, ECPublicKey_senderRatchetKey=None,
counter=None, previousCounter=None, ciphertext=None, senderIdentityKey=None,
receiverIdentityKey=None, serialized=None):
self.serialized = ""
if serialized:
try:
assert type(serialized) in (str, bytes), "Expected serialized %s, got %s" % (str, type(serialized))
messageParts = ByteUtil.split(serialized, 1, len(serialized) - 1 - WhisperMessage.MAC_LENGTH,
WhisperMessage.MAC_LENGTH)
version = messageParts[0][0]
message = messageParts[1]
mac = messageParts[2]
if ByteUtil.highBitsToInt(version) <= self.__class__.UNSUPPORTED_VERSION:
raise LegacyMessageException("Legacy message %s" % ByteUtil.highBitsToInt(version))
if ByteUtil.highBitsToInt(version) > self.__class__.CURRENT_VERSION:
raise InvalidMessageException("Unknown version: %s" % ByteUtil.highBitsToInt(version))
whisperMessage = whisperprotos.WhisperMessage()
whisperMessage.ParseFromString(message)
if not whisperMessage.ciphertext or whisperMessage.counter is None or not whisperMessage.ratchetKey:
raise InvalidMessageException("Incomplete message")
self.serialized = serialized
self.senderRatchetKey = Curve.decodePoint(bytearray(whisperMessage.ratchetKey), 0)
self.messageVersion = ByteUtil.highBitsToInt(version)
self.counter = whisperMessage.counter
self.previousCounter = whisperMessage.previousCounter
self.ciphertext = whisperMessage.ciphertext
except InvalidKeyException as e:
raise InvalidMessageException(e)
else:
version = ByteUtil.intsToByteHighAndLow(messageVersion, self.__class__.CURRENT_VERSION)
message = whisperprotos.WhisperMessage()
message.ratchetKey = ECPublicKey_senderRatchetKey.serialize()
message.counter = counter
message.previousCounter = previousCounter
message.ciphertext = ciphertext
message = message.SerializeToString()
mac = self.getMac(messageVersion, senderIdentityKey, receiverIdentityKey, macKey,
ByteUtil.combine(version, message))
self.serialized = bytes(ByteUtil.combine(version, message, mac))
self.senderRatchetKey = ECPublicKey_senderRatchetKey
self.counter = counter
self.previousCounter = previousCounter
self.ciphertext = ciphertext
self.messageVersion = messageVersion
def getSenderRatchetKey(self):
return self.senderRatchetKey
def getMessageVersion(self):
return self.messageVersion
def getCounter(self):
return self.counter
def getBody(self):
return self.ciphertext
def verifyMac(self, messageVersion, senderIdentityKey, receiverIdentityKey, macKey):
parts = ByteUtil.split(self.serialized,
len(self.serialized) - self.__class__.MAC_LENGTH,
self.__class__.MAC_LENGTH)
ourMac = self.getMac(messageVersion, senderIdentityKey, receiverIdentityKey, macKey, parts[0])
theirMac = parts[1]
if ourMac != theirMac:
raise InvalidMessageException("Bad Mac!")
def getMac(self, messageVersion, senderIdentityKey, receiverIdentityKey, macKey, serialized):
mac = hmac.new(macKey, digestmod=hashlib.sha256)
if messageVersion >= 3:
mac.update(senderIdentityKey.getPublicKey().serialize())
mac.update(receiverIdentityKey.getPublicKey().serialize())
mac.update(bytes(serialized))
fullMac = mac.digest()
return ByteUtil.trim(fullMac, self.__class__.MAC_LENGTH)
def serialize(self):
return self.serialized
def getType(self):
return CiphertextMessage.WHISPER_TYPE
def isLegacy(self, message):
return message is not None and \
len(message) >= 1 and \
ByteUtil.highBitsToInt(message[0]) <= CiphertextMessage.UNSUPPORTED_VERSION
|