def __init__(self, blockNumber, previousHash, data, nonce): self.blockNum = blockNumber self.prevHash = previousHash self.nonce = nonce self.data = data toMine = dict() toMine["blockNumber"] = self.blockNum toMine["previousHash"] = self.prevHash toMine["nonce"] = self.nonce toMine["data"] = self.data self.hash = b64encode(calculateHashOverFields(toMine)).decode("ascii") self.next = None
def validReceiptSignature(signature, certificate, data): signature = b64decode(bytes(signature, "ascii")) certificateBytes = b64decode(bytes(certificate, "ascii")) certificate = load_pem_x509_certificate(certificateBytes, default_backend()) valid, _, _, _ = validCertificate(certificateBytes) if not valid: return False serverPublicKey = PublicKeyServer(certificate.public_key()) if not serverPublicKey.verify(calculateHashOverFields({"": data}), signature): return False return True
def newBid(sock, clientCert, symmetricEncryption, sessionId): mutex.acquire() openAuctionList = [] for auction in OPEN_AUCTIONS.values(): openAuctionList.append(auction.getAuctionInfo()) #Sends lists with all open auctions sendEncryptedMessage(sock, {"openAuctionList": openAuctionList}, symmetricEncryption, sessionId, 4) mandatoryFields = [] mandatoryFields.append(Field("auctionId", int)) mandatoryFields.append(Field("timestamp", int)) mandatoryFields.append(Field("amount", float)) mandatoryFields.append(BytesField("nonce")) mandatoryFields.append(BytesField("signature")) msg = readMessage(sock, mandatoryFields, symmetricEncryption, sessionId, 5) auctionId = msg["auctionId"] if auctionId not in OPEN_AUCTIONS.keys(): sendEncryptedMessage(sock, {"error": "No auction with that id"}, symmetricEncryption, sessionId, 6) return clientId, clientName = getUserInfo(clientCert) clientCertBytes = b64encode(clientCert.public_bytes( Encoding.PEM)).decode("ascii") bid = { "timestamp": msg["timestamp"], "clientId": clientId, "clientName": clientName, "clientCertificate": clientCertBytes, "amount": msg["amount"], "nonce": msg["nonce"], "auctionId": auctionId, "auctionType": OPEN_AUCTIONS[auctionId].getAuctionInfo()["type"] } if not PublicKeyClient(clientCert.public_key()).verify( calculateHashOverFields(bid), b64decode(bytes(msg["signature"], "ascii"))): mutex.release() sendEncryptedMessage(sock, {"error": "Invalid signature over bid"}, symmetricEncryption, sessionId, 6) return sock2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock2.connect(constants.MANAGER_ADDR) symmetricEncryption2, sessionId2 = handshake.clientHandShake( sock2, privateKey, certificate, POSSIB_CIPHERS, POSSIB_MODES, POSSIB_PADDING) sendEncryptedMessage(sock2, {"action": ActionTypes.VALIDATE_BID}, symmetricEncryption2, sessionId2, 3) toValidate = {"clientValidation": msg["signature"], "bid": bid} auction = OPEN_AUCTIONS[auctionId] if auction.getAuctionInfo()["type"] == "BlindShown": if clientId not in CLIENTS_BIDS_COUNT.keys(): CLIENTS_BIDS_COUNT[clientId] = dict() if auctionId not in CLIENTS_BIDS_COUNT[clientId].keys(): CLIENTS_BIDS_COUNT[clientId][auctionId] = 0 toValidate["countBidsDone"] = CLIENTS_BIDS_COUNT[clientId][auctionId] sendEncryptedMessage(sock2, toValidate, symmetricEncryption2, sessionId2, 4) exceptionHappen = False try: msg = readMessage(sock2, [], symmetricEncryption2, sessionId2, 5) except ErrorMessage as e: exceptionHappen = True sendEncryptedMessage(sock, {"error": e.args[0]}, symmetricEncryption, sessionId, 6) if exceptionHappen: mutex.release() return sock2.close() blockNum, prevHash = auction.lastBlockInfo() blockNum += 1 cryptopuzzleChallange = { "difficulty": auction.getAuctionInfo()["difficulty"], "toMine": { "blockNumber": blockNum, "previousHash": prevHash, "data": msg } } sendEncryptedMessage(sock, cryptopuzzleChallange, symmetricEncryption, sessionId, 6) mandatoryFields = [] mandatoryFields.append(BytesField("hash")) mandatoryFields.append(BytesField("nonce")) msg = readMessage(sock, mandatoryFields, symmetricEncryption, sessionId, 7, 60) blockInfo = cryptopuzzleChallange["toMine"] blockInfo["nonce"] = msg["nonce"] valid, cause = verifyCryptopuzzle(msg["hash"], blockInfo, auction.getAuctionInfo()["difficulty"]) if not valid: mutex.release() sendEncryptedMessage(sock, {"error": cause}, symmetricEncryption, sessionId, 8) return if auction.getAuctionInfo()["type"] == "BlindShown": if clientId not in CLIENTS.keys(): CLIENTS[clientId] = set() CLIENTS[clientId].add(auctionId) auction.newBid(blockInfo["data"], blockInfo["nonce"], msg["hash"]) receipt = auction.getAllData() signature = privateKey.sign(calculateHashOverFields({"": receipt})) signature = b64encode(signature).decode("ascii") cert = b64encode(certificate.public_bytes(Encoding.PEM)).decode("ascii") sendEncryptedMessage(sock, { "receipt": receipt, "signature": signature, "certificate": cert }, symmetricEncryption, sessionId, 8) mutex.release()
def validateAuctionContent(allData, compareBid=None, compareBlock=None): previousHash = b64encode(bytes(32)).decode("ascii") key = None validateOpen = not all(k in allData[-1]["block"]["data"].keys() for k in ["key", "winnerBlockNumber"]) if not validateOpen: key = b64decode(bytes(allData[-1]["block"]["data"]["key"], "ascii")) winnerAmount = winnerBlockNumber = difficulty = -1 for i, blockData in enumerate(allData): blockHash = b64decode(bytes(blockData["hash"], "ascii")) block = blockData["block"] #print(block) if compareBlock != None and compareBlock["blockNumber"] == block[ "blockNumber"] and compareBlock != block: print("Data on the blockchain is different from the receipt") return if block["previousHash"] != previousHash: print("Hash of previous block don't match") return if block["blockNumber"] != i: print("Number of block does not match sequence") return if blockHash != calculateHashOverFields(block): print("Hash of blocks don't match") return previousHash = blockData["hash"] if i == 0: difficulty = block["data"]["difficulty"] continue elif i == len(allData) - 1 and not validateOpen: if winnerBlockNumber != block["data"]["winnerBlockNumber"]: print("Winner block number don't match") return continue if not (int(blockHash.hex(), 16) < 2**(256 - difficulty)): print("Hash of a block not under the target") return data = block["data"] managerValidation = data.pop("managerValidation") managerCertificateBytes = b64decode( bytes(managerValidation["certificate"], "ascii")) managerCertificate = load_pem_x509_certificate(managerCertificateBytes, default_backend()) managerPublicKey = PublicKeyServer(managerCertificate.public_key()) signature = b64decode(bytes(managerValidation["signature"], "ascii")) if not managerPublicKey.verify(calculateHashOverFields(data), signature): print("Signature of manager validation not valid") return if not validateOpen: originalBid = deepcopy(data["bid"]) bid = data["bid"] if compareBlock != None and compareBlock["blockNumber"] == block[ "blockNumber"] and compareBid != bid: print("Bid sent is different!") return decryptBid(bid, key) if bid["auctionId"] != allData[0]["block"]["data"]["auctionId"]: print("Auction Id on a bid doesn't match") return if bid["auctionType"] != allData[0]["block"]["data"]["type"]: print("Auction type on a bid doesn't match") return valid, _, _, _ = validCertificate( managerCertificateBytes, datetime.fromtimestamp(int(bid["timestamp"]))) if not valid: print("Manager certificate not valid") return clientCertificateBytes = b64decode( bytes(bid["clientCertificate"], "ascii")) clientCertificate = load_pem_x509_certificate( clientCertificateBytes, default_backend()) valid, _, _, _ = validCertificate( clientCertificateBytes, datetime.fromtimestamp(int(bid["timestamp"]))) if not valid: print("Client certificate not valid") return clientPublicKey = PublicKeyClient(clientCertificate.public_key()) signature = data["clientValidation"] if bid["auctionType"] in ["English", "BlindHidden"]: signature, iv = signature.split("\n") iv = b64decode(bytes(iv, "ascii")) signature = b64decode(bytes(signature, "ascii")) decryptor = Cipher(AES(key), CBC(iv), default_backend()).decryptor() uncryptedField = decryptor.update( signature) + decryptor.finalize() unpadder = PKCS7(AES.block_size).unpadder() signature = unpadder.update( uncryptedField) + unpadder.finalize() signature = b64decode(signature) else: signature = b64decode(bytes(signature, "ascii")) if not clientPublicKey.verify(calculateHashOverFields(bid), signature): print("Signature of client over bids not valid") return if float(bid["amount"]) > winnerAmount: winnerAmount = float(bid["amount"]) winnerBlockNumber = block["blockNumber"] print("All ok")
def newBid(): while True: amount = input("Amount to bid: ") if not match("^[0-9]+(\.[0-9][0-9]?)?$", amount): print("ERROR: Insert a valid amount") continue amount = float(amount) break sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(constants.REPOSITORY_ADDR) cert = getCertificate() symmetricEncryption, sessionId = clientHandShake(sock, privateKey, cert, ciphers, modes, paddings) sendEncryptedMessage(sock, {'action':ActionTypes.NEW_BID}, symmetricEncryption, sessionId, 3) msgRecv = readMessage(sock, [], symmetricEncryption, sessionId, 4) #display data openAuctionList = msgRecv["openAuctionList"] if len(openAuctionList) == 0: print("No open auctions") sock.close() return for i, auction in enumerate(openAuctionList): print("## {} ##".format(i+1)) print("Auction Id: ", auction["auctionId"]) print("Name: ", auction["name"]) print("Description: ", auction["description"]) print("Type: ", auction["type"]) print("Duration: ", auction["duration"]) print("Creation Time: ", auction["creationTime"]) print("Difficulty: ", auction["difficulty"]) print("Base amount: ", auction["baseAmount"]) print("Validation Code\n" + auction["validationCode"]) print("Modification Code\n" + auction["modificationCode"]) print("Creator Id: ", auction["creatorId"]) print("Creator Name: ", auction["creatorName"]) print("--------------------------------------\n") while True: opt = input("$ ") if not match("^[0-9]+$", opt): print("ERROR: Insert a valid number!") continue opt = int(opt) if opt < 1 or opt > len(openAuctionList): print("Error: Insert a number between 1 and " + str(len(openAuctionList))) continue opt -= 1 break clientId, clientName = getUserInfo(cert) auctionId = openAuctionList[opt]["auctionId"] auctionType = openAuctionList[opt]["type"] timestamp = int(time.time()) nonce = b64encode(urandom(32)).decode("ascii") bid = { "timestamp":timestamp, "clientId":clientId, "clientName":clientName, "clientCertificate":b64encode(cert.public_bytes(Encoding.PEM)).decode("ascii"), "amount":amount, "nonce":nonce, "auctionId":auctionId, "auctionType":auctionType } signature = b64encode(privateKey.sign(calculateHashOverFields(bid))).decode("ascii") sendEncryptedMessage(sock, {'auctionId': auctionId, "timestamp":timestamp, "nonce":nonce, "amount":amount, "signature":signature}, symmetricEncryption, sessionId, 5) cryptopuzzleChallange = readMessage(sock, [], symmetricEncryption, sessionId, 6) nonce, newHash = solveCriptopuzzle(cryptopuzzleChallange["difficulty"], cryptopuzzleChallange["toMine"]) sendEncryptedMessage(sock, {"nonce":nonce, "hash":newHash}, symmetricEncryption, sessionId, 7) msg = readMessage(sock, [], symmetricEncryption, sessionId, 8) if not validReceiptSignature(msg["signature"], msg["certificate"], msg["receipt"]): print("Signature on receipt received not valid") return else: print("Signature on receipt ok") if not os.path.exists("receipts"): os.mkdir("receipts") os.mkdir("receipts/" + clientId) if not os.path.exists("receipts/" + clientId): os.mkdir("receipts/" + clientId) while True: receiptName = input("Name for receipt: ") if receiptName == "": print("ERROR: Insert a valid name") continue break cryptopuzzleChallange["toMine"]["nonce"] = nonce receipt = { "whatISaw":{ 'bid': bid, "cryptopuzzleChallange":cryptopuzzleChallange }, "received":msg } f = open("receipts/" + clientId + "/" + receiptName + ".txt", "w+") f.write(json.dumps({"auctionId":auctionId, "receipt":receipt})) f.close() sock.close()
def validateBid(sock, symmetricEncryption, sessionId): msg = readMessage(sock, [], symmetricEncryption, sessionId, 4) bid = msg["bid"] clientValidation = msg["clientValidation"] auction = AUCTIONS[bid["auctionId"]] type = auction.auctionInfo["type"] if type == "BlindShown": assert "countBidsDone" in msg.keys() countBidsDone = msg["countBidsDone"] else: countBidsDone = None if not bidValidation(auction.validationCode, type, deepcopy(bid), auction.lastAmount, countBidsDone): sendEncryptedMessage(sock, {"error": "Bid failed bid validation"}, symmetricEncryption, sessionId, 5) return payload = bidModification(auction.modificationCode, type, deepcopy(bid), auction.lastAmount, countBidsDone) if float(bid["amount"]) < auction.baseAmount: sendEncryptedMessage( sock, {"error": "Amount has to greater than the base amount"}, symmetricEncryption, sessionId, 5) return bidAmount = float(bid["amount"]) if type == "English": if bidAmount <= auction.lastAmount: sendEncryptedMessage( sock, {"error": "Amount has to greater than the last one"}, symmetricEncryption, sessionId, 5) return else: auction.lastAmount = bidAmount if type == "English" or type == "BlindHidden": for field in [ "clientId", "clientName", "clientCertificate", "timestamp" ]: bid[field] = auction.encryptField(bid[field]) clientValidation = auction.encryptField(clientValidation) if "Blind" in type: bid["amount"] = auction.encryptField(bid["amount"]) bid["nonce"] = auction.encryptField(bid["nonce"]) posValidation = { "bid": bid, "payload": payload, "clientValidation": clientValidation } signature = b64encode( privateKey.sign( calculateHashOverFields(posValidation))).decode("ascii") posValidation["managerValidation"] = { "signature": signature, "certificate": b64encode(certificate.public_bytes(Encoding.PEM)).decode("ascii") } sendEncryptedMessage(sock, posValidation, symmetricEncryption, sessionId, 5)