From b563c141380a55e7950a9aa1138711e77b55b695 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 12 Mar 2021 10:11:47 +0100 Subject: [PATCH 001/144] Rename arrayutils to better reflect usage + refactor Token to correct package --- .../{identity => tokenTree}/Token.kt | 32 ++++++++++++++----- .../util/{ArrayUtils.kt => ByteArrayUtils.kt} | 0 2 files changed, 24 insertions(+), 8 deletions(-) rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/{identity => tokenTree}/Token.kt (78%) rename ipv8/src/main/java/nl/tudelft/ipv8/util/{ArrayUtils.kt => ByteArrayUtils.kt} (100%) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Token.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt similarity index 78% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Token.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt index 86bad85f..85a141ed 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Token.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt @@ -1,4 +1,4 @@ -package nl.tudelft.ipv8.attestation.identity +package nl.tudelft.ipv8.attestation.token_tree import nl.tudelft.ipv8.attestation.SignedObject import nl.tudelft.ipv8.keyvault.PrivateKey @@ -7,14 +7,14 @@ import nl.tudelft.ipv8.util.sha3_256 import nl.tudelft.ipv8.util.toHex class Token( - private val previousTokenHash: ByteArray, + val previousTokenHash: ByteArray, content: ByteArray? = null, contentHash: ByteArray? = null, privateKey: PrivateKey? = null, - signature: ByteArray? = null + signature: ByteArray? = null, ) : SignedObject(privateKey, signature) { - private var content: ByteArray? = null + var content: ByteArray? = null var contentHash: ByteArray init { @@ -36,7 +36,7 @@ class Token( fun receiveContent(content: ByteArray): Boolean { contentHash = sha3_256(content) - if (this.contentHash == contentHash) { + if (this.contentHash.contentEquals(contentHash)) { this.content = content return true } @@ -51,6 +51,22 @@ class Token( return "Token[${this.hash.toHex()}](${this.previousTokenHash.toHex()}, ${contentHash.toHex()})" } + operator fun component1(): ByteArray { + return this.previousTokenHash + } + + operator fun component2(): ByteArray { + return this.signature + } + + operator fun component3(): ByteArray { + return this.contentHash + } + + operator fun component4(): ByteArray? { + return this.content + } + companion object { fun deserialize(data: ByteArray, publicKey: PublicKey, offset: Int = 0): Token { val sigLength = publicKey.getSignatureLength() @@ -65,9 +81,9 @@ class Token( fun fromDatabaseTuple( previousTokenHash: ByteArray, - signature: ByteArray, - contentHash: ByteArray, - content: ByteArray? + signature: ByteArray?, + contentHash: ByteArray?, + content: ByteArray?, ): Token { val token = Token(previousTokenHash, signature, contentHash = contentHash) if (content != null) { diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/util/ArrayUtils.kt b/ipv8/src/main/java/nl/tudelft/ipv8/util/ByteArrayUtils.kt similarity index 100% rename from ipv8/src/main/java/nl/tudelft/ipv8/util/ArrayUtils.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/util/ByteArrayUtils.kt From f1c5e0996c2fba34cad08a2475d76df2997f3297 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 12 Mar 2021 10:12:08 +0100 Subject: [PATCH 002/144] Add tokentree --- .../ipv8/attestation/tokenTree/TokenTree.kt | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt new file mode 100644 index 00000000..479446da --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt @@ -0,0 +1,175 @@ +package nl.tudelft.ipv8.attestation.tokenTree + +import mu.KotlinLogging +import nl.tudelft.ipv8.keyvault.PrivateKey +import nl.tudelft.ipv8.keyvault.PublicKey +import nl.tudelft.ipv8.util.ByteArrayKey +import nl.tudelft.ipv8.util.sha3_256 + +const val UNCHAINED_MAX_SIZE = 100 +const val DEFAULT_CHUNK_SUZE = 64 + +private val logger = KotlinLogging.logger {} + +class TokenTree(publicKey: PublicKey? = null, privateKey: PrivateKey? = null) { + + val elements = hashMapOf() + val unchained = mutableMapOf() + + var publicKey: PublicKey + var privateKey: PrivateKey? + var genesisHash: ByteArray + + init { + if (publicKey != null && privateKey == null) { + this.publicKey = publicKey.pub() + this.privateKey = null + } else if (publicKey == null && privateKey != null) { + this.privateKey = privateKey + this.publicKey = privateKey.pub() + } else { + throw RuntimeException("Both public key and private key are null.") + } + this.genesisHash = sha3_256(this.publicKey.keyToBin()) + } + + fun add(content: ByteArray, after: Token? = null): Token { + if (privateKey == null) { + throw RuntimeException("Attempted to create a token without a private key.") + } + val previousHash = after?.hash ?: this.genesisHash + return this.append(Token(previousHash, content = content, privateKey = this.privateKey)) + } + + fun addByHash(contentHash: ByteArray, after: Token? = null): Token { + if (privateKey == null) { + throw RuntimeException("Attempted to create a token without a private key.") + } + val previousHash = after?.hash ?: this.genesisHash + return this.append(Token(previousHash, contentHash = contentHash, privateKey = this.privateKey)) + } + + fun gatherToken(token: Token): Token? { + if (token.verify(this.publicKey)) { + if (!token.previousTokenHash.contentEquals(this.genesisHash) && !this.elements.containsKey(ByteArrayKey( + token.previousTokenHash)) + ) { + this.unchained[token] = null + if (this.unchained.size > UNCHAINED_MAX_SIZE) { + this.unchained.remove(this.unchained.keys.last()) + } + logger.info("Delaying unchained token $token!") + return null + } else if (this.elements.containsKey(ByteArrayKey(token.hash))) { + val shadowToken = this.elements[ByteArrayKey(token.hash)]!! + if (shadowToken.content == null && token.content != null) { + shadowToken.receiveContent(token.content!!) + } + return shadowToken + } else { + this.appendChainReactionToken(token) + } + return token + } + return null + } + + fun getMissing(): Set { + return this.unchained.keys.map { it.previousTokenHash }.toSet() + } + + fun verify(token: Token, maxDepth: Int = 1000): Boolean { + var current = token + var steps = 0 + while (maxDepth == -1 || maxDepth > steps) { + if (!current.verify(this.publicKey)) { + return false + } + if (current.previousTokenHash.contentEquals(this.genesisHash)) { + return false + } + if (!this.elements.containsKey(ByteArrayKey(current.previousTokenHash))) { + return false + } + current = this.elements[ByteArrayKey(current.previousTokenHash)]!! + steps += 1 + } + return steps < maxDepth + } + + fun getRootPath(token: Token, maxDepth: Int = 1000): List { + var current = token + var steps = 0 + val path = arrayListOf(token) + while (maxDepth == -1 || maxDepth > steps) { + if (!current.verify(this.publicKey)) { + return arrayListOf() + } + if (current.previousTokenHash.contentEquals(this.genesisHash)) { + break + } + if (!this.elements.containsKey(ByteArrayKey(current.previousTokenHash))) { + return arrayListOf() + } + current = this.elements[ByteArrayKey(current.previousTokenHash)]!! + path.add(current) + steps += 1 + } + return if (steps < maxDepth) { + path + } else { + arrayListOf() + } + } + + fun serializePublic(upTo: Token? = null): ByteArray { + return if (upTo != null) { + var out = upTo.getPlaintextSigned() + var nextTokenHash = upTo.previousTokenHash + var token: Token + while (this.elements.contains(ByteArrayKey(nextTokenHash))) { + token = this.elements[ByteArrayKey(nextTokenHash)]!! + out += token.getPlaintextSigned() + nextTokenHash = token.previousTokenHash + } + out + } else { + var out = byteArrayOf() + this.elements.values.forEach { out += it.getPlaintextSigned() } + out + } + } + + fun deserializePublic(serialized: ByteArray): Boolean { + val signatureLength = this.publicKey.getSignatureLength() + val chunkSize = DEFAULT_CHUNK_SUZE + signatureLength + var isCorrect = true + for (i in serialized.indices step chunkSize) { + isCorrect = isCorrect && this.gatherToken(Token.deserialize(serialized, this.publicKey, offset = i)) != null + } + return isCorrect + } + + private fun append(token: Token): Token { + this.elements[ByteArrayKey(token.hash)] = token + return token + } + + private fun appendChainReactionToken(token: Token) { + this.append(token) + var retryToken: Token? = null + for (lostToken in this.unchained.keys) { + if (lostToken.previousTokenHash.contentEquals(token.hash)) { + retryToken = lostToken + break + } + } + if (retryToken != null) { + this.unchained.remove(retryToken) + if (this.gatherToken(retryToken) != null) { + logger.warn { "Dropped illegal token $retryToken!" } + } + } + } + +} From 0fa6be616eacefd13181ccc7b2606579ee33a17f Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 12 Mar 2021 10:12:24 +0100 Subject: [PATCH 003/144] Add identitycommunity --- .../attestation/identity/IdentityCommunity.kt | 355 ++++++++++++++++++ 1 file changed, 355 insertions(+) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt new file mode 100644 index 00000000..f5eec6cd --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -0,0 +1,355 @@ +package nl.tudelft.ipv8.attestation.identity + +import mu.KotlinLogging +import nl.tudelft.ipv8.Community +import nl.tudelft.ipv8.IPv8 +import nl.tudelft.ipv8.Peer +import nl.tudelft.ipv8.attestation.identity.database.Credential +import nl.tudelft.ipv8.attestation.identity.database.IdentityAttestationStore +import nl.tudelft.ipv8.attestation.identity.manager.Disclosure +import nl.tudelft.ipv8.attestation.identity.manager.IdentityManager +import nl.tudelft.ipv8.attestation.identity.manager.PseudonymManager +import nl.tudelft.ipv8.attestation.identity.payloads.AttestPayload +import nl.tudelft.ipv8.attestation.identity.payloads.DisclosePayload +import nl.tudelft.ipv8.attestation.identity.payloads.MissingResponsePayload +import nl.tudelft.ipv8.attestation.identity.payloads.RequestMissingPayload +import nl.tudelft.ipv8.attestation.schema.ID_METADATA +import nl.tudelft.ipv8.attestation.tokenTree.Token +import nl.tudelft.ipv8.keyvault.PrivateKey +import nl.tudelft.ipv8.keyvault.PublicKey +import nl.tudelft.ipv8.messaging.Packet +import nl.tudelft.ipv8.peerdiscovery.Network +import nl.tudelft.ipv8.peerdiscovery.strategy.RandomWalk +import nl.tudelft.ipv8.util.ByteArrayKey +import nl.tudelft.ipv8.util.toHex +import nl.tudelft.ipv8.util.toKey +import org.json.JSONObject +import kotlin.math.max + +const val SAFE_UDP_PACKET_LENGTH = 1296 +const val DEFAULT_TIME_OUT = 300 +const val TOKEN_SIZE = 64 + +const val DISCLOSURE_PAYLOAD = 1 +const val ATTEST_PAYLOAD = 2 +const val REQUEST_MISSING_PAYLOAD = 3 +const val MISSING_RESPONSE_PAYLOAD = 4 + +class HashInformation( + val name: String, + val time: Float, + val publicKey: PublicKey, + val metadata: HashMap?, +) + +private val logger = KotlinLogging.logger {} + +class IdentityCommunity( + override var myPeer: Peer, + identityManager: IdentityManager? = null, + database: IdentityAttestationStore, + override var serviceId: String = SERVICE_ID, + override var network: Network = Network(), +) : Community() { + + internal var identityManager: IdentityManager = identityManager ?: IdentityManager(database) + private val knownAttestationHashes = hashMapOf() + private val pseudonymManager = this.identityManager.getPseudonym(this.myPeer.publicKey) + + private var tokenChain: List = arrayListOf() + private val metadataChain: List = listOf() + private val attestationChain: List = listOf() + private val permissions: HashMap = hashMapOf() + + init { + for (token in this.pseudonymManager.tree.elements.values) { + val chain = this.pseudonymManager.tree.getRootPath(token) + if (chain.size > this.tokenChain.size) { + this.tokenChain = chain + } + } + for (credential in this.pseudonymManager.getCredentials()) { + for (token in this.tokenChain) { + if (credential.metadata.tokenPointer.contentEquals(token.hash)) { + this.metadataChain.plus(credential.metadata) + this.attestationChain.plus(credential.attestations) + break + } + } + } + + messageHandlers[DISCLOSURE_PAYLOAD] = ::onDisclosureWrapper + messageHandlers[ATTEST_PAYLOAD] = ::onAttestWrapper + messageHandlers[REQUEST_MISSING_PAYLOAD] = ::onRequestMissingWrapper + messageHandlers[MISSING_RESPONSE_PAYLOAD] = ::onMissingResponseWrapper + } + + + private fun padHash(attributeHash: ByteArray): ByteArray { + logger.debug("Padding deprecated SHA-1 hash to 32 bytes. SHA3-256 should be used instead.") + return "SHA-1".toByteArray() + byteArrayOf(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + attributeHash + } + + private fun onDisclosureWrapper(packet: Packet) { + val (peer, payload) = packet.getAuthPayload(DisclosePayload.Deserializer) + logger.info("Received Disclose payload from ${peer.mid}.") + this.onDisclosure(peer, payload) + } + + private fun onAttestWrapper(packet: Packet) { + val (peer, payload) = packet.getAuthPayload(AttestPayload.Deserializer) + logger.info("Received Attest payload from ${peer.mid}.") + this.onAttest(peer, payload) + } + + private fun onRequestMissingWrapper(packet: Packet) { + val (peer, payload) = packet.getAuthPayload(RequestMissingPayload.Deserializer) + logger.info("Received Request Missing payload from ${peer.mid}.") + this.onRequestMissing(peer, payload) + } + + private fun onMissingResponseWrapper(packet: Packet) { + val (peer, payload) = packet.getAuthPayload(MissingResponsePayload.Deserializer) + logger.info("Received Missing Response payload from ${peer.mid}.") + this.onMissingResponse(peer, payload) + } + + fun addKnownHash( + attributeHash: ByteArray, + name: String, + publicKey: PublicKey, + metadata: HashMap? = null, + ) { + val hash = if (attributeHash.size == 20) this.padHash(attributeHash) else attributeHash + this.knownAttestationHashes[ByteArrayKey(hash)] = + HashInformation(name, System.currentTimeMillis() / 1000F, publicKey, metadata) + } + + fun getAttestationByHash(attributeHash: ByteArray): Metadata? { + val hash = if (attributeHash.size == 20) this.padHash(attributeHash) else attributeHash + for (credential in this.pseudonymManager.getCredentials()) { + val token = this.pseudonymManager.tree.elements.get(ByteArrayKey(credential.metadata.tokenPointer)) + if (token?.hash.contentEquals(hash)) { + return credential.metadata + } + } + return null + } + + fun shouldSign(pseudonym: PseudonymManager, metadata: Metadata): Boolean { + val transaction = JSONObject(metadata.serializedMetadata) + val requestedKeys = transaction.keySet() + if (!pseudonym.tree.elements.containsKey(metadata.tokenPointer.toKey())) { + return false + } + val attributeHash = pseudonym.tree.elements[metadata.tokenPointer.toKey()]!!.contentHash + if ("name" !in requestedKeys || "date" !in requestedKeys || "schema" !in requestedKeys) { + logger.debug("Not signing $metadata, it doesn't include the required fields!") + return false + } + if (!this.knownAttestationHashes.containsKey(attributeHash.toKey())) { + logger.debug("Not signing $metadata, it doesn't point to known content!") + return false + } + if (!pseudonym.publicKey.keyToBin() + .contentEquals(this.knownAttestationHashes[attributeHash.toKey()]?.publicKey?.keyToBin()) + ) { + logger.debug("Not signing $metadata, attribute doesn't belong to key!") + return false + } + // Refuse to sign blocks older than 5 minutes + if (System.currentTimeMillis() / 1000F > this.knownAttestationHashes[attributeHash.toKey()]?.time?.plus((DEFAULT_TIME_OUT)) ?: 0F) { + logger.debug("Not signing $metadata, timed out!") + return false + } + if (transaction["name"] != this.knownAttestationHashes[attributeHash.toKey()]?.name) { + logger.debug("Not signing $metadata, name does not match!") + return false + } + if (this.knownAttestationHashes[attributeHash.toKey()]!!.metadata != null + && transaction.toMap().filterKeys { it !in arrayOf("name", "data", "schema") } + != this.knownAttestationHashes[attributeHash.toKey()]!!.metadata + ) { + logger.debug("Not signing $metadata, metadata does not match!") + return false + } + for (attestation in pseudonym.database.getAttestationsOver(metadata)) { + if (this.myPeer.publicKey.keyToBin().contentEquals(pseudonym.database.getAuthority(attestation))) { + logger.debug("Not signing $metadata, already attested!") + return false + } + } + return true + } + + private fun fitDisclosure(disclosure: Disclosure): Disclosure { + val tokenSize = 64 + this.myPeer.publicKey.getSignatureLength() + val (metadata, tokens, attestations, authorities) = disclosure + var tokensOut = tokens + val metaLength = metadata.size + attestations.size + authorities.size + if (metaLength + tokens.size > SAFE_UDP_PACKET_LENGTH) { + var packetSpace = SAFE_UDP_PACKET_LENGTH - metaLength + if (packetSpace < 0) { + logger.warn("Attempting to disclose with packet of length $metaLength, hoping for the best!") + } + packetSpace = max(0, packetSpace) + val trimLength = packetSpace / tokenSize + tokensOut = tokens.copyOfRange(-trimLength * tokenSize, tokensOut.size) + } + return Disclosure(metadata, tokensOut, attestations, authorities) + } + + private fun receivedDisclosureForAttest(peer: Peer, disclosure: Disclosure) { + val solicited = this.knownAttestationHashes.values.filter { it.publicKey == peer.publicKey } + if (solicited.isNotEmpty()) { + val (correct, pseudonym) = this.identityManager.substantiate(peer.publicKey, + disclosure.metadata, + disclosure.tokens, + disclosure.attestations, + disclosure.authorities) + val requiredAttributes = + this.knownAttestationHashes.filter { it.value.publicKey == peer.publicKey }.keys.toTypedArray() + val knownAttributes: List = + pseudonym.tree.elements.values.map { ByteArrayKey(it.contentHash) } + + if (correct && requiredAttributes.any { knownAttributes.contains(it) }) { + for (credential in pseudonym.getCredentials()) { + logger.info("Attesting to ${credential.metadata}.") + val attestation = pseudonym.createAttestation(credential.metadata, this.myPeer.key as PrivateKey) + pseudonym.addAttestation(this.myPeer.publicKey, attestation) + val payload = AttestPayload(attestation.getPlaintextSigned()) + this.endpoint.send(peer, serializePacket(ATTEST_PAYLOAD, payload)) + } + } + + for (attributeHash in requiredAttributes) { + if (!knownAttributes.contains(attributeHash)) { + logger.info("Missing information for attestation ${attributeHash.bytes.toHex()}, requesting more.") + val payload = RequestMissingPayload(pseudonym.tree.elements.size) + this.endpoint.send(peer, serializePacket(REQUEST_MISSING_PAYLOAD, payload)) + } + } + + } else { + logger.warn("Received unsolicited disclosure from $peer, dropping.") + } + } + + fun requestAttestationAdvertisement( + peer: Peer, + attributeHash: ByteArray, + name: String, + blockType: String = ID_METADATA, + metadata: HashMap?, + ) { + val credential = this.selfAdvertise(attributeHash, name, blockType, metadata) + this.permissions[peer] = this.tokenChain.size + val disclosure = this.pseudonymManager.discloseCredentials(listOf(credential), setOf()) + val (metadata, tokens, attestations, authorities) = this.fitDisclosure(disclosure) + val payload = DisclosePayload(metadata, tokens, attestations, authorities) + this.endpoint.send(peer, serializePacket(DISCLOSURE_PAYLOAD, payload)) + } + + fun selfAdvertise( + attributeHash: ByteArray, + name: String, + blockType: String, + metadata: HashMap?, + ): Credential { + val hash = if (attributeHash.size == 20) this.padHash(attributeHash) else attributeHash + + val extendedMetadata = + hashMapOf("name" to name, "schema" to blockType, "date" to System.currentTimeMillis() / 1000F) + if (metadata != null) { + extendedMetadata.putAll(metadata) + } + + val credential = this.pseudonymManager.createCredential(hash, + extendedMetadata, + if (this.metadataChain.isNotEmpty()) this.metadataChain.last() else null) + + this.attestationChain.plus(credential.attestations) + this.metadataChain.plus(credential.metadata) + this.tokenChain.plus(this.pseudonymManager.tree.elements[credential.metadata.tokenPointer.toKey()]) + + return credential + } + + private fun onDisclosure(peer: Peer, payload: DisclosePayload) { + this.receivedDisclosureForAttest(peer, + Disclosure(payload.metadata, payload.tokens, payload.attestations, payload.authorities)) + } + + private fun onAttest(peer: Peer, payload: AttestPayload) { + val attestation = IdentityAttestation.deserialize(payload.attestation, peer.publicKey) + if (this.pseudonymManager.addAttestation(peer.publicKey, attestation)) { + logger.info("Received attestation from ${peer.mid}.") + } else { + logger.warn("Received invalid attestation from ${peer.mid}.") + } + } + + private fun onRequestMissing(peer: Peer, payload: RequestMissingPayload) { + var out = byteArrayOf() + val permitted = this.tokenChain.subList(0, this.permissions.get(peer) ?: 0) + permitted.forEachIndexed { index, token -> + if (index >= payload.known) { + val serialized = token.getPlaintextSigned() + if (out.size + serialized.size > SAFE_UDP_PACKET_LENGTH) { + return@forEachIndexed + } + out += serialized + } + } + val responsePayload = MissingResponsePayload(out) + this.endpoint.send(peer, serializePacket(MISSING_RESPONSE_PAYLOAD, responsePayload)) + } + + private fun onMissingResponse(peer: Peer, payload: MissingResponsePayload) { + this.receivedDisclosureForAttest(peer, Disclosure(byteArrayOf(), payload.tokens, byteArrayOf(), byteArrayOf())) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as IdentityCommunity + + if (serviceId != other.serviceId) return false + + return true + } + + override fun hashCode(): Int { + return serviceId.hashCode() + } + + companion object { + const val SERVICE_ID = "d5889074c1e4c50423cdb6e9307ee0ca5695ead7" + } +} + +fun createCommunity( + privateKey: PrivateKey, + ipv8: IPv8, + identityManager: IdentityManager, + database: IdentityAttestationStore, + rendezvousToken: ByteArray?, +): IdentityCommunity { + val myPeer = Peer(privateKey) + + var rendezvousId: String? = null + if (rendezvousToken != null) { + val tokenString = rendezvousToken.toHex() + rendezvousId = + IdentityCommunity.SERVICE_ID.mapIndexed { i, c -> if (i < rendezvousToken.size) (c.toInt() xor rendezvousToken[i].toInt()).toChar() else c } + .joinToString("") + } + + val community = if (rendezvousId != null) IdentityCommunity(myPeer, + identityManager, + database, + rendezvousId) else IdentityCommunity(myPeer, identityManager, database) + ipv8.addSecondaryOverlayStrategy(community, RandomWalk(community, 3.0, 5, 50, 0, 20)) + return community +} From ea6275fee51dc8ebbb32b76534150c320211fb06 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 12 Mar 2021 10:13:03 +0100 Subject: [PATCH 004/144] Add identity database --- .../database/IdentityAttestationStore.kt | 25 ++++++ .../identity/database/IdentitySQLiteStore.kt | 87 +++++++++++++++++++ .../nl/tudelft/ipv8/sqldelight/DbIdentity.sq | 54 ++++++++++++ 3 files changed, 166 insertions(+) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentityAttestationStore.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt create mode 100644 ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentityAttestationStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentityAttestationStore.kt new file mode 100644 index 00000000..4653f18d --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentityAttestationStore.kt @@ -0,0 +1,25 @@ +package nl.tudelft.ipv8.attestation.identity.database + +import nl.tudelft.ipv8.attestation.identity.IdentityAttestation +import nl.tudelft.ipv8.attestation.identity.Metadata +import nl.tudelft.ipv8.attestation.tokenTree.Token +import nl.tudelft.ipv8.keyvault.PublicKey + +class Credential(val metadata: Metadata, val attestations: Set) + +interface IdentityAttestationStore { + + fun insertToken(publicKey: PublicKey, token: Token) + fun insertMetadata(publicKey: PublicKey, metadata: Metadata) + fun insertAttestation(publicKey: PublicKey, authorityKey: PublicKey, attestation: IdentityAttestation) + fun getTokensFor(publicKey: PublicKey): List + fun getMetadataFor(publicKey: PublicKey): List + fun getAttestationsFor(publicKey: PublicKey): Set + fun getAttestationsBy(publicKey: PublicKey): Set + fun getAttestationsOver(metadata: Metadata): Set + fun getAuthority(attestation: IdentityAttestation): ByteArray + fun getCredentialOver(metadata: Metadata): Credential + fun getCredentialsFor(publicKey: PublicKey): List + fun getKnownIdentities(): List + +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt new file mode 100644 index 00000000..9168778a --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt @@ -0,0 +1,87 @@ +package nl.tudelft.ipv8.attestation.identity.database + +import nl.tudelft.ipv8.attestation.identity.IdentityAttestation +import nl.tudelft.ipv8.attestation.identity.Metadata +import nl.tudelft.ipv8.attestation.tokenTree.Token +import nl.tudelft.ipv8.keyvault.PublicKey +import nl.tudelft.ipv8.keyvault.defaultCryptoProvider +import nl.tudelft.ipv8.sqldelight.Database + +private val tokenMapper: ( + ByteArray, + ByteArray?, + ByteArray?, + ByteArray?, +) -> Token = { previousTokenHash, signature, contentHash, content -> + Token.fromDatabaseTuple(previousTokenHash, signature, contentHash, content) +} + +private val metadataMapper: ( + ByteArray, + ByteArray?, + ByteArray, +) -> Metadata = { tokenPointer, signature, serializedMetadata -> + Metadata.fromDatabaseTuple(tokenPointer, signature, serializedMetadata) +} + +private val identityAttestationMapper: ( + ByteArray, + ByteArray?, +) -> IdentityAttestation = { metadataPointer, signature -> + IdentityAttestation.fromDatabaseTuple(metadataPointer, signature) +} + +class IdentitySQLiteStore(database: Database) : IdentityAttestationStore { + private val dao = database.dbIdentityQueries + + override fun insertToken(publicKey: PublicKey, token: Token) { + val (previousTokenHash, signature, contentHash, content) = token + dao.insertToken(publicKey.keyToBin(), previousTokenHash, signature, contentHash, content) + } + + override fun insertMetadata(publicKey: PublicKey, metadata: Metadata) { + val (tokenPointer, signature, serializedMetadata) = metadata.toDatabaseTuple() + dao.insertMetadata(publicKey.keyToBin(), tokenPointer, signature, serializedMetadata) + } + + override fun insertAttestation(publicKey: PublicKey, authorityKey: PublicKey, attestation: IdentityAttestation) { + val (metadataPointer, signature) = attestation.toDatabaseTuple() + dao.insertIdentityAttestation(publicKey.keyToBin(), authorityKey.keyToBin(), metadataPointer, signature) + } + + override fun getTokensFor(publicKey: PublicKey): List { + return dao.getTokensFor(publicKey.keyToBin(), tokenMapper).executeAsList() + } + + override fun getMetadataFor(publicKey: PublicKey): List { + return dao.getMetadataFor(publicKey.keyToBin(), metadataMapper).executeAsList() + } + + override fun getAttestationsFor(publicKey: PublicKey): Set { + return dao.getAttestationsFor(publicKey.keyToBin(), identityAttestationMapper).executeAsList().toSet() + } + + override fun getAttestationsBy(publicKey: PublicKey): Set { + return dao.getAttestationsBy(publicKey.keyToBin(), identityAttestationMapper).executeAsList().toSet() + } + + override fun getAttestationsOver(metadata: Metadata): Set { + return dao.getAttestationsOver(metadata.hash, identityAttestationMapper).executeAsList().toSet() + } + + override fun getAuthority(attestation: IdentityAttestation): ByteArray { + return dao.getAuthority(attestation.signature).executeAsOne() + } + + override fun getCredentialOver(metadata: Metadata): Credential { + return Credential(metadata, this.getAttestationsOver(metadata)) + } + + override fun getCredentialsFor(publicKey: PublicKey): List { + return this.getMetadataFor(publicKey).map { Credential(it, this.getAttestationsOver(it)) } + } + + override fun getKnownIdentities(): List { + return dao.getKnownIdentities().executeAsList().map { defaultCryptoProvider.keyFromPublicBin(it) } + } +} diff --git a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq new file mode 100644 index 00000000..923d593a --- /dev/null +++ b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq @@ -0,0 +1,54 @@ +CREATE TABLE tokens ( + public_key BLOB NOT NULL, + previous_token_hash BLOB NOT NULL, + signature BLOB, + content_hash BLOB, + content BLOB, + PRIMARY KEY (public_key, previous_token_hash, content_hash) +); + +CREATE TABLE metadata ( + public_key BLOB NOT NULL, + token_pointer BLOB NOT NULL, + signature BLOB, + serialized_json BLOB NOT NULL, + PRIMARY KEY (public_key, token_pointer) +); + +CREATE TABLE identity_attestations ( + public_key BLOB NOT NULL, + authority_key BLOB NOT NULL, + metadata_pointer BLOB NOT NULL, + signature BLOB, + PRIMARY KEY (public_key, metadata_pointer) +); + +insertToken: +INSERT OR IGNORE INTO tokens (public_key, previous_token_hash, signature, content_hash, content) VALUES(?, ?, ?, ?, ?); + +insertMetadata: +INSERT OR IGNORE INTO metadata (public_key, token_pointer, signature, serialized_json) VALUES(?, ?, ?, ?); + +insertIdentityAttestation: +INSERT OR IGNORE INTO identity_attestations (public_key, authority_key, metadata_pointer, signature) VALUES(?, ?, ?, ?); + +getTokensFor: +SELECT previous_token_hash, signature, content_hash, content FROM tokens WHERE public_key = ?; + +getMetadataFor: +SELECT token_pointer, signature, serialized_json FROM metadata WHERE public_key = ?; + +getAttestationsFor: +SELECT metadata_pointer, signature FROM identity_attestations WHERE public_key = ?; + +getAttestationsBy: +SELECT metadata_pointer, signature FROM identity_attestations WHERE authority_key = ?; + +getAttestationsOver: +SELECT metadata_pointer, signature FROM identity_attestations WHERE metadata_pointer = ?; + +getAuthority: +SELECT authority_key FROM identity_attestations WHERE signature = ?; + +getKnownIdentities: +SELECT public_key FROM tokens; \ No newline at end of file From c3aca80ba3f0fb347ac55919259251f7f2b0fbff Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 12 Mar 2021 10:13:13 +0100 Subject: [PATCH 005/144] Add identity manager --- .../identity/manager/IdentityManager.kt | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt new file mode 100644 index 00000000..d3ad7787 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt @@ -0,0 +1,70 @@ +package nl.tudelft.ipv8.attestation.identity.manager + +import nl.tudelft.ipv8.attestation.identity.IdentityAttestation +import nl.tudelft.ipv8.attestation.identity.Metadata +import nl.tudelft.ipv8.attestation.identity.database.IdentityAttestationStore +import nl.tudelft.ipv8.attestation.wallet.cryptography.attest +import nl.tudelft.ipv8.keyvault.Key +import nl.tudelft.ipv8.keyvault.PrivateKey +import nl.tudelft.ipv8.keyvault.PublicKey +import nl.tudelft.ipv8.keyvault.defaultCryptoProvider +import nl.tudelft.ipv8.messaging.SERIALIZED_UINT_SIZE +import nl.tudelft.ipv8.messaging.SERIALIZED_USHORT_SIZE +import nl.tudelft.ipv8.messaging.deserializeUInt +import nl.tudelft.ipv8.messaging.deserializeUShort +import nl.tudelft.ipv8.util.ByteArrayKey + +class IdentityManager(internal val database: IdentityAttestationStore) { + + val pseudonyms = hashMapOf() + + fun getPseudonym(key: Key): PseudonymManager { + val publicKeyMaterial = key.pub().keyToBin() + if (!this.pseudonyms.containsKey(ByteArrayKey(publicKeyMaterial))) { + if (key is PrivateKey) { + this.pseudonyms[ByteArrayKey(publicKeyMaterial)] = PseudonymManager(this.database, privateKey = key) + } else { + this.pseudonyms[ByteArrayKey(publicKeyMaterial)] = PseudonymManager(this.database, publicKey = key as PublicKey) + } + } + return this.pseudonyms[ByteArrayKey(publicKeyMaterial)]!! + } + + fun substantiate( + publicKey: PublicKey, + serializeMetadata: ByteArray, + serializedTokens: ByteArray, + serializedAttestations: ByteArray, + serializedAuthorities: ByteArray, + ): Pair { + val pseudonym = this.getPseudonym(publicKey) + var correct = pseudonym.tree.deserializePublic(serializedTokens) + + var metadataOffset = 0 + while (metadataOffset < serializeMetadata.size) { + val metadataSize = deserializeUInt(serializeMetadata, metadataOffset).toInt() + metadataOffset += SERIALIZED_UINT_SIZE + val metadata = + Metadata.deserialize(serializeMetadata.copyOfRange(metadataOffset, metadataOffset + metadataSize), + publicKey) + pseudonym.addMetadata(metadata) + metadataOffset + metadataSize + } + + var attestationOffset = 0 + var authorityOffset = 0 + + while (authorityOffset < serializedAttestations.size) { + val authoritySize = deserializeUShort(serializedAuthorities, authorityOffset) + authorityOffset += SERIALIZED_USHORT_SIZE + val authority = defaultCryptoProvider.keyFromPublicBin(serializedAuthorities.copyOfRange(authorityOffset, + authorityOffset + authoritySize)) + authorityOffset += authoritySize + correct = correct && pseudonym.addAttestation(authority, + IdentityAttestation.deserialize(serializedAttestations, authority, attestationOffset)) + attestationOffset += 32 + authority.getSignatureLength() + } + + return Pair(correct, pseudonym) + } +} From dbb9459a442dd5f68aa94f3ebe173478845feca7 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 12 Mar 2021 10:13:24 +0100 Subject: [PATCH 006/144] Add pesudonymmanager --- .../identity/manager/PseudonymManager.kt | 177 ++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt new file mode 100644 index 00000000..b199f74a --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt @@ -0,0 +1,177 @@ +package nl.tudelft.ipv8.attestation.identity.manager + +import mu.KotlinLogging +import nl.tudelft.ipv8.attestation.identity.IdentityAttestation +import nl.tudelft.ipv8.attestation.identity.Metadata +import nl.tudelft.ipv8.attestation.identity.database.Credential +import nl.tudelft.ipv8.attestation.identity.database.IdentityAttestationStore +import nl.tudelft.ipv8.attestation.tokenTree.Token +import nl.tudelft.ipv8.attestation.tokenTree.TokenTree +import nl.tudelft.ipv8.keyvault.PrivateKey +import nl.tudelft.ipv8.keyvault.PublicKey +import nl.tudelft.ipv8.messaging.serializeUInt +import nl.tudelft.ipv8.messaging.serializeUShort +import nl.tudelft.ipv8.util.ByteArrayKey +import nl.tudelft.ipv8.util.toKey +import org.json.JSONObject + +private val logger = KotlinLogging.logger {} + +class PseudonymManager( + internal val database: IdentityAttestationStore, + publicKey: PublicKey? = null, + privateKey: PrivateKey? = null, +) { + + internal val tree = TokenTree(publicKey, privateKey) + + val publicKey: PublicKey + get() = this.tree.publicKey + + private val credentials = this.database.getCredentialsFor(this.publicKey) + + init { + logger.info("Loading public key ${this.publicKey.keyToHash()} from database") + for (token in this.database.getTokensFor(this.publicKey)) { + this.tree.elements[token.hash.toKey()] = token + } + } + + fun addCredential( + token: Token, + metadata: Metadata, + attestations: Set> = setOf(), + ): Credential? { + if (this.tree.gatherToken(token) != null) { + this.database.insertToken(this.publicKey, token) + + if (metadata.verify(this.publicKey) && metadata.tokenPointer.contentEquals(token.hash)) { + this.database.insertMetadata(this.publicKey, metadata) + } + + val validAttestations = setOf() + + for ((authorityPublicKey, identityAttestation) in attestations) { + if (this.addAttestation(authorityPublicKey, identityAttestation)) { + validAttestations.plus(identityAttestation) + } + } + + val out = Credential(metadata, validAttestations) + this.credentials.plus(out) + return out + } + return null + } + + fun addAttestation(publicKey: PublicKey, attestation: IdentityAttestation): Boolean { + if (attestation.verify(publicKey)) { + this.database.insertAttestation(this.publicKey, publicKey, attestation) + return true + } + return false + } + + fun addMetadata(metadata: Metadata): Boolean { + if (metadata.verify(this.publicKey)) { + this.database.insertMetadata(this.publicKey, metadata) + return true + } + return false + } + + fun createAttestation(metadata: Metadata, privateKey: PrivateKey): IdentityAttestation { + return IdentityAttestation.create(metadata, privateKey) + } + + fun createCredential( + attestationHash: ByteArray, + metadata: HashMap, + after: Metadata? = null, + ): Credential { + val preceding = if (after == null) null else this.tree.elements.get(after.tokenPointer.toKey()) + val token = this.tree.addByHash(attestationHash, preceding) + val metadataObj = Metadata(token.hash, JSONObject(metadata).toString().toByteArray(), this.tree.privateKey) + return this.addCredential(token, metadataObj, setOf())!! + } + + fun getCredential(metadata: Metadata): Credential { + return this.database.getCredentialOver(metadata) + } + + fun getCredentials(): List { + return this.database.getCredentialsFor(this.publicKey) + } + + fun discloseCredentials(credentials: List, attestationSelector: Set): Disclosure { + return createDisclosure(credentials.map { it.metadata }.toSet(), attestationSelector) + } + + fun createDisclosure(metadata: Set, attestationSelector: Set): Disclosure { + val attSelector = attestationSelector.map { ByteArrayKey(it) } + var serializedMetadata = byteArrayOf() + for (md in metadata) { + val serialized = md.getPlaintextSigned() + serializedMetadata += serializeUInt(serialized.size.toUInt()) + serialized + } + + var attestations = byteArrayOf() + var authorities = byteArrayOf() + + for (md in metadata) { + val availableAttestations = this.database.getAttestationsOver(md) + for (attestation in availableAttestations) { + if (attSelector.contains(attestation.hash.toKey())) { + attestations += attestation.getPlaintextSigned() + val authority = this.database.getAuthority(attestation) + authorities += serializeUShort(authority.size) + authority + } + } + } + val requiredTokenHashes = metadata.map { it.tokenPointer } + val tokens = setOf() + + for (requiredTokenHash in requiredTokenHashes) { + val rootToken = this.tree.elements[requiredTokenHash.toKey()]!! + + if (!this.tree.verify(rootToken)) { + throw RuntimeException("Attempted to create disclosure for undisclosable Token!") + } + + tokens.plus(rootToken) + var currentToken = rootToken + + while (!currentToken.previousTokenHash.contentEquals(this.tree.genesisHash)) { + currentToken = this.tree.elements[currentToken.previousTokenHash.toKey()]!! + tokens.plus(currentToken) + } + } + var serializedTokens = byteArrayOf() + tokens.forEach { serializedTokens += it.getPlaintextSigned() } + return Disclosure(serializedMetadata, serializedTokens, attestations, authorities) + } +} + +class Disclosure( + val metadata: ByteArray, + val tokens: ByteArray, + val attestations: ByteArray, + val authorities: ByteArray, +) { + operator fun component1(): ByteArray { + return metadata + } + + operator fun component2(): ByteArray { + return tokens + } + + operator fun component3(): ByteArray { + return attestations + } + + operator fun component4(): ByteArray { + return authorities + } +} + From 3eac2c7ef0aff111d1f84484d7f0b02f84362b94 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 12 Mar 2021 10:13:57 +0100 Subject: [PATCH 007/144] Add identity payloads --- .../identity/payloads/AttestPayload.kt | 20 +++++++++++ .../identity/payloads/DisclosePayload.kt | 35 +++++++++++++++++++ .../payloads/MissingResponsePayload.kt | 19 ++++++++++ .../payloads/RequestMissingPayload.kt | 19 ++++++++++ 4 files changed, 93 insertions(+) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/AttestPayload.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/DisclosePayload.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/MissingResponsePayload.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/RequestMissingPayload.kt diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/AttestPayload.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/AttestPayload.kt new file mode 100644 index 00000000..c07a2051 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/AttestPayload.kt @@ -0,0 +1,20 @@ +package nl.tudelft.ipv8.attestation.identity.payloads + +import nl.tudelft.ipv8.messaging.Deserializable +import nl.tudelft.ipv8.messaging.Serializable +import nl.tudelft.ipv8.messaging.deserializeVarLen +import nl.tudelft.ipv8.messaging.serializeVarLen + +class AttestPayload(val attestation: ByteArray) : Serializable { + override fun serialize(): ByteArray { + return serializeVarLen(attestation) + } + + companion object Deserializer : Deserializable { + override fun deserialize(buffer: ByteArray, offset: Int): Pair { + val (deserialized, localOffset) = deserializeVarLen(buffer, offset) + return Pair(AttestPayload(deserialized), offset + localOffset) + } + } + +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/DisclosePayload.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/DisclosePayload.kt new file mode 100644 index 00000000..595ae103 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/DisclosePayload.kt @@ -0,0 +1,35 @@ +package nl.tudelft.ipv8.attestation.identity.payloads + +import nl.tudelft.ipv8.messaging.* + +class DisclosePayload( + val metadata: ByteArray, + val tokens: ByteArray, + val attestations: ByteArray, + val authorities: ByteArray, +) : Serializable { + override fun serialize(): ByteArray { + return serializeVarLen(metadata) + serializeVarLen(metadata) + serializeVarLen(attestations) + serializeVarLen( + authorities) + } + + companion object Deserializer : Deserializable { + override fun deserialize(buffer: ByteArray, offset: Int): Pair { + var localOffset = offset + val (metadata, offset1) = deserializeVarLen(buffer, localOffset) + localOffset += offset1 + + val (tokens, offset2) = deserializeVarLen(buffer, localOffset) + localOffset += offset2 + + val (attestations, offset3) = deserializeVarLen(buffer, localOffset) + localOffset += offset3 + + val (authorities, offset4) = deserializeVarLen(buffer, localOffset) + localOffset += offset4 + + return Pair(DisclosePayload(metadata, tokens, attestations, authorities), localOffset) + } + } + +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/MissingResponsePayload.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/MissingResponsePayload.kt new file mode 100644 index 00000000..4eb2ff7a --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/MissingResponsePayload.kt @@ -0,0 +1,19 @@ +package nl.tudelft.ipv8.attestation.identity.payloads + +import nl.tudelft.ipv8.messaging.* + +class MissingResponsePayload( + val tokens: ByteArray, +) : Serializable { + override fun serialize(): ByteArray { + return tokens + } + + companion object Deserializer : Deserializable { + override fun deserialize(buffer: ByteArray, offset: Int): Pair { + val (tokens, localOffset) = deserializeRaw(buffer, offset) + return Pair(MissingResponsePayload(tokens), offset + localOffset) + } + } + +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/RequestMissingPayload.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/RequestMissingPayload.kt new file mode 100644 index 00000000..1defcd47 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/RequestMissingPayload.kt @@ -0,0 +1,19 @@ +package nl.tudelft.ipv8.attestation.identity.payloads + +import nl.tudelft.ipv8.messaging.* + +class RequestMissingPayload( + val known: Int, +) : Serializable { + override fun serialize(): ByteArray { + return serializeUInt(known.toUInt()) + } + + companion object Deserializer : Deserializable { + override fun deserialize(buffer: ByteArray, offset: Int): Pair { + val known = deserializeUInt(buffer, offset) + return Pair(RequestMissingPayload(known.toInt()), offset + SERIALIZED_UINT_SIZE) + } + } + +} From 8f307282d92af5f13448f341b73f2a5282397427 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 12 Mar 2021 10:14:53 +0100 Subject: [PATCH 008/144] Add communication manager --- .../ipv8/attestation/CommunicationManager.kt | 310 ++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt new file mode 100644 index 00000000..d090489a --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt @@ -0,0 +1,310 @@ +package nl.tudelft.ipv8.attestation + +import kotlinx.coroutines.* +import mu.KotlinLogging +import nl.tudelft.ipv8.IPv8 +import nl.tudelft.ipv8.Peer +import nl.tudelft.ipv8.attestation.identity.IdentityCommunity +import nl.tudelft.ipv8.attestation.identity.createCommunity +import nl.tudelft.ipv8.attestation.identity.database.IdentityAttestationStore +import nl.tudelft.ipv8.attestation.identity.manager.IdentityManager +import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity +import nl.tudelft.ipv8.attestation.wallet.AttestationStore +import nl.tudelft.ipv8.keyvault.PrivateKey +import nl.tudelft.ipv8.keyvault.defaultCryptoProvider +import nl.tudelft.ipv8.util.ByteArrayKey +import nl.tudelft.ipv8.util.defaultEncodingUtils +import nl.tudelft.ipv8.util.toHex +import nl.tudelft.ipv8.util.toKey +import org.json.JSONObject +import java.io.File +import java.io.FileNotFoundException +import java.nio.file.Files +import java.nio.file.Paths + +private val logger = KotlinLogging.logger {} + +class CommunicationManager( + private val iPv8Instance: IPv8, + private val attestationStore: AttestationStore, + private val identityStore: IdentityAttestationStore, +) { + private val channels = hashMapOf() + private val nameToChannel = hashMapOf() + private val loadedCommunity + get() = iPv8Instance.getOverlay() + var identityManager = loadedCommunity?.identityManager + + + fun lazyIdentityManager(): IdentityManager { + if (this.identityManager == null) { + this.identityManager = IdentityManager(identityStore) + } + return this.identityManager!! + } + + fun load( + name: String, + rendezvousToken: String?, + storePseudonym: ((String, PrivateKey) -> Unit)? = null, + loadPseudonym: ((String) -> PrivateKey)? = null, + ): CommunicationChannel { + if (nameToChannel.containsKey(name)) { + return this.nameToChannel[name]!! + } + + // Load private key with function or via default method. + var privateKey = loadPseudonym?.let { it(name) } ?: loadPseudonym(name) + if (privateKey == null) { + privateKey = defaultCryptoProvider.generateKey() + storePseudonym?.let { it(name, privateKey) } ?: storePseudonym(name, privateKey) + } + val publicKeyBytes = privateKey.pub().keyToBin() + + if (this.channels.containsKey(publicKeyBytes.toKey())) { + val decodedRendezvousToken: ByteArray? = + (rendezvousToken ?: defaultEncodingUtils.decodeBase64FromString(rendezvousToken!!)) as ByteArray? + val identityOverlay = createCommunity(privateKey, + this.iPv8Instance, + this.lazyIdentityManager(), + identityStore, + decodedRendezvousToken) + + val attestationOverlay = AttestationCommunity(identityOverlay.myPeer, + identityOverlay.endpoint, + identityOverlay.network, + attestationStore) + + this.channels[publicKeyBytes.toKey()] = CommunicationChannel(attestationOverlay, identityOverlay) + this.nameToChannel[name] = this.channels[publicKeyBytes.toKey()]!! + } + return this.nameToChannel[name]!! + } + + fun unload(name: String) { + TODO() + } + + fun listPseudonyms(): List { + return getPseudonyms() + } + + fun listLoadedPseudonyms(): List { + val pseudonyms = this.listPseudonyms() + return this.nameToChannel.keys.filter { pseudonyms.contains(it) } + } + + companion object { + private const val PSEUDONYM_PATH = "\\pseudonyms\\" + + // Note. This is not secure and should not be used in a production setting without encryption. + @Suppress("NewApi") + fun loadPseudonym(name: String): PrivateKey? { + return try { + val directoryPath = "${System.getProperty("user.dir")}\\$PSEUDONYM_PATH" + val directory = File(directoryPath) + if (!directory.exists()) { + directory.mkdirs() + } + val bytes = File("$directoryPath\\$name").readBytes() + if (bytes.isNotEmpty()) { + defaultCryptoProvider.keyFromPrivateBin(bytes) + } else { + null + } + } catch (e: FileNotFoundException) { + logger.error("Failed to locate pseudonym file $name") + null + } + } + + // Note. This is not secure and should not be used in a production setting without encryption. + @Suppress("NewApi") + fun storePseudonym(name: String, privateKey: PrivateKey) { + val directoryPath = "${System.getProperty("user.dir")}\\$PSEUDONYM_PATH" + val directory = File(directoryPath) + if (!directory.exists()) { + directory.mkdirs() + } + File("$directoryPath\\$name").writeBytes(privateKey.keyToBin()) + } + + @Suppress("NewApi", "UNCHECKED_CAST") + fun getPseudonyms(): List { + return Files.walk(Paths.get("${System.getProperty("user.dir")}\\$PSEUDONYM_PATH")) + .filter(Files::isRegularFile).map { it.fileName.toString() } + .toArray().toList() as List + } + } + +} + +class AttributePointer(val peer: Peer, val attributeName: String) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as AttributePointer + + if (peer != other.peer) return false + if (attributeName != other.attributeName) return false + + return true + } + + override fun hashCode(): Int { + var result = peer.hashCode() + result = 31 * result + attributeName.hashCode() + return result + } +} + +class CommunicationChannel(val attestationOverlay: AttestationCommunity, val identityOverlay: IdentityCommunity) { + + private val attestationRequests = hashMapOf, String>>() + private val verifyRequests = hashMapOf>() + private val verificationOutput = hashMapOf>>() + private val attestationMetadata = hashMapOf>() + + init { + this.attestationOverlay.setAttestationRequestCallback(this::onRequestAttestationAsync) + this.attestationOverlay.setAttestationRequestCompleteCallback(this::onAttestationComplete) + this.attestationOverlay.setVerifyRequestCallback(this::onVerifyRequestAsync) + } + + val publicKeyBin + get() = this.identityOverlay.myPeer.publicKey.keyToBin() + + val peers + get() = this.identityOverlay.getPeers() + + val myPeer + get() = this.identityOverlay.myPeer + + val schemas + get() = this.attestationOverlay.schemaManager.getSchemaNames() + + private fun onRequestAttestationAsync( + peer: Peer, + attributeName: String, + metadataString: String, + ): Deferred { + // Promise some ByteArray. + val deferred: Deferred = GlobalScope.async(start = CoroutineStart.LAZY) { null } + this.attestationRequests[AttributePointer(peer, attributeName)] = Pair(deferred, metadataString) + this.attestationMetadata[AttributePointer(peer, attributeName)] + return deferred + } + + @Suppress("UNUSED_PARAMETER") + private fun onAttestationComplete( + forPeer: Peer, + attributeName: String, + attestation: WalletAttestation, + attributeHash: ByteArray, + idFormat: String, + fromPeer: Peer?, + metaData: String?, + Signature: ByteArray?, + ) { + val metadata = this.attestationMetadata.get(AttributePointer(forPeer, attributeName)) + + if (forPeer == myPeer) { + if (fromPeer == myPeer) { + @Suppress("UNCHECKED_CAST") + this.identityOverlay.selfAdvertise(attributeHash, attributeName, idFormat, + JSONObject(metadata).toMap() as HashMap?) + } else { + this.identityOverlay.requestAttestationAdvertisement(fromPeer!!, attributeHash, attributeName, idFormat, + metadata as HashMap?) + } + } else { + this.identityOverlay.addKnownHash(attributeHash, attributeName, forPeer.publicKey, + metadata as HashMap?) + } + } + + private fun onVerifyRequestAsync(peer: Peer, attributeHash: ByteArray): Deferred { + val metadata = this.identityOverlay.getAttestationByHash(attributeHash) ?: return CompletableDeferred(null) + val attributeName = JSONObject(String(metadata.serializedMetadata)).getString("name") + val deferred = GlobalScope.async(start = CoroutineStart.LAZY) { false } + this.verifyRequests[AttributePointer(peer, attributeName)] = deferred + return deferred + } + + private fun onVerificationResults(attributeHash: ByteArray, value: List) { + val references = this.verificationOutput[attributeHash.toKey()] + val out = arrayListOf>() + if (references != null) { + for (i in references.indices) { + out.add(Pair(references[i].first, value[i])) + } + this.verificationOutput[attributeHash.toKey()] = out + } else { + throw RuntimeException("Could not locate reference for ${attributeHash.toHex()} in verification output.") + } + } + + private fun dropIdentityTableData() { + TODO("") + } + + private fun dropAttestationTableData() { + TODO("") + } + + fun remove() { + TODO("") + } + + fun getAttributes(peer: Peer): HashMap, List>> { + val pseudonym = this.identityOverlay.identityManager.getPseudonym(peer.publicKey) + val out: HashMap, List>> = hashMapOf() + + for (credential in pseudonym.getCredentials()) { + val attestations = credential.attestations.toList() + val attesters = listOf() + + for (attestation in attestations) { + attesters.plus(this.identityOverlay.identityManager.database.getAuthority(attestation)) + } + val attributeHash = pseudonym.tree.elements[credential.metadata.tokenPointer.toKey()]!!.contentHash + val jsonMetadata = JSONObject(String(credential.metadata.serializedMetadata)) + out[attributeHash.toKey()] = + Triple(jsonMetadata.getString("name"), jsonMetadata.toMap() as HashMap, attesters) + } + return out + } + + fun requestAttestation(peer: Peer, attributeName: String, idFormat: String, metadata: HashMap) { + val key = this.attestationOverlay.getIdAlgorithm(idFormat).generateSecretKey() + metadata.put("id_format", idFormat) + this.attestationMetadata[AttributePointer(peer, attributeName)] = metadata + this.attestationOverlay.requestAttestation(peer, attributeName, key, metadata) + } + + fun attest(peer: Peer, attributeName: String, value: ByteArray) { + val outstanding = this.attestationRequests.remove(AttributePointer(peer, attributeName))!! + GlobalScope.launch { outstanding.first.await() } + } + + fun allowVerification(peer: Peer, attributeName: String) { + val outstanding = this.verifyRequests.remove(AttributePointer(peer, attributeName))!! + GlobalScope.launch { outstanding.await() } + } + + fun disallowVerification(peer: Peer, attributeName: String) { + val outstanding = this.verifyRequests.remove(AttributePointer(peer, attributeName))!! + GlobalScope.launch { outstanding.await() } + } + + fun verify(peer: Peer, attributeHash: ByteArray, referenceValues: List, idFormat: String) { + this.verificationOutput[attributeHash.toKey()] = referenceValues.map { Pair(it, null) } + this.attestationOverlay.verifyAttestationValues(peer.address, + attributeHash, + referenceValues, + this::onVerificationResults, + idFormat) + } + +} From 42759f7f24eed89cb1801aeb4e2265e741f8dd07 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 12 Mar 2021 10:16:28 +0100 Subject: [PATCH 009/144] Rename tokentree package --- .../main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt index 85a141ed..b996b208 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt @@ -1,4 +1,4 @@ -package nl.tudelft.ipv8.attestation.token_tree +package nl.tudelft.ipv8.attestation.tokenTree import nl.tudelft.ipv8.attestation.SignedObject import nl.tudelft.ipv8.keyvault.PrivateKey From a22fd8cef5a16a55c1e789f5d9a0548a91fc4757 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 12 Mar 2021 10:16:41 +0100 Subject: [PATCH 010/144] fix metadata type usage --- .../ipv8/attestation/identity/Metadata.kt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt index b3d1b2fe..358be923 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt @@ -1,30 +1,30 @@ package nl.tudelft.ipv8.attestation.identity import nl.tudelft.ipv8.attestation.SignedObject +import nl.tudelft.ipv8.attestation.tokenTree.Token import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.util.toHex import org.json.JSONObject class Metadata( - private val tokenPointer: ByteArray, - private val serializedJSONObject: ByteArray, + val tokenPointer: ByteArray, + val serializedMetadata: ByteArray, privateKey: PrivateKey? = null, - signature: ByteArray? = null + signature: ByteArray? = null, ) : SignedObject(privateKey, signature) { override fun getPlaintext(): ByteArray { - return this.tokenPointer + this.serializedJSONObject + return this.tokenPointer + this.serializedMetadata } - fun toDatabaseTuple(): Array { - return arrayOf(this.tokenPointer, this.signature, this.serializedJSONObject) + fun toDatabaseTuple(): Triple { + return Triple(this.tokenPointer, this.signature, this.serializedMetadata) } - @ExperimentalStdlibApi override fun toString(): String { - return "Metadata(${this.tokenPointer.toHex()},\n${this.serializedJSONObject.toString(Charsets.UTF_8)}" + return "Metadata(${this.tokenPointer.toHex()},\n${String(this.serializedMetadata)}" } override fun deserialize(data: ByteArray, publicKey: PublicKey, offset: Int): Metadata { @@ -52,8 +52,8 @@ class Metadata( fun fromDatabaseTuple( tokenPointer: ByteArray, - signature: ByteArray, - serializedJSONObject: ByteArray + signature: ByteArray?, + serializedJSONObject: ByteArray, ): Metadata { return Metadata(tokenPointer, serializedJSONObject, signature = signature) } From 8195ec1c125c6577466ed36eedfc49e4a5a67453 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 12 Mar 2021 10:16:55 +0100 Subject: [PATCH 011/144] Make signature nullable --- .../nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt index f24f0419..7fa0aaca 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt @@ -39,7 +39,7 @@ class IdentityAttestation( return IdentityAttestation(metadata.hash, privateKey = privateKey) } - fun fromDatabaseTuple(metadataPointer: ByteArray, signature: ByteArray): IdentityAttestation { + fun fromDatabaseTuple(metadataPointer: ByteArray, signature: ByteArray?): IdentityAttestation { return IdentityAttestation(metadataPointer, signature = signature) } } From 72ed083c56fd9a072501cae4bf6592e7d3ad4cf9 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 12 Mar 2021 10:17:17 +0100 Subject: [PATCH 012/144] Add tokey extension to bytearray --- ipv8/src/main/java/nl/tudelft/ipv8/util/ByteArrayUtils.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/util/ByteArrayUtils.kt b/ipv8/src/main/java/nl/tudelft/ipv8/util/ByteArrayUtils.kt index 4058d3d3..8aac5c63 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/util/ByteArrayUtils.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/util/ByteArrayUtils.kt @@ -20,3 +20,7 @@ class ByteArrayKey(val bytes: ByteArray) { return bytes.contentToString() } } + +fun ByteArray.toKey(): ByteArrayKey { + return ByteArrayKey(this) +} From 65562a76f3d57266488595cba658b29e7984b730 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 17 Mar 2021 10:02:40 +0100 Subject: [PATCH 013/144] Rename identitystore --- .../nl/tudelft/ipv8/attestation/CommunicationManager.kt | 8 ++++++-- .../ipv8/attestation/identity/IdentityCommunity.kt | 6 +++--- .../attestation/identity/database/IdentitySQLiteStore.kt | 2 +- .../{IdentityAttestationStore.kt => IdentityStore.kt} | 2 +- .../ipv8/attestation/identity/manager/IdentityManager.kt | 5 ++--- .../ipv8/attestation/identity/manager/PseudonymManager.kt | 4 ++-- 6 files changed, 15 insertions(+), 12 deletions(-) rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/{IdentityAttestationStore.kt => IdentityStore.kt} (96%) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt index d090489a..1461e55f 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt @@ -6,7 +6,7 @@ import nl.tudelft.ipv8.IPv8 import nl.tudelft.ipv8.Peer import nl.tudelft.ipv8.attestation.identity.IdentityCommunity import nl.tudelft.ipv8.attestation.identity.createCommunity -import nl.tudelft.ipv8.attestation.identity.database.IdentityAttestationStore +import nl.tudelft.ipv8.attestation.identity.database.IdentityStore import nl.tudelft.ipv8.attestation.identity.manager.IdentityManager import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity import nl.tudelft.ipv8.attestation.wallet.AttestationStore @@ -27,7 +27,7 @@ private val logger = KotlinLogging.logger {} class CommunicationManager( private val iPv8Instance: IPv8, private val attestationStore: AttestationStore, - private val identityStore: IdentityAttestationStore, + private val identityStore: IdentityStore, ) { private val channels = hashMapOf() private val nameToChannel = hashMapOf() @@ -94,6 +94,10 @@ class CommunicationManager( return this.nameToChannel.keys.filter { pseudonyms.contains(it) } } + fun shutdown() { + TODO() + } + companion object { private const val PSEUDONYM_PATH = "\\pseudonyms\\" diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index f5eec6cd..a892473a 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -5,7 +5,7 @@ import nl.tudelft.ipv8.Community import nl.tudelft.ipv8.IPv8 import nl.tudelft.ipv8.Peer import nl.tudelft.ipv8.attestation.identity.database.Credential -import nl.tudelft.ipv8.attestation.identity.database.IdentityAttestationStore +import nl.tudelft.ipv8.attestation.identity.database.IdentityStore import nl.tudelft.ipv8.attestation.identity.manager.Disclosure import nl.tudelft.ipv8.attestation.identity.manager.IdentityManager import nl.tudelft.ipv8.attestation.identity.manager.PseudonymManager @@ -47,7 +47,7 @@ private val logger = KotlinLogging.logger {} class IdentityCommunity( override var myPeer: Peer, identityManager: IdentityManager? = null, - database: IdentityAttestationStore, + database: IdentityStore, override var serviceId: String = SERVICE_ID, override var network: Network = Network(), ) : Community() { @@ -333,7 +333,7 @@ fun createCommunity( privateKey: PrivateKey, ipv8: IPv8, identityManager: IdentityManager, - database: IdentityAttestationStore, + database: IdentityStore, rendezvousToken: ByteArray?, ): IdentityCommunity { val myPeer = Peer(privateKey) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt index 9168778a..dd5356ad 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt @@ -31,7 +31,7 @@ private val identityAttestationMapper: ( IdentityAttestation.fromDatabaseTuple(metadataPointer, signature) } -class IdentitySQLiteStore(database: Database) : IdentityAttestationStore { +class IdentitySQLiteStore(database: Database) : IdentityStore { private val dao = database.dbIdentityQueries override fun insertToken(publicKey: PublicKey, token: Token) { diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentityAttestationStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentityStore.kt similarity index 96% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentityAttestationStore.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentityStore.kt index 4653f18d..afab814e 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentityAttestationStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentityStore.kt @@ -7,7 +7,7 @@ import nl.tudelft.ipv8.keyvault.PublicKey class Credential(val metadata: Metadata, val attestations: Set) -interface IdentityAttestationStore { +interface IdentityStore { fun insertToken(publicKey: PublicKey, token: Token) fun insertMetadata(publicKey: PublicKey, metadata: Metadata) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt index d3ad7787..eafa8524 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt @@ -2,8 +2,7 @@ package nl.tudelft.ipv8.attestation.identity.manager import nl.tudelft.ipv8.attestation.identity.IdentityAttestation import nl.tudelft.ipv8.attestation.identity.Metadata -import nl.tudelft.ipv8.attestation.identity.database.IdentityAttestationStore -import nl.tudelft.ipv8.attestation.wallet.cryptography.attest +import nl.tudelft.ipv8.attestation.identity.database.IdentityStore import nl.tudelft.ipv8.keyvault.Key import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.PublicKey @@ -14,7 +13,7 @@ import nl.tudelft.ipv8.messaging.deserializeUInt import nl.tudelft.ipv8.messaging.deserializeUShort import nl.tudelft.ipv8.util.ByteArrayKey -class IdentityManager(internal val database: IdentityAttestationStore) { +class IdentityManager(internal val database: IdentityStore) { val pseudonyms = hashMapOf() diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt index b199f74a..0a7f4b5c 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt @@ -4,7 +4,7 @@ import mu.KotlinLogging import nl.tudelft.ipv8.attestation.identity.IdentityAttestation import nl.tudelft.ipv8.attestation.identity.Metadata import nl.tudelft.ipv8.attestation.identity.database.Credential -import nl.tudelft.ipv8.attestation.identity.database.IdentityAttestationStore +import nl.tudelft.ipv8.attestation.identity.database.IdentityStore import nl.tudelft.ipv8.attestation.tokenTree.Token import nl.tudelft.ipv8.attestation.tokenTree.TokenTree import nl.tudelft.ipv8.keyvault.PrivateKey @@ -18,7 +18,7 @@ import org.json.JSONObject private val logger = KotlinLogging.logger {} class PseudonymManager( - internal val database: IdentityAttestationStore, + internal val database: IdentityStore, publicKey: PublicKey? = null, privateKey: PrivateKey? = null, ) { From 650cc49ed4d74bd78e868f8eccfafe5c74f4a757 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 19 Mar 2021 10:12:21 +0100 Subject: [PATCH 014/144] Add logic for secondary overlays + make attestation value synchronous. --- ipv8/src/main/java/nl/tudelft/ipv8/IPv8.kt | 25 ++++++- .../wallet/AttestationCommunity.kt | 70 ++++++++++++++----- 2 files changed, 77 insertions(+), 18 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/IPv8.kt b/ipv8/src/main/java/nl/tudelft/ipv8/IPv8.kt index ee0fdb63..d6d3fa6a 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/IPv8.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/IPv8.kt @@ -11,11 +11,21 @@ class IPv8( private val endpoint: EndpointAggregator, private val configuration: IPv8Configuration, val myPeer: Peer, - val network: Network = Network() + val network: Network = Network(), ) { private val overlayLock = Object() + /* + * Primary Overlays. Should not contain duplicates. + */ val overlays = mutableMapOf, Overlay>() + + /* + * Secondary Overlays. These contain alternative channels of an Overlay. + * Ensure unique Service IDs. TODO: remove Overlays singleton constraint. + */ + val secondaryOverlays = mutableMapOf() + private val strategies = mutableListOf() private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) @@ -31,6 +41,10 @@ class IPv8( return overlays[T::class.java] as? T } + inline fun getSecondaryOverlay(serviceId: String): T? { + return secondaryOverlays[serviceId] as? T + } + fun start() { if (isStarted()) throw IllegalStateException("IPv8 has already started") @@ -68,6 +82,15 @@ class IPv8( startLoopingCall() } + fun addSecondaryOverlayStrategy(overlay: Overlay, strategy: DiscoveryStrategy) { + synchronized(overlayLock) { + if (!this.secondaryOverlays.containsKey(overlay.serviceId)) { + this.secondaryOverlays[overlay.serviceId] = overlay + } + this.strategies.add(strategy) + } + } + private fun onTick() { if (endpoint.isOpen()) { synchronized(overlayLock) { diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt index 36024287..72b90fe9 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt @@ -1,5 +1,9 @@ package nl.tudelft.ipv8.attestation.wallet +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.async +import kotlinx.coroutines.launch import mu.KotlinLogging import nl.tudelft.ipv8.Community import nl.tudelft.ipv8.IPv4Address @@ -19,8 +23,11 @@ import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPrivateKe import nl.tudelft.ipv8.attestation.wallet.payloads.* import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.PublicKey +import nl.tudelft.ipv8.messaging.Endpoint +import nl.tudelft.ipv8.messaging.EndpointAggregator import nl.tudelft.ipv8.messaging.Packet import nl.tudelft.ipv8.messaging.payload.GlobalTimeDistributionPayload +import nl.tudelft.ipv8.peerdiscovery.Network import nl.tudelft.ipv8.util.* import org.json.JSONObject import java.math.BigInteger @@ -35,14 +42,26 @@ private val logger = KotlinLogging.logger {} private const val CHUNK_SIZE = 800 class AttestationCommunity(val database: AttestationStore) : Community() { + + override lateinit var myPeer: Peer + override lateinit var endpoint: EndpointAggregator + override lateinit var network: Network + + constructor(myPeer: Peer, endpoint: EndpointAggregator, network: Network, database: AttestationStore) : this( + database) { + this.myPeer = myPeer + this.endpoint = endpoint + this.network = network + } + override val serviceId = "e5d116f803a916a84850b9057cc0f662163f71f5" private val receiveBlockLock = ReentrantLock() val schemaManager = SchemaManager() - private lateinit var attestationRequestCallback: (peer: Peer, attributeName: String, metaData: String) -> ByteArray + private lateinit var attestationRequestCallback: (peer: Peer, attributeName: String, metaData: String) -> Deferred private lateinit var attestationRequestCompleteCallback: (forPeer: Peer, attributeName: String, attestation: WalletAttestation, attestationHash: ByteArray, idFormat: String, fromPeer: Peer?, metaData: String?, signature: ByteArray?) -> Unit - private lateinit var verifyRequestCallback: (peer: Peer, attributeHash: ByteArray) -> Boolean + private lateinit var verifyRequestCallback: (peer: Peer, attributeHash: ByteArray) -> Deferred private lateinit var attestationChunkCallback: (peer: Peer, sequenceNumber: Int) -> Unit val attestationKeys: MutableMap> = mutableMapOf() @@ -55,6 +74,17 @@ class AttestationCommunity(val database: AttestationStore) : Community() { val requestCache = RequestCache() init { + // Use parameters of baseclass if not overridden. + if (!this::myPeer.isInitialized) { + this.myPeer = super.myPeer + } + if (!this::endpoint.isInitialized) { + this.endpoint = super.endpoint + } + if (!this::network.isInitialized) { + this.network = super.network + } + trustedAuthorityManager.loadAuthorities() schemaManager.registerDefaultSchemas() for (att in this.database.getAllAttestations()) { @@ -74,11 +104,11 @@ class AttestationCommunity(val database: AttestationStore) : Community() { private fun onRequestAttestationWrapper(packet: Packet) { val (peer, dist, payload) = packet.getAuthPayloadWithDist(RequestAttestationPayload.Deserializer) logger.info("Received RequestAttestation from ${peer.mid} for metadata ${payload.metadata}.") - this.onRequestAttestation(peer, dist, payload) + GlobalScope.launch { onRequestAttestation(peer, dist, payload) } } private fun onChallengeResponseWrapper(packet: Packet) { - val (peer, _, payload) = packet.getAuthPayloadWithDist(ChallengeResponsePayload.Deserializer) + val (peer, payload) = packet.getAuthPayload(ChallengeResponsePayload.Deserializer) logger.info("Received ChallengeResponse from ${peer.mid} for hash ${String(payload.challengeHash)} with response ${ String(payload.response) }.") @@ -86,7 +116,7 @@ class AttestationCommunity(val database: AttestationStore) : Community() { } private fun onChallengeWrapper(packet: Packet) { - val (peer, _, payload) = packet.getAuthPayloadWithDist(ChallengePayload.Deserializer) + val (peer, payload) = packet.getAuthPayload(ChallengePayload.Deserializer) logger.info("Received Challenge from ${peer.mid} for hash ${String(payload.attestationHash)} with challenge ${ String(payload.challenge) }.") @@ -102,17 +132,17 @@ class AttestationCommunity(val database: AttestationStore) : Community() { } private fun onVerifyAttestationRequestWrapper(packet: Packet) { - val (peer, _, payload) = packet.getAuthPayloadWithDist(VerifyAttestationRequestPayload.Deserializer) + val (peer, payload) = packet.getAuthPayload(VerifyAttestationRequestPayload.Deserializer) logger.info("Received VerifyAttestationRequest from ${peer.mid} for hash ${String(payload.hash)}.") - this.onVerifyAttestationRequest(peer, payload) + GlobalScope.launch { onVerifyAttestationRequest(peer, payload) } } - private fun getIdAlgorithm(idFormat: String): IdentityAlgorithm { + fun getIdAlgorithm(idFormat: String): IdentityAlgorithm { return this.schemaManager.getAlgorithmInstance(idFormat) } - fun setAttestationRequestCallback(f: (peer: Peer, attributeName: String, metaData: String) -> ByteArray) { + fun setAttestationRequestCallback(f: (peer: Peer, attributeName: String, metaData: String) -> Deferred) { this.attestationRequestCallback = f } @@ -120,7 +150,7 @@ class AttestationCommunity(val database: AttestationStore) : Community() { this.attestationRequestCompleteCallback = f } - fun setVerifyRequestCallback(f: (attributeName: Peer, attributeHash: ByteArray) -> Boolean) { + fun setVerifyRequestCallback(f: (attributeName: Peer, attributeHash: ByteArray) -> Deferred) { this.verifyRequestCallback = f } @@ -197,22 +227,28 @@ class AttestationCommunity(val database: AttestationStore) : Community() { endpoint.send(peer, packet) } - private fun onRequestAttestation( + private suspend fun onRequestAttestation( peer: Peer, dist: GlobalTimeDistributionPayload, payload: RequestAttestationPayload, ) { val metadata = JSONObject(payload.metadata) val attribute = metadata.getString("attribute") - var value = metadata.optString("value").toByteArray() + var value: ByteArray? = metadata.optString("value").toByteArray() val pubkeyEncoded = metadata.getString("public_key") val idFormat = metadata.getString("id_format") val idAlgorithm = this.getIdAlgorithm(idFormat) val shouldSign = metadata.optBoolean("signature", false) - if (value.isEmpty()) { - value = this.attestationRequestCallback(peer, attribute, payload.metadata) + if (value?.isNotEmpty() == true) { + logger.info("Client passed value of his own") + } + + value = this.attestationRequestCallback(peer, attribute, payload.metadata).await() + if (value == null) { + logger.error("Failed to get value from callback") + return } val stringifiedValue = when (idFormat) { @@ -287,7 +323,7 @@ class AttestationCommunity(val database: AttestationStore) : Community() { fun verifyAttestationValues( socketAddress: IPv4Address, attestationHash: ByteArray, - values: ArrayList, + values: List, callback: ((ByteArray, List) -> Unit), idFormat: String, ) { @@ -313,7 +349,7 @@ class AttestationCommunity(val database: AttestationStore) : Community() { this.endpoint.send(socketAddress, packet) } - private fun onVerifyAttestationRequest( + private suspend fun onVerifyAttestationRequest( peer: Peer, payload: VerifyAttestationRequestPayload, ) { @@ -327,7 +363,7 @@ class AttestationCommunity(val database: AttestationStore) : Community() { logger.warn("Attestation blob for verification is empty: ${payload.hash}!") } - val value = verifyRequestCallback(peer, payload.hash) + val value = verifyRequestCallback(peer, payload.hash).await() if (!value) { logger.info("Verify request callback returned false for $peer, ${payload.hash}") return From 25731fabf3887ed7dc3228fe80af0d8fcf4249ef Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 29 Mar 2021 10:41:02 +0200 Subject: [PATCH 015/144] Add RevocationCommunity --- .../revocation/RevocationCommunity.kt | 282 ++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt new file mode 100644 index 00000000..fa83e616 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt @@ -0,0 +1,282 @@ +package nl.tudelft.ipv8.attestation.revocation + +import kotlinx.coroutines.* +import mu.KotlinLogging +import nl.tudelft.ipv8.Community +import nl.tudelft.ipv8.Overlay +import nl.tudelft.ipv8.Peer +import nl.tudelft.ipv8.attestation.AuthorityManager +import nl.tudelft.ipv8.attestation.revocation.caches.PENDING_REVOCATION_UPDATE_CACHE_PREFIX +import nl.tudelft.ipv8.attestation.revocation.caches.PendingRevocationUpdateCache +import nl.tudelft.ipv8.attestation.revocation.payloads.RevocationUpdateChunkPayload +import nl.tudelft.ipv8.attestation.revocation.payloads.RevocationUpdatePreviewPayload +import nl.tudelft.ipv8.attestation.revocation.payloads.RevocationUpdateRequestPayload +import nl.tudelft.ipv8.attestation.wallet.RequestCache +import nl.tudelft.ipv8.attestation.wallet.caches.PeerCache +import nl.tudelft.ipv8.keyvault.PrivateKey +import nl.tudelft.ipv8.messaging.* +import nl.tudelft.ipv8.peerdiscovery.Network +import nl.tudelft.ipv8.util.* +import org.json.JSONObject + +const val DELAY = 5000L +const val DEFAULT_GOSSIP_AMOUNT = 5 +private const val CHUNK_SIZE = 800 + +private val logger = KotlinLogging.logger {} + +const val REVOCATION_PRESENTATION_PAYLOAD = 1 +const val REVOCATION_UPDATE_REQUEST_PAYLOAD = 2 +const val REVOCATION_UPDATE_CHUNK_PAYLOAD = 3 + +class RevocationCommunity(val authorityManager: AuthorityManager) : Community() { + override val serviceId = "fdbb9c5c18bf480a4baba08d352727e66ee89173" + override var network = Network() + + private lateinit var gossipRoutine: Job + + private val lock = Object() + private val requestCache = RequestCache() + + +// private lateinit var onRevocationUpdatePreviewCallback: (List>) -> Unit +// private lateinit var onRevocationUpdateRequestCallback: (Map>) -> Unit + + init { + messageHandlers[REVOCATION_PRESENTATION_PAYLOAD] = ::onRevocationUpdatePreviewPayloadWrapper + messageHandlers[REVOCATION_UPDATE_REQUEST_PAYLOAD] = ::onRevocationUpdateRequestPayloadWrapper + messageHandlers[REVOCATION_UPDATE_CHUNK_PAYLOAD] = ::onRevocationUpdateChunkPayloadWrapper + } + + suspend fun start() { + this.gossipRoutine = GlobalScope.launch { + while (isActive) { + gossipRevocations(getRandomPeers(DEFAULT_GOSSIP_AMOUNT)) + delay(DELAY) + } + } + } + + fun revokeAttestation(attestationHashes: List) { + logger.info("Revoking ${attestationHashes.size} hash(es)!") + + val myPublicKeyHash = this.myPeer.publicKey.keyToHash() + var myAuthority = this.authorityManager.getAuthority(myPublicKeyHash) + if (myAuthority == null) { + this.authorityManager.addTrustedAuthority(this.myPeer.publicKey) + myAuthority = this.authorityManager.getAuthority(myPublicKeyHash)!! + } + val version = myAuthority.version + 1 + var signableData = serializeULong(version.toULong()) + attestationHashes.forEach { signableData += it } + val signature = (this.myPeer.key as PrivateKey).sign(sha1(signableData)) + + logger.info("Revoking signatures with version $version") + this.authorityManager.insertRevocations(myPublicKeyHash, version, signature, attestationHashes) + this.gossipMyRevocations() + } + + private fun onRevocationUpdatePreviewPayloadWrapper(packet: Packet) { + val (peer, payload) = packet.getAuthPayload(RevocationUpdatePreviewPayload.Deserializer) + logger.info("Received RevocationPresentationPayload from ${peer.mid}.") + this.onRevocationUpdatePreviewPayload(peer, payload) +// this.onRevocationUpdatePreviewCallback(payload.revocationRefs) + } + + private fun onRevocationUpdateRequestPayloadWrapper(packet: Packet) { + val (peer, payload) = packet.getAuthPayload(RevocationUpdateRequestPayload.Deserializer) + logger.info("Received RevocationUpdateRequestPayload from ${peer.mid}.") + this.onRevocationUpdateRequestPayload(peer, payload) + } + + private fun onRevocationUpdateChunkPayloadWrapper(packet: Packet) { + val (peer, payload) = packet.getAuthPayload(RevocationUpdateChunkPayload.Deserializer) + logger.info("Received RevocationUpdateChunkPayload ${payload.sequenceNumber} from ${peer.mid}.") + this.onRevocationUpdateChunkPayload(peer, payload) + } + + private fun onRevocationUpdatePreviewPayload(peer: Peer, payload: RevocationUpdatePreviewPayload) { + val remoteRefs = payload.revocationRefs + val localRefs = this.authorityManager.getLatestRevocationPreviews() + val requestedRefs = hashMapOf() + + for (key in remoteRefs.keys) { + if (localRefs.get(key) == null) { + requestedRefs[key] = 0L + } else if (localRefs[key]!! < remoteRefs[key]!!) { + requestedRefs[key] = remoteRefs[key]!! + } + } + + if (requestedRefs.isNotEmpty()) { + logger.info("Requesting revocation update.") + logger.info("Remoterefs: $remoteRefs") + logger.info("Localrefs: $localRefs") + val updateRequestPayload = RevocationUpdateRequestPayload(requestedRefs) + val packet = serializePacket(REVOCATION_UPDATE_REQUEST_PAYLOAD, updateRequestPayload) + if (!this.requestCache.has(PeerCache.idFromAddress( + PENDING_REVOCATION_UPDATE_CACHE_PREFIX, peer.mid)) + ) { + this.requestCache.add(PendingRevocationUpdateCache(this.requestCache, peer.mid)) + this.endpoint.send(peer, packet) + } + } + } + + private fun onRevocationUpdateRequestPayload(peer: Peer, payload: RevocationUpdateRequestPayload) { + // TODO make sure we want to send to this clients. + + val revocations = hashMapOf>() + payload.revocationRefs.forEach { (hash, version) -> + revocations[hash] = this.authorityManager.getRevocations(hash.bytes, version) + } + + val blob = serializeRevocationMap(revocations) + val hash = sha1(blob) + var sequenceNumber = 0 +// logger.info { "Sending update ${JSONObject(revocations).toString()}" } + for (i in blob.indices step CHUNK_SIZE) { + val endIndex = if (i + CHUNK_SIZE > blob.size) blob.size else i + CHUNK_SIZE + val chunkPayload = RevocationUpdateChunkPayload(hash, sequenceNumber, blob.copyOfRange(i, endIndex)) + val packet = serializePacket(REVOCATION_UPDATE_CHUNK_PAYLOAD, chunkPayload) + logger.info("Sending update chunk $sequenceNumber") + Thread.sleep(10) + this.endpoint.send(peer, packet) + sequenceNumber += 1 + } + + } + + private fun onRevocationUpdateChunkPayload(peer: Peer, payload: RevocationUpdateChunkPayload) { + val (prefix, id) = PeerCache.idFromAddress(PENDING_REVOCATION_UPDATE_CACHE_PREFIX, peer.mid) + if (this.requestCache.has(prefix, id)) { + val cache = this.requestCache.get(prefix, id) as PendingRevocationUpdateCache + var localBlob = byteArrayOf() + cache.revocationMap[payload.sequenceNumber] = payload.data + cache.revocationMap.keys.sorted().forEach { localBlob += cache.revocationMap[it]!! } + if (sha1(localBlob).contentEquals(payload.hash)) { + this.requestCache.pop(prefix, id) as PendingRevocationUpdateCache + val revocationMap = this.deserializeRevocationMap(localBlob) + logger.info("Received update: ${JSONObject(revocationMap).toString()}") + revocationMap.forEach { (hash, list) -> + for (blob in list) { + val authority = this.authorityManager.getAuthority(hash.bytes) + + if (authority?.publicKey != null) { + var signable = serializeULong(blob.version.toULong()) + blob.revocations.forEach { signable += it } + if (!authority.publicKey.verify(blob.signature, signable)) { + logger.warn("Peer ${peer.mid} might have altered the revoked signatures, skipping!") + continue + } + } else { + logger.info("Inserting revocations without verification as authority is not recognized.") + } + + this.authorityManager.insertRevocations( + hash.bytes, + blob.version, + blob.signature, + blob.revocations) + } + } + } + } else { + logger.warn { "Received update we did not request, dropping." } + } + } + + private fun serializeRevocationMap(map: Map>): ByteArray { + val size = map.size + var out = serializeUInt(size.toUInt()) + map.forEach { (keyHashKey, list) -> + out += keyHashKey.bytes + val versionAmount = list.size.toUInt() + out += serializeUInt(versionAmount) + for (blob in list) { + out += serializeULong(blob.version.toULong()) + out += serializeVarLen(blob.signature) + val revocationAmount = blob.revocations.size.toUInt() + out += serializeUInt(revocationAmount) + for (revocation in blob.revocations) { + out += revocation + } + } + } + return out + } + + private fun deserializeRevocationMap(serialized: ByteArray): Map> { + var localOffset = 0 + val out = hashMapOf>() + val size = deserializeUInt(serialized, localOffset).toInt() + localOffset += SERIALIZED_UINT_SIZE + for (i in 0 until size) { + val keyHash = serialized.copyOfRange(localOffset, localOffset + SERIALIZED_SHA1_HASH_SIZE) + localOffset += SERIALIZED_SHA1_HASH_SIZE + val versionAmount = deserializeUInt(serialized, localOffset).toInt() + localOffset += SERIALIZED_UINT_SIZE + + val revocationBlobs = mutableListOf() + for (j in 0 until versionAmount) { + val version = deserializeULong(serialized, localOffset).toLong() + localOffset += SERIALIZED_ULONG_SIZE + val (signature, signatureOffset) = deserializeVarLen(serialized, localOffset) + localOffset += signatureOffset + val revocationAmount = deserializeUInt(serialized, localOffset).toInt() + localOffset += SERIALIZED_UINT_SIZE + + val revocations = mutableListOf() + for (k in 0 until revocationAmount) { + val revocation = serialized.copyOfRange(localOffset, localOffset + SERIALIZED_SHA1_HASH_SIZE) + revocations.add(revocation) + localOffset += SERIALIZED_SHA1_HASH_SIZE + } + revocationBlobs.add(RevocationBlob(version, signature, revocations)) + } + out[keyHash.toKey()] = revocationBlobs + } + return out + } + + +// fun setOnRevocationPresentationCallback(f: (List, List) -> Unit) { +// this.onRevocationUpdatePreviewCallback = f +// } + + fun shutdown() { + this.gossipRoutine.cancel() + } + + private fun gossipMyRevocations() { + val peers = this.getPeers() + this.gossipRevocations(peers) + } + + private fun getRandomPeers(amount: Int): List { + return this.getPeers().random(amount).toList() + } + + private fun gossipRevocations(peers: List) { + val revocations = this.authorityManager.getLatestRevocationPreviews() + val payload = RevocationUpdatePreviewPayload(revocations) + val packet = serializePacket(REVOCATION_PRESENTATION_PAYLOAD, payload) + runBlocking { + peers.forEach { + launch { + endpoint.send(it, packet) + } + } + } + } + + class Factory( + private val authorityManager: AuthorityManager, + ) : Overlay.Factory(RevocationCommunity::class.java) { + override fun create(): RevocationCommunity { + return RevocationCommunity(authorityManager) + } + } + + +} From b38933c6fa052e243d9eb3eb370b752438259d27 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 29 Mar 2021 10:41:28 +0200 Subject: [PATCH 016/144] Update AuthorityManager --- .../ipv8/attestation/AuthorityManager.kt | 108 ++++++++++++++++ .../attestation/TrustedAuthorityManager.kt | 60 --------- .../revocation/AuthoritySQLiteStore.kt | 121 ++++++++++++++++++ .../attestation/revocation/AuthorityStore.kt | 33 +++++ 4 files changed, 262 insertions(+), 60 deletions(-) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt delete mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/TrustedAuthorityManager.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt new file mode 100644 index 00000000..050301b9 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt @@ -0,0 +1,108 @@ +package nl.tudelft.ipv8.attestation + +import nl.tudelft.ipv8.attestation.revocation.AuthorityStore +import nl.tudelft.ipv8.attestation.revocation.RevocationBlob +import nl.tudelft.ipv8.keyvault.PublicKey +import nl.tudelft.ipv8.util.ByteArrayKey +import nl.tudelft.ipv8.util.toKey + +class Authority( + val publicKey: PublicKey?, + val hash: ByteArray, + var version: Long = 0L, + val recognized: Boolean = false, +) + +class Revocations( + val publicKeyHash: String, + val encryptedVersion: ByteArray, + val signature: String, + val revocations: List, +) + +class AuthorityManager(val database: AuthorityStore) { + + private val trustedAuthorities = hashMapOf() + private val lock = Object() + + fun loadTrustedAuthorities() { + val authorities = database.getRecognizedAuthorities() + synchronized(lock) { + authorities.forEach { + trustedAuthorities[it.hash.toKey()] = it + } + } + } + + fun insertRevocations(publicKeyHash: ByteArray, versionNumber: Long, signature: ByteArray, revokedHashes: List) { + database.insertRevocations(publicKeyHash, versionNumber, signature, revokedHashes) + if (this.trustedAuthorities.containsKey(publicKeyHash.toKey())) { + this.trustedAuthorities[publicKeyHash.toKey()]!!.version = versionNumber + } + } + + fun getLatestRevocationPreviews(): Map { + val authorities = database.getKnownAuthorities() + val localRefs = hashMapOf() + authorities.forEach { + localRefs[it.hash.toKey()] = it.version + } + return localRefs + } + + fun getRevocations(publicKeyHash: ByteArray, fromVersion: Long = 0): List { + val versions = database.getVersionsSince(publicKeyHash, fromVersion) + return database.getRevocations(publicKeyHash, versions) + } + + fun loadDefaultAuthorities() { + TODO("Preinstalled Authorities yet to be designed.") + } + + fun getAuthorities(): List { + return this.database.getKnownAuthorities() + } + + fun addTrustedAuthority(publicKey: PublicKey) { + val hash = publicKey.keyToHash() + if (!this.contains(hash)) { + val localAuthority = database.getAuthorityByHash(hash) + if (localAuthority == null) { + database.insertAuthority(publicKey) + synchronized(lock) { + this.trustedAuthorities[hash.toKey()] = Authority(publicKey, hash) + } + } else { + database.recognizeAuthority(publicKey.keyToHash()) + synchronized(lock) { + this.trustedAuthorities[hash.toKey()] = localAuthority + } + } + } + } + + fun deleteTrustedAuthority(hash: ByteArray) { + if (this.contains(hash)) { + this.trustedAuthorities.remove(hash) + this.database.disregardAuthority(hash) + } + } + + fun getTrustedAuthority(hash: ByteArray): Authority? { + return this.trustedAuthorities.get(hash.toKey()) + } + + fun getAuthority(hash: ByteArray): Authority? { + return this.trustedAuthorities.get(hash.toKey()) ?: database.getAuthorityByHash(hash) + } + + fun deleteTrustedAuthority(publicKey: PublicKey) { + return this.deleteTrustedAuthority(publicKey.keyToHash()) + } + + fun contains(hash: ByteArray): Boolean { + return this.trustedAuthorities.containsKey(hash.toKey()) + } + + +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/TrustedAuthorityManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/TrustedAuthorityManager.kt deleted file mode 100644 index b3483f79..00000000 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/TrustedAuthorityManager.kt +++ /dev/null @@ -1,60 +0,0 @@ -package nl.tudelft.ipv8.attestation - -import nl.tudelft.ipv8.attestation.wallet.AttestationStore -import nl.tudelft.ipv8.keyvault.PublicKey -import nl.tudelft.ipv8.util.toHex - -class Authority( - val publicKey: PublicKey, - val hash: String, -) - -class TrustedAuthorityManager(private val database: AttestationStore) { - - private val trustedAuthorities = hashMapOf() - private val lock = Object() - - fun loadAuthorities() { - val authorities = database.getAllAuthorities() - synchronized(lock) { - authorities.forEach { - trustedAuthorities[it.hash] = Authority(it.publicKey, it.hash) - } - } - } - - fun loadDefaultAuthorities() { - TODO("Preinstalled Authorities yet to be designed.") - } - - fun getAuthorities(): List { - return this.database.getAllAuthorities() - } - - fun addTrustedAuthority(publicKey: PublicKey) { - val hash = publicKey.keyToHash().toHex() - if (!this.contains(hash)) { - database.insertAuthority(publicKey, hash) - synchronized(lock) { - this.trustedAuthorities[hash] = Authority(publicKey, hash) - } - } - } - - fun deleteTrustedAuthority(hash: String) { - if (this.contains(hash)) { - this.trustedAuthorities.remove(hash) - this.database.deleteAuthorityByHash(hash) - } - } - - fun deleteTrustedAuthority(publicKey: PublicKey) { - return this.deleteTrustedAuthority(publicKey.keyToHash().toHex()) - } - - fun contains(hash: String): Boolean { - return this.trustedAuthorities.containsKey(hash) - } - - -} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt new file mode 100644 index 00000000..93efb7d2 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt @@ -0,0 +1,121 @@ +package nl.tudelft.ipv8.attestation.revocation + +import nl.tudelft.ipv8.attestation.Authority +import nl.tudelft.ipv8.keyvault.PublicKey +import nl.tudelft.ipv8.keyvault.defaultCryptoProvider +import nl.tudelft.ipv8.sqldelight.Database +import nl.tudelft.ipv8.sqldelight.GetAllRevocations + +private val authorityMapper: ( + ByteArray?, + ByteArray, + Long?, + Long?, +) -> Authority = { public_key, hash, version, recognized -> + Authority(public_key?.let { defaultCryptoProvider.keyFromPublicBin(it) }, + hash, + version ?: 0L, + recognized?.toInt() == 1) +} + +class AuthoritySQLiteStore(database: Database) : AuthorityStore { + private val dao = database.dbAuthorityQueries + + override fun getKnownAuthorities(): List { + return dao.getAllAuthorities(authorityMapper).executeAsList() + } + + override fun getRecognizedAuthorities(): List { + return dao.getAllRecognizedAuthorities(authorityMapper).executeAsList() + } + + override fun getAuthorityByHash(hash: ByteArray): Authority? { + return dao.getAuthorityByHash(hash, authorityMapper).executeAsOneOrNull() + } + + override fun recognizeAuthority(hash: ByteArray) { + return dao.recognizeAuthority(hash) + } + + override fun disregardAuthority(hash: ByteArray) { + return dao.disregardAuthority(hash) + } + + override fun insertAuthority(publicKey: PublicKey) { + return dao.insertAuthority(publicKey.keyToBin(), publicKey.keyToHash(), null, null) + } + + override fun insertAuthority(hash: ByteArray) { + return dao.insertAuthority(null, hash, null, null) + } + + override fun insertRevocations( + publicKeyHash: ByteArray, + version: Long, + signature: ByteArray, + revokedHashes: List, + ) { + var authorityId = dao.getAuthorityIdByHash(publicKeyHash).executeAsOneOrNull() + if (authorityId == null) { + this.insertAuthority(publicKeyHash) + authorityId = dao.getAuthorityIdByHash(publicKeyHash).executeAsOne() + } + + var versionId = + dao.getVersionByAuthorityIDandVersionNumber(authorityId, version).executeAsOneOrNull()?.version_id + if (versionId == null) { + dao.insertVersion(authorityId, version, signature) + versionId = dao.getVersionByAuthorityIDandVersionNumber(authorityId, version).executeAsOne().version_id + } + + revokedHashes.forEach { dao.insertRevocation(authorityId, versionId, it) } + dao.updateVersionFor(versionId, publicKeyHash) + } + + override fun getVersionsSince(publicKeyHash: ByteArray, sinceVersion: Long): List { + val authorityId = dao.getAuthorityIdByHash(publicKeyHash).executeAsOneOrNull() + return if (authorityId == null) { + emptyList() + } else + dao.getVersionsSince(authorityId, sinceVersion).executeAsList() + } + + override fun getRevocations( + publicKeyHash: ByteArray, + versions: List, + ): List { + val authorityId = dao.getAuthorityIdByHash(publicKeyHash).executeAsOne() + val versionEntries = + dao.getVersionsByAuthorityIDandVersionNumbers(authorityId, versions).executeAsList() + + return versionEntries.map { + RevocationBlob(it.version_number, + it.signature, + dao.getRevocationsByAuthorityIdAndVersionId(authorityId, it.version_id) + .executeAsList()) + } + } + + override fun getAllRevocations(): List { + return dao.getAllRevocations().executeAsList() + } + + +// fun insertAuthority(publicKey: PublicKey, hash: String, version: Long, recognized: Boolean) { +// val keyBin = publicKey.keyToBin() +// dao.insertAuthority(keyBin, hash, version, if (recognized) 1 else 0) +// } +// +// fun getAuthorityByPublicKey(publicKey: PublicKey): Authority? { +// return dao.getAuthorityByPublicKey(publicKey.keyToBin(), authorityMapper).executeAsOneOrNull() +// } +// +// fun getAuthorityByHash(hash: String): Authority? { +// return dao.getAuthorityByHash(hash, authorityMapper).executeAsOneOrNull() +// } +// +// fun deleteAuthorityByHash(hash: String) { +// return dao.deleteAuthorityByHash(hash) +// } + +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt new file mode 100644 index 00000000..d97e2a41 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt @@ -0,0 +1,33 @@ +package nl.tudelft.ipv8.attestation.revocation + +import nl.tudelft.ipv8.attestation.Authority +import nl.tudelft.ipv8.attestation.Revocations +import nl.tudelft.ipv8.keyvault.PublicKey +import nl.tudelft.ipv8.sqldelight.GetAllRevocations + +class RevocationBlob(val version: Long, val signature: ByteArray, val revocations: List) + +interface AuthorityStore { + + fun getKnownAuthorities(): List + fun getRecognizedAuthorities(): List + fun getAuthorityByHash(hash: ByteArray): Authority? + fun recognizeAuthority(hash: ByteArray) + fun disregardAuthority(hash: ByteArray) + fun insertAuthority(publicKey: PublicKey) + fun insertAuthority(hash: ByteArray) + + fun insertRevocations( + publicKeyHash: ByteArray, + version: Long, + signature: ByteArray, + revokedHashes: List, + ) + + fun getRevocations(publicKeyHash: ByteArray, versions: List): List + + fun getVersionsSince(publicKeyHash: ByteArray, sinceVersion: Long): List + + fun getAllRevocations(): List + +} From bc4c08b87baa19460e84c530ee9905b770522a8f Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 29 Mar 2021 10:41:39 +0200 Subject: [PATCH 017/144] Add payload definitions --- .../payloads/RevocationUpdateChunkPayload.kt | 33 ++++++++++++++ .../RevocationUpdatePreviewPayload.kt | 43 +++++++++++++++++++ .../RevocationUpdateRequestPayload.kt | 22 ++++++++++ 3 files changed, 98 insertions(+) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateChunkPayload.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdatePreviewPayload.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateRequestPayload.kt diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateChunkPayload.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateChunkPayload.kt new file mode 100644 index 00000000..c3aaf436 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateChunkPayload.kt @@ -0,0 +1,33 @@ +package nl.tudelft.ipv8.attestation.revocation.payloads + +import nl.tudelft.ipv8.messaging.* +import nl.tudelft.ipv8.util.hexToBytes +import nl.tudelft.ipv8.util.toHex +import java.lang.RuntimeException + +class RevocationUpdateChunkPayload( + val hash: ByteArray, + val sequenceNumber: Int, + val data: ByteArray, +) : Serializable { + override fun serialize(): ByteArray { + return hash + serializeUInt(sequenceNumber.toUInt()) + serializeVarLen(data) + } + + companion object Deserializer : Deserializable { + override fun deserialize(buffer: ByteArray, offset: Int): Pair { + var localOffset = offset + val hash = buffer.copyOfRange(localOffset, localOffset + SERIALIZED_SHA1_HASH_SIZE) + localOffset += SERIALIZED_SHA1_HASH_SIZE + + val sequenceNumber = deserializeUInt(buffer, localOffset).toInt() + localOffset += SERIALIZED_UINT_SIZE + + val (data, dataOffset) = deserializeVarLen(buffer, localOffset) + + return Pair(RevocationUpdateChunkPayload(hash, sequenceNumber, data), localOffset + dataOffset) + } + } + +} + diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdatePreviewPayload.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdatePreviewPayload.kt new file mode 100644 index 00000000..7b576b7b --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdatePreviewPayload.kt @@ -0,0 +1,43 @@ +package nl.tudelft.ipv8.attestation.revocation.payloads + +import nl.tudelft.ipv8.keyvault.PublicKey +import nl.tudelft.ipv8.keyvault.defaultCryptoProvider +import nl.tudelft.ipv8.messaging.* +import nl.tudelft.ipv8.util.* +import java.lang.RuntimeException + +open class RevocationUpdatePreviewPayload( + val revocationRefs: Map, +) : Serializable { + override fun serialize(): ByteArray { + + var out = byteArrayOf() + revocationRefs.forEach { + out += it.key.bytes + out += serializeULong(it.value.toULong()) + } + return serializeUInt(revocationRefs.size.toUInt()) + out + } + + companion object Deserializer : Deserializable { + override fun deserialize(buffer: ByteArray, offset: Int): Pair { + var localOffset = offset + val size = deserializeUInt(buffer, localOffset).toInt() + localOffset += SERIALIZED_UINT_SIZE + + val refs = hashMapOf() + + for (i in 0 until size) { + val hash = buffer.copyOfRange(localOffset, localOffset + SERIALIZED_SHA1_HASH_SIZE) + localOffset += SERIALIZED_SHA1_HASH_SIZE + val version = deserializeULong(buffer, localOffset).toLong() + localOffset += SERIALIZED_ULONG_SIZE + refs[hash.toKey()] = version + } + + return Pair(RevocationUpdateRequestPayload(refs), localOffset) + } + } + +} + diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateRequestPayload.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateRequestPayload.kt new file mode 100644 index 00000000..d3e78ac6 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateRequestPayload.kt @@ -0,0 +1,22 @@ +package nl.tudelft.ipv8.attestation.revocation.payloads + +import nl.tudelft.ipv8.keyvault.PublicKey +import nl.tudelft.ipv8.keyvault.defaultCryptoProvider +import nl.tudelft.ipv8.messaging.* +import nl.tudelft.ipv8.util.ByteArrayKey +import nl.tudelft.ipv8.util.hexToBytes +import nl.tudelft.ipv8.util.toHex +import org.json.JSONObject + +class RevocationUpdateRequestPayload( + revocationRefs: Map +) : RevocationUpdatePreviewPayload(revocationRefs) { + + companion object Deserializer : Deserializable { + override fun deserialize(buffer: ByteArray, offset: Int): Pair { + return RevocationUpdatePreviewPayload.deserialize(buffer, offset) as Pair + } + } + +} + From d3d7efa6dbc74fab6b83c55ffc61e77d70dc2a39 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 29 Mar 2021 10:42:09 +0200 Subject: [PATCH 018/144] Add revocation cache --- .../caches/PendingRevocationUpdateCache.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt new file mode 100644 index 00000000..51b65353 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt @@ -0,0 +1,15 @@ +package nl.tudelft.ipv8.attestation.revocation.caches + +import nl.tudelft.ipv8.attestation.wallet.RequestCache +import nl.tudelft.ipv8.attestation.wallet.caches.HashCache +import nl.tudelft.ipv8.attestation.wallet.caches.NumberCache +import nl.tudelft.ipv8.attestation.wallet.caches.PeerCache + +const val PENDING_REVOCATION_UPDATE_CACHE_PREFIX = "receive-revocation" + +class PendingRevocationUpdateCache(requestCache: RequestCache, peerMID: String) : + NumberCache(requestCache, PENDING_REVOCATION_UPDATE_CACHE_PREFIX, PeerCache.idFromAddress( + PENDING_REVOCATION_UPDATE_CACHE_PREFIX, peerMID).second) { + + val revocationMap = hashMapOf() +} From 6552c4dd38275e3aae07e161f7234e94d3b4315e Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 29 Mar 2021 10:42:28 +0200 Subject: [PATCH 019/144] Add authority database definitions --- .../tudelft/ipv8/sqldelight/DbAttestation.sq | 20 ------ .../nl/tudelft/ipv8/sqldelight/DbAuthority.sq | 71 +++++++++++++++++++ 2 files changed, 71 insertions(+), 20 deletions(-) create mode 100644 ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq diff --git a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAttestation.sq b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAttestation.sq index b7a88a93..a8691260 100644 --- a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAttestation.sq +++ b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAttestation.sq @@ -8,11 +8,6 @@ CREATE TABLE attestations ( attestor_key BLOB ); -CREATE TABLE authorities ( - public_key BLOB NOT NULL, - hash TEXT NOT NULL -); - getAllAttestations: SELECT * FROM attestations; @@ -24,18 +19,3 @@ SELECT blob FROM attestations WHERE hash = ?; deleteAttestationByHash: DELETE FROM attestations WHERE hash = ?; - -getAllAuthorities: -SELECT * FROM authorities; - -insertAuthority: -INSERT INTO authorities (public_key, hash) VALUES (?, ?); - -getAuthorityByPublicKey: -SELECT public_key, hash FROM authorities WHERE public_key = ?; - -getAuthorityByHash: -SELECT public_key, hash FROM authorities WHERE hash = ?; - -deleteAuthorityByHash: -DELETE FROM authorities WHERE hash = ?; diff --git a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq new file mode 100644 index 00000000..e8ac68ee --- /dev/null +++ b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq @@ -0,0 +1,71 @@ +CREATE TABLE revocations ( + authority_id INTEGER NOT NULL, + version_id INTEGER NOT NULL, + attestation_hash BLOB NOT NULL, + FOREIGN KEY(authority_id) REFERENCES authorities(authority_id), + FOREIGN KEY(version_id) REFERENCES versions(version_id) +); + +CREATE TABLE versions ( + version_id INTEGER PRIMARY KEY, + authority_id INTEGER NOT NULL, + version_number INTEGER NOT NULL, + signature BLOB NOT NULL, + FOREIGN KEY(authority_id) REFERENCES authorities(authority_id) +); + +CREATE TABLE authorities ( + authority_id INTEGER PRIMARY KEY, + public_key BLOB, + public_key_hash BLOB UNIQUE NOT NULL, + latest_version_id INTEGER, + recognized INTEGER +); + +insertRevocation: +INSERT INTO revocations (authority_id, version_id, attestation_hash) VALUES (?, ?, ?); + +insertVersion: +INSERT INTO versions (authority_id, version_number, signature) VALUES (?, ?, ?); + +insertAuthority: +INSERT INTO authorities (public_key, public_key_hash, latest_version_id, recognized) VALUES (?, ?, ?, ?); + +getAllRecognizedAuthorities: +SELECT authorities.public_key, authorities.public_key_hash, versions.version_number, authorities.recognized FROM authorities LEFT JOIN versions ON authorities.latest_version_id = versions.version_id WHERE authorities.recognized = 1; + +getAllAuthorities: +SELECT authorities.public_key, authorities.public_key_hash, versions.version_number, authorities.recognized FROM authorities LEFT JOIN versions ON authorities.latest_version_id = versions.version_id; + +getAuthorityIdByHash: +SELECT authority_id FROM authorities WHERE authorities.public_key_hash = ? LIMIT 1; + +getAuthorityByHash: +SELECT authorities.public_key, authorities.public_key_hash, versions.version_number, authorities.recognized FROM authorities LEFT JOIN versions ON authorities.latest_version_id = versions.version_id WHERE public_key_hash = ?; + +recognizeAuthority: +UPDATE authorities SET recognized = 1 WHERE public_key_hash = ?; + +disregardAuthority: +UPDATE authorities SET recognized = 0 WHERE public_key_hash = ?; + +getRevocationsByAuthorityId: +SELECT attestation_hash FROM revocations WHERE authority_id = ?; + +getRevocationsByAuthorityIdAndVersionId: +SELECT attestation_hash FROM revocations WHERE authority_id = ? AND version_id = ?; + +updateVersionFor: +UPDATE authorities SET latest_version_id = ? WHERE public_key_hash = ?; + +getVersionByAuthorityIDandVersionNumber: +SELECT * FROM versions WHERE authority_id = ? AND version_number = ?; + +getVersionsByAuthorityIDandVersionNumbers: +SELECT * FROM versions WHERE authority_id = ? AND version_number IN ?; + +getVersionsSince: +SELECT version_number FROM versions WHERE authority_id = ? AND version_number > ?; + +getAllRevocations: +SELECT authorities.public_key_hash, versions.version_number, versions.signature, revocations.attestation_hash FROM authorities LEFT JOIN versions ON authorities.latest_version_id = versions.version_id LEFT JOIN revocations ON authorities.authority_id = revocations.authority_id; \ No newline at end of file From 843b2722f374c8211bade2547e69993f61ee84b7 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 31 Mar 2021 11:17:07 +0200 Subject: [PATCH 020/144] Make revocation update per version and public key --- .../revocation/RevocationCommunity.kt | 248 +++++++++++++----- .../caches/PendingRevocationUpdateCache.kt | 25 +- .../payloads/RevocationUpdateChunkPayload.kt | 26 +- 3 files changed, 222 insertions(+), 77 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt index fa83e616..9e16351a 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt @@ -17,9 +17,8 @@ import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.messaging.* import nl.tudelft.ipv8.peerdiscovery.Network import nl.tudelft.ipv8.util.* -import org.json.JSONObject -const val DELAY = 5000L +const val DELAY = 30000L const val DEFAULT_GOSSIP_AMOUNT = 5 private const val CHUNK_SIZE = 800 @@ -73,7 +72,7 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() logger.info("Revoking signatures with version $version") this.authorityManager.insertRevocations(myPublicKeyHash, version, signature, attestationHashes) - this.gossipMyRevocations() +// this.gossipMyRevocations() } private fun onRevocationUpdatePreviewPayloadWrapper(packet: Packet) { @@ -101,91 +100,212 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() val requestedRefs = hashMapOf() for (key in remoteRefs.keys) { - if (localRefs.get(key) == null) { - requestedRefs[key] = 0L - } else if (localRefs[key]!! < remoteRefs[key]!!) { - requestedRefs[key] = remoteRefs[key]!! + val localVersion = localRefs.get(key) + val remoteVersion = remoteRefs[key]!! + + // If we're already waiting on a version, wait until we receive it or the cache times out. + // We want to receive versions concurrent for now. + val idPair = PendingRevocationUpdateCache.generateId(peer.publicKey.keyToHash(), key.bytes, (localVersion ?: 0L) + 1) + if (!this.requestCache.has(idPair)) { + if (localVersion == null) { + requestedRefs[key] = 0L + for (i in 1L..remoteVersion) { + this.requestCache.add(PendingRevocationUpdateCache(this.requestCache, peer.publicKey.keyToHash(), key.bytes, i)) + } + } else if (localVersion < remoteVersion) { + requestedRefs[key] = localVersion + for (i in (localVersion + 1L)..remoteVersion) { + this.requestCache.add(PendingRevocationUpdateCache(this.requestCache, peer.publicKey.keyToHash(), key.bytes, i)) + } + } + } else { + logger.info("Not requesting V$remoteVersion:${key.bytes.toHex()} as we have already requested it.") } } if (requestedRefs.isNotEmpty()) { - logger.info("Requesting revocation update.") - logger.info("Remoterefs: $remoteRefs") - logger.info("Localrefs: $localRefs") val updateRequestPayload = RevocationUpdateRequestPayload(requestedRefs) val packet = serializePacket(REVOCATION_UPDATE_REQUEST_PAYLOAD, updateRequestPayload) - if (!this.requestCache.has(PeerCache.idFromAddress( - PENDING_REVOCATION_UPDATE_CACHE_PREFIX, peer.mid)) - ) { - this.requestCache.add(PendingRevocationUpdateCache(this.requestCache, peer.mid)) - this.endpoint.send(peer, packet) - } + logger.info("Requesting revocation update: ${requestedRefs}.") +// logger.info("Remoterefs: $remoteRefs") +// logger.info("Localrefs: $localRefs") +// this.requestCache.add(PendingRevocationUpdateCache(this.requestCache, peer.mid)) + this.endpoint.send(peer, packet) } } - private fun onRevocationUpdateRequestPayload(peer: Peer, payload: RevocationUpdateRequestPayload) { + + private fun onRevocationUpdateRequestPayload( + peer: Peer, + payload: RevocationUpdateRequestPayload, + bulkSending: Boolean = false, + ) { // TODO make sure we want to send to this clients. - val revocations = hashMapOf>() - payload.revocationRefs.forEach { (hash, version) -> - revocations[hash] = this.authorityManager.getRevocations(hash.bytes, version) - } + if (bulkSending) { + val revocations = hashMapOf>() + payload.revocationRefs.forEach { (hash, version) -> + revocations[hash] = this.authorityManager.getRevocations(hash.bytes, version) + } - val blob = serializeRevocationMap(revocations) - val hash = sha1(blob) - var sequenceNumber = 0 -// logger.info { "Sending update ${JSONObject(revocations).toString()}" } - for (i in blob.indices step CHUNK_SIZE) { - val endIndex = if (i + CHUNK_SIZE > blob.size) blob.size else i + CHUNK_SIZE - val chunkPayload = RevocationUpdateChunkPayload(hash, sequenceNumber, blob.copyOfRange(i, endIndex)) - val packet = serializePacket(REVOCATION_UPDATE_CHUNK_PAYLOAD, chunkPayload) - logger.info("Sending update chunk $sequenceNumber") - Thread.sleep(10) - this.endpoint.send(peer, packet) - sequenceNumber += 1 + val blob = serializeRevocationMap(revocations) + val hash = sha1(blob) + var sequenceNumber = 0 + for (i in blob.indices step CHUNK_SIZE) { + val endIndex = if (i + CHUNK_SIZE > blob.size) blob.size else i + CHUNK_SIZE + val chunkPayload = RevocationUpdateChunkPayload(sequenceNumber, + hash, + this.myPeer.publicKey.keyToHash(), + 0L, + blob.copyOfRange(i, endIndex)) + val packet = serializePacket(REVOCATION_UPDATE_CHUNK_PAYLOAD, chunkPayload) + logger.info("Sending update chunk $sequenceNumber") + this.endpoint.send(peer, packet) + sequenceNumber += 1 + } + } else { + val revocations = mutableListOf() + + payload.revocationRefs.forEach { (hash, version) -> + revocations.addAll(this.authorityManager.getRevocations(hash.bytes, version)) + } + logger.info("CLIENT REQUESTED THE FOLLOWING VERSIONS: ") + revocations.forEach { print("${it.version}, ") } + + // TODO: ths could be performed in coroutines, however, would most likely lead to package lost. + for (rev in revocations) { +// logger.info("Sending version ${rev.version}") + val blob = serializeRevocationBlob(rev) + val hash = sha1(blob) + var sequenceNumber = 0 + for (i in blob.indices step CHUNK_SIZE) { + val endIndex = if (i + CHUNK_SIZE > blob.size) blob.size else i + CHUNK_SIZE + val chunkPayload = + RevocationUpdateChunkPayload(sequenceNumber, hash, rev.publicKeyHash, rev.version, + blob.copyOfRange(i, endIndex)) + val packet = serializePacket(REVOCATION_UPDATE_CHUNK_PAYLOAD, chunkPayload) + logger.info("Sending update chunk $sequenceNumber") + this.endpoint.send(peer, packet) + sequenceNumber += 1 + } + } } } - private fun onRevocationUpdateChunkPayload(peer: Peer, payload: RevocationUpdateChunkPayload) { - val (prefix, id) = PeerCache.idFromAddress(PENDING_REVOCATION_UPDATE_CACHE_PREFIX, peer.mid) - if (this.requestCache.has(prefix, id)) { - val cache = this.requestCache.get(prefix, id) as PendingRevocationUpdateCache - var localBlob = byteArrayOf() - cache.revocationMap[payload.sequenceNumber] = payload.data - cache.revocationMap.keys.sorted().forEach { localBlob += cache.revocationMap[it]!! } - if (sha1(localBlob).contentEquals(payload.hash)) { - this.requestCache.pop(prefix, id) as PendingRevocationUpdateCache - val revocationMap = this.deserializeRevocationMap(localBlob) - logger.info("Received update: ${JSONObject(revocationMap).toString()}") - revocationMap.forEach { (hash, list) -> - for (blob in list) { - val authority = this.authorityManager.getAuthority(hash.bytes) - - if (authority?.publicKey != null) { - var signable = serializeULong(blob.version.toULong()) - blob.revocations.forEach { signable += it } - if (!authority.publicKey.verify(blob.signature, signable)) { - logger.warn("Peer ${peer.mid} might have altered the revoked signatures, skipping!") - continue + private fun onRevocationUpdateChunkPayload( + peer: Peer, + payload: RevocationUpdateChunkPayload, + bulkSending: Boolean = false, + ) { + if (bulkSending) { + val (prefix, id) = PeerCache.idFromAddress(PENDING_REVOCATION_UPDATE_CACHE_PREFIX, peer.mid) + if (this.requestCache.has(prefix, id)) { + val cache = this.requestCache.get(prefix, id) as PendingRevocationUpdateCache + var localBlob = byteArrayOf() + cache.revocationMap[payload.sequenceNumber] = payload.data + cache.revocationMap.keys.sorted().forEach { localBlob += cache.revocationMap[it]!! } + if (sha1(localBlob).contentEquals(payload.hash)) { + this.requestCache.pop(prefix, id) as PendingRevocationUpdateCache + val revocationMap = this.deserializeRevocationMap(localBlob) + logger.info("Received update: ${revocationMap.keys.size}") + revocationMap.forEach { (hash, list) -> + for (blob in list) { + val authority = this.authorityManager.getAuthority(hash.bytes) + + if (authority?.publicKey != null) { + var signable = serializeULong(blob.version.toULong()) + blob.revocations.forEach { signable += it } + if (!authority.publicKey.verify(blob.signature, signable)) { + logger.warn("Peer ${peer.mid} might have altered the revoked signatures, skipping!") + continue + } + } else { + logger.info("Inserting revocations without verification as authority is not recognized.") } - } else { - logger.info("Inserting revocations without verification as authority is not recognized.") - } - this.authorityManager.insertRevocations( - hash.bytes, - blob.version, - blob.signature, - blob.revocations) + this.authorityManager.insertRevocations( + hash.bytes, + blob.version, + blob.signature, + blob.revocations) + } } } + } else { + logger.warn { "Received update we did not request, dropping." } } } else { - logger.warn { "Received update we did not request, dropping." } + val idPair = + PendingRevocationUpdateCache.generateId(peer.publicKey.keyToHash(), payload.publicKeyHash, payload.version) + if (this.requestCache.has(idPair)) { + val cache = this.requestCache.get(idPair) as PendingRevocationUpdateCache + var localBlob = byteArrayOf() + cache.revocationMap[payload.sequenceNumber] = payload.data + cache.revocationMap.keys.sorted().forEach { localBlob += cache.revocationMap[it]!! } + if (sha1(localBlob).contentEquals(payload.hash)) { + this.requestCache.pop(idPair) as PendingRevocationUpdateCache + val revocationBlob = this.deserializeRevocationBlob(localBlob) + logger.info("Received update: ${revocationBlob.revocations.size} revoked signatures") + + val authority = this.authorityManager.getAuthority(revocationBlob.publicKeyHash) + if (authority?.publicKey != null) { + var signable = serializeULong(revocationBlob.version.toULong()) + revocationBlob.revocations.forEach { signable += it } + if (!authority.publicKey.verify(revocationBlob.signature, signable)) { + logger.warn("Peer ${peer.mid} might have altered the revoked signatures, skipping!") + } + } else { + logger.info("Inserting revocations without verification as authority is not recognized.") + } + + this.authorityManager.insertRevocations( + revocationBlob.publicKeyHash, + revocationBlob.version, + revocationBlob.signature, + revocationBlob.revocations) + } + } else { + logger.warn { "Received update for version ${payload.version} we did not request, dropping." } + } + } } + private fun serializeRevocationBlob(blob: RevocationBlob): ByteArray { + var out = + blob.publicKeyHash + blob.signature + serializeULong(blob.version.toULong()) + serializeUInt(blob.revocations.size.toUInt()) + for (hash in blob.revocations) { + out += hash + } + return out + } + + private fun deserializeRevocationBlob(serialized: ByteArray): RevocationBlob { + var offset = 0 + + val keyHash = serialized.copyOfRange(offset, offset + SERIALIZED_SHA1_HASH_SIZE) + offset += SERIALIZED_SHA1_HASH_SIZE + + val signature = serialized.copyOfRange(offset, offset + SIGNATURE_SIZE) + offset += SIGNATURE_SIZE + + val version = deserializeULong(serialized, offset).toLong() + offset += SERIALIZED_ULONG_SIZE + + val revocationAmount = deserializeUInt(serialized, offset).toInt() + offset += SERIALIZED_UINT_SIZE + + val revocations = mutableListOf() + for (i in 0 until revocationAmount) { + val revocation = serialized.copyOfRange(offset, offset + SERIALIZED_SHA1_HASH_SIZE) + offset += SERIALIZED_SHA1_HASH_SIZE + revocations.add(revocation) + } + + return RevocationBlob(keyHash, version, signature, revocations) + } + private fun serializeRevocationMap(map: Map>): ByteArray { val size = map.size var out = serializeUInt(size.toUInt()) @@ -232,7 +352,7 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() revocations.add(revocation) localOffset += SERIALIZED_SHA1_HASH_SIZE } - revocationBlobs.add(RevocationBlob(version, signature, revocations)) + revocationBlobs.add(RevocationBlob(keyHash, version, signature, revocations)) } out[keyHash.toKey()] = revocationBlobs } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt index 51b65353..9eee5794 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt @@ -3,13 +3,28 @@ package nl.tudelft.ipv8.attestation.revocation.caches import nl.tudelft.ipv8.attestation.wallet.RequestCache import nl.tudelft.ipv8.attestation.wallet.caches.HashCache import nl.tudelft.ipv8.attestation.wallet.caches.NumberCache -import nl.tudelft.ipv8.attestation.wallet.caches.PeerCache +import nl.tudelft.ipv8.util.sha1 +import nl.tudelft.ipv8.util.toByteArray +import java.math.BigInteger const val PENDING_REVOCATION_UPDATE_CACHE_PREFIX = "receive-revocation" -class PendingRevocationUpdateCache(requestCache: RequestCache, peerMID: String) : - NumberCache(requestCache, PENDING_REVOCATION_UPDATE_CACHE_PREFIX, PeerCache.idFromAddress( - PENDING_REVOCATION_UPDATE_CACHE_PREFIX, peerMID).second) { +class PendingRevocationUpdateCache( + requestCache: RequestCache, + senderHash: ByteArray, + signeeHash: ByteArray, + version: Long, + override val timeout: Int = 10, +) : + NumberCache(requestCache, PENDING_REVOCATION_UPDATE_CACHE_PREFIX, this.generateId( + senderHash, signeeHash, version).second) { - val revocationMap = hashMapOf() + val revocationMap = hashMapOf() + + companion object { + fun generateId(senderHash: ByteArray, signeeHash: ByteArray, version: Long): Pair { + val hash = sha1(senderHash + signeeHash + version.toByteArray()) + return HashCache.idFromHash(PENDING_REVOCATION_UPDATE_CACHE_PREFIX, hash) + } + } } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateChunkPayload.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateChunkPayload.kt index c3aaf436..c95708a1 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateChunkPayload.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateChunkPayload.kt @@ -1,31 +1,41 @@ package nl.tudelft.ipv8.attestation.revocation.payloads import nl.tudelft.ipv8.messaging.* -import nl.tudelft.ipv8.util.hexToBytes -import nl.tudelft.ipv8.util.toHex -import java.lang.RuntimeException class RevocationUpdateChunkPayload( - val hash: ByteArray, val sequenceNumber: Int, + val hash: ByteArray, + val publicKeyHash: ByteArray, + val version: Long, val data: ByteArray, ) : Serializable { override fun serialize(): ByteArray { - return hash + serializeUInt(sequenceNumber.toUInt()) + serializeVarLen(data) + return serializeUInt(sequenceNumber.toUInt()) + hash + publicKeyHash + serializeULong(version.toULong()) + serializeVarLen( + data) } companion object Deserializer : Deserializable { override fun deserialize(buffer: ByteArray, offset: Int): Pair { var localOffset = offset - val hash = buffer.copyOfRange(localOffset, localOffset + SERIALIZED_SHA1_HASH_SIZE) - localOffset += SERIALIZED_SHA1_HASH_SIZE val sequenceNumber = deserializeUInt(buffer, localOffset).toInt() localOffset += SERIALIZED_UINT_SIZE + val hash = buffer.copyOfRange(localOffset, localOffset + SERIALIZED_SHA1_HASH_SIZE) + localOffset += SERIALIZED_SHA1_HASH_SIZE + + val publicKeyHash = buffer.copyOfRange(localOffset, localOffset + SERIALIZED_SHA1_HASH_SIZE) + localOffset += SERIALIZED_SHA1_HASH_SIZE + + val version = deserializeULong(buffer, localOffset).toLong() + localOffset += SERIALIZED_ULONG_SIZE + val (data, dataOffset) = deserializeVarLen(buffer, localOffset) - return Pair(RevocationUpdateChunkPayload(hash, sequenceNumber, data), localOffset + dataOffset) + return Pair( + RevocationUpdateChunkPayload(sequenceNumber, hash, publicKeyHash, version, data), + localOffset + dataOffset + ) } } From 73f465f2d3c30118ec17c0c769a689835c74952f Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 31 Mar 2021 11:19:05 +0200 Subject: [PATCH 021/144] Add key hash to revocation blob structure --- .../tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt | 2 +- .../nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt index 93efb7d2..5a75a3b0 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt @@ -89,7 +89,7 @@ class AuthoritySQLiteStore(database: Database) : AuthorityStore { dao.getVersionsByAuthorityIDandVersionNumbers(authorityId, versions).executeAsList() return versionEntries.map { - RevocationBlob(it.version_number, + RevocationBlob(publicKeyHash, it.version_number, it.signature, dao.getRevocationsByAuthorityIdAndVersionId(authorityId, it.version_id) .executeAsList()) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt index d97e2a41..8ac5625c 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt @@ -5,7 +5,7 @@ import nl.tudelft.ipv8.attestation.Revocations import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.sqldelight.GetAllRevocations -class RevocationBlob(val version: Long, val signature: ByteArray, val revocations: List) +class RevocationBlob(val publicKeyHash: ByteArray, val version: Long, val signature: ByteArray, val revocations: List) interface AuthorityStore { From 417957f5ca0a53f4b416b56a4fed6b24123e0142 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 31 Mar 2021 11:19:33 +0200 Subject: [PATCH 022/144] Force concurrent insertion of revocations --- .../attestation/revocation/AuthoritySQLiteStore.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt index 5a75a3b0..86a0d364 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt @@ -1,10 +1,12 @@ package nl.tudelft.ipv8.attestation.revocation +import mu.KotlinLogging import nl.tudelft.ipv8.attestation.Authority import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.keyvault.defaultCryptoProvider import nl.tudelft.ipv8.sqldelight.Database import nl.tudelft.ipv8.sqldelight.GetAllRevocations +import nl.tudelft.ipv8.util.toHex private val authorityMapper: ( ByteArray?, @@ -18,6 +20,7 @@ private val authorityMapper: ( recognized?.toInt() == 1) } +private val logger = KotlinLogging.logger {} class AuthoritySQLiteStore(database: Database) : AuthorityStore { private val dao = database.dbAuthorityQueries @@ -61,6 +64,15 @@ class AuthoritySQLiteStore(database: Database) : AuthorityStore { authorityId = dao.getAuthorityIdByHash(publicKeyHash).executeAsOne() } + if (version >= 2L) { + val previousId = dao.getVersionByAuthorityIDandVersionNumber(authorityId, version - 1L).executeAsOneOrNull()?.version_id + if (previousId == null) { + logger.warn("Received revocations out of order, skipping!") + return + } + + } + var versionId = dao.getVersionByAuthorityIDandVersionNumber(authorityId, version).executeAsOneOrNull()?.version_id if (versionId == null) { From 179be174d4ccf37d9097a7586c7e2f7e06c1876a Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 31 Mar 2021 11:20:52 +0200 Subject: [PATCH 023/144] Add cache timeouts --- .../ipv8/attestation/wallet/RequestCache.kt | 10 ++++- .../attestation/wallet/caches/NumberCache.kt | 39 ++++++++++++++++++- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/RequestCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/RequestCache.kt index ce503a4b..3d3379fb 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/RequestCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/RequestCache.kt @@ -1,9 +1,14 @@ package nl.tudelft.ipv8.attestation.wallet +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.async +import kotlinx.coroutines.launch import mu.KotlinLogging import nl.tudelft.ipv8.attestation.wallet.caches.NumberCache import java.math.BigInteger +private val logger = KotlinLogging.logger {} + class RequestCache { private val logger = KotlinLogging.logger {} @@ -21,6 +26,7 @@ class RequestCache { } else { this.logger.debug("Add cache $cache") this.identifiers[identifier] = cache + GlobalScope.launch { cache.start(calleeCallback = { pop(cache.prefix, cache.number) }) } cache } } @@ -36,7 +42,9 @@ class RequestCache { fun pop(prefix: String, number: BigInteger): NumberCache? { val identifier = this.createIdentifier(prefix, number) - return this.identifiers.remove(identifier) + val cache = this.identifiers.remove(identifier) + cache?.stop() + return cache } fun get(prefix: String, number: BigInteger): NumberCache? { diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt index 010105dc..3d614f1d 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt @@ -1,9 +1,24 @@ package nl.tudelft.ipv8.attestation.wallet.caches +import kotlinx.coroutines.* +import kotlinx.coroutines.time.withTimeout +import mu.KotlinLogging import nl.tudelft.ipv8.attestation.wallet.RequestCache import java.math.BigInteger -abstract class NumberCache(val requestCache: RequestCache, val prefix: String, val number: BigInteger) { +private val logger = KotlinLogging.logger {} + +const val DEFAULT_TIMEOUT = 180 +const val SECOND_IN_MILLISECONDS = 1000L + +abstract class NumberCache( + val requestCache: RequestCache, + val prefix: String, + val number: BigInteger, + open val timeout: Int = DEFAULT_TIMEOUT, + private val onTimeout: () -> Unit = {}, +) { + private lateinit var timeOutJob: Job init { if (requestCache.has(prefix, number)) { @@ -11,6 +26,26 @@ abstract class NumberCache(val requestCache: RequestCache, val prefix: String, v } } - // TODO: implement futures. + suspend fun start(overWrittenTimeout: Int? = null, calleeCallback: (() -> Unit)? = null) { + try { + val timeoutValue = (overWrittenTimeout ?: timeout) * SECOND_IN_MILLISECONDS + withTimeout(timeoutValue) { + timeOutJob = launch { + // Add some delta to ensure the timeout is triggered. + delay(timeoutValue + SECOND_IN_MILLISECONDS) + } + } + } catch (e: TimeoutCancellationException) { + logger.warn("Cache $prefix$number timed out") + calleeCallback?.invoke() + onTimeout() + } + } + + fun stop() { + if (this::timeOutJob.isInitialized) { + this.timeOutJob.cancel() + } + } } From f565499d2b97361b62309215a04e716632c9d17f Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 31 Mar 2021 11:21:09 +0200 Subject: [PATCH 024/144] Add identityPair method definitions --- .../nl/tudelft/ipv8/attestation/wallet/RequestCache.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/RequestCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/RequestCache.kt index 3d3379fb..bb91d26e 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/RequestCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/RequestCache.kt @@ -40,6 +40,10 @@ class RequestCache { return this.has(identifierPair.first, identifierPair.second) } + fun pop(identifierPair: Pair): NumberCache? { + return this.pop(identifierPair.first, identifierPair.second) + } + fun pop(prefix: String, number: BigInteger): NumberCache? { val identifier = this.createIdentifier(prefix, number) val cache = this.identifiers.remove(identifier) @@ -51,9 +55,12 @@ class RequestCache { return this.identifiers.get(this.createIdentifier(prefix, number)) } + fun get(identifierPair: Pair): NumberCache? { + return this.get(identifierPair.first, identifierPair.second) + } + private fun createIdentifier(prefix: String, number: BigInteger): String { return "$prefix:$number" } - } From d699e77acacc45756b3ef9fc2cea308a94b93f60 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 31 Mar 2021 11:21:35 +0200 Subject: [PATCH 025/144] Simplify HashCache id generation --- .../nl/tudelft/ipv8/attestation/wallet/caches/HashCache.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/HashCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/HashCache.kt index fa7ea109..0eac7d00 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/HashCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/HashCache.kt @@ -11,14 +11,12 @@ open class HashCache(requestCache: RequestCache, prefix: String, cacheHash: Byte fun idFromHash(prefix: String, cacheHash: ByteArray): Pair { var number = BigInteger.ZERO for (i in cacheHash.indices) { - // TODO: Verify whether we can simply invoke cacheHash[i].toUByte(). - val b = deserializeUChar(cacheHash.copyOfRange(i, i + 1)) + val b = cacheHash[i].toUByte() number = number shl 8 number = number or BigInteger(b.toString()) } return Pair(prefix, number) } - } } From 0d0cf63e0883cac0758179eb89144a765f44281d Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 31 Mar 2021 11:21:55 +0200 Subject: [PATCH 026/144] Add bytearray serializaiton for Long --- .../nl/tudelft/ipv8/util/ByteArrayUtils.kt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/util/ByteArrayUtils.kt b/ipv8/src/main/java/nl/tudelft/ipv8/util/ByteArrayUtils.kt index 8aac5c63..7e1322b5 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/util/ByteArrayUtils.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/util/ByteArrayUtils.kt @@ -1,10 +1,13 @@ package nl.tudelft.ipv8.util +import java.nio.Buffer +import java.nio.ByteBuffer + class ByteArrayKey(val bytes: ByteArray) { override fun equals(other: Any?): Boolean { // Note: this is the same as contentEquals. - return this.contentEquals(other) + return this.contentEquals(other) } fun contentEquals(other: Any?): Boolean { @@ -24,3 +27,17 @@ class ByteArrayKey(val bytes: ByteArray) { fun ByteArray.toKey(): ByteArrayKey { return ByteArrayKey(this) } + +const val BYTES = 8 +fun Long.toByteArray(): ByteArray { + val buffer: ByteBuffer = ByteBuffer.allocate(BYTES) + buffer.putLong(this) + return buffer.array() +} + +fun ByteArray.toLong(): Long { + val buffer: ByteBuffer = ByteBuffer.allocate(BYTES) + buffer.put(this) + (buffer as Buffer).flip() + return buffer.getLong() +} From 210b14d9a119c31643f605051b62f52bf38bd523 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 31 Mar 2021 11:22:10 +0200 Subject: [PATCH 027/144] Rename parameter in PeerCache --- .../nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt index a0ba6d75..0a626cc3 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt @@ -3,8 +3,8 @@ package nl.tudelft.ipv8.attestation.wallet.caches import nl.tudelft.ipv8.attestation.wallet.RequestCache import java.math.BigInteger -open class PeerCache(val cacheHash: RequestCache, prefix: String, val mid: String, val idFormat: String) : - NumberCache(cacheHash, prefix, idFromAddress(prefix, mid).second) { +open class PeerCache(val cache: RequestCache, prefix: String, val mid: String, val idFormat: String) : + NumberCache(cache, prefix, idFromAddress(prefix, mid).second) { companion object { fun idFromAddress(prefix: String, mid: String): Pair { From f7bdf179c28df1f2ea3c8df7e93d0c1c7f0ef0d3 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 31 Mar 2021 11:22:45 +0200 Subject: [PATCH 028/144] Add required authorityManager in CommunicationManager --- .../java/nl/tudelft/ipv8/attestation/CommunicationManager.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt index 1461e55f..c45794c4 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt @@ -28,6 +28,7 @@ class CommunicationManager( private val iPv8Instance: IPv8, private val attestationStore: AttestationStore, private val identityStore: IdentityStore, + private val authorityManager: AuthorityManager, ) { private val channels = hashMapOf() private val nameToChannel = hashMapOf() @@ -73,6 +74,7 @@ class CommunicationManager( val attestationOverlay = AttestationCommunity(identityOverlay.myPeer, identityOverlay.endpoint, identityOverlay.network, + authorityManager, attestationStore) this.channels[publicKeyBytes.toKey()] = CommunicationChannel(attestationOverlay, identityOverlay) From 087fd950d81ae8d1849e50c177706e15812c8edd Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 31 Mar 2021 11:22:58 +0200 Subject: [PATCH 029/144] Make logger statement in PseudonymManager readable --- .../ipv8/attestation/identity/manager/PseudonymManager.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt index 0a7f4b5c..d0833ffe 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt @@ -12,6 +12,7 @@ import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.messaging.serializeUInt import nl.tudelft.ipv8.messaging.serializeUShort import nl.tudelft.ipv8.util.ByteArrayKey +import nl.tudelft.ipv8.util.toHex import nl.tudelft.ipv8.util.toKey import org.json.JSONObject @@ -31,7 +32,7 @@ class PseudonymManager( private val credentials = this.database.getCredentialsFor(this.publicKey) init { - logger.info("Loading public key ${this.publicKey.keyToHash()} from database") + logger.info("Loading public key ${this.publicKey.keyToHash().toHex()} from database") for (token in this.database.getTokensFor(this.publicKey)) { this.tree.elements[token.hash.toKey()] = token } From cc301d6a8feedda71da7d88a17e94e02f71c21c0 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 31 Mar 2021 11:23:22 +0200 Subject: [PATCH 030/144] Fix typos + missing information in Overlay --- ipv8/src/main/java/nl/tudelft/ipv8/Overlay.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/Overlay.kt b/ipv8/src/main/java/nl/tudelft/ipv8/Overlay.kt index e3a9ab04..78170b8c 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/Overlay.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/Overlay.kt @@ -22,7 +22,7 @@ interface Overlay : EndpointListener { get() = myPeer.lamportTimestamp /** - * Called to inintialize this overlay. + * Called to initialize this overlay. */ fun load() { endpoint.addListener(this) @@ -84,7 +84,7 @@ interface Overlay : EndpointListener { /** * Get a peer for introduction. * - * @param Optionally specify a peer that is not considered eligible for introduction. + * @param exclude Optionally specify a peer that is not considered eligible for introduction. * @return A peer to send an introduction request to, or null if are none available. */ fun getPeerForIntroduction(exclude: Peer? = null): Peer? From b828061f2f2fb3480a84391b2e1fa4a3b768e0b2 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 31 Mar 2021 11:23:37 +0200 Subject: [PATCH 031/144] Remove unused import in RevocationUpdatePreviewPayload --- .../revocation/payloads/RevocationUpdatePreviewPayload.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdatePreviewPayload.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdatePreviewPayload.kt index 7b576b7b..6716ba94 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdatePreviewPayload.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdatePreviewPayload.kt @@ -1,10 +1,7 @@ package nl.tudelft.ipv8.attestation.revocation.payloads -import nl.tudelft.ipv8.keyvault.PublicKey -import nl.tudelft.ipv8.keyvault.defaultCryptoProvider import nl.tudelft.ipv8.messaging.* import nl.tudelft.ipv8.util.* -import java.lang.RuntimeException open class RevocationUpdatePreviewPayload( val revocationRefs: Map, From 4cd0051a1b2f1e91855d219d72db18015c76c17c Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 31 Mar 2021 11:23:54 +0200 Subject: [PATCH 032/144] Remove unused import in TrustChainCommunity --- .../tudelft/ipv8/attestation/trustchain/TrustChainCommunity.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/trustchain/TrustChainCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/trustchain/TrustChainCommunity.kt index c47c2cf3..3205115c 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/trustchain/TrustChainCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/trustchain/TrustChainCommunity.kt @@ -11,7 +11,6 @@ import nl.tudelft.ipv8.messaging.Packet import nl.tudelft.ipv8.util.random import nl.tudelft.ipv8.attestation.trustchain.payload.* import nl.tudelft.ipv8.attestation.trustchain.store.TrustChainStore -import nl.tudelft.ipv8.attestation.trustchain.validation.ValidationErrors import nl.tudelft.ipv8.keyvault.defaultCryptoProvider import nl.tudelft.ipv8.messaging.Address import nl.tudelft.ipv8.util.toHex From f3040cc50520cfc6064bdde868549d941f2f5b9b Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 31 Mar 2021 11:25:40 +0200 Subject: [PATCH 033/144] Remove authority notions from attestation store + update usage in AttestationCommunity --- .../wallet/AttestationCommunity.kt | 24 ++++++++------- .../wallet/AttestationSQLiteStore.kt | 29 ------------------- .../attestation/wallet/AttestationStore.kt | 10 ------- 3 files changed, 13 insertions(+), 50 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt index 72b90fe9..a4648974 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt @@ -2,7 +2,6 @@ package nl.tudelft.ipv8.attestation.wallet import kotlinx.coroutines.Deferred import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.async import kotlinx.coroutines.launch import mu.KotlinLogging import nl.tudelft.ipv8.Community @@ -11,7 +10,7 @@ import nl.tudelft.ipv8.Overlay import nl.tudelft.ipv8.Peer import nl.tudelft.ipv8.attestation.WalletAttestation import nl.tudelft.ipv8.attestation.IdentityAlgorithm -import nl.tudelft.ipv8.attestation.TrustedAuthorityManager +import nl.tudelft.ipv8.attestation.AuthorityManager import nl.tudelft.ipv8.attestation.schema.* import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity.MessageId.ATTESTATION import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity.MessageId.ATTESTATION_REQUEST @@ -23,7 +22,6 @@ import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPrivateKe import nl.tudelft.ipv8.attestation.wallet.payloads.* import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.PublicKey -import nl.tudelft.ipv8.messaging.Endpoint import nl.tudelft.ipv8.messaging.EndpointAggregator import nl.tudelft.ipv8.messaging.Packet import nl.tudelft.ipv8.messaging.payload.GlobalTimeDistributionPayload @@ -32,7 +30,6 @@ import nl.tudelft.ipv8.util.* import org.json.JSONObject import java.math.BigInteger import java.util.concurrent.locks.ReentrantLock -import kotlin.collections.ArrayList import kotlin.collections.HashMap import kotlin.random.Random import kotlin.random.nextUBytes @@ -41,13 +38,19 @@ import kotlin.random.nextUBytes private val logger = KotlinLogging.logger {} private const val CHUNK_SIZE = 800 -class AttestationCommunity(val database: AttestationStore) : Community() { +class AttestationCommunity(val authorityManager: AuthorityManager, val database: AttestationStore) : Community() { override lateinit var myPeer: Peer override lateinit var endpoint: EndpointAggregator override lateinit var network: Network - constructor(myPeer: Peer, endpoint: EndpointAggregator, network: Network, database: AttestationStore) : this( + constructor( + myPeer: Peer, + endpoint: EndpointAggregator, + network: Network, + authorityManager: AuthorityManager, + database: AttestationStore, + ) : this(authorityManager, database) { this.myPeer = myPeer this.endpoint = endpoint @@ -69,8 +72,6 @@ class AttestationCommunity(val database: AttestationStore) : Community() { private val cachedAttestationBlobs = mutableMapOf() private val allowedAttestations = mutableMapOf>() - val trustedAuthorityManager = TrustedAuthorityManager(database) - val requestCache = RequestCache() init { @@ -85,7 +86,7 @@ class AttestationCommunity(val database: AttestationStore) : Community() { this.network = super.network } - trustedAuthorityManager.loadAuthorities() + authorityManager.loadTrustedAuthorities() schemaManager.registerDefaultSchemas() for (att in this.database.getAllAttestations()) { val hash = att.attestationHash @@ -175,7 +176,7 @@ class AttestationCommunity(val database: AttestationStore) : Community() { val attesteeKeyHash = parsedMetadata.optString("trustchain_address_hash") attesteeKeyHash ?: return false - val isTrusted = this.trustedAuthorityManager.contains(attestorKey.keyToHash().toHex()) + val isTrusted = this.authorityManager.contains(attestorKey.keyToHash()) val isOwner = peer.publicKey.keyToHash().toHex() == attesteeKeyHash val isSignatureValid = attestorKey.verify(signature, sha1(attestationHash + metadata.toByteArray())) @@ -645,10 +646,11 @@ class AttestationCommunity(val database: AttestationStore) : Community() { } class Factory( + private val authorityManager: AuthorityManager, private val database: AttestationStore, ) : Overlay.Factory(AttestationCommunity::class.java) { override fun create(): AttestationCommunity { - return AttestationCommunity(database) + return AttestationCommunity(authorityManager, database) } } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationSQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationSQLiteStore.kt index 89dda90b..d202e87d 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationSQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationSQLiteStore.kt @@ -29,14 +29,6 @@ private val attestationMapper: ( ) } -private val authorityMapper: ( - ByteArray, - String, -) -> Authority = { public_key, hash -> - Authority(defaultCryptoProvider.keyFromPublicBin(public_key), hash) -} - - private val logger = KotlinLogging.logger {} class AttestationSQLiteStore(database: Database) : AttestationStore { @@ -74,25 +66,4 @@ class AttestationSQLiteStore(database: Database) : AttestationStore { return dao.deleteAttestationByHash(attestationHash) } - override fun getAllAuthorities(): List { - return dao.getAllAuthorities(authorityMapper).executeAsList() - } - - override fun insertAuthority(publicKey: PublicKey, hash: String) { - val keyBin = publicKey.keyToBin() - dao.insertAuthority(keyBin, hash) - } - - override fun getAuthorityByPublicKey(publicKey: PublicKey): Authority? { - return dao.getAuthorityByPublicKey(publicKey.keyToBin(), authorityMapper).executeAsOneOrNull() - } - - override fun getAuthorityByHash(hash: String): Authority? { - return dao.getAuthorityByHash(hash, authorityMapper).executeAsOneOrNull() - } - - override fun deleteAuthorityByHash(hash: String) { - return dao.deleteAuthorityByHash(hash) - } - } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationStore.kt index 993bce9a..598800e0 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationStore.kt @@ -31,14 +31,4 @@ interface AttestationStore { fun getAttestationByHash(attestationHash: ByteArray): ByteArray? fun deleteAttestationByHash(attestationHash: ByteArray) - - fun getAllAuthorities(): List - - fun insertAuthority(publicKey: PublicKey, hash: String) - - fun getAuthorityByPublicKey(publicKey: PublicKey): Authority? - - fun getAuthorityByHash(hash: String): Authority? - - fun deleteAuthorityByHash(hash: String) } From 1bb44a2c1eaa77590390be3c5fc6497654eae6bb Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 31 Mar 2021 14:09:14 +0200 Subject: [PATCH 034/144] Remove unused logic --- .../revocation/AuthoritySQLiteStore.kt | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt index 86a0d364..12e06960 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt @@ -21,6 +21,7 @@ private val authorityMapper: ( } private val logger = KotlinLogging.logger {} + class AuthoritySQLiteStore(database: Database) : AuthorityStore { private val dao = database.dbAuthorityQueries @@ -65,7 +66,8 @@ class AuthoritySQLiteStore(database: Database) : AuthorityStore { } if (version >= 2L) { - val previousId = dao.getVersionByAuthorityIDandVersionNumber(authorityId, version - 1L).executeAsOneOrNull()?.version_id + val previousId = + dao.getVersionByAuthorityIDandVersionNumber(authorityId, version - 1L).executeAsOneOrNull()?.version_id if (previousId == null) { logger.warn("Received revocations out of order, skipping!") return @@ -111,23 +113,5 @@ class AuthoritySQLiteStore(database: Database) : AuthorityStore { override fun getAllRevocations(): List { return dao.getAllRevocations().executeAsList() } - - -// fun insertAuthority(publicKey: PublicKey, hash: String, version: Long, recognized: Boolean) { -// val keyBin = publicKey.keyToBin() -// dao.insertAuthority(keyBin, hash, version, if (recognized) 1 else 0) -// } -// -// fun getAuthorityByPublicKey(publicKey: PublicKey): Authority? { -// return dao.getAuthorityByPublicKey(publicKey.keyToBin(), authorityMapper).executeAsOneOrNull() -// } -// -// fun getAuthorityByHash(hash: String): Authority? { -// return dao.getAuthorityByHash(hash, authorityMapper).executeAsOneOrNull() -// } -// -// fun deleteAuthorityByHash(hash: String) { -// return dao.deleteAuthorityByHash(hash) -// } - + } From bc7c333924941c8fdda0fc2036ed2a1f04a1197f Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 1 Apr 2021 14:35:25 +0200 Subject: [PATCH 035/144] Fix liniting issues --- .../main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt | 2 +- .../nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt | 4 ++-- .../ipv8/attestation/revocation/AuthoritySQLiteStore.kt | 2 +- .../revocation/payloads/RevocationUpdateRequestPayload.kt | 1 + .../nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt | 1 - 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt index 050301b9..73439132 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt @@ -83,7 +83,7 @@ class AuthorityManager(val database: AuthorityStore) { fun deleteTrustedAuthority(hash: ByteArray) { if (this.contains(hash)) { - this.trustedAuthorities.remove(hash) + this.trustedAuthorities.remove(hash.toKey()) this.database.disregardAuthority(hash) } } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index a892473a..5937881a 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -245,8 +245,8 @@ class IdentityCommunity( val credential = this.selfAdvertise(attributeHash, name, blockType, metadata) this.permissions[peer] = this.tokenChain.size val disclosure = this.pseudonymManager.discloseCredentials(listOf(credential), setOf()) - val (metadata, tokens, attestations, authorities) = this.fitDisclosure(disclosure) - val payload = DisclosePayload(metadata, tokens, attestations, authorities) + val (metadataObj, tokens, attestations, authorities) = this.fitDisclosure(disclosure) + val payload = DisclosePayload(metadataObj, tokens, attestations, authorities) this.endpoint.send(peer, serializePacket(DISCLOSURE_PAYLOAD, payload)) } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt index 12e06960..56389303 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt @@ -113,5 +113,5 @@ class AuthoritySQLiteStore(database: Database) : AuthorityStore { override fun getAllRevocations(): List { return dao.getAllRevocations().executeAsList() } - + } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateRequestPayload.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateRequestPayload.kt index d3e78ac6..ac5b6f8f 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateRequestPayload.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateRequestPayload.kt @@ -14,6 +14,7 @@ class RevocationUpdateRequestPayload( companion object Deserializer : Deserializable { override fun deserialize(buffer: ByteArray, offset: Int): Pair { + @Suppress("UNCHECKED_CAST") return RevocationUpdatePreviewPayload.deserialize(buffer, offset) as Pair } } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt index 3d614f1d..d96a7ddb 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt @@ -1,7 +1,6 @@ package nl.tudelft.ipv8.attestation.wallet.caches import kotlinx.coroutines.* -import kotlinx.coroutines.time.withTimeout import mu.KotlinLogging import nl.tudelft.ipv8.attestation.wallet.RequestCache import java.math.BigInteger From b43f46adf36927e44d97c855259dcc9cd14957c7 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 15 Apr 2021 17:53:26 +0200 Subject: [PATCH 036/144] Make secondary overlays initialize properly --- ipv8/src/main/java/nl/tudelft/ipv8/IPv8.kt | 28 ++++++++++++- .../java/nl/tudelft/ipv8/IPv8Configuration.kt | 13 +++++- .../attestation/identity/IdentityCommunity.kt | 42 +++++++++++++++---- 3 files changed, 72 insertions(+), 11 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/IPv8.kt b/ipv8/src/main/java/nl/tudelft/ipv8/IPv8.kt index d6d3fa6a..7ef0d0b2 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/IPv8.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/IPv8.kt @@ -82,12 +82,31 @@ class IPv8( startLoopingCall() } - fun addSecondaryOverlayStrategy(overlay: Overlay, strategy: DiscoveryStrategy) { + /* + * Method for adding secondary overlays. These allow for multiple class instances, however, service IDs must be unique. + * As a consequence, the used peer, endpoint and network can be different than the main ones. + */ + fun addSecondaryOverlayStrategy(overlayConfiguration: SecondaryOverlayConfiguration<*>): Overlay { synchronized(overlayLock) { + val overlay = overlayConfiguration.factory.create() if (!this.secondaryOverlays.containsKey(overlay.serviceId)) { + overlay.myPeer = overlayConfiguration.myPeer ?: myPeer + overlay.endpoint = overlayConfiguration.endpoint ?: endpoint + overlay.network = overlayConfiguration.network ?: network + overlay.maxPeers = overlayConfiguration.maxPeers + overlay.load() + this.secondaryOverlays[overlay.serviceId] = overlay + + for (strategyFactory in overlayConfiguration.walkers) { + val strategy = strategyFactory + .setOverlay(overlay) + .create() + strategy.load() + strategies.add(strategy) + } } - this.strategies.add(strategy) + return secondaryOverlays[overlay.serviceId]!! } } @@ -127,6 +146,11 @@ class IPv8( } overlays.clear() + for ((_, overlay) in secondaryOverlays) { + overlay.unload() + } + secondaryOverlays.clear() + for (strategy in strategies) { strategy.unload() } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/IPv8Configuration.kt b/ipv8/src/main/java/nl/tudelft/ipv8/IPv8Configuration.kt index 33adc73a..f9634bdb 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/IPv8Configuration.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/IPv8Configuration.kt @@ -1,5 +1,7 @@ package nl.tudelft.ipv8 +import nl.tudelft.ipv8.messaging.EndpointAggregator +import nl.tudelft.ipv8.peerdiscovery.Network import nl.tudelft.ipv8.peerdiscovery.strategy.DiscoveryStrategy class IPv8Configuration( @@ -9,8 +11,17 @@ class IPv8Configuration( val overlays: List> ) -class OverlayConfiguration( +open class OverlayConfiguration( val factory: Overlay.Factory, val walkers: List>, val maxPeers: Int = 30 ) + +class SecondaryOverlayConfiguration( + factory: Overlay.Factory, + walkers: List>, + maxPeers: Int = 30, + val myPeer: Peer? = null, + val endpoint: EndpointAggregator? = null, + val network: Network? = null +) : OverlayConfiguration(factory, walkers, maxPeers) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index 5937881a..d284133f 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -327,6 +327,30 @@ class IdentityCommunity( companion object { const val SERVICE_ID = "d5889074c1e4c50423cdb6e9307ee0ca5695ead7" } + + class Factory( + private val myPeer: Peer, + private val identityManager: IdentityManager, + private val database: IdentityStore, + private val rendezvousId: String? = null, + private val network: Network? = null + ) : Overlay.Factory(IdentityCommunity::class.java) { + override fun create(): IdentityCommunity { + return if (rendezvousId != null) { + if (network != null) { + IdentityCommunity(myPeer, identityManager, database, rendezvousId, network) + } else { + IdentityCommunity(myPeer, identityManager, database, rendezvousId) + } + } else { + if (network != null) { + IdentityCommunity(myPeer, identityManager, database, network = network) + } else { + IdentityCommunity(myPeer, identityManager, database) + } + } + } + } } fun createCommunity( @@ -337,19 +361,21 @@ fun createCommunity( rendezvousToken: ByteArray?, ): IdentityCommunity { val myPeer = Peer(privateKey) - + val network = Network() var rendezvousId: String? = null if (rendezvousToken != null) { - val tokenString = rendezvousToken.toHex() rendezvousId = IdentityCommunity.SERVICE_ID.mapIndexed { i, c -> if (i < rendezvousToken.size) (c.toInt() xor rendezvousToken[i].toInt()).toChar() else c } .joinToString("") } - val community = if (rendezvousId != null) IdentityCommunity(myPeer, - identityManager, - database, - rendezvousId) else IdentityCommunity(myPeer, identityManager, database) - ipv8.addSecondaryOverlayStrategy(community, RandomWalk(community, 3.0, 5, 50, 0, 20)) - return community + val randomWalk = RandomWalk.Factory(timeout = 3.0, peers = 20) + val config = SecondaryOverlayConfiguration( + IdentityCommunity.Factory(myPeer, identityManager, database, rendezvousId, network), + listOf(randomWalk), + myPeer = myPeer, + network = network + ) + + return ipv8.addSecondaryOverlayStrategy(config) as IdentityCommunity } From dfef72d281ef7c373158abd1b6609487bef02a70 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:08:14 +0200 Subject: [PATCH 037/144] Make SignedObject init after children --- .../java/nl/tudelft/ipv8/attestation/SignedObject.kt | 9 ++++----- .../ipv8/attestation/identity/IdentityAttestation.kt | 4 ++++ .../nl/tudelft/ipv8/attestation/identity/Metadata.kt | 3 +++ .../java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt | 1 + 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/SignedObject.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/SignedObject.kt index a8931ac3..db7cdb33 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/SignedObject.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/SignedObject.kt @@ -6,15 +6,14 @@ import nl.tudelft.ipv8.keyvault.defaultCryptoProvider import nl.tudelft.ipv8.messaging.deserializeULong import nl.tudelft.ipv8.util.sha3_256 -abstract class SignedObject(val privateKey: PrivateKey? = null, signature: ByteArray? = null) { +abstract class SignedObject(val privateKey: PrivateKey? = null, private val knownSignature: ByteArray? = null) { var hash = byteArrayOf() open lateinit var signature: ByteArray private val crypto = defaultCryptoProvider - - init { - this.sign(privateKey, signature) + fun init() { + this.sign(privateKey, knownSignature) } fun verify(publicKey: PublicKey): Boolean { @@ -43,7 +42,7 @@ abstract class SignedObject(val privateKey: PrivateKey? = null, signature: ByteA abstract fun deserialize(data: ByteArray, publicKey: PublicKey, offset: Int = 0): SignedObject override fun equals(other: Any?): Boolean { - if (other !is SignedObject){ + if (other !is SignedObject) { return false } return this.getPlaintextSigned().contentEquals(other.getPlaintextSigned()) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt index 7fa0aaca..1c5a449f 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt @@ -11,6 +11,10 @@ class IdentityAttestation( signature: ByteArray? = null, ) : SignedObject(privateKey, signature) { + init { + super.init() + } + override fun getPlaintext(): ByteArray { return this.metadataPointer } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt index 358be923..5f35f7d0 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt @@ -14,6 +14,9 @@ class Metadata( signature: ByteArray? = null, ) : SignedObject(privateKey, signature) { + init { + super.init() + } override fun getPlaintext(): ByteArray { return this.tokenPointer + this.serializedMetadata diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt index b996b208..1ca0275d 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt @@ -24,6 +24,7 @@ class Token( } else if (content == null && contentHash != null) { this.contentHash = contentHash } else throw RuntimeException("Specify either `content` or `content_hash`.") + super.init() } override fun getPlaintext(): ByteArray { From 7d24d955cb685491c565062e2e967601720ffc81 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:09:46 +0200 Subject: [PATCH 038/144] Make database type more apparent in AuthorityManager --- .../ipv8/attestation/AuthorityManager.kt | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt index 73439132..435036bf 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt @@ -20,13 +20,13 @@ class Revocations( val revocations: List, ) -class AuthorityManager(val database: AuthorityStore) { +class AuthorityManager(val authorityDatabase: AuthorityStore) { private val trustedAuthorities = hashMapOf() private val lock = Object() fun loadTrustedAuthorities() { - val authorities = database.getRecognizedAuthorities() + val authorities = authorityDatabase.getRecognizedAuthorities() synchronized(lock) { authorities.forEach { trustedAuthorities[it.hash.toKey()] = it @@ -35,14 +35,14 @@ class AuthorityManager(val database: AuthorityStore) { } fun insertRevocations(publicKeyHash: ByteArray, versionNumber: Long, signature: ByteArray, revokedHashes: List) { - database.insertRevocations(publicKeyHash, versionNumber, signature, revokedHashes) + authorityDatabase.insertRevocations(publicKeyHash, versionNumber, signature, revokedHashes) if (this.trustedAuthorities.containsKey(publicKeyHash.toKey())) { this.trustedAuthorities[publicKeyHash.toKey()]!!.version = versionNumber } } fun getLatestRevocationPreviews(): Map { - val authorities = database.getKnownAuthorities() + val authorities = authorityDatabase.getKnownAuthorities() val localRefs = hashMapOf() authorities.forEach { localRefs[it.hash.toKey()] = it.version @@ -51,8 +51,8 @@ class AuthorityManager(val database: AuthorityStore) { } fun getRevocations(publicKeyHash: ByteArray, fromVersion: Long = 0): List { - val versions = database.getVersionsSince(publicKeyHash, fromVersion) - return database.getRevocations(publicKeyHash, versions) + val versions = authorityDatabase.getVersionsSince(publicKeyHash, fromVersion) + return authorityDatabase.getRevocations(publicKeyHash, versions) } fun loadDefaultAuthorities() { @@ -60,20 +60,20 @@ class AuthorityManager(val database: AuthorityStore) { } fun getAuthorities(): List { - return this.database.getKnownAuthorities() + return this.authorityDatabase.getKnownAuthorities() } fun addTrustedAuthority(publicKey: PublicKey) { val hash = publicKey.keyToHash() if (!this.contains(hash)) { - val localAuthority = database.getAuthorityByHash(hash) + val localAuthority = authorityDatabase.getAuthorityByHash(hash) if (localAuthority == null) { - database.insertAuthority(publicKey) + authorityDatabase.insertAuthority(publicKey) synchronized(lock) { this.trustedAuthorities[hash.toKey()] = Authority(publicKey, hash) } } else { - database.recognizeAuthority(publicKey.keyToHash()) + authorityDatabase.recognizeAuthority(publicKey.keyToHash()) synchronized(lock) { this.trustedAuthorities[hash.toKey()] = localAuthority } @@ -84,7 +84,7 @@ class AuthorityManager(val database: AuthorityStore) { fun deleteTrustedAuthority(hash: ByteArray) { if (this.contains(hash)) { this.trustedAuthorities.remove(hash.toKey()) - this.database.disregardAuthority(hash) + this.authorityDatabase.disregardAuthority(hash) } } @@ -93,7 +93,7 @@ class AuthorityManager(val database: AuthorityStore) { } fun getAuthority(hash: ByteArray): Authority? { - return this.trustedAuthorities.get(hash.toKey()) ?: database.getAuthorityByHash(hash) + return this.trustedAuthorities.get(hash.toKey()) ?: authorityDatabase.getAuthorityByHash(hash) } fun deleteTrustedAuthority(publicKey: PublicKey) { From c40ceef024da7988807cad2e1ecd2968f5321d84 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:10:29 +0200 Subject: [PATCH 039/144] Set signature variable in SignedObject when signing --- .../src/main/java/nl/tudelft/ipv8/attestation/SignedObject.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/SignedObject.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/SignedObject.kt index db7cdb33..d886b32a 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/SignedObject.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/SignedObject.kt @@ -22,15 +22,13 @@ abstract class SignedObject(val privateKey: PrivateKey? = null, private val know private fun sign(privateKey: PrivateKey? = null, signature: ByteArray? = null) { if (privateKey != null && signature == null) { - privateKey.sign(this.getPlaintext()) + this.signature = privateKey.sign(this.getPlaintext()) } else if (privateKey == null && signature != null) { this.signature = signature } else { throw RuntimeException("Specify either a private key or a signature.") } - this.hash = sha3_256(this.getPlaintextSigned()) - } abstract fun getPlaintext(): ByteArray From a51d54f280111bcfaef12c04b23faf280972d45a Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:11:04 +0200 Subject: [PATCH 040/144] Correctly extract metadata in Metadata --- .../main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt index 5f35f7d0..7ee8326a 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt @@ -41,7 +41,7 @@ class Metadata( } // Index on which signature start. - val signIndex = data.lastIndex - publicKey.getSignatureLength() + val signIndex = data.size - publicKey.getSignatureLength() return Metadata(data.copyOfRange(0, 32), data.copyOfRange(32, signIndex), signature = data.copyOfRange(signIndex, data.size)) From 93f6b108511bab7794a940fa42e7d570de363e96 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:11:33 +0200 Subject: [PATCH 041/144] Use toKey() in IdentityManager --- .../ipv8/attestation/identity/manager/IdentityManager.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt index eafa8524..b56bb4b9 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt @@ -12,6 +12,7 @@ import nl.tudelft.ipv8.messaging.SERIALIZED_USHORT_SIZE import nl.tudelft.ipv8.messaging.deserializeUInt import nl.tudelft.ipv8.messaging.deserializeUShort import nl.tudelft.ipv8.util.ByteArrayKey +import nl.tudelft.ipv8.util.toKey class IdentityManager(internal val database: IdentityStore) { @@ -19,14 +20,14 @@ class IdentityManager(internal val database: IdentityStore) { fun getPseudonym(key: Key): PseudonymManager { val publicKeyMaterial = key.pub().keyToBin() - if (!this.pseudonyms.containsKey(ByteArrayKey(publicKeyMaterial))) { + if (!this.pseudonyms.containsKey(publicKeyMaterial.toKey())) { if (key is PrivateKey) { - this.pseudonyms[ByteArrayKey(publicKeyMaterial)] = PseudonymManager(this.database, privateKey = key) + this.pseudonyms[publicKeyMaterial.toKey()] = PseudonymManager(this.database, privateKey = key) } else { - this.pseudonyms[ByteArrayKey(publicKeyMaterial)] = PseudonymManager(this.database, publicKey = key as PublicKey) + this.pseudonyms[publicKeyMaterial.toKey()] = PseudonymManager(this.database, publicKey = key as PublicKey) } } - return this.pseudonyms[ByteArrayKey(publicKeyMaterial)]!! + return this.pseudonyms[publicKeyMaterial.toKey()]!! } fun substantiate( From 659e1b2da432ea3b3e06e1a27cb4164ebdf10283 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:11:56 +0200 Subject: [PATCH 042/144] Correctly increment metadata offset when deserializing --- .../ipv8/attestation/identity/manager/IdentityManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt index b56bb4b9..e86dcbec 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt @@ -48,7 +48,7 @@ class IdentityManager(internal val database: IdentityStore) { Metadata.deserialize(serializeMetadata.copyOfRange(metadataOffset, metadataOffset + metadataSize), publicKey) pseudonym.addMetadata(metadata) - metadataOffset + metadataSize + metadataOffset += metadataSize } var attestationOffset = 0 From 4d3e450b15267bb0e62c3a78169601cfcf1d964d Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:12:36 +0200 Subject: [PATCH 043/144] Remove unnecessary val in PeerCache --- .../java/nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt index 0a626cc3..83bb4d93 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt @@ -3,7 +3,7 @@ package nl.tudelft.ipv8.attestation.wallet.caches import nl.tudelft.ipv8.attestation.wallet.RequestCache import java.math.BigInteger -open class PeerCache(val cache: RequestCache, prefix: String, val mid: String, val idFormat: String) : +open class PeerCache(cache: RequestCache, prefix: String, val mid: String, val idFormat: String) : NumberCache(cache, prefix, idFromAddress(prefix, mid).second) { companion object { From a0ec92ae487f0ffdcea83e6c287992c25a4a6f94 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:13:13 +0200 Subject: [PATCH 044/144] Correctly init Token when deserializing --- .../main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt index 1ca0275d..a4a4332d 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt @@ -72,8 +72,8 @@ class Token( fun deserialize(data: ByteArray, publicKey: PublicKey, offset: Int = 0): Token { val sigLength = publicKey.getSignatureLength() return Token(data.copyOfRange(offset, offset + 32), - data.copyOfRange(offset + 32, offset + 64), - data.copyOfRange(offset + 64, offset + 64 + sigLength)) + contentHash = data.copyOfRange(offset + 32, offset + 64), + signature = data.copyOfRange(offset + 64, offset + 64 + sigLength)) } fun create(previousToken: Token, content: ByteArray, privateKey: PrivateKey): Token { From d0d2993f6723d92cfa259b594d05889145c6abce Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:13:49 +0200 Subject: [PATCH 045/144] Use toKey() + break when correct hash is found in TokenTree --- .../nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt index 479446da..e0872cd1 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt @@ -5,6 +5,7 @@ import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.util.ByteArrayKey import nl.tudelft.ipv8.util.sha3_256 +import nl.tudelft.ipv8.util.toKey const val UNCHAINED_MAX_SIZE = 100 const val DEFAULT_CHUNK_SUZE = 64 @@ -60,8 +61,8 @@ class TokenTree(publicKey: PublicKey? = null, privateKey: PrivateKey? = null) { } logger.info("Delaying unchained token $token!") return null - } else if (this.elements.containsKey(ByteArrayKey(token.hash))) { - val shadowToken = this.elements[ByteArrayKey(token.hash)]!! + } else if (this.elements.containsKey(token.hash.toKey())) { + val shadowToken = this.elements[token.hash.toKey()]!! if (shadowToken.content == null && token.content != null) { shadowToken.receiveContent(token.content!!) } @@ -86,7 +87,7 @@ class TokenTree(publicKey: PublicKey? = null, privateKey: PrivateKey? = null) { return false } if (current.previousTokenHash.contentEquals(this.genesisHash)) { - return false + break } if (!this.elements.containsKey(ByteArrayKey(current.previousTokenHash))) { return false From 254f8bc4deab1729b4a43284023bc86d4347434a Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:14:26 +0200 Subject: [PATCH 046/144] serialize tokens in DisclosePayload --- .../ipv8/attestation/identity/payloads/DisclosePayload.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/DisclosePayload.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/DisclosePayload.kt index 595ae103..b4e16844 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/DisclosePayload.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/DisclosePayload.kt @@ -9,7 +9,7 @@ class DisclosePayload( val authorities: ByteArray, ) : Serializable { override fun serialize(): ByteArray { - return serializeVarLen(metadata) + serializeVarLen(metadata) + serializeVarLen(attestations) + serializeVarLen( + return serializeVarLen(metadata) + serializeVarLen(tokens) + serializeVarLen(attestations) + serializeVarLen( authorities) } From c72f911f25b145dee0f9cc18c9d48b709c7348cf Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:39:41 +0200 Subject: [PATCH 047/144] Add SettableDeferred class --- .../nl/tudelft/ipv8/util/SettableDeferred.kt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/util/SettableDeferred.kt diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/util/SettableDeferred.kt b/ipv8/src/main/java/nl/tudelft/ipv8/util/SettableDeferred.kt new file mode 100644 index 00000000..faeedf32 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/util/SettableDeferred.kt @@ -0,0 +1,33 @@ +package nl.tudelft.ipv8.util + +import kotlinx.coroutines.* + +class SettableDeferred { + + private val job = GlobalScope.async(start = CoroutineStart.LAZY) { + try { + while (isActive) { + delay(50) + } + } catch (e: CancellationException) { + // NO-OP + } + } + + private var result: T? = null + + suspend fun await(): T? { + // We are manually throwing an error and, thus, want to return in both cases. + @Suppress("ReturnInsideFinallyBlock") + try { + job.await() + } finally { + return result + } + } + + fun setResult(result: T) { + this.result = result + job.cancel(CancellationException("Value has been set.")) + } +} From f83ed0c452e8745cf296f7ff73de2371e6b142c1 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:41:37 +0200 Subject: [PATCH 048/144] Make boolean result nullable --- .../tudelft/ipv8/attestation/wallet/AttestationCommunity.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt index a4648974..92ab5ebd 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt @@ -64,7 +64,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: private lateinit var attestationRequestCallback: (peer: Peer, attributeName: String, metaData: String) -> Deferred private lateinit var attestationRequestCompleteCallback: (forPeer: Peer, attributeName: String, attestation: WalletAttestation, attestationHash: ByteArray, idFormat: String, fromPeer: Peer?, metaData: String?, signature: ByteArray?) -> Unit - private lateinit var verifyRequestCallback: (peer: Peer, attributeHash: ByteArray) -> Deferred + private lateinit var verifyRequestCallback: (peer: Peer, attributeHash: ByteArray) -> Deferred private lateinit var attestationChunkCallback: (peer: Peer, sequenceNumber: Int) -> Unit val attestationKeys: MutableMap> = mutableMapOf() @@ -151,7 +151,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: this.attestationRequestCompleteCallback = f } - fun setVerifyRequestCallback(f: (attributeName: Peer, attributeHash: ByteArray) -> Deferred) { + fun setVerifyRequestCallback(f: (attributeName: Peer, attributeHash: ByteArray) -> Deferred) { this.verifyRequestCallback = f } @@ -365,7 +365,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: } val value = verifyRequestCallback(peer, payload.hash).await() - if (!value) { + if (value == null || !value) { logger.info("Verify request callback returned false for $peer, ${payload.hash}") return } From c0a1c8e03ad63386f8c139668aae6e3e21aee2cd Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:42:08 +0200 Subject: [PATCH 049/144] Disable printing of raw bytes --- .../tudelft/ipv8/attestation/wallet/AttestationCommunity.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt index 92ab5ebd..2d36028a 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt @@ -126,9 +126,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: private fun onAttestationChunkWrapper(packet: Packet) { val (peer, dist, payload) = packet.getAuthPayloadWithDist(AttestationChunkPayload.Deserializer) - logger.info("Received AttestationChunk from ${peer.mid} with sequence number ${payload.sequenceNumber}, data ${ - String(payload.data) - } hash ${String(payload.hash)}.") + logger.info("Received AttestationChunk from ${peer.mid} with sequence number ${payload.sequenceNumber}, data ${payload.data.size} bytes, hash ${payload.hash.toHex()}.") this.onAttestationChunk(peer, dist, payload) } From 5e83113018204f5ef893d8917fefc1683f6c07d9 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:42:35 +0200 Subject: [PATCH 050/144] Make lists and sets mutable in PseudonymManager --- .../identity/manager/PseudonymManager.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt index d0833ffe..7cca3f3f 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt @@ -29,7 +29,7 @@ class PseudonymManager( val publicKey: PublicKey get() = this.tree.publicKey - private val credentials = this.database.getCredentialsFor(this.publicKey) + private var credentials = this.database.getCredentialsFor(this.publicKey).toMutableList() init { logger.info("Loading public key ${this.publicKey.keyToHash().toHex()} from database") @@ -50,16 +50,16 @@ class PseudonymManager( this.database.insertMetadata(this.publicKey, metadata) } - val validAttestations = setOf() + val validAttestations = mutableSetOf() for ((authorityPublicKey, identityAttestation) in attestations) { if (this.addAttestation(authorityPublicKey, identityAttestation)) { - validAttestations.plus(identityAttestation) + validAttestations += identityAttestation } } val out = Credential(metadata, validAttestations) - this.credentials.plus(out) + this.credentials.plusAssign(out) return out } return null @@ -130,7 +130,7 @@ class PseudonymManager( } } val requiredTokenHashes = metadata.map { it.tokenPointer } - val tokens = setOf() + val tokens = mutableSetOf() for (requiredTokenHash in requiredTokenHashes) { val rootToken = this.tree.elements[requiredTokenHash.toKey()]!! @@ -139,12 +139,12 @@ class PseudonymManager( throw RuntimeException("Attempted to create disclosure for undisclosable Token!") } - tokens.plus(rootToken) + tokens += rootToken var currentToken = rootToken while (!currentToken.previousTokenHash.contentEquals(this.tree.genesisHash)) { currentToken = this.tree.elements[currentToken.previousTokenHash.toKey()]!! - tokens.plus(currentToken) + tokens += currentToken } } var serializedTokens = byteArrayOf() From add82ae599bf8b3ab7088ed308cff5db1659b7af Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:43:24 +0200 Subject: [PATCH 051/144] Make i/o functions be set on object initialization in CommunicationManager --- .../nl/tudelft/ipv8/attestation/CommunicationManager.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt index c45794c4..19cece81 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt @@ -29,6 +29,8 @@ class CommunicationManager( private val attestationStore: AttestationStore, private val identityStore: IdentityStore, private val authorityManager: AuthorityManager, + private val storePseudonym: ((String, PrivateKey) -> Unit)? = null, + private val loadPseudonym: ((String) -> PrivateKey)? = null, ) { private val channels = hashMapOf() private val nameToChannel = hashMapOf() @@ -46,9 +48,7 @@ class CommunicationManager( fun load( name: String, - rendezvousToken: String?, - storePseudonym: ((String, PrivateKey) -> Unit)? = null, - loadPseudonym: ((String) -> PrivateKey)? = null, + rendezvousToken: String? = null, ): CommunicationChannel { if (nameToChannel.containsKey(name)) { return this.nameToChannel[name]!! From d6fc8bd0a8185736f6d04370c680eb68852c788f Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:44:23 +0200 Subject: [PATCH 052/144] Correctly initialize overlays in CommunicationManager --- .../ipv8/attestation/CommunicationManager.kt | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt index 19cece81..569d4a52 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt @@ -62,20 +62,26 @@ class CommunicationManager( } val publicKeyBytes = privateKey.pub().keyToBin() - if (this.channels.containsKey(publicKeyBytes.toKey())) { + if (!this.channels.containsKey(publicKeyBytes.toKey())) { val decodedRendezvousToken: ByteArray? = - (rendezvousToken ?: defaultEncodingUtils.decodeBase64FromString(rendezvousToken!!)) as ByteArray? - val identityOverlay = createCommunity(privateKey, + (rendezvousToken?.let { defaultEncodingUtils.decodeBase64FromString(it) }) + + val identityOverlay = createCommunity( + privateKey, this.iPv8Instance, this.lazyIdentityManager(), identityStore, - decodedRendezvousToken) + decodedRendezvousToken + ) - val attestationOverlay = AttestationCommunity(identityOverlay.myPeer, + val attestationOverlay = AttestationCommunity( + identityOverlay.myPeer, identityOverlay.endpoint, identityOverlay.network, authorityManager, - attestationStore) + attestationStore + ) + attestationOverlay.load() this.channels[publicKeyBytes.toKey()] = CommunicationChannel(attestationOverlay, identityOverlay) this.nameToChannel[name] = this.channels[publicKeyBytes.toKey()]!! From 58b6c000dafd4f4a78d2d2aaa52ed5de5952e986 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:45:22 +0200 Subject: [PATCH 053/144] Use correct peer when requesting attestations --- .../java/nl/tudelft/ipv8/attestation/CommunicationManager.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt index 569d4a52..4ce0bc19 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt @@ -290,8 +290,8 @@ class CommunicationChannel(val attestationOverlay: AttestationCommunity, val ide fun requestAttestation(peer: Peer, attributeName: String, idFormat: String, metadata: HashMap) { val key = this.attestationOverlay.getIdAlgorithm(idFormat).generateSecretKey() - metadata.put("id_format", idFormat) - this.attestationMetadata[AttributePointer(peer, attributeName)] = metadata + metadata["id_format"] = idFormat + this.attestationMetadata[AttributePointer(this.identityOverlay.myPeer, attributeName)] = metadata this.attestationOverlay.requestAttestation(peer, attributeName, key, metadata) } From ee06d48222dea0fe5ae9e49a73b20c038998cdc1 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:46:00 +0200 Subject: [PATCH 054/144] Use setResult method from SettableDeferred --- .../ipv8/attestation/CommunicationManager.kt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt index 4ce0bc19..a63ced48 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt @@ -297,26 +297,28 @@ class CommunicationChannel(val attestationOverlay: AttestationCommunity, val ide fun attest(peer: Peer, attributeName: String, value: ByteArray) { val outstanding = this.attestationRequests.remove(AttributePointer(peer, attributeName))!! - GlobalScope.launch { outstanding.first.await() } + GlobalScope.launch { outstanding.first.setResult(value) } } fun allowVerification(peer: Peer, attributeName: String) { val outstanding = this.verifyRequests.remove(AttributePointer(peer, attributeName))!! - GlobalScope.launch { outstanding.await() } + GlobalScope.launch { outstanding.setResult(true) } } fun disallowVerification(peer: Peer, attributeName: String) { val outstanding = this.verifyRequests.remove(AttributePointer(peer, attributeName))!! - GlobalScope.launch { outstanding.await() } + GlobalScope.launch { outstanding.setResult(false) } } - fun verify(peer: Peer, attributeHash: ByteArray, referenceValues: List, idFormat: String) { - this.verificationOutput[attributeHash.toKey()] = referenceValues.map { Pair(it, null) } - this.attestationOverlay.verifyAttestationValues(peer.address, - attributeHash, + fun verify(peer: Peer, attestationHash: ByteArray, referenceValues: List, idFormat: String) { + this.verificationOutput[attestationHash.toKey()] = referenceValues.map { Pair(it, null) } + this.attestationOverlay.verifyAttestationValues( + peer.address, + attestationHash, referenceValues, this::onVerificationResults, - idFormat) + idFormat + ) } } From 9df9033e874cb8193cb27b7b425e0c6de11076a9 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:46:27 +0200 Subject: [PATCH 055/144] Use SettableDeferred --- .../ipv8/attestation/CommunicationManager.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt index a63ced48..305561bf 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt @@ -202,10 +202,13 @@ class CommunicationChannel(val attestationOverlay: AttestationCommunity, val ide metadataString: String, ): Deferred { // Promise some ByteArray. - val deferred: Deferred = GlobalScope.async(start = CoroutineStart.LAZY) { null } + val deferred = SettableDeferred() this.attestationRequests[AttributePointer(peer, attributeName)] = Pair(deferred, metadataString) - this.attestationMetadata[AttributePointer(peer, attributeName)] - return deferred + @Suppress("UNCHECKED_CAST") + this.attestationMetadata[AttributePointer(peer, attributeName)] = + JSONObject(metadataString).toMap() as Map + + return GlobalScope.async(start = CoroutineStart.LAZY) { deferred.await() } } @Suppress("UNUSED_PARAMETER") @@ -236,12 +239,12 @@ class CommunicationChannel(val attestationOverlay: AttestationCommunity, val ide } } - private fun onVerifyRequestAsync(peer: Peer, attributeHash: ByteArray): Deferred { + private fun onVerifyRequestAsync(peer: Peer, attributeHash: ByteArray): Deferred { val metadata = this.identityOverlay.getAttestationByHash(attributeHash) ?: return CompletableDeferred(null) val attributeName = JSONObject(String(metadata.serializedMetadata)).getString("name") - val deferred = GlobalScope.async(start = CoroutineStart.LAZY) { false } + val deferred = SettableDeferred() this.verifyRequests[AttributePointer(peer, attributeName)] = deferred - return deferred + return GlobalScope.async(start = CoroutineStart.LAZY) { deferred.await() } } private fun onVerificationResults(attributeHash: ByteArray, value: List) { From 09382649f668a463b6aae8dbf9a9807ce661bacb Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:47:27 +0200 Subject: [PATCH 056/144] Fix formatting + supress unimplemented method --- .../ipv8/attestation/CommunicationManager.kt | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt index 305561bf..3eb44966 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt @@ -12,10 +12,7 @@ import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity import nl.tudelft.ipv8.attestation.wallet.AttestationStore import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.defaultCryptoProvider -import nl.tudelft.ipv8.util.ByteArrayKey -import nl.tudelft.ipv8.util.defaultEncodingUtils -import nl.tudelft.ipv8.util.toHex -import nl.tudelft.ipv8.util.toKey +import nl.tudelft.ipv8.util.* import org.json.JSONObject import java.io.File import java.io.FileNotFoundException @@ -89,6 +86,7 @@ class CommunicationManager( return this.nameToChannel[name]!! } + @Suppress("UNUSED_PARAMETER") fun unload(name: String) { TODO() } @@ -173,9 +171,9 @@ class AttributePointer(val peer: Peer, val attributeName: String) { class CommunicationChannel(val attestationOverlay: AttestationCommunity, val identityOverlay: IdentityCommunity) { - private val attestationRequests = hashMapOf, String>>() - private val verifyRequests = hashMapOf>() - private val verificationOutput = hashMapOf>>() + val attestationRequests = hashMapOf, String>>() + val verifyRequests = hashMapOf>() + val verificationOutput = hashMapOf>>() private val attestationMetadata = hashMapOf>() init { @@ -227,15 +225,21 @@ class CommunicationChannel(val attestationOverlay: AttestationCommunity, val ide if (forPeer == myPeer) { if (fromPeer == myPeer) { @Suppress("UNCHECKED_CAST") - this.identityOverlay.selfAdvertise(attributeHash, attributeName, idFormat, - JSONObject(metadata).toMap() as HashMap?) + this.identityOverlay.selfAdvertise( + attributeHash, attributeName, idFormat, + JSONObject(metadata).toMap() as HashMap? + ) } else { - this.identityOverlay.requestAttestationAdvertisement(fromPeer!!, attributeHash, attributeName, idFormat, - metadata as HashMap?) + this.identityOverlay.requestAttestationAdvertisement( + fromPeer!!, attributeHash, attributeName, idFormat, + metadata as HashMap? + ) } } else { - this.identityOverlay.addKnownHash(attributeHash, attributeName, forPeer.publicKey, - metadata as HashMap?) + this.identityOverlay.addKnownHash( + attributeHash, attributeName, forPeer.publicKey, + metadata as HashMap? + ) } } @@ -278,10 +282,10 @@ class CommunicationChannel(val attestationOverlay: AttestationCommunity, val ide for (credential in pseudonym.getCredentials()) { val attestations = credential.attestations.toList() - val attesters = listOf() + val attesters = mutableListOf() for (attestation in attestations) { - attesters.plus(this.identityOverlay.identityManager.database.getAuthority(attestation)) + attesters += this.identityOverlay.identityManager.database.getAuthority(attestation) } val attributeHash = pseudonym.tree.elements[credential.metadata.tokenPointer.toKey()]!!.contentHash val jsonMetadata = JSONObject(String(credential.metadata.serializedMetadata)) From 747bbfa45019a66920eb6b2392b279a0f27bee5c Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:48:14 +0200 Subject: [PATCH 057/144] Use mutable types + correctly init peer and network --- .../ipv8/attestation/identity/IdentityCommunity.kt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index d284133f..367f30f6 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -52,16 +52,19 @@ class IdentityCommunity( override var network: Network = Network(), ) : Community() { - internal var identityManager: IdentityManager = identityManager ?: IdentityManager(database) + var identityManager: IdentityManager = identityManager ?: IdentityManager(database) private val knownAttestationHashes = hashMapOf() - private val pseudonymManager = this.identityManager.getPseudonym(this.myPeer.publicKey) + private val pseudonymManager = this.identityManager.getPseudonym(this.myPeer.key) - private var tokenChain: List = arrayListOf() - private val metadataChain: List = listOf() - private val attestationChain: List = listOf() + private var tokenChain: List = mutableListOf() + private var metadataChain: List = mutableListOf() + private var attestationChain: List = mutableListOf() private val permissions: HashMap = hashMapOf() init { + super.myPeer = myPeer + super.network = network + for (token in this.pseudonymManager.tree.elements.values) { val chain = this.pseudonymManager.tree.getRootPath(token) if (chain.size > this.tokenChain.size) { From 2ce7826e753857c3a928a2cd5d1dfdbd70c38961 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:49:35 +0200 Subject: [PATCH 058/144] Use external padhash function + add elements correctly to collections --- .../attestation/identity/IdentityCommunity.kt | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index 367f30f6..f65a9819 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -1,9 +1,7 @@ package nl.tudelft.ipv8.attestation.identity import mu.KotlinLogging -import nl.tudelft.ipv8.Community -import nl.tudelft.ipv8.IPv8 -import nl.tudelft.ipv8.Peer +import nl.tudelft.ipv8.* import nl.tudelft.ipv8.attestation.identity.database.Credential import nl.tudelft.ipv8.attestation.identity.database.IdentityStore import nl.tudelft.ipv8.attestation.identity.manager.Disclosure @@ -21,6 +19,7 @@ import nl.tudelft.ipv8.messaging.Packet import nl.tudelft.ipv8.peerdiscovery.Network import nl.tudelft.ipv8.peerdiscovery.strategy.RandomWalk import nl.tudelft.ipv8.util.ByteArrayKey +import nl.tudelft.ipv8.util.padSHA1Hash import nl.tudelft.ipv8.util.toHex import nl.tudelft.ipv8.util.toKey import org.json.JSONObject @@ -74,8 +73,8 @@ class IdentityCommunity( for (credential in this.pseudonymManager.getCredentials()) { for (token in this.tokenChain) { if (credential.metadata.tokenPointer.contentEquals(token.hash)) { - this.metadataChain.plus(credential.metadata) - this.attestationChain.plus(credential.attestations) + this.metadataChain += credential.metadata + this.attestationChain += credential.attestations break } } @@ -87,12 +86,6 @@ class IdentityCommunity( messageHandlers[MISSING_RESPONSE_PAYLOAD] = ::onMissingResponseWrapper } - - private fun padHash(attributeHash: ByteArray): ByteArray { - logger.debug("Padding deprecated SHA-1 hash to 32 bytes. SHA3-256 should be used instead.") - return "SHA-1".toByteArray() + byteArrayOf(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + attributeHash - } - private fun onDisclosureWrapper(packet: Packet) { val (peer, payload) = packet.getAuthPayload(DisclosePayload.Deserializer) logger.info("Received Disclose payload from ${peer.mid}.") @@ -123,13 +116,13 @@ class IdentityCommunity( publicKey: PublicKey, metadata: HashMap? = null, ) { - val hash = if (attributeHash.size == 20) this.padHash(attributeHash) else attributeHash + val hash = if (attributeHash.size == 20) padSHA1Hash(attributeHash) else attributeHash this.knownAttestationHashes[ByteArrayKey(hash)] = HashInformation(name, System.currentTimeMillis() / 1000F, publicKey, metadata) } fun getAttestationByHash(attributeHash: ByteArray): Metadata? { - val hash = if (attributeHash.size == 20) this.padHash(attributeHash) else attributeHash + val hash = if (attributeHash.size == 20) padSHA1Hash(attributeHash) else attributeHash for (credential in this.pseudonymManager.getCredentials()) { val token = this.pseudonymManager.tree.elements.get(ByteArrayKey(credential.metadata.tokenPointer)) if (token?.hash.contentEquals(hash)) { @@ -205,11 +198,13 @@ class IdentityCommunity( private fun receivedDisclosureForAttest(peer: Peer, disclosure: Disclosure) { val solicited = this.knownAttestationHashes.values.filter { it.publicKey == peer.publicKey } if (solicited.isNotEmpty()) { - val (correct, pseudonym) = this.identityManager.substantiate(peer.publicKey, + val (correct, pseudonym) = this.identityManager.substantiate( + peer.publicKey, disclosure.metadata, disclosure.tokens, disclosure.attestations, - disclosure.authorities) + disclosure.authorities + ) val requiredAttributes = this.knownAttestationHashes.filter { it.value.publicKey == peer.publicKey }.keys.toTypedArray() val knownAttributes: List = @@ -259,7 +254,7 @@ class IdentityCommunity( blockType: String, metadata: HashMap?, ): Credential { - val hash = if (attributeHash.size == 20) this.padHash(attributeHash) else attributeHash + val hash = if (attributeHash.size == 20) padSHA1Hash(attributeHash) else attributeHash val extendedMetadata = hashMapOf("name" to name, "schema" to blockType, "date" to System.currentTimeMillis() / 1000F) @@ -267,20 +262,24 @@ class IdentityCommunity( extendedMetadata.putAll(metadata) } - val credential = this.pseudonymManager.createCredential(hash, + val credential = this.pseudonymManager.createCredential( + hash, extendedMetadata, - if (this.metadataChain.isNotEmpty()) this.metadataChain.last() else null) + if (this.metadataChain.isNotEmpty()) this.metadataChain.last() else null + ) - this.attestationChain.plus(credential.attestations) - this.metadataChain.plus(credential.metadata) - this.tokenChain.plus(this.pseudonymManager.tree.elements[credential.metadata.tokenPointer.toKey()]) + this.attestationChain += credential.attestations + this.metadataChain += credential.metadata + this.tokenChain += this.pseudonymManager.tree.elements[credential.metadata.tokenPointer.toKey()]!! return credential } private fun onDisclosure(peer: Peer, payload: DisclosePayload) { - this.receivedDisclosureForAttest(peer, - Disclosure(payload.metadata, payload.tokens, payload.attestations, payload.authorities)) + this.receivedDisclosureForAttest( + peer, + Disclosure(payload.metadata, payload.tokens, payload.attestations, payload.authorities) + ) } private fun onAttest(peer: Peer, payload: AttestPayload) { From fc70c208bc38fb74918154c32b7133f9e17c148b Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:50:02 +0200 Subject: [PATCH 059/144] Fitler out fields used by AttestationCommunity --- .../ipv8/attestation/identity/IdentityCommunity.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index f65a9819..c86c3a3e 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -34,6 +34,9 @@ const val ATTEST_PAYLOAD = 2 const val REQUEST_MISSING_PAYLOAD = 3 const val MISSING_RESPONSE_PAYLOAD = 4 +// TODO: "clean up". +val DEFAULT_METADATA = arrayOf("name", "date", "schema", "signature", "public_key", "attribute") + class HashInformation( val name: String, val time: Float, @@ -163,8 +166,9 @@ class IdentityCommunity( return false } if (this.knownAttestationHashes[attributeHash.toKey()]!!.metadata != null - && transaction.toMap().filterKeys { it !in arrayOf("name", "data", "schema") } - != this.knownAttestationHashes[attributeHash.toKey()]!!.metadata + && transaction.toMap().filterKeys { it !in DEFAULT_METADATA } + // TODO: Remove filter here. + != this.knownAttestationHashes[attributeHash.toKey()]!!.metadata!!.filterKeys { it !in DEFAULT_METADATA } ) { logger.debug("Not signing $metadata, metadata does not match!") return false From b5b9ca9290380fb48bd0f46cdd0ae675ac91aeea Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:50:10 +0200 Subject: [PATCH 060/144] Correctly parse metadata --- .../nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index c86c3a3e..ef1bc533 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -136,7 +136,7 @@ class IdentityCommunity( } fun shouldSign(pseudonym: PseudonymManager, metadata: Metadata): Boolean { - val transaction = JSONObject(metadata.serializedMetadata) + val transaction = JSONObject(String(metadata.serializedMetadata)) val requestedKeys = transaction.keySet() if (!pseudonym.tree.elements.containsKey(metadata.tokenPointer.toKey())) { return false From e9c7dd8f75566f98089680bdf7f5341e83b85498 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:50:28 +0200 Subject: [PATCH 061/144] Correctly trim tokens --- .../nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index ef1bc533..2eb59472 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -194,7 +194,7 @@ class IdentityCommunity( } packetSpace = max(0, packetSpace) val trimLength = packetSpace / tokenSize - tokensOut = tokens.copyOfRange(-trimLength * tokenSize, tokensOut.size) + tokensOut = tokens.copyOfRange(tokens.size - (trimLength * tokenSize), tokens.size) } return Disclosure(metadata, tokensOut, attestations, authorities) } From 7b5705d17d9386e488208c6affbe7716c31bdbd7 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:50:55 +0200 Subject: [PATCH 062/144] Check if data is valid to sign + use correct hash from token --- .../attestation/identity/IdentityCommunity.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index 2eb59472..c3ca40c7 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -128,7 +128,7 @@ class IdentityCommunity( val hash = if (attributeHash.size == 20) padSHA1Hash(attributeHash) else attributeHash for (credential in this.pseudonymManager.getCredentials()) { val token = this.pseudonymManager.tree.elements.get(ByteArrayKey(credential.metadata.tokenPointer)) - if (token?.hash.contentEquals(hash)) { + if (token?.contentHash.contentEquals(hash)) { return credential.metadata } } @@ -216,11 +216,14 @@ class IdentityCommunity( if (correct && requiredAttributes.any { knownAttributes.contains(it) }) { for (credential in pseudonym.getCredentials()) { - logger.info("Attesting to ${credential.metadata}.") - val attestation = pseudonym.createAttestation(credential.metadata, this.myPeer.key as PrivateKey) - pseudonym.addAttestation(this.myPeer.publicKey, attestation) - val payload = AttestPayload(attestation.getPlaintextSigned()) - this.endpoint.send(peer, serializePacket(ATTEST_PAYLOAD, payload)) + if (shouldSign(pseudonym, credential.metadata)) { + logger.info("Attesting to ${credential.metadata}.") + val attestation = + pseudonym.createAttestation(credential.metadata, this.myPeer.key as PrivateKey) + pseudonym.addAttestation(this.myPeer.publicKey, attestation) + val payload = AttestPayload(attestation.getPlaintextSigned()) + this.endpoint.send(peer, serializePacket(ATTEST_PAYLOAD, payload)) + } } } From 3383f302c989097022b835b4d1d261c0e8be9df6 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:51:14 +0200 Subject: [PATCH 063/144] Fix sha3 + add hash padding --- .../java/nl/tudelft/ipv8/util/HashUtils.kt | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/util/HashUtils.kt b/ipv8/src/main/java/nl/tudelft/ipv8/util/HashUtils.kt index 0a81f401..12f8011d 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/util/HashUtils.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/util/HashUtils.kt @@ -1,5 +1,7 @@ package nl.tudelft.ipv8.util +import org.bouncycastle.jcajce.provider.digest.SHA3 +import org.bouncycastle.jcajce.provider.digest.SHA3.DigestSHA3 import java.math.BigInteger import java.security.MessageDigest @@ -7,6 +9,7 @@ private const val SHA1 = "SHA-1" private const val SHA256 = "SHA-256" private const val SHA512 = "SHA-512" private const val SHA3_256 = "SHA3-256" +private val SHA1_PADDING = "SHA-1".toByteArray() + byteArrayOf(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) fun sha1(input: ByteArray): ByteArray { return MessageDigest @@ -27,10 +30,10 @@ fun sha512(input: ByteArray): ByteArray { } fun sha3_256(input: ByteArray): ByteArray { - return MessageDigest.getInstance(SHA3_256).digest(input) + val digestSHA3: DigestSHA3 = SHA3.Digest256() + return digestSHA3.digest(input) } - fun toASCII(value: String): ByteArray { return value.toByteArray(Charsets.US_ASCII) } @@ -64,3 +67,15 @@ fun sha512AsBigInt(input: ByteArray): BigInteger { } return out } + +fun stripSHA1Padding(input: ByteArray): ByteArray { + val prefix = input.copyOfRange(0, 12) + return if (prefix.contentEquals(SHA1_PADDING)) input.copyOfRange(12, input.size) else input +} + +fun padSHA1Hash(attributeHash: ByteArray): ByteArray { + return SHA1_PADDING + attributeHash +} + + + From c4d7ba0977bb105fe4ca72d3f23d0f47ea80cf5a Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sat, 17 Apr 2021 15:51:34 +0200 Subject: [PATCH 064/144] Update klint --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 47fa350b..3c4d9e45 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ buildscript { ext.kotlin_version = '1.4.21' - ext.ktlint_version = '0.36.0' + ext.ktlint_version = '0.41.0' ext.coroutines_version = '1.4.2' ext.ktlint_gradle_version = '9.1.1' // https://github.com/cashapp/sqldelight/issues/1574 From e6ba2827b658af1a1084a5d975965721b791adb3 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sun, 18 Apr 2021 14:41:01 +0200 Subject: [PATCH 065/144] Adhere to klint styling --- .../ipv8/attestation/CommunicationManager.kt | 3 - .../attestation/identity/IdentityCommunity.kt | 1 - .../wallet/AttestationCommunity.kt | 152 +++++++++++------- 3 files changed, 93 insertions(+), 63 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt index 3eb44966..c32e582f 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt @@ -35,7 +35,6 @@ class CommunicationManager( get() = iPv8Instance.getOverlay() var identityManager = loadedCommunity?.identityManager - fun lazyIdentityManager(): IdentityManager { if (this.identityManager == null) { this.identityManager = IdentityManager(identityStore) @@ -146,7 +145,6 @@ class CommunicationManager( .toArray().toList() as List } } - } class AttributePointer(val peer: Peer, val attributeName: String) { @@ -327,5 +325,4 @@ class CommunicationChannel(val attestationOverlay: AttestationCommunity, val ide idFormat ) } - } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index c3ca40c7..7dd19b96 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -234,7 +234,6 @@ class IdentityCommunity( this.endpoint.send(peer, serializePacket(REQUEST_MISSING_PAYLOAD, payload)) } } - } else { logger.warn("Received unsolicited disclosure from $peer, dropping.") } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt index 2d36028a..fd8c1878 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt @@ -34,7 +34,6 @@ import kotlin.collections.HashMap import kotlin.random.Random import kotlin.random.nextUBytes - private val logger = KotlinLogging.logger {} private const val CHUNK_SIZE = 800 @@ -50,8 +49,10 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: network: Network, authorityManager: AuthorityManager, database: AttestationStore, - ) : this(authorityManager, - database) { + ) : this( + authorityManager, + database + ) { this.myPeer = myPeer this.endpoint = endpoint this.network = network @@ -75,15 +76,14 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val requestCache = RequestCache() init { - // Use parameters of baseclass if not overridden. if (!this::myPeer.isInitialized) { - this.myPeer = super.myPeer + throw RuntimeException("MyPeer is not initialized!") } if (!this::endpoint.isInitialized) { - this.endpoint = super.endpoint + throw RuntimeException("Endpoint is not initialized!") } if (!this::network.isInitialized) { - this.network = super.network + throw RuntimeException("Network is not initialized!") } authorityManager.loadTrustedAuthorities() @@ -110,17 +110,21 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: private fun onChallengeResponseWrapper(packet: Packet) { val (peer, payload) = packet.getAuthPayload(ChallengeResponsePayload.Deserializer) - logger.info("Received ChallengeResponse from ${peer.mid} for hash ${String(payload.challengeHash)} with response ${ - String(payload.response) - }.") + logger.info( + "Received ChallengeResponse from ${peer.mid} for hash ${String(payload.challengeHash)} with response ${ + String(payload.response) + }." + ) this.onChallengeResponse(peer, payload) } private fun onChallengeWrapper(packet: Packet) { val (peer, payload) = packet.getAuthPayload(ChallengePayload.Deserializer) - logger.info("Received Challenge from ${peer.mid} for hash ${String(payload.attestationHash)} with challenge ${ - String(payload.challenge) - }.") + logger.info( + "Received Challenge from ${peer.mid} for hash ${String(payload.attestationHash)} with challenge ${ + String(payload.challenge) + }." + ) this.onChallenge(peer, payload) } @@ -134,7 +138,6 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val (peer, payload) = packet.getAuthPayload(VerifyAttestationRequestPayload.Deserializer) logger.info("Received VerifyAttestationRequest from ${peer.mid} for hash ${String(payload.hash)}.") GlobalScope.launch { onVerifyAttestationRequest(peer, payload) } - } fun getIdAlgorithm(idFormat: String): IdentityAlgorithm { @@ -176,8 +179,10 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val isTrusted = this.authorityManager.contains(attestorKey.keyToHash()) val isOwner = peer.publicKey.keyToHash().toHex() == attesteeKeyHash - val isSignatureValid = attestorKey.verify(signature, - sha1(attestationHash + metadata.toByteArray())) + val isSignatureValid = attestorKey.verify( + signature, + sha1(attestationHash + metadata.toByteArray()) + ) return isTrusted && isOwner && isSignatureValid } @@ -209,20 +214,26 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val payload = RequestAttestationPayload(metadataJson.toString()) val gTimeStr = globalTime.toString().toByteArray() - this.requestCache.add(ReceiveAttestationRequestCache(this, - peer.mid + gTimeStr, - privateKey, - attributeName, - idFormat, - signature)) + this.requestCache.add( + ReceiveAttestationRequestCache( + this, + peer.mid + gTimeStr, + privateKey, + attributeName, + idFormat, + signature + ) + ) this.allowedAttestations[peer.mid] = (this.allowedAttestations[peer.mid] ?: emptyArray()) + arrayOf(gTimeStr) val packet = - serializePacket(ATTESTATION_REQUEST, + serializePacket( + ATTESTATION_REQUEST, payload, prefix = this.prefix, - timestamp = globalTime) + timestamp = globalTime + ) endpoint.send(peer, packet) } @@ -281,11 +292,13 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: ) } - this.sendAttestation(peer.address, + this.sendAttestation( + peer.address, attestationBlob, dist.globalTime, metadata.toString().toByteArray(), - if (shouldSign) signature else null) + if (shouldSign) signature else null + ) } private fun onAttestationComplete( @@ -299,23 +312,27 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: signature: ByteArray? = null, ) { this.attestationKeys[ByteArrayKey(attestationHash)] = Pair(privateKey, idFormat) - this.database.insertAttestation(deserialized, + this.database.insertAttestation( + deserialized, attestationHash, privateKey, idFormat, metaData, signature, - peer.publicKey) + peer.publicKey + ) if (this::attestationRequestCompleteCallback.isInitialized) { - this.attestationRequestCompleteCallback(this.myPeer, + this.attestationRequestCompleteCallback( + this.myPeer, name, deserialized, attestationHash, idFormat, peer, metaData, - signature) + signature + ) } } @@ -411,8 +428,12 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val allowedGlobs = this.allowedAttestations.get(peer.mid) ?: arrayOf() allowedGlobs.forEach { if (it.contentEquals(dist.globalTime.toString().toByteArray())) { - peerIds.add(PeerCache.idFromAddress(ATTESTATION_REQUEST_PREFIX, - peer.mid + it)) + peerIds.add( + PeerCache.idFromAddress( + ATTESTATION_REQUEST_PREFIX, + peer.mid + it + ) + ) } } if (this.requestCache.has(prefix, number)) { @@ -427,9 +448,11 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: if (sha1(serialized).contentEquals(payload.hash)) { val deserialized = schemaManager.deserialize(serialized, cache.idFormat) this.requestCache.pop(prefix, number) - this.onReceivedAttestation(peer, + this.onReceivedAttestation( + peer, deserialized, - payload.hash) + payload.hash + ) } logger.info("Received attestation chunk ${payload.sequenceNumber} for proving by $peer") @@ -477,7 +500,6 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: logger.warn("Received Attestation chunk which we did not request!") } } - } private fun onReceivedAttestation( @@ -521,10 +543,8 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val packet = serializePacket(CHALLENGE, payload, prefix = this.prefix) this.endpoint.send(peer.address, packet) } - } - private fun onChallenge(peer: Peer, payload: ChallengePayload) { if (!this.attestationKeys.containsKey(ByteArrayKey(payload.attestationHash))) { logger.error("Received ChallengePayload $payload for unknown attestation hash ${payload.attestationHash}.") @@ -536,11 +556,12 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val algorithm = this.getIdAlgorithm(idFormat) val attestation = this.cachedAttestationBlobs[ByteArrayKey(payload.attestationHash)]!! - val outGoingPayload = ChallengeResponsePayload(challengeHash, - algorithm.createChallengeResponse(privateKey, attestation, payload.challenge)) + val outGoingPayload = ChallengeResponsePayload( + challengeHash, + algorithm.createChallengeResponse(privateKey, attestation, payload.challenge) + ) val packet = serializePacket(CHALLENGE_RESPONSE, outGoingPayload, prefix = this.prefix) this.endpoint.send(peer.address, packet) - } private fun onChallengeResponse( @@ -552,8 +573,10 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: if (this.requestCache.has(prefix, number)) { val cache = this.requestCache.pop(prefix, number) as PendingChallengesCache val provingCache = cache.provingCache - val (provingCachePrefix, provingCacheId) = HashCache.idFromHash(PROVING_ATTESTATION_PREFIX, - provingCache.cacheHash) + val (provingCachePrefix, provingCacheId) = HashCache.idFromHash( + PROVING_ATTESTATION_PREFIX, + provingCache.cacheHash + ) var challenge: ByteArray? = null // TODO: Come up with more elegant solution for ByteArray checking. @@ -587,27 +610,37 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: } provingCache.attestationCallbacks(provingCache.cacheHash, provingCache.relativityMap) } else { - // TODO: Add secure random. val honestyCheck = algorithm.honestCheck && (Random.nextUBytes(1)[0].toInt() < 38) var honestyCheckByte = if (honestyCheck) arrayOf(0, 1, 2).random() else -1 challenge = null if (honestyCheck) { - while (challenge == null || this.requestCache.has(HashCache.idFromHash(PENDING_CHALLENGES_PREFIX, - sha1(challenge))) + while (challenge == null || this.requestCache.has( + HashCache.idFromHash( + PENDING_CHALLENGES_PREFIX, + sha1(challenge) + ) + ) ) { challenge = algorithm.createHonestyChallenge(provingCache.publicKey!!, honestyCheckByte) } } - if (!honestyCheck || (challenge != null && this.requestCache.has(HashCache.idFromHash( - PENDING_CHALLENGES_PREFIX, - sha1(challenge)))) + if (!honestyCheck || (challenge != null && this.requestCache.has( + HashCache.idFromHash( + PENDING_CHALLENGES_PREFIX, + sha1(challenge) + ) + )) ) { honestyCheckByte = -1 challenge = null for (c in provingCache.challenges) { - if (!this.requestCache.has(HashCache.idFromHash(PENDING_CHALLENGES_PREFIX, - sha1(c))) + if (!this.requestCache.has( + HashCache.idFromHash( + PENDING_CHALLENGES_PREFIX, + sha1(c) + ) + ) ) { challenge = c break @@ -619,20 +652,22 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: } } logger.info("Sending challenge $honestyCheckByte (${provingCache.hashedChallenges.size}).") - this.requestCache.add(PendingChallengesCache(this, - sha1(challenge!!), - provingCache, - cache.idFormat, - honestyCheckByte)) + this.requestCache.add( + PendingChallengesCache( + this, + sha1(challenge!!), + provingCache, + cache.idFormat, + honestyCheckByte + ) + ) val outGoingPayload = ChallengePayload(provingCache.cacheHash, challenge) val packet = serializePacket(CHALLENGE, outGoingPayload, prefix = this.prefix) this.endpoint.send(peer.address, packet) } - } } - } object MessageId { @@ -640,7 +675,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: const val ATTESTATION = 2 const val CHALLENGE = 3 const val CHALLENGE_RESPONSE = 4 - const val ATTESTATION_REQUEST = 5; + const val ATTESTATION_REQUEST = 5 } class Factory( @@ -651,7 +686,6 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: return AttestationCommunity(authorityManager, database) } } - } From 3ac95aa3c8229c64fa652c9ebcf8b9994d9b5436 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 19 Apr 2021 12:23:39 +0200 Subject: [PATCH 066/144] Apply correct EOF + remove unnecessary initialization checks --- .../ipv8/attestation/wallet/AttestationCommunity.kt | 10 ---------- .../nl/tudelft/ipv8/sqldelight/DbAuthority.sq | 2 +- .../nl/tudelft/ipv8/sqldelight/DbIdentity.sq | 2 +- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt index fd8c1878..7c38f191 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt @@ -76,16 +76,6 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val requestCache = RequestCache() init { - if (!this::myPeer.isInitialized) { - throw RuntimeException("MyPeer is not initialized!") - } - if (!this::endpoint.isInitialized) { - throw RuntimeException("Endpoint is not initialized!") - } - if (!this::network.isInitialized) { - throw RuntimeException("Network is not initialized!") - } - authorityManager.loadTrustedAuthorities() schemaManager.registerDefaultSchemas() for (att in this.database.getAllAttestations()) { diff --git a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq index e8ac68ee..b7c74e10 100644 --- a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq +++ b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq @@ -68,4 +68,4 @@ getVersionsSince: SELECT version_number FROM versions WHERE authority_id = ? AND version_number > ?; getAllRevocations: -SELECT authorities.public_key_hash, versions.version_number, versions.signature, revocations.attestation_hash FROM authorities LEFT JOIN versions ON authorities.latest_version_id = versions.version_id LEFT JOIN revocations ON authorities.authority_id = revocations.authority_id; \ No newline at end of file +SELECT authorities.public_key_hash, versions.version_number, versions.signature, revocations.attestation_hash FROM authorities LEFT JOIN versions ON authorities.latest_version_id = versions.version_id LEFT JOIN revocations ON authorities.authority_id = revocations.authority_id; diff --git a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq index 923d593a..5c71ceb8 100644 --- a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq +++ b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq @@ -51,4 +51,4 @@ getAuthority: SELECT authority_key FROM identity_attestations WHERE signature = ?; getKnownIdentities: -SELECT public_key FROM tokens; \ No newline at end of file +SELECT public_key FROM tokens; From d59155142dbdd8a253c31ddc3a0bcc62b50285a1 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sun, 25 Apr 2021 21:11:41 +0200 Subject: [PATCH 067/144] Add value to AttestationStore --- .../wallet/AttestationSQLiteStore.kt | 26 +++++++++++-------- .../attestation/wallet/AttestationStore.kt | 9 ++++--- .../tudelft/ipv8/sqldelight/DbAttestation.sq | 10 ++++--- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationSQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationSQLiteStore.kt index d202e87d..226f2089 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationSQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationSQLiteStore.kt @@ -1,14 +1,12 @@ package nl.tudelft.ipv8.attestation.wallet import mu.KotlinLogging -import nl.tudelft.ipv8.attestation.Authority import nl.tudelft.ipv8.attestation.WalletAttestation import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPrivateKey import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.keyvault.defaultCryptoProvider import nl.tudelft.ipv8.sqldelight.Database - private val attestationMapper: ( ByteArray, ByteArray, @@ -17,13 +15,13 @@ private val attestationMapper: ( String?, ByteArray?, ByteArray?, -) -> AttestationBlob = { hash, blob, key, id_format, metadata, signature, attestor_key -> +) -> AttestationBlob = { hash, blob, key, id_format, value, signature, attestor_key -> AttestationBlob( hash, blob, key, id_format, - metadata, + value, signature, attestor_key?.let { defaultCryptoProvider.keyFromPublicBin(it) } ) @@ -43,27 +41,33 @@ class AttestationSQLiteStore(database: Database) : AttestationStore { attestationHash: ByteArray, privateKey: BonehPrivateKey, idFormat: String, - metadata: String?, + value: String?, signature: ByteArray?, attestorKey: PublicKey?, ) { val blob = attestation.serializePrivate(privateKey.publicKey()) - logger.info(" *** Inserting to DB: $attestation: [${String(attestationHash)}, ${String(blob)}, ${privateKey.serialize()}, $idFormat]") - dao.insertAttestation(attestationHash, + dao.insertAttestation( + attestationHash, blob, privateKey.serialize(), idFormat, - metadata, + value, signature, - attestorKey?.keyToBin()) + attestorKey?.keyToBin() + ) } - override fun getAttestationByHash(attestationHash: ByteArray): ByteArray? { + override fun getAttestationBlobByHash(attestationHash: ByteArray): ByteArray? { return dao.getAttestationByHash(attestationHash).executeAsOneOrNull() } + override fun getValueAndSignatureByHash(attestationHash: ByteArray): Pair? { + val pair = + dao.getValueAndSignatureByHash(attestationHash).executeAsOneOrNull() ?: return null + return Pair(pair.value!!, pair.signature!!) + } + override fun deleteAttestationByHash(attestationHash: ByteArray) { return dao.deleteAttestationByHash(attestationHash) } - } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationStore.kt index 598800e0..2e575a8c 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationStore.kt @@ -1,6 +1,5 @@ package nl.tudelft.ipv8.attestation.wallet -import nl.tudelft.ipv8.attestation.Authority import nl.tudelft.ipv8.attestation.WalletAttestation import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPrivateKey import nl.tudelft.ipv8.keyvault.PublicKey @@ -10,7 +9,7 @@ class AttestationBlob( val blob: ByteArray, val key: ByteArray, val idFormat: String, - val metadata: String?, + val value: String?, val signature: ByteArray?, val attestorKey: PublicKey?, ) @@ -23,12 +22,14 @@ interface AttestationStore { attestationHash: ByteArray, privateKey: BonehPrivateKey, idFormat: String, - metadata: String? = null, + value: String? = null, signature: ByteArray? = null, attestorKey: PublicKey? = null, ) - fun getAttestationByHash(attestationHash: ByteArray): ByteArray? + fun getAttestationBlobByHash(attestationHash: ByteArray): ByteArray? + + fun getValueAndSignatureByHash(attestationHash: ByteArray): Pair? fun deleteAttestationByHash(attestationHash: ByteArray) } diff --git a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAttestation.sq b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAttestation.sq index a8691260..d8a4e89b 100644 --- a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAttestation.sq +++ b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAttestation.sq @@ -3,19 +3,23 @@ CREATE TABLE attestations ( blob BLOB NOT NULL, key BLOB NOT NULL, id_format TEXT NOT NULL, - meta_data TEXT, + value TEXT, signature BLOB, - attestor_key BLOB + attestor_key BLOB, + PRIMARY KEY(hash) ); getAllAttestations: SELECT * FROM attestations; insertAttestation: -INSERT INTO attestations (hash, blob, key, id_format, meta_data, signature, attestor_key) VALUES(?, ?, ?, ?, ?, ?, ?); +INSERT INTO attestations (hash, blob, key, id_format, value, signature, attestor_key) VALUES(?, ?, ?, ?, ?, ?, ?); getAttestationByHash: SELECT blob FROM attestations WHERE hash = ?; +getValueAndSignatureByHash: +SELECT value, signature FROM attestations WHERE hash = ?; + deleteAttestationByHash: DELETE FROM attestations WHERE hash = ?; From dc5d8f20fb46caa069c3c12edbdf10218dddb56d Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sun, 25 Apr 2021 21:13:01 +0200 Subject: [PATCH 068/144] Add value to AttestationCommunity and AttestationChunkPayload + remove local verification logic --- .../wallet/AttestationCommunity.kt | 101 +++++++----------- .../payloads/AttestationChunkPayload.kt | 14 +-- 2 files changed, 48 insertions(+), 67 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt index 7c38f191..00b31ec9 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt @@ -21,7 +21,6 @@ import nl.tudelft.ipv8.attestation.wallet.caches.* import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPrivateKey import nl.tudelft.ipv8.attestation.wallet.payloads.* import nl.tudelft.ipv8.keyvault.PrivateKey -import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.messaging.EndpointAggregator import nl.tudelft.ipv8.messaging.Packet import nl.tudelft.ipv8.messaging.payload.GlobalTimeDistributionPayload @@ -64,7 +63,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val schemaManager = SchemaManager() private lateinit var attestationRequestCallback: (peer: Peer, attributeName: String, metaData: String) -> Deferred - private lateinit var attestationRequestCompleteCallback: (forPeer: Peer, attributeName: String, attestation: WalletAttestation, attestationHash: ByteArray, idFormat: String, fromPeer: Peer?, metaData: String?, signature: ByteArray?) -> Unit + private lateinit var attestationRequestCompleteCallback: (forPeer: Peer, attributeName: String, attestation: WalletAttestation, attestationHash: ByteArray, idFormat: String, fromPeer: Peer?, value: ByteArray?, signature: ByteArray?) -> Unit private lateinit var verifyRequestCallback: (peer: Peer, attributeHash: ByteArray) -> Deferred private lateinit var attestationChunkCallback: (peer: Peer, sequenceNumber: Int) -> Unit @@ -138,7 +137,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: this.attestationRequestCallback = f } - fun setAttestationRequestCompleteCallback(f: (forPeer: Peer, attributeName: String, attestation: WalletAttestation, attributeHash: ByteArray, idFormat: String, fromPeer: Peer?, metaData: String?, Signature: ByteArray?) -> Unit) { + fun setAttestationRequestCompleteCallback(f: (forPeer: Peer, attributeName: String, attestation: WalletAttestation, attributeHash: ByteArray, idFormat: String, fromPeer: Peer?, value: ByteArray?, Signature: ByteArray?) -> Unit) { this.attestationRequestCompleteCallback = f } @@ -156,45 +155,22 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: throw NotImplementedError() } - fun verifyAttestationLocally( - peer: Peer, - attestationHash: ByteArray, - metadata: String, - signature: ByteArray, - attestorKey: PublicKey, - ): Boolean { - val parsedMetadata = JSONObject(metadata) - val attesteeKeyHash = parsedMetadata.optString("trustchain_address_hash") - attesteeKeyHash ?: return false - - val isTrusted = this.authorityManager.contains(attestorKey.keyToHash()) - val isOwner = peer.publicKey.keyToHash().toHex() == attesteeKeyHash - val isSignatureValid = attestorKey.verify( - signature, - sha1(attestationHash + metadata.toByteArray()) - ) - - return isTrusted && isOwner && isSignatureValid - } - fun requestAttestation( peer: Peer, attributeName: String, privateKey: BonehPrivateKey, metadata: HashMap = hashMapOf(), - signature: Boolean = false, ) { logger.info("Sending attestation request $attributeName to peer ${peer.mid}.") val publicKey = privateKey.publicKey() val inputMetadata = JSONObject(metadata) - val idFormat = inputMetadata.optString("id_format", "id_metadata") + val idFormat = (inputMetadata.remove("id_format") ?: ID_METADATA) as String val metadataJson = JSONObject() metadataJson.put("attribute", attributeName) // Encode to UTF-8 metadataJson.put("public_key", defaultEncodingUtils.encodeBase64ToString(publicKey.serialize())) - metadataJson.putOpt("id_format", idFormat) - metadataJson.putOpt("signature", signature) + metadataJson.put("id_format", idFormat) inputMetadata.keys().forEach { metadataJson.put(it, inputMetadata.get(it)) @@ -211,7 +187,6 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: privateKey, attributeName, idFormat, - signature ) ) this.allowedAttestations[peer.mid] = @@ -233,41 +208,39 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: payload: RequestAttestationPayload, ) { val metadata = JSONObject(payload.metadata) - val attribute = metadata.getString("attribute") - var value: ByteArray? = metadata.optString("value").toByteArray() - val pubkeyEncoded = metadata.getString("public_key") - val idFormat = metadata.getString("id_format") - val idAlgorithm = this.getIdAlgorithm(idFormat) - val shouldSign = metadata.optBoolean("signature", false) + val attribute = metadata.remove("attribute") as String + val pubkeyEncoded = metadata.remove("public_key") as String + val idFormat = metadata.remove("id_format") as String + val metadataString = metadata.toString() - if (value?.isNotEmpty() == true) { - logger.info("Client passed value of his own") - } + val idAlgorithm = this.getIdAlgorithm(idFormat) - value = this.attestationRequestCallback(peer, attribute, payload.metadata).await() + val value = this.attestationRequestCallback(peer, attribute, metadataString).await() if (value == null) { logger.error("Failed to get value from callback") return } + // Decode as UTF-8 ByteArray + val publicKey = idAlgorithm.loadPublicKey(defaultEncodingUtils.decodeBase64FromString(pubkeyEncoded)) + + val attestationBlob = idAlgorithm.attest(publicKey, value) + val attestation = + idAlgorithm.deserialize(attestationBlob, idFormat) + val stringifiedValue = when (idFormat) { ID_METADATA_RANGE_18PLUS -> ID_METADATA_RANGE_18PLUS_PUBLIC_VALUE ID_METADATA_RANGE_UNDERAGE -> ID_METADATA_RANGE_UNDERAGE_PUBLIC_VALUE else -> String(value) } - metadata.put("value", stringifiedValue) - metadata.put("trustchain_address_hash", peer.publicKey.keyToHash().toHex()) + val signableMetadata = JSONObject(metadataString) + signableMetadata.put("value", stringifiedValue) + signableMetadata.put("subject", peer.publicKey.keyToHash().toHex()) - // Decode as UTF-8 ByteArray - val publicKey = idAlgorithm.loadPublicKey(defaultEncodingUtils.decodeBase64FromString(pubkeyEncoded)) - val attestationBlob = idAlgorithm.attest(publicKey, value) - val attestation = - idAlgorithm.deserialize(attestationBlob, idFormat) - - val signableData = attestation.getHash() + metadata.toString().toByteArray() - val signature = (myPeer.key as PrivateKey).sign(sha1(signableData)) + val signableData = attestation.getHash() + signableMetadata.toString().toByteArray() + val signature = (myPeer.key as PrivateKey).sign(signableData) if (this::attestationRequestCompleteCallback.isInitialized) { this.attestationRequestCompleteCallback( @@ -277,7 +250,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: attestation.getHash(), idFormat, null, - metadata.toString(), + value, signature, ) } @@ -286,8 +259,8 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: peer.address, attestationBlob, dist.globalTime, - metadata.toString().toByteArray(), - if (shouldSign) signature else null + value, + signature ) } @@ -298,7 +271,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: name: String, attestationHash: ByteArray, idFormat: String, - metaData: String? = null, + value: ByteArray? = null, signature: ByteArray? = null, ) { this.attestationKeys[ByteArrayKey(attestationHash)] = Pair(privateKey, idFormat) @@ -307,7 +280,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: attestationHash, privateKey, idFormat, - metaData, + value?.let { String(it, Charsets.US_ASCII) }, signature, peer.publicKey ) @@ -320,7 +293,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: attestationHash, idFormat, peer, - metaData, + value, signature ) } @@ -359,7 +332,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: peer: Peer, payload: VerifyAttestationRequestPayload, ) { - val attestationBlob = this.database.getAttestationByHash(payload.hash) + val attestationBlob = this.database.getAttestationBlobByHash(payload.hash) if (attestationBlob == null) { logger.warn("Dropping verification request of unknown hash ${payload.hash}!") return @@ -386,7 +359,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: sockedAddress: IPv4Address, blob: ByteArray, globalTime: ULong? = null, - metaData: ByteArray? = null, + value: ByteArray? = null, signature: ByteArray? = null, ) { var sequenceNumber = 0 @@ -399,7 +372,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: // Only send metadata and signature on final package to reduce overhead. val payload = if (i + CHUNK_SIZE > blob.size) - AttestationChunkPayload(sha1(blob), sequenceNumber, blobChunk, metaData, signature) + AttestationChunkPayload(sha1(blob), sequenceNumber, blobChunk, value, signature) else AttestationChunkPayload(sha1(blob), sequenceNumber, blobChunk) val packet = serializePacket(ATTESTATION, payload, prefix = this.prefix, timestamp = globalTime) @@ -452,6 +425,12 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: if (this.requestCache.has(peerId.first, peerId.second)) { var cache = this.requestCache.get(peerId.first, peerId.second) as ReceiveAttestationRequestCache cache.attestationMap.add(Pair(payload.sequenceNumber, payload.data)) + if (payload.value != null) { + cache.value = payload.value + } + if (payload.signature != null) { + cache.signature = payload.signature + } var serialized = byteArrayOf() for ((_, chunk) in cache.attestationMap.sortedBy { attestation -> attestation.first }) { @@ -470,6 +449,8 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: this.allowedAttestations.remove(peer.mid) } + // TODO: Verify received signature and value + this.onAttestationComplete( deserialized, cache.privateKey, @@ -477,8 +458,8 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: cache.name, deserialized.getHash(), cache.idFormat, - if (payload.metadata != null) String(payload.metadata) else null, - if (payload.signature != null) payload.signature else null + cache.value, + cache.signature ) } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/payloads/AttestationChunkPayload.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/payloads/AttestationChunkPayload.kt index bc6c4d7a..902330b4 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/payloads/AttestationChunkPayload.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/payloads/AttestationChunkPayload.kt @@ -6,7 +6,7 @@ class AttestationChunkPayload( val hash: ByteArray, val sequenceNumber: Int, val data: ByteArray, - val metadata: ByteArray? = null, + val value: ByteArray? = null, val signature: ByteArray? = null, ) : Serializable { private val msgId = 2 @@ -15,7 +15,7 @@ class AttestationChunkPayload( return ( hash + serializeUInt(sequenceNumber.toUInt()) + serializeVarLen(data) + ( - if (metadata != null && signature != null) serializeVarLen(metadata) + serializeVarLen(signature) + if (value != null && signature != null) serializeVarLen(value) + signature else byteArrayOf() ) ) @@ -39,13 +39,13 @@ class AttestationChunkPayload( localoffset += dataSize return if (buffer.lastIndex > offset + localoffset) { - val (metadata, metadataSize) = deserializeVarLen(buffer, offset + localoffset) - localoffset += metadataSize + val (value, valueSize) = deserializeVarLen(buffer, offset + localoffset) + localoffset += valueSize - val (signature, signatureSize) = deserializeVarLen(buffer, offset + localoffset) - localoffset += signatureSize + val signature = buffer.copyOfRange(offset + localoffset, offset + localoffset + SIGNATURE_SIZE) + localoffset += SIGNATURE_SIZE - val payload = AttestationChunkPayload(hash, sequenceNumber.toInt(), data, metadata, signature) + val payload = AttestationChunkPayload(hash, sequenceNumber.toInt(), data, value, signature) Pair(payload, localoffset) } else { val payload = AttestationChunkPayload(hash, sequenceNumber.toInt(), data) From 1e45a09b99ba626faaf281ef02942410ba9d72d3 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sun, 25 Apr 2021 21:13:42 +0200 Subject: [PATCH 069/144] Optimize AttestPayload serialization logic --- .../identity/payloads/AttestPayload.kt | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/AttestPayload.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/AttestPayload.kt index c07a2051..ad3d2541 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/AttestPayload.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/AttestPayload.kt @@ -1,20 +1,24 @@ -package nl.tudelft.ipv8.attestation.identity.payloads + package nl.tudelft.ipv8.attestation.identity.payloads import nl.tudelft.ipv8.messaging.Deserializable +import nl.tudelft.ipv8.messaging.SERIALIZED_SHA3_256_SIZE +import nl.tudelft.ipv8.messaging.SIGNATURE_SIZE import nl.tudelft.ipv8.messaging.Serializable -import nl.tudelft.ipv8.messaging.deserializeVarLen -import nl.tudelft.ipv8.messaging.serializeVarLen +import nl.tudelft.ipv8.messaging.deserializeSHA3_256 class AttestPayload(val attestation: ByteArray) : Serializable { override fun serialize(): ByteArray { - return serializeVarLen(attestation) + return attestation } companion object Deserializer : Deserializable { override fun deserialize(buffer: ByteArray, offset: Int): Pair { - val (deserialized, localOffset) = deserializeVarLen(buffer, offset) - return Pair(AttestPayload(deserialized), offset + localOffset) + var localOffset = offset + + val attestation = buffer.copyOfRange(localOffset, localOffset + SERIALIZED_SHA3_256_SIZE + SIGNATURE_SIZE) + localOffset += SERIALIZED_SHA3_256_SIZE + SIGNATURE_SIZE + + return Pair(AttestPayload(attestation), localOffset) } } - } From f9f6345a8a57d82e04b220c5032e7231b20e0657 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sun, 25 Apr 2021 21:14:03 +0200 Subject: [PATCH 070/144] Format Serialization + add sha3 serialization logic --- .../tudelft/ipv8/messaging/Serialization.kt | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/messaging/Serialization.kt b/ipv8/src/main/java/nl/tudelft/ipv8/messaging/Serialization.kt index de3edf4b..e0efe787 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/messaging/Serialization.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/messaging/Serialization.kt @@ -13,6 +13,7 @@ const val SERIALIZED_PUBLIC_KEY_SIZE = 74 const val HASH_SIZE = 32 const val SIGNATURE_SIZE = 64 const val SERIALIZED_SHA1_HASH_SIZE = 20 +const val SERIALIZED_SHA3_256_SIZE = 32 interface Serializable { fun serialize(): ByteArray @@ -101,14 +102,20 @@ fun deserializeUChar(buffer: ByteArray, offset: Int = 0): UByte { return ubuffer[offset] } +fun deserializeSHA3_256(buffer: ByteArray, offset: Int = 0): Pair { + return Pair(buffer.copyOfRange(offset, offset + SERIALIZED_SHA3_256_SIZE), SERIALIZED_SHA3_256_SIZE) +} + fun serializeVarLen(bytes: ByteArray): ByteArray { return serializeUInt(bytes.size.toUInt()) + bytes } fun deserializeVarLen(buffer: ByteArray, offset: Int = 0): Pair { val len = deserializeUInt(buffer, offset).toInt() - val payload = buffer.copyOfRange(offset + SERIALIZED_UINT_SIZE, - offset + SERIALIZED_UINT_SIZE + len) + val payload = buffer.copyOfRange( + offset + SERIALIZED_UINT_SIZE, + offset + SERIALIZED_UINT_SIZE + len + ) return Pair(payload, SERIALIZED_UINT_SIZE + len) } @@ -117,19 +124,31 @@ fun deserializeRecursively(buffer: ByteArray, offset: Int = 0): Array return arrayOf() } val len = deserializeUInt(buffer, offset).toInt() - val payload = buffer.copyOfRange(offset + SERIALIZED_UINT_SIZE, - offset + SERIALIZED_UINT_SIZE + len) - return arrayOf(payload) + deserializeRecursively(buffer.copyOfRange(offset + SERIALIZED_UINT_SIZE + len, - buffer.size), offset) -} - -fun deserializeAmount(buffer: ByteArray, amount: Int, offset: Int = 0): Pair, ByteArray> { + val payload = buffer.copyOfRange( + offset + SERIALIZED_UINT_SIZE, + offset + SERIALIZED_UINT_SIZE + len + ) + return arrayOf(payload) + deserializeRecursively( + buffer.copyOfRange( + offset + SERIALIZED_UINT_SIZE + len, + buffer.size + ), offset + ) +} + +fun deserializeAmount( + buffer: ByteArray, + amount: Int, + offset: Int = 0 +): Pair, ByteArray> { val returnValues = arrayListOf() var localOffset = offset for (i in 0 until amount) { val len = deserializeUInt(buffer, localOffset).toInt() - val payload = buffer.copyOfRange(localOffset + SERIALIZED_UINT_SIZE, - localOffset + SERIALIZED_UINT_SIZE + len) + val payload = buffer.copyOfRange( + localOffset + SERIALIZED_UINT_SIZE, + localOffset + SERIALIZED_UINT_SIZE + len + ) localOffset += SERIALIZED_UINT_SIZE + len returnValues.add(payload) } From 2203966f5e8e5b6c0697024ea9ed4538d3259e89 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sun, 25 Apr 2021 21:15:15 +0200 Subject: [PATCH 071/144] Format Metadata + make signature non nullable --- .../ipv8/attestation/identity/Metadata.kt | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt index 7ee8326a..735ef3e7 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt @@ -22,7 +22,7 @@ class Metadata( return this.tokenPointer + this.serializedMetadata } - fun toDatabaseTuple(): Triple { + fun toDatabaseTuple(): Triple { return Triple(this.tokenPointer, this.signature, this.serializedMetadata) } @@ -42,15 +42,19 @@ class Metadata( // Index on which signature start. val signIndex = data.size - publicKey.getSignatureLength() - return Metadata(data.copyOfRange(0, 32), + return Metadata( + data.copyOfRange(0, 32), data.copyOfRange(32, signIndex), - signature = data.copyOfRange(signIndex, data.size)) + signature = data.copyOfRange(signIndex, data.size) + ) } fun create(token: Token, jsonObject: JSONObject, privateKey: PrivateKey): Metadata { - return Metadata(token.hash, + return Metadata( + token.hash, jsonObject.toString().toByteArray(), - privateKey = privateKey) + privateKey = privateKey + ) } fun fromDatabaseTuple( @@ -61,6 +65,4 @@ class Metadata( return Metadata(tokenPointer, serializedJSONObject, signature = signature) } } - - } From c9014f18b97b9200411e11ee08862b97cfb62932 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sun, 25 Apr 2021 21:15:45 +0200 Subject: [PATCH 072/144] Add method for listing Trusted Authorities --- .../main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt index 435036bf..6af27135 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt @@ -63,6 +63,10 @@ class AuthorityManager(val authorityDatabase: AuthorityStore) { return this.authorityDatabase.getKnownAuthorities() } + fun getTrustedAuthorities(): List { + return this.trustedAuthorities.values.toList() + } + fun addTrustedAuthority(publicKey: PublicKey) { val hash = publicKey.keyToHash() if (!this.contains(hash)) { From 76f9a1feb2d3bf65b15ba2833d6f66fe0b53228d Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sun, 25 Apr 2021 21:17:41 +0200 Subject: [PATCH 073/144] Add offline veriafiability to CommunicationManager + change types --- .../ipv8/attestation/CommunicationManager.kt | 186 +++++++++++++++--- 1 file changed, 162 insertions(+), 24 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt index c32e582f..6cf23a6f 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt @@ -4,6 +4,7 @@ import kotlinx.coroutines.* import mu.KotlinLogging import nl.tudelft.ipv8.IPv8 import nl.tudelft.ipv8.Peer +import nl.tudelft.ipv8.attestation.identity.DEFAULT_METADATA import nl.tudelft.ipv8.attestation.identity.IdentityCommunity import nl.tudelft.ipv8.attestation.identity.createCommunity import nl.tudelft.ipv8.attestation.identity.database.IdentityStore @@ -11,6 +12,7 @@ import nl.tudelft.ipv8.attestation.identity.manager.IdentityManager import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity import nl.tudelft.ipv8.attestation.wallet.AttestationStore import nl.tudelft.ipv8.keyvault.PrivateKey +import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.keyvault.defaultCryptoProvider import nl.tudelft.ipv8.util.* import org.json.JSONObject @@ -25,9 +27,9 @@ class CommunicationManager( private val iPv8Instance: IPv8, private val attestationStore: AttestationStore, private val identityStore: IdentityStore, - private val authorityManager: AuthorityManager, + val authorityManager: AuthorityManager, private val storePseudonym: ((String, PrivateKey) -> Unit)? = null, - private val loadPseudonym: ((String) -> PrivateKey)? = null, + private val loadPseudonym: ((String) -> PrivateKey?)? = null, ) { private val channels = hashMapOf() private val nameToChannel = hashMapOf() @@ -51,10 +53,10 @@ class CommunicationManager( } // Load private key with function or via default method. - var privateKey = loadPseudonym?.let { it(name) } ?: loadPseudonym(name) + var privateKey = this.loadPseudonym?.let { it(name) } ?: loadPseudonym(name) if (privateKey == null) { privateKey = defaultCryptoProvider.generateKey() - storePseudonym?.let { it(name, privateKey) } ?: storePseudonym(name, privateKey) + this.storePseudonym?.let { it(name, privateKey) } ?: storePseudonym(name, privateKey) } val publicKeyBytes = privateKey.pub().keyToBin() @@ -79,7 +81,8 @@ class CommunicationManager( ) attestationOverlay.load() - this.channels[publicKeyBytes.toKey()] = CommunicationChannel(attestationOverlay, identityOverlay) + this.channels[publicKeyBytes.toKey()] = + CommunicationChannel(attestationOverlay, identityOverlay) this.nameToChannel[name] = this.channels[publicKeyBytes.toKey()]!! } return this.nameToChannel[name]!! @@ -103,6 +106,12 @@ class CommunicationManager( TODO() } + fun getAllPeers(): List { + val peers = mutableListOf() + this.channels.values.map { peers += it.peers } + return peers + } + companion object { private const val PSEUDONYM_PATH = "\\pseudonyms\\" @@ -167,10 +176,34 @@ class AttributePointer(val peer: Peer, val attributeName: String) { } } -class CommunicationChannel(val attestationOverlay: AttestationCommunity, val identityOverlay: IdentityCommunity) { +class PrivateAttestationBlob( + val attributeName: String, + val attributeHash: ByteArray, + val metadataString: String, + val idFormat: String, + val attributeValue: String, + val signature: ByteArray, + val attestorKeys: List +) { + override fun equals(other: Any?): Boolean { + return other is PrivateAttestationBlob && this.attributeName == other.attributeName && this.attributeHash.contentEquals( + other.attributeHash + ) && this.metadataString == other.metadataString && this.idFormat == other.idFormat && this.attributeValue == other.attributeValue && this.signature.contentEquals( + other.signature + ) && this.attestorKeys == other.attestorKeys + } +} + +const val DEFAULT_TIME_OUT = 3000000 + +class CommunicationChannel( + val attestationOverlay: AttestationCommunity, + val identityOverlay: IdentityCommunity +) { - val attestationRequests = hashMapOf, String>>() - val verifyRequests = hashMapOf>() + val attestationRequests = + hashMapOf, String>>() + val verifyRequests = hashMapOf>() val verificationOutput = hashMapOf>>() private val attestationMetadata = hashMapOf>() @@ -198,11 +231,12 @@ class CommunicationChannel(val attestationOverlay: AttestationCommunity, val ide metadataString: String, ): Deferred { // Promise some ByteArray. - val deferred = SettableDeferred() - this.attestationRequests[AttributePointer(peer, attributeName)] = Pair(deferred, metadataString) + val deferred = SettableDeferred() + this.attestationRequests[AttributePointer(peer, attributeName)] = + Pair(deferred, metadataString) @Suppress("UNCHECKED_CAST") this.attestationMetadata[AttributePointer(peer, attributeName)] = - JSONObject(metadataString).toMap() as Map + JSONObject(metadataString).asMap() as Map return GlobalScope.async(start = CoroutineStart.LAZY) { deferred.await() } } @@ -215,7 +249,7 @@ class CommunicationChannel(val attestationOverlay: AttestationCommunity, val ide attributeHash: ByteArray, idFormat: String, fromPeer: Peer?, - metaData: String?, + value: ByteArray?, Signature: ByteArray?, ) { val metadata = this.attestationMetadata.get(AttributePointer(forPeer, attributeName)) @@ -225,26 +259,31 @@ class CommunicationChannel(val attestationOverlay: AttestationCommunity, val ide @Suppress("UNCHECKED_CAST") this.identityOverlay.selfAdvertise( attributeHash, attributeName, idFormat, - JSONObject(metadata).toMap() as HashMap? + metadata as HashMap? ) } else { + @Suppress("UNCHECKED_CAST") this.identityOverlay.requestAttestationAdvertisement( fromPeer!!, attributeHash, attributeName, idFormat, metadata as HashMap? ) } } else { + @Suppress("UNCHECKED_CAST") this.identityOverlay.addKnownHash( - attributeHash, attributeName, forPeer.publicKey, + attributeHash, attributeName, value, forPeer.publicKey, metadata as HashMap? ) } } private fun onVerifyRequestAsync(peer: Peer, attributeHash: ByteArray): Deferred { - val metadata = this.identityOverlay.getAttestationByHash(attributeHash) ?: return CompletableDeferred(null) + val metadata = + this.identityOverlay.getAttestationByHash(attributeHash) ?: return CompletableDeferred( + null + ) val attributeName = JSONObject(String(metadata.serializedMetadata)).getString("name") - val deferred = SettableDeferred() + val deferred = SettableDeferred() this.verifyRequests[AttributePointer(peer, attributeName)] = deferred return GlobalScope.async(start = CoroutineStart.LAZY) { deferred.await() } } @@ -274,9 +313,55 @@ class CommunicationChannel(val attestationOverlay: AttestationCommunity, val ide TODO("") } - fun getAttributes(peer: Peer): HashMap, List>> { + fun getOfflineVerifiableAttributes(): List { + val peer = this.myPeer val pseudonym = this.identityOverlay.identityManager.getPseudonym(peer.publicKey) - val out: HashMap, List>> = hashMapOf() + val out = mutableListOf() + for (credential in pseudonym.getCredentials()) { + val attestations = credential.attestations.toList() + val attestors = mutableListOf() + + for (attestation in attestations) { + attestors += defaultCryptoProvider.keyFromPublicBin( + this.identityOverlay.identityManager.database.getAuthority( + attestation + ) + ).keyToHash().toHex() + } + val attributeHash = + stripSHA1Padding(pseudonym.tree.elements[credential.metadata.tokenPointer.toKey()]!!.contentHash) + val jsonMetadata = JSONObject(String(credential.metadata.serializedMetadata)) + + val attributeName = jsonMetadata.getString("name") + val idFormat = jsonMetadata.getString("schema") + val (value, signature) = this.attestationOverlay.database.getValueAndSignatureByHash( + attributeHash + )!! + + for (md in DEFAULT_METADATA) { + jsonMetadata.remove(md) + } + jsonMetadata.put("value", value) + jsonMetadata.put("subject", peer.publicKey.keyToHash().toHex()) + + out += PrivateAttestationBlob( + attributeName, + attributeHash, + jsonMetadata.toString(), + idFormat, + value, + signature, + attestors + ) + } + return out.sortedBy { it.attributeName } + } + + @Deprecated("This should not be used.") + fun getAttributes(peer: Peer): HashMap, List>> { + val pseudonym = this.identityOverlay.identityManager.getPseudonym(peer.publicKey) + val out: HashMap, List>> = + hashMapOf() for (credential in pseudonym.getCredentials()) { val attestations = credential.attestations.toList() @@ -285,18 +370,28 @@ class CommunicationChannel(val attestationOverlay: AttestationCommunity, val ide for (attestation in attestations) { attesters += this.identityOverlay.identityManager.database.getAuthority(attestation) } - val attributeHash = pseudonym.tree.elements[credential.metadata.tokenPointer.toKey()]!!.contentHash + val attributeHash = + pseudonym.tree.elements[credential.metadata.tokenPointer.toKey()]!!.contentHash val jsonMetadata = JSONObject(String(credential.metadata.serializedMetadata)) out[attributeHash.toKey()] = - Triple(jsonMetadata.getString("name"), jsonMetadata.toMap() as HashMap, attesters) + Triple( + jsonMetadata.getString("name"), + jsonMetadata.asMap() as HashMap, + attesters + ) } return out } - fun requestAttestation(peer: Peer, attributeName: String, idFormat: String, metadata: HashMap) { + fun requestAttestation( + peer: Peer, + attributeName: String, + idFormat: String, + metadata: HashMap + ) { val key = this.attestationOverlay.getIdAlgorithm(idFormat).generateSecretKey() - metadata["id_format"] = idFormat - this.attestationMetadata[AttributePointer(this.identityOverlay.myPeer, attributeName)] = metadata + this.attestationMetadata[AttributePointer(this.identityOverlay.myPeer, attributeName)] = + metadata this.attestationOverlay.requestAttestation(peer, attributeName, key, metadata) } @@ -305,6 +400,11 @@ class CommunicationChannel(val attestationOverlay: AttestationCommunity, val ide GlobalScope.launch { outstanding.first.setResult(value) } } + fun dismissAttestionRequest(peer: Peer, attributeName: String) { + val outstanding = this.attestationRequests.remove(AttributePointer(peer, attributeName))!! + GlobalScope.launch { outstanding.first.setResult(null) } + } + fun allowVerification(peer: Peer, attributeName: String) { val outstanding = this.verifyRequests.remove(AttributePointer(peer, attributeName))!! GlobalScope.launch { outstanding.setResult(true) } @@ -315,7 +415,12 @@ class CommunicationChannel(val attestationOverlay: AttestationCommunity, val ide GlobalScope.launch { outstanding.setResult(false) } } - fun verify(peer: Peer, attestationHash: ByteArray, referenceValues: List, idFormat: String) { + fun verify( + peer: Peer, + attestationHash: ByteArray, + referenceValues: List, + idFormat: String + ) { this.verificationOutput[attestationHash.toKey()] = referenceValues.map { Pair(it, null) } this.attestationOverlay.verifyAttestationValues( peer.address, @@ -325,4 +430,37 @@ class CommunicationChannel(val attestationOverlay: AttestationCommunity, val ide idFormat ) } + + fun verifyLocally( + challengeSignature: ByteArray, + challengeTimeStamp: Long, + subjectKey: PublicKey, + attestationHash: ByteArray, + metadata: String, + signature: ByteArray, + attestorKeyHash: ByteArray, + ): Boolean { + if (System.currentTimeMillis() - challengeTimeStamp > DEFAULT_TIME_OUT) { + // Do not accept old challenges. + return false + } + + val isChallengeValid = + subjectKey.verify(challengeSignature, challengeTimeStamp.toByteArray()) + val parsedMetadata = JSONObject(metadata) + val isTrusted = this.attestationOverlay.authorityManager.contains(attestorKeyHash) + val isOwner = parsedMetadata.optString("subject") == subjectKey.keyToHash().toHex() + + val authority = this.attestationOverlay.authorityManager.getAuthority(attestorKeyHash) + val isSignatureValid = authority?.publicKey?.verify( + signature, attestationHash + metadata.toByteArray() + ) ?: false + + return isChallengeValid && isTrusted && isOwner && isSignatureValid + } + + fun generateChallenge(): Pair { + val timestamp = System.currentTimeMillis() + return Pair(timestamp, (this.myPeer.key as PrivateKey).sign(timestamp.toByteArray())) + } } From 0a0eecdf3087a81e4666fa1a3dfdd6eac80b2e3c Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sun, 25 Apr 2021 21:20:00 +0200 Subject: [PATCH 074/144] Change default timeout in CommunicationManager + remove metadata dependency in IdentityCommunity --- .../ipv8/attestation/CommunicationManager.kt | 2 +- .../attestation/identity/IdentityCommunity.kt | 40 ++++++++++++++----- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt index 6cf23a6f..42a3ab2e 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt @@ -194,7 +194,7 @@ class PrivateAttestationBlob( } } -const val DEFAULT_TIME_OUT = 3000000 +const val DEFAULT_TIME_OUT = 30_000 class CommunicationChannel( val attestationOverlay: AttestationCommunity, diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index 7dd19b96..4bbda0cd 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -19,6 +19,7 @@ import nl.tudelft.ipv8.messaging.Packet import nl.tudelft.ipv8.peerdiscovery.Network import nl.tudelft.ipv8.peerdiscovery.strategy.RandomWalk import nl.tudelft.ipv8.util.ByteArrayKey +import nl.tudelft.ipv8.util.asMap import nl.tudelft.ipv8.util.padSHA1Hash import nl.tudelft.ipv8.util.toHex import nl.tudelft.ipv8.util.toKey @@ -34,11 +35,11 @@ const val ATTEST_PAYLOAD = 2 const val REQUEST_MISSING_PAYLOAD = 3 const val MISSING_RESPONSE_PAYLOAD = 4 -// TODO: "clean up". -val DEFAULT_METADATA = arrayOf("name", "date", "schema", "signature", "public_key", "attribute") +val DEFAULT_METADATA = arrayOf("name", "date", "schema") class HashInformation( val name: String, + val value: ByteArray?, val time: Float, val publicKey: PublicKey, val metadata: HashMap?, @@ -116,18 +117,20 @@ class IdentityCommunity( fun addKnownHash( attributeHash: ByteArray, name: String, + value: ByteArray?, publicKey: PublicKey, metadata: HashMap? = null, ) { val hash = if (attributeHash.size == 20) padSHA1Hash(attributeHash) else attributeHash this.knownAttestationHashes[ByteArrayKey(hash)] = - HashInformation(name, System.currentTimeMillis() / 1000F, publicKey, metadata) + HashInformation(name, value, System.currentTimeMillis() / 1000F, publicKey, metadata) } fun getAttestationByHash(attributeHash: ByteArray): Metadata? { val hash = if (attributeHash.size == 20) padSHA1Hash(attributeHash) else attributeHash for (credential in this.pseudonymManager.getCredentials()) { - val token = this.pseudonymManager.tree.elements.get(ByteArrayKey(credential.metadata.tokenPointer)) + val token = + this.pseudonymManager.tree.elements.get(ByteArrayKey(credential.metadata.tokenPointer)) if (token?.contentHash.contentEquals(hash)) { return credential.metadata } @@ -157,7 +160,10 @@ class IdentityCommunity( return false } // Refuse to sign blocks older than 5 minutes - if (System.currentTimeMillis() / 1000F > this.knownAttestationHashes[attributeHash.toKey()]?.time?.plus((DEFAULT_TIME_OUT)) ?: 0F) { + if (System.currentTimeMillis() / 1000F > this.knownAttestationHashes[attributeHash.toKey()]?.time?.plus( + (DEFAULT_TIME_OUT) + ) ?: 0F + ) { logger.debug("Not signing $metadata, timed out!") return false } @@ -166,7 +172,7 @@ class IdentityCommunity( return false } if (this.knownAttestationHashes[attributeHash.toKey()]!!.metadata != null - && transaction.toMap().filterKeys { it !in DEFAULT_METADATA } + && transaction.asMap().filterKeys { it !in DEFAULT_METADATA } // TODO: Remove filter here. != this.knownAttestationHashes[attributeHash.toKey()]!!.metadata!!.filterKeys { it !in DEFAULT_METADATA } ) { @@ -174,7 +180,9 @@ class IdentityCommunity( return false } for (attestation in pseudonym.database.getAttestationsOver(metadata)) { - if (this.myPeer.publicKey.keyToBin().contentEquals(pseudonym.database.getAuthority(attestation))) { + if (this.myPeer.publicKey.keyToBin() + .contentEquals(pseudonym.database.getAuthority(attestation)) + ) { logger.debug("Not signing $metadata, already attested!") return false } @@ -218,8 +226,13 @@ class IdentityCommunity( for (credential in pseudonym.getCredentials()) { if (shouldSign(pseudonym, credential.metadata)) { logger.info("Attesting to ${credential.metadata}.") + val myPrivateKey = this.myPeer.key as PrivateKey + val attestation = - pseudonym.createAttestation(credential.metadata, this.myPeer.key as PrivateKey) + pseudonym.createAttestation( + credential.metadata, + myPrivateKey + ) pseudonym.addAttestation(this.myPeer.publicKey, attestation) val payload = AttestPayload(attestation.getPlaintextSigned()) this.endpoint.send(peer, serializePacket(ATTEST_PAYLOAD, payload)) @@ -263,7 +276,11 @@ class IdentityCommunity( val hash = if (attributeHash.size == 20) padSHA1Hash(attributeHash) else attributeHash val extendedMetadata = - hashMapOf("name" to name, "schema" to blockType, "date" to System.currentTimeMillis() / 1000F) + hashMapOf( + "name" to name, + "schema" to blockType, + "date" to System.currentTimeMillis() / 1000F + ) if (metadata != null) { extendedMetadata.putAll(metadata) } @@ -314,7 +331,10 @@ class IdentityCommunity( } private fun onMissingResponse(peer: Peer, payload: MissingResponsePayload) { - this.receivedDisclosureForAttest(peer, Disclosure(byteArrayOf(), payload.tokens, byteArrayOf(), byteArrayOf())) + this.receivedDisclosureForAttest( + peer, + Disclosure(byteArrayOf(), payload.tokens, byteArrayOf(), byteArrayOf()) + ) } override fun equals(other: Any?): Boolean { From 8d9464154d26364b09d0eb6c72ba43b321b8a7aa Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sun, 25 Apr 2021 21:20:45 +0200 Subject: [PATCH 075/144] Format IdentityManager + make signature non nullable in Identity database --- .../identity/database/IdentitySQLiteStore.kt | 6 ++--- .../identity/manager/IdentityManager.kt | 23 +++++++++++++------ .../nl/tudelft/ipv8/sqldelight/DbIdentity.sq | 8 +++---- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt index dd5356ad..972d23d0 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt @@ -9,8 +9,8 @@ import nl.tudelft.ipv8.sqldelight.Database private val tokenMapper: ( ByteArray, - ByteArray?, - ByteArray?, + ByteArray, + ByteArray, ByteArray?, ) -> Token = { previousTokenHash, signature, contentHash, content -> Token.fromDatabaseTuple(previousTokenHash, signature, contentHash, content) @@ -18,7 +18,7 @@ private val tokenMapper: ( private val metadataMapper: ( ByteArray, - ByteArray?, + ByteArray, ByteArray, ) -> Metadata = { tokenPointer, signature, serializedMetadata -> Metadata.fromDatabaseTuple(tokenPointer, signature, serializedMetadata) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt index e86dcbec..1f3afcd6 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt @@ -24,7 +24,8 @@ class IdentityManager(internal val database: IdentityStore) { if (key is PrivateKey) { this.pseudonyms[publicKeyMaterial.toKey()] = PseudonymManager(this.database, privateKey = key) } else { - this.pseudonyms[publicKeyMaterial.toKey()] = PseudonymManager(this.database, publicKey = key as PublicKey) + this.pseudonyms[publicKeyMaterial.toKey()] = + PseudonymManager(this.database, publicKey = key as PublicKey) } } return this.pseudonyms[publicKeyMaterial.toKey()]!! @@ -45,8 +46,10 @@ class IdentityManager(internal val database: IdentityStore) { val metadataSize = deserializeUInt(serializeMetadata, metadataOffset).toInt() metadataOffset += SERIALIZED_UINT_SIZE val metadata = - Metadata.deserialize(serializeMetadata.copyOfRange(metadataOffset, metadataOffset + metadataSize), - publicKey) + Metadata.deserialize( + serializeMetadata.copyOfRange(metadataOffset, metadataOffset + metadataSize), + publicKey + ) pseudonym.addMetadata(metadata) metadataOffset += metadataSize } @@ -57,11 +60,17 @@ class IdentityManager(internal val database: IdentityStore) { while (authorityOffset < serializedAttestations.size) { val authoritySize = deserializeUShort(serializedAuthorities, authorityOffset) authorityOffset += SERIALIZED_USHORT_SIZE - val authority = defaultCryptoProvider.keyFromPublicBin(serializedAuthorities.copyOfRange(authorityOffset, - authorityOffset + authoritySize)) + val authority = defaultCryptoProvider.keyFromPublicBin( + serializedAuthorities.copyOfRange( + authorityOffset, + authorityOffset + authoritySize + ) + ) authorityOffset += authoritySize - correct = correct && pseudonym.addAttestation(authority, - IdentityAttestation.deserialize(serializedAttestations, authority, attestationOffset)) + correct = correct && pseudonym.addAttestation( + authority, + IdentityAttestation.deserialize(serializedAttestations, authority, attestationOffset) + ) attestationOffset += 32 + authority.getSignatureLength() } diff --git a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq index 5c71ceb8..e3b792e1 100644 --- a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq +++ b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq @@ -1,8 +1,8 @@ CREATE TABLE tokens ( public_key BLOB NOT NULL, previous_token_hash BLOB NOT NULL, - signature BLOB, - content_hash BLOB, + signature BLOB NOT NULL, + content_hash BLOB NOT NULL, content BLOB, PRIMARY KEY (public_key, previous_token_hash, content_hash) ); @@ -10,7 +10,7 @@ CREATE TABLE tokens ( CREATE TABLE metadata ( public_key BLOB NOT NULL, token_pointer BLOB NOT NULL, - signature BLOB, + signature BLOB NOT NULL, serialized_json BLOB NOT NULL, PRIMARY KEY (public_key, token_pointer) ); @@ -19,7 +19,7 @@ CREATE TABLE identity_attestations ( public_key BLOB NOT NULL, authority_key BLOB NOT NULL, metadata_pointer BLOB NOT NULL, - signature BLOB, + signature BLOB NOT NULL, PRIMARY KEY (public_key, metadata_pointer) ); From c060e07f964f5957935e5ff5db21d288c88d9373 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sun, 25 Apr 2021 21:21:25 +0200 Subject: [PATCH 076/144] Format IdentityAttestation --- .../ipv8/attestation/identity/IdentityAttestation.kt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt index 1c5a449f..a741613b 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt @@ -27,7 +27,6 @@ class IdentityAttestation( return "Attestation${metadataPointer.toHex()})" } - override fun deserialize(data: ByteArray, publicKey: PublicKey, offset: Int): IdentityAttestation { return Companion.deserialize(data, publicKey, offset) } @@ -35,8 +34,10 @@ class IdentityAttestation( companion object { fun deserialize(data: ByteArray, publicKey: PublicKey, offset: Int = 0): IdentityAttestation { val signLength = publicKey.getSignatureLength() - return IdentityAttestation(data.copyOfRange(offset, offset + 32), - signature = data.copyOfRange(offset + 32, offset + 32 + signLength)) + return IdentityAttestation( + data.copyOfRange(offset, offset + 32), + signature = data.copyOfRange(offset + 32, offset + 32 + signLength) + ) } fun create(metadata: Metadata, privateKey: PrivateKey): IdentityAttestation { @@ -47,6 +48,4 @@ class IdentityAttestation( return IdentityAttestation(metadataPointer, signature = signature) } } - - } From d2a410626044839669c6ecb18c450948936ae80f Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sun, 25 Apr 2021 21:21:49 +0200 Subject: [PATCH 077/144] Add toMap function for JSONObject --- .../nl/tudelft/ipv8/util/EncodingUtils.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/util/EncodingUtils.kt b/ipv8/src/main/java/nl/tudelft/ipv8/util/EncodingUtils.kt index 18304fb2..9c5b7f47 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/util/EncodingUtils.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/util/EncodingUtils.kt @@ -1,5 +1,8 @@ package nl.tudelft.ipv8.util +import org.json.JSONArray +import org.json.JSONObject + interface EncodingUtils { fun encodeBase64(bin: ByteArray): ByteArray @@ -12,3 +15,21 @@ interface EncodingUtils { } var defaultEncodingUtils: EncodingUtils = JavaEncodingUtils + +fun JSONObject.asMap(): Map { + val results: MutableMap = HashMap() + for (key in this.keys()) { + val value1 = this[key] + val value: Any? = if (value1 == null || JSONObject.NULL == value1) { + null + } else if (value1 is JSONObject) { + value1.asMap() + } else if (value1 is JSONArray) { + value1.toList() + } else { + value1 + } + results[key] = value + } + return results +} From 8fb97fd4b7f6e02edacc28307a0a6ec3f374a0c2 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sun, 25 Apr 2021 21:22:09 +0200 Subject: [PATCH 078/144] Add signature and value fields in ReceiveAttestationRequestCache --- .../wallet/caches/ReceiveAttestationRequestCache.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/ReceiveAttestationRequestCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/ReceiveAttestationRequestCache.kt index 08d71750..d27e3a15 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/ReceiveAttestationRequestCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/ReceiveAttestationRequestCache.kt @@ -11,9 +11,10 @@ class ReceiveAttestationRequestCache( val privateKey: BonehPrivateKey, val name: String, idFormat: String, - val signature: Boolean = false, ) : PeerCache(community.requestCache, ATTESTATION_REQUEST_PREFIX, mid, idFormat) { + var signature: ByteArray? = null + var value: ByteArray? = null val attestationMap: MutableSet> = mutableSetOf() } From a30400488f8016a120ad1da930a11794e726bb16 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sun, 25 Apr 2021 21:22:26 +0200 Subject: [PATCH 079/144] Set parameters correctly in Token initialization in Token --- .../main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt index a4a4332d..6182716a 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt @@ -86,7 +86,7 @@ class Token( contentHash: ByteArray?, content: ByteArray?, ): Token { - val token = Token(previousTokenHash, signature, contentHash = contentHash) + val token = Token(previousTokenHash, contentHash = contentHash, signature = signature) if (content != null) { token.receiveContent(content) } From f3d103a8ed8ed07216e5f5ac9f9c2f49e34118c1 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Sun, 25 Apr 2021 21:22:43 +0200 Subject: [PATCH 080/144] Change ZKP values to booleans --- .../java/nl/tudelft/ipv8/attestation/schema/SchemaManager.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/schema/SchemaManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/schema/SchemaManager.kt index 51de6cc3..02ab688f 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/schema/SchemaManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/schema/SchemaManager.kt @@ -21,9 +21,9 @@ const val ID_METADATA = "id_metadata" const val ID_METADATA_BIG = "id_metadata_big" const val ID_METADATA_HUGE = "id_metadata_huge" const val ID_METADATA_RANGE_18PLUS = "id_metadata_range_18plus" -const val ID_METADATA_RANGE_18PLUS_PUBLIC_VALUE = "18+" +const val ID_METADATA_RANGE_18PLUS_PUBLIC_VALUE = true const val ID_METADATA_RANGE_UNDERAGE = "id_metadata_range_underage" -const val ID_METADATA_RANGE_UNDERAGE_PUBLIC_VALUE = "underage" +const val ID_METADATA_RANGE_UNDERAGE_PUBLIC_VALUE = true class SchemaManager { From 57f161512774817e2c33d2e36337d3456d798acb Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 26 Apr 2021 13:07:37 +0200 Subject: [PATCH 081/144] Refactor CommunicationManager + add proposed value --- .../ipv8/attestation/CommunicationManager.kt | 466 ------------------ .../communication/CommunicationChannel.kt | 324 ++++++++++++ .../communication/CommunicationManager.kt | 177 +++++++ 3 files changed, 501 insertions(+), 466 deletions(-) delete mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt deleted file mode 100644 index 42a3ab2e..00000000 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/CommunicationManager.kt +++ /dev/null @@ -1,466 +0,0 @@ -package nl.tudelft.ipv8.attestation - -import kotlinx.coroutines.* -import mu.KotlinLogging -import nl.tudelft.ipv8.IPv8 -import nl.tudelft.ipv8.Peer -import nl.tudelft.ipv8.attestation.identity.DEFAULT_METADATA -import nl.tudelft.ipv8.attestation.identity.IdentityCommunity -import nl.tudelft.ipv8.attestation.identity.createCommunity -import nl.tudelft.ipv8.attestation.identity.database.IdentityStore -import nl.tudelft.ipv8.attestation.identity.manager.IdentityManager -import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity -import nl.tudelft.ipv8.attestation.wallet.AttestationStore -import nl.tudelft.ipv8.keyvault.PrivateKey -import nl.tudelft.ipv8.keyvault.PublicKey -import nl.tudelft.ipv8.keyvault.defaultCryptoProvider -import nl.tudelft.ipv8.util.* -import org.json.JSONObject -import java.io.File -import java.io.FileNotFoundException -import java.nio.file.Files -import java.nio.file.Paths - -private val logger = KotlinLogging.logger {} - -class CommunicationManager( - private val iPv8Instance: IPv8, - private val attestationStore: AttestationStore, - private val identityStore: IdentityStore, - val authorityManager: AuthorityManager, - private val storePseudonym: ((String, PrivateKey) -> Unit)? = null, - private val loadPseudonym: ((String) -> PrivateKey?)? = null, -) { - private val channels = hashMapOf() - private val nameToChannel = hashMapOf() - private val loadedCommunity - get() = iPv8Instance.getOverlay() - var identityManager = loadedCommunity?.identityManager - - fun lazyIdentityManager(): IdentityManager { - if (this.identityManager == null) { - this.identityManager = IdentityManager(identityStore) - } - return this.identityManager!! - } - - fun load( - name: String, - rendezvousToken: String? = null, - ): CommunicationChannel { - if (nameToChannel.containsKey(name)) { - return this.nameToChannel[name]!! - } - - // Load private key with function or via default method. - var privateKey = this.loadPseudonym?.let { it(name) } ?: loadPseudonym(name) - if (privateKey == null) { - privateKey = defaultCryptoProvider.generateKey() - this.storePseudonym?.let { it(name, privateKey) } ?: storePseudonym(name, privateKey) - } - val publicKeyBytes = privateKey.pub().keyToBin() - - if (!this.channels.containsKey(publicKeyBytes.toKey())) { - val decodedRendezvousToken: ByteArray? = - (rendezvousToken?.let { defaultEncodingUtils.decodeBase64FromString(it) }) - - val identityOverlay = createCommunity( - privateKey, - this.iPv8Instance, - this.lazyIdentityManager(), - identityStore, - decodedRendezvousToken - ) - - val attestationOverlay = AttestationCommunity( - identityOverlay.myPeer, - identityOverlay.endpoint, - identityOverlay.network, - authorityManager, - attestationStore - ) - attestationOverlay.load() - - this.channels[publicKeyBytes.toKey()] = - CommunicationChannel(attestationOverlay, identityOverlay) - this.nameToChannel[name] = this.channels[publicKeyBytes.toKey()]!! - } - return this.nameToChannel[name]!! - } - - @Suppress("UNUSED_PARAMETER") - fun unload(name: String) { - TODO() - } - - fun listPseudonyms(): List { - return getPseudonyms() - } - - fun listLoadedPseudonyms(): List { - val pseudonyms = this.listPseudonyms() - return this.nameToChannel.keys.filter { pseudonyms.contains(it) } - } - - fun shutdown() { - TODO() - } - - fun getAllPeers(): List { - val peers = mutableListOf() - this.channels.values.map { peers += it.peers } - return peers - } - - companion object { - private const val PSEUDONYM_PATH = "\\pseudonyms\\" - - // Note. This is not secure and should not be used in a production setting without encryption. - @Suppress("NewApi") - fun loadPseudonym(name: String): PrivateKey? { - return try { - val directoryPath = "${System.getProperty("user.dir")}\\$PSEUDONYM_PATH" - val directory = File(directoryPath) - if (!directory.exists()) { - directory.mkdirs() - } - val bytes = File("$directoryPath\\$name").readBytes() - if (bytes.isNotEmpty()) { - defaultCryptoProvider.keyFromPrivateBin(bytes) - } else { - null - } - } catch (e: FileNotFoundException) { - logger.error("Failed to locate pseudonym file $name") - null - } - } - - // Note. This is not secure and should not be used in a production setting without encryption. - @Suppress("NewApi") - fun storePseudonym(name: String, privateKey: PrivateKey) { - val directoryPath = "${System.getProperty("user.dir")}\\$PSEUDONYM_PATH" - val directory = File(directoryPath) - if (!directory.exists()) { - directory.mkdirs() - } - File("$directoryPath\\$name").writeBytes(privateKey.keyToBin()) - } - - @Suppress("NewApi", "UNCHECKED_CAST") - fun getPseudonyms(): List { - return Files.walk(Paths.get("${System.getProperty("user.dir")}\\$PSEUDONYM_PATH")) - .filter(Files::isRegularFile).map { it.fileName.toString() } - .toArray().toList() as List - } - } -} - -class AttributePointer(val peer: Peer, val attributeName: String) { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as AttributePointer - - if (peer != other.peer) return false - if (attributeName != other.attributeName) return false - - return true - } - - override fun hashCode(): Int { - var result = peer.hashCode() - result = 31 * result + attributeName.hashCode() - return result - } -} - -class PrivateAttestationBlob( - val attributeName: String, - val attributeHash: ByteArray, - val metadataString: String, - val idFormat: String, - val attributeValue: String, - val signature: ByteArray, - val attestorKeys: List -) { - override fun equals(other: Any?): Boolean { - return other is PrivateAttestationBlob && this.attributeName == other.attributeName && this.attributeHash.contentEquals( - other.attributeHash - ) && this.metadataString == other.metadataString && this.idFormat == other.idFormat && this.attributeValue == other.attributeValue && this.signature.contentEquals( - other.signature - ) && this.attestorKeys == other.attestorKeys - } -} - -const val DEFAULT_TIME_OUT = 30_000 - -class CommunicationChannel( - val attestationOverlay: AttestationCommunity, - val identityOverlay: IdentityCommunity -) { - - val attestationRequests = - hashMapOf, String>>() - val verifyRequests = hashMapOf>() - val verificationOutput = hashMapOf>>() - private val attestationMetadata = hashMapOf>() - - init { - this.attestationOverlay.setAttestationRequestCallback(this::onRequestAttestationAsync) - this.attestationOverlay.setAttestationRequestCompleteCallback(this::onAttestationComplete) - this.attestationOverlay.setVerifyRequestCallback(this::onVerifyRequestAsync) - } - - val publicKeyBin - get() = this.identityOverlay.myPeer.publicKey.keyToBin() - - val peers - get() = this.identityOverlay.getPeers() - - val myPeer - get() = this.identityOverlay.myPeer - - val schemas - get() = this.attestationOverlay.schemaManager.getSchemaNames() - - private fun onRequestAttestationAsync( - peer: Peer, - attributeName: String, - metadataString: String, - ): Deferred { - // Promise some ByteArray. - val deferred = SettableDeferred() - this.attestationRequests[AttributePointer(peer, attributeName)] = - Pair(deferred, metadataString) - @Suppress("UNCHECKED_CAST") - this.attestationMetadata[AttributePointer(peer, attributeName)] = - JSONObject(metadataString).asMap() as Map - - return GlobalScope.async(start = CoroutineStart.LAZY) { deferred.await() } - } - - @Suppress("UNUSED_PARAMETER") - private fun onAttestationComplete( - forPeer: Peer, - attributeName: String, - attestation: WalletAttestation, - attributeHash: ByteArray, - idFormat: String, - fromPeer: Peer?, - value: ByteArray?, - Signature: ByteArray?, - ) { - val metadata = this.attestationMetadata.get(AttributePointer(forPeer, attributeName)) - - if (forPeer == myPeer) { - if (fromPeer == myPeer) { - @Suppress("UNCHECKED_CAST") - this.identityOverlay.selfAdvertise( - attributeHash, attributeName, idFormat, - metadata as HashMap? - ) - } else { - @Suppress("UNCHECKED_CAST") - this.identityOverlay.requestAttestationAdvertisement( - fromPeer!!, attributeHash, attributeName, idFormat, - metadata as HashMap? - ) - } - } else { - @Suppress("UNCHECKED_CAST") - this.identityOverlay.addKnownHash( - attributeHash, attributeName, value, forPeer.publicKey, - metadata as HashMap? - ) - } - } - - private fun onVerifyRequestAsync(peer: Peer, attributeHash: ByteArray): Deferred { - val metadata = - this.identityOverlay.getAttestationByHash(attributeHash) ?: return CompletableDeferred( - null - ) - val attributeName = JSONObject(String(metadata.serializedMetadata)).getString("name") - val deferred = SettableDeferred() - this.verifyRequests[AttributePointer(peer, attributeName)] = deferred - return GlobalScope.async(start = CoroutineStart.LAZY) { deferred.await() } - } - - private fun onVerificationResults(attributeHash: ByteArray, value: List) { - val references = this.verificationOutput[attributeHash.toKey()] - val out = arrayListOf>() - if (references != null) { - for (i in references.indices) { - out.add(Pair(references[i].first, value[i])) - } - this.verificationOutput[attributeHash.toKey()] = out - } else { - throw RuntimeException("Could not locate reference for ${attributeHash.toHex()} in verification output.") - } - } - - private fun dropIdentityTableData() { - TODO("") - } - - private fun dropAttestationTableData() { - TODO("") - } - - fun remove() { - TODO("") - } - - fun getOfflineVerifiableAttributes(): List { - val peer = this.myPeer - val pseudonym = this.identityOverlay.identityManager.getPseudonym(peer.publicKey) - val out = mutableListOf() - for (credential in pseudonym.getCredentials()) { - val attestations = credential.attestations.toList() - val attestors = mutableListOf() - - for (attestation in attestations) { - attestors += defaultCryptoProvider.keyFromPublicBin( - this.identityOverlay.identityManager.database.getAuthority( - attestation - ) - ).keyToHash().toHex() - } - val attributeHash = - stripSHA1Padding(pseudonym.tree.elements[credential.metadata.tokenPointer.toKey()]!!.contentHash) - val jsonMetadata = JSONObject(String(credential.metadata.serializedMetadata)) - - val attributeName = jsonMetadata.getString("name") - val idFormat = jsonMetadata.getString("schema") - val (value, signature) = this.attestationOverlay.database.getValueAndSignatureByHash( - attributeHash - )!! - - for (md in DEFAULT_METADATA) { - jsonMetadata.remove(md) - } - jsonMetadata.put("value", value) - jsonMetadata.put("subject", peer.publicKey.keyToHash().toHex()) - - out += PrivateAttestationBlob( - attributeName, - attributeHash, - jsonMetadata.toString(), - idFormat, - value, - signature, - attestors - ) - } - return out.sortedBy { it.attributeName } - } - - @Deprecated("This should not be used.") - fun getAttributes(peer: Peer): HashMap, List>> { - val pseudonym = this.identityOverlay.identityManager.getPseudonym(peer.publicKey) - val out: HashMap, List>> = - hashMapOf() - - for (credential in pseudonym.getCredentials()) { - val attestations = credential.attestations.toList() - val attesters = mutableListOf() - - for (attestation in attestations) { - attesters += this.identityOverlay.identityManager.database.getAuthority(attestation) - } - val attributeHash = - pseudonym.tree.elements[credential.metadata.tokenPointer.toKey()]!!.contentHash - val jsonMetadata = JSONObject(String(credential.metadata.serializedMetadata)) - out[attributeHash.toKey()] = - Triple( - jsonMetadata.getString("name"), - jsonMetadata.asMap() as HashMap, - attesters - ) - } - return out - } - - fun requestAttestation( - peer: Peer, - attributeName: String, - idFormat: String, - metadata: HashMap - ) { - val key = this.attestationOverlay.getIdAlgorithm(idFormat).generateSecretKey() - this.attestationMetadata[AttributePointer(this.identityOverlay.myPeer, attributeName)] = - metadata - this.attestationOverlay.requestAttestation(peer, attributeName, key, metadata) - } - - fun attest(peer: Peer, attributeName: String, value: ByteArray) { - val outstanding = this.attestationRequests.remove(AttributePointer(peer, attributeName))!! - GlobalScope.launch { outstanding.first.setResult(value) } - } - - fun dismissAttestionRequest(peer: Peer, attributeName: String) { - val outstanding = this.attestationRequests.remove(AttributePointer(peer, attributeName))!! - GlobalScope.launch { outstanding.first.setResult(null) } - } - - fun allowVerification(peer: Peer, attributeName: String) { - val outstanding = this.verifyRequests.remove(AttributePointer(peer, attributeName))!! - GlobalScope.launch { outstanding.setResult(true) } - } - - fun disallowVerification(peer: Peer, attributeName: String) { - val outstanding = this.verifyRequests.remove(AttributePointer(peer, attributeName))!! - GlobalScope.launch { outstanding.setResult(false) } - } - - fun verify( - peer: Peer, - attestationHash: ByteArray, - referenceValues: List, - idFormat: String - ) { - this.verificationOutput[attestationHash.toKey()] = referenceValues.map { Pair(it, null) } - this.attestationOverlay.verifyAttestationValues( - peer.address, - attestationHash, - referenceValues, - this::onVerificationResults, - idFormat - ) - } - - fun verifyLocally( - challengeSignature: ByteArray, - challengeTimeStamp: Long, - subjectKey: PublicKey, - attestationHash: ByteArray, - metadata: String, - signature: ByteArray, - attestorKeyHash: ByteArray, - ): Boolean { - if (System.currentTimeMillis() - challengeTimeStamp > DEFAULT_TIME_OUT) { - // Do not accept old challenges. - return false - } - - val isChallengeValid = - subjectKey.verify(challengeSignature, challengeTimeStamp.toByteArray()) - val parsedMetadata = JSONObject(metadata) - val isTrusted = this.attestationOverlay.authorityManager.contains(attestorKeyHash) - val isOwner = parsedMetadata.optString("subject") == subjectKey.keyToHash().toHex() - - val authority = this.attestationOverlay.authorityManager.getAuthority(attestorKeyHash) - val isSignatureValid = authority?.publicKey?.verify( - signature, attestationHash + metadata.toByteArray() - ) ?: false - - return isChallengeValid && isTrusted && isOwner && isSignatureValid - } - - fun generateChallenge(): Pair { - val timestamp = System.currentTimeMillis() - return Pair(timestamp, (this.myPeer.key as PrivateKey).sign(timestamp.toByteArray())) - } -} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt new file mode 100644 index 00000000..fd2beac6 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt @@ -0,0 +1,324 @@ +package nl.tudelft.ipv8.attestation.communication + +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.CoroutineStart +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.async +import kotlinx.coroutines.launch +import mu.KotlinLogging +import nl.tudelft.ipv8.Peer +import nl.tudelft.ipv8.attestation.WalletAttestation +import nl.tudelft.ipv8.attestation.identity.IdentityCommunity +import nl.tudelft.ipv8.attestation.identity.Metadata +import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity +import nl.tudelft.ipv8.keyvault.PrivateKey +import nl.tudelft.ipv8.keyvault.PublicKey +import nl.tudelft.ipv8.keyvault.defaultCryptoProvider +import nl.tudelft.ipv8.util.ByteArrayKey +import nl.tudelft.ipv8.util.SettableDeferred +import nl.tudelft.ipv8.util.asMap +import nl.tudelft.ipv8.util.toByteArray +import nl.tudelft.ipv8.util.toHex +import nl.tudelft.ipv8.util.toKey +import org.json.JSONObject + +const val DEFAULT_TIME_OUT = 30_000 +private val logger = KotlinLogging.logger {} + +class CommunicationChannel( + val attestationOverlay: AttestationCommunity, + val identityOverlay: IdentityCommunity +) { + + val attestationRequests = + hashMapOf, String, String?>>() + val verifyRequests = hashMapOf>() + val verificationOutput = hashMapOf>>() + private val attestationMetadata = hashMapOf>() + + init { + this.attestationOverlay.setAttestationRequestCallback(this::onRequestAttestationAsync) + this.attestationOverlay.setAttestationRequestCompleteCallback(this::onAttestationComplete) + this.attestationOverlay.setVerifyRequestCallback(this::onVerifyRequestAsync) + } + + val peers + get() = this.identityOverlay.getPeers() + + val myPeer + get() = this.identityOverlay.myPeer + + val schemas + get() = this.attestationOverlay.schemaManager.getSchemaNames() + + private fun onRequestAttestationAsync( + peer: Peer, + attributeName: String, + metadataString: String, + proposedValue: String? + ): Deferred { + // Promise some ByteArray. + val deferred = SettableDeferred() + this.attestationRequests[AttributePointer(peer, attributeName)] = + Triple(deferred, metadataString, proposedValue) + @Suppress("UNCHECKED_CAST") + this.attestationMetadata[AttributePointer(peer, attributeName)] = + JSONObject(metadataString).asMap() as MutableMap + + return GlobalScope.async(start = CoroutineStart.LAZY) { deferred.await() } + } + + @Suppress("UNUSED_PARAMETER") + private fun onAttestationComplete( + forPeer: Peer, + attributeName: String, + attestation: WalletAttestation, + attributeHash: ByteArray, + idFormat: String, + fromPeer: Peer?, + value: ByteArray?, + Signature: ByteArray?, + ) { + val metadata = this.attestationMetadata[AttributePointer(forPeer, attributeName)]!! + value?.let { metadata["value"] = String(it) } + + if (forPeer == myPeer) { + if (fromPeer == myPeer) { + @Suppress("UNCHECKED_CAST") + this.identityOverlay.selfAdvertise( + attributeHash, attributeName, idFormat, + metadata as HashMap? + ) + } else { + @Suppress("UNCHECKED_CAST") + this.identityOverlay.requestAttestationAdvertisement( + fromPeer!!, attributeHash, attributeName, idFormat, + metadata as HashMap? + ) + } + } else { + @Suppress("UNCHECKED_CAST") + this.identityOverlay.addKnownHash( + attributeHash, attributeName, value, forPeer.publicKey, + metadata as HashMap? + ) + } + } + + private fun onVerifyRequestAsync(peer: Peer, attributeHash: ByteArray): Deferred { + val metadata = + this.identityOverlay.getAttestationByHash(attributeHash) ?: return CompletableDeferred( + null + ) + val attributeName = JSONObject(String(metadata.serializedMetadata)).getString("name") + val deferred = SettableDeferred() + this.verifyRequests[AttributePointer(peer, attributeName)] = deferred + return GlobalScope.async(start = CoroutineStart.LAZY) { deferred.await() } + } + + private fun onVerificationResults(attributeHash: ByteArray, value: List) { + val references = this.verificationOutput[attributeHash.toKey()] + val out = arrayListOf>() + if (references != null) { + for (i in references.indices) { + out.add(Pair(references[i].first, value[i])) + } + this.verificationOutput[attributeHash.toKey()] = out + } else { + throw RuntimeException("Could not locate reference for ${attributeHash.toHex()} in verification output.") + } + } + + private fun dropIdentityTableData() { + TODO("") + } + + private fun dropAttestationTableData() { + TODO("") + } + + fun remove() { + TODO("") + } + + fun getOfflineVerifiableAttributes(): List { + val out = mutableListOf() + val peer = this.myPeer + val pseudonym = this.identityOverlay.identityManager.getPseudonym(peer.publicKey) + + for (credential in pseudonym.getCredentials()) { + val attestations = credential.attestations.toList() + + val attestors = mutableListOf>() + + for (attestation in attestations) { + val attestor = defaultCryptoProvider.keyFromPublicBin( + this.identityOverlay.identityManager.database.getAuthority( + attestation + ) + ).keyToHash() + attestors += Pair(attestor, attestation.signature) + } + + val attributeHash = pseudonym.tree.elements[credential.metadata.tokenPointer.toKey()]!!.contentHash + val jsonMetadata = JSONObject(String(credential.metadata.serializedMetadata)) + + val attributeName = jsonMetadata.getString("name") + val idFormat = jsonMetadata.getString("schema") + val signDate = jsonMetadata.getFloat("date") + out += AttestationPresentation( + attributeHash, + attributeName, + idFormat, + signDate, + credential.metadata, + attestors + ) + } + return out.sortedBy { it.attributeName } + } + + @Deprecated("This should not be used.") + fun getAttributes(peer: Peer): HashMap, List>> { + val pseudonym = this.identityOverlay.identityManager.getPseudonym(peer.publicKey) + val out: HashMap, List>> = + hashMapOf() + + for (credential in pseudonym.getCredentials()) { + val attestations = credential.attestations.toList() + val attestors = mutableListOf() + + for (attestation in attestations) { + attestors += this.identityOverlay.identityManager.database.getAuthority(attestation) + } + val attributeHash = + pseudonym.tree.elements[credential.metadata.tokenPointer.toKey()]!!.contentHash + val jsonMetadata = JSONObject(String(credential.metadata.serializedMetadata)) + out[attributeHash.toKey()] = + Triple( + jsonMetadata.getString("name"), + jsonMetadata.asMap() as HashMap, + attestors + ) + } + return out + } + + fun requestAttestation( + peer: Peer, + attributeName: String, + idFormat: String, + metadata: HashMap, + proposedValue: String? = null, + ) { + val key = this.attestationOverlay.getIdAlgorithm(idFormat).generateSecretKey() + this.attestationMetadata[AttributePointer(this.identityOverlay.myPeer, attributeName)] = + metadata + this.attestationOverlay.requestAttestation(peer, attributeName, key, metadata, proposedValue) + } + + fun attest(peer: Peer, attributeName: String, value: ByteArray) { + val outstanding = this.attestationRequests.remove(AttributePointer(peer, attributeName))!! + GlobalScope.launch { outstanding.first.setResult(value) } + } + + fun dismissAttestationRequest(peer: Peer, attributeName: String) { + val outstanding = this.attestationRequests.remove(AttributePointer(peer, attributeName))!! + GlobalScope.launch { outstanding.first.setResult(null) } + } + + fun allowVerification(peer: Peer, attributeName: String) { + val outstanding = this.verifyRequests.remove(AttributePointer(peer, attributeName))!! + GlobalScope.launch { outstanding.setResult(true) } + } + + fun disallowVerification(peer: Peer, attributeName: String) { + val outstanding = this.verifyRequests.remove(AttributePointer(peer, attributeName))!! + GlobalScope.launch { outstanding.setResult(false) } + } + + fun verify( + peer: Peer, + attestationHash: ByteArray, + referenceValues: List, + idFormat: String + ) { + this.verificationOutput[attestationHash.toKey()] = referenceValues.map { Pair(it, null) } + this.attestationOverlay.verifyAttestationValues( + peer.address, + attestationHash, + referenceValues, + this::onVerificationResults, + idFormat + ) + } + + fun verifyLocally( + attestationHash: ByteArray, + metadata: Metadata, + subjectKey: PublicKey, + challengePair: Pair, + attestors: List> + ): Boolean { + if (System.currentTimeMillis() - challengePair.second > DEFAULT_TIME_OUT) { + logger.info("Not accepting ${attestationHash.toHex()}, challenge timed out!") + return false + } + + if (!subjectKey.verify(challengePair.first, challengePair.second.toByteArray())) { + logger.info("Not accepting ${attestationHash.toHex()}, challenge not valid!") + } + + if (!subjectKey.verify(metadata.signature, metadata.getPlaintext())) { + logger.info("Not accepting ${attestationHash.toHex()}, metadata signature not valid!") + } + + if (!attestors.any { attestor -> + val authority = this.attestationOverlay.authorityManager.getAuthority(attestor.first) + authority?.let { + it.publicKey!!.verify(attestor.second, metadata.hash) + } == true + }) { + logger.info("Not accepting ${attestationHash.toHex()}, no recognized authority or valid signature found.") + } + + return true + } + + fun generateChallenge(): Pair { + val timestamp = System.currentTimeMillis() + return Pair(timestamp, (this.myPeer.key as PrivateKey).sign(timestamp.toByteArray())) + } +} + +class AttestationPresentation( + val attributeHash: ByteArray, + val attributeName: String, + val idFormat: String, + val signDate: Float, + val metadata: Metadata, + val attestors: List> +) { + override fun equals(other: Any?): Boolean { + return other is AttestationPresentation && this.attributeHash.contentEquals(other.attributeHash) + } +} + +// class PrivateAttestationBlob( +// val attributeName: String, +// val attributeHash: ByteArray, +// val metadataString: String, +// val idFormat: String, +// val attributeValue: String, +// val signature: ByteArray, +// val attestorKeys: List +// ) { +// override fun equals(other: Any?): Boolean { +// return other is PrivateAttestationBlob && this.attributeName == other.attributeName && this.attributeHash.contentEquals( +// other.attributeHash +// ) && this.metadataString == other.metadataString && this.idFormat == other.idFormat && this.attributeValue == other.attributeValue && this.signature.contentEquals( +// other.signature +// ) && this.attestorKeys == other.attestorKeys +// } +// } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt new file mode 100644 index 00000000..dd7d6840 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt @@ -0,0 +1,177 @@ +package nl.tudelft.ipv8.attestation.communication + +import mu.KotlinLogging +import nl.tudelft.ipv8.IPv8 +import nl.tudelft.ipv8.Peer +import nl.tudelft.ipv8.attestation.AuthorityManager +import nl.tudelft.ipv8.attestation.identity.IdentityCommunity +import nl.tudelft.ipv8.attestation.identity.createCommunity +import nl.tudelft.ipv8.attestation.identity.database.IdentityStore +import nl.tudelft.ipv8.attestation.identity.manager.IdentityManager +import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity +import nl.tudelft.ipv8.attestation.wallet.AttestationStore +import nl.tudelft.ipv8.keyvault.PrivateKey +import nl.tudelft.ipv8.keyvault.defaultCryptoProvider +import nl.tudelft.ipv8.util.* +import java.io.File +import java.io.FileNotFoundException +import java.nio.file.Files +import java.nio.file.Paths + +private val logger = KotlinLogging.logger {} + +class CommunicationManager( + private val iPv8Instance: IPv8, + private val attestationStore: AttestationStore, + private val identityStore: IdentityStore, + val authorityManager: AuthorityManager, + storePseudonym: ((String, PrivateKey) -> Unit)? = null, + loadPseudonym: ((String) -> PrivateKey?)? = null, +) { + private val channels = hashMapOf() + private val nameToChannel = hashMapOf() + private val loadedCommunity + get() = iPv8Instance.getOverlay() + var identityManager = loadedCommunity?.identityManager + + private val loadPseudonym = loadPseudonym ?: Companion::loadPseudonym + private val storePseudonym = storePseudonym ?: Companion::storePseudonym + + private fun lazyIdentityManager(): IdentityManager { + if (this.identityManager == null) { + this.identityManager = IdentityManager(identityStore) + } + return this.identityManager!! + } + + fun load( + name: String, + rendezvousToken: String? = null, + ): CommunicationChannel { + if (nameToChannel.containsKey(name)) { + return this.nameToChannel[name]!! + } + + // Load private key with function or via default method. + var privateKey = this.loadPseudonym(name) + if (privateKey == null) { + privateKey = defaultCryptoProvider.generateKey() + this.storePseudonym(name, privateKey) + } + val publicKeyBytes = privateKey.pub().keyToBin() + + if (!this.channels.containsKey(publicKeyBytes.toKey())) { + val decodedRendezvousToken: ByteArray? = + (rendezvousToken?.let { defaultEncodingUtils.decodeBase64FromString(it) }) + + val identityOverlay = createCommunity( + privateKey, + this.iPv8Instance, + this.lazyIdentityManager(), + identityStore, + decodedRendezvousToken + ) + + val attestationOverlay = AttestationCommunity( + identityOverlay.myPeer, + identityOverlay.endpoint, + identityOverlay.network, + authorityManager, + attestationStore + ) + attestationOverlay.load() + + this.channels[publicKeyBytes.toKey()] = + CommunicationChannel(attestationOverlay, identityOverlay) + this.nameToChannel[name] = this.channels[publicKeyBytes.toKey()]!! + } + return this.nameToChannel[name]!! + } + + @Suppress("UNUSED_PARAMETER") + fun unload(name: String) { + TODO() + } + + fun listPseudonyms(): List { + return getPseudonyms() + } + + fun listLoadedPseudonyms(): List { + val pseudonyms = this.listPseudonyms() + return this.nameToChannel.keys.filter { pseudonyms.contains(it) } + } + + fun shutdown() { + TODO() + } + + fun getAllPeers(): List { + val peers = mutableListOf() + this.channels.values.map { peers += it.peers } + return peers + } + + companion object { + private const val PSEUDONYM_PATH = "\\pseudonyms\\" + + // Note. This is not secure and should not be used in a production setting without encryption. + @Suppress("NewApi") + fun loadPseudonym(name: String): PrivateKey? { + return try { + val directoryPath = "${System.getProperty("user.dir")}\\$PSEUDONYM_PATH" + val directory = File(directoryPath) + if (!directory.exists()) { + directory.mkdirs() + } + val bytes = File("$directoryPath\\$name").readBytes() + if (bytes.isNotEmpty()) { + defaultCryptoProvider.keyFromPrivateBin(bytes) + } else { + null + } + } catch (e: FileNotFoundException) { + logger.error("Failed to locate pseudonym file $name") + null + } + } + + // Note. This is not secure and should not be used in a production setting without encryption. + @Suppress("NewApi") + fun storePseudonym(name: String, privateKey: PrivateKey) { + val directoryPath = "${System.getProperty("user.dir")}\\$PSEUDONYM_PATH" + val directory = File(directoryPath) + if (!directory.exists()) { + directory.mkdirs() + } + File("$directoryPath\\$name").writeBytes(privateKey.keyToBin()) + } + + @Suppress("NewApi", "UNCHECKED_CAST") + fun getPseudonyms(): List { + return Files.walk(Paths.get("${System.getProperty("user.dir")}\\$PSEUDONYM_PATH")) + .filter(Files::isRegularFile).map { it.fileName.toString() } + .toArray().toList() as List + } + } +} + +class AttributePointer(val peer: Peer, val attributeName: String) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as AttributePointer + + if (peer != other.peer) return false + if (attributeName != other.attributeName) return false + + return true + } + + override fun hashCode(): Int { + var result = peer.hashCode() + result = 31 * result + attributeName.hashCode() + return result + } +} From fad39058480ba93eaa0e6f6740d2dbfe0b2e2c33 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 26 Apr 2021 13:08:37 +0200 Subject: [PATCH 082/144] Clean up code + add proposed value to AttestationCommunity --- .../identity/IdentityAttestation.kt | 1 - .../attestation/identity/IdentityCommunity.kt | 12 ++++------ .../wallet/AttestationCommunity.kt | 23 ++++++++++++------- .../bonehexact/BonehExactAlgorithm.kt | 2 -- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt index a741613b..875d7340 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt @@ -10,7 +10,6 @@ class IdentityAttestation( privateKey: PrivateKey? = null, signature: ByteArray? = null, ) : SignedObject(privateKey, signature) { - init { super.init() } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index 4bbda0cd..abccc791 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -138,7 +138,7 @@ class IdentityCommunity( return null } - fun shouldSign(pseudonym: PseudonymManager, metadata: Metadata): Boolean { + private fun shouldSign(pseudonym: PseudonymManager, metadata: Metadata): Boolean { val transaction = JSONObject(String(metadata.serializedMetadata)) val requestedKeys = transaction.keySet() if (!pseudonym.tree.elements.containsKey(metadata.tokenPointer.toKey())) { @@ -227,12 +227,10 @@ class IdentityCommunity( if (shouldSign(pseudonym, credential.metadata)) { logger.info("Attesting to ${credential.metadata}.") val myPrivateKey = this.myPeer.key as PrivateKey - - val attestation = - pseudonym.createAttestation( - credential.metadata, - myPrivateKey - ) + val attestation = pseudonym.createAttestation( + credential.metadata, + myPrivateKey + ) pseudonym.addAttestation(this.myPeer.publicKey, attestation) val payload = AttestPayload(attestation.getPlaintextSigned()) this.endpoint.send(peer, serializePacket(ATTEST_PAYLOAD, payload)) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt index 00b31ec9..5811952e 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt @@ -62,12 +62,12 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: private val receiveBlockLock = ReentrantLock() val schemaManager = SchemaManager() - private lateinit var attestationRequestCallback: (peer: Peer, attributeName: String, metaData: String) -> Deferred + private lateinit var attestationRequestCallback: (peer: Peer, attributeName: String, metaData: String, proposedValue: String?) -> Deferred private lateinit var attestationRequestCompleteCallback: (forPeer: Peer, attributeName: String, attestation: WalletAttestation, attestationHash: ByteArray, idFormat: String, fromPeer: Peer?, value: ByteArray?, signature: ByteArray?) -> Unit private lateinit var verifyRequestCallback: (peer: Peer, attributeHash: ByteArray) -> Deferred private lateinit var attestationChunkCallback: (peer: Peer, sequenceNumber: Int) -> Unit - val attestationKeys: MutableMap> = mutableMapOf() + private val attestationKeys: MutableMap> = mutableMapOf() private val cachedAttestationBlobs = mutableMapOf() private val allowedAttestations = mutableMapOf>() @@ -133,7 +133,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: return this.schemaManager.getAlgorithmInstance(idFormat) } - fun setAttestationRequestCallback(f: (peer: Peer, attributeName: String, metaData: String) -> Deferred) { + fun setAttestationRequestCallback(f: (peer: Peer, attributeName: String, metaData: String, proposedValue: String?) -> Deferred) { this.attestationRequestCallback = f } @@ -160,6 +160,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: attributeName: String, privateKey: BonehPrivateKey, metadata: HashMap = hashMapOf(), + proposedValue: String? = null, ) { logger.info("Sending attestation request $attributeName to peer ${peer.mid}.") val publicKey = privateKey.publicKey() @@ -168,9 +169,10 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val metadataJson = JSONObject() metadataJson.put("attribute", attributeName) - // Encode to UTF-8 metadataJson.put("public_key", defaultEncodingUtils.encodeBase64ToString(publicKey.serialize())) metadataJson.put("id_format", idFormat) + // Will not be added if null. + metadataJson.put("proposed_value", proposedValue) inputMetadata.keys().forEach { metadataJson.put(it, inputMetadata.get(it)) @@ -212,11 +214,16 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val attribute = metadata.remove("attribute") as String val pubkeyEncoded = metadata.remove("public_key") as String val idFormat = metadata.remove("id_format") as String - val metadataString = metadata.toString() + var proposedValue: String? = null + // We cannot cast null to string, hence member checking. + if (metadata.has("proposed_value")) { + proposedValue = metadata.remove("proposed_value") as String + } + val metadataString = metadata.toString() val idAlgorithm = this.getIdAlgorithm(idFormat) - val value = this.attestationRequestCallback(peer, attribute, metadataString).await() + val value = this.attestationRequestCallback(peer, attribute, metadataString, proposedValue).await() if (value == null) { logger.error("Failed to get value from callback") return @@ -229,14 +236,14 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val attestation = idAlgorithm.deserialize(attestationBlob, idFormat) - val stringifiedValue = when (idFormat) { + val valueAsString = when (idFormat) { ID_METADATA_RANGE_18PLUS -> ID_METADATA_RANGE_18PLUS_PUBLIC_VALUE ID_METADATA_RANGE_UNDERAGE -> ID_METADATA_RANGE_UNDERAGE_PUBLIC_VALUE else -> String(value) } val signableMetadata = JSONObject(metadataString) - signableMetadata.put("value", stringifiedValue) + signableMetadata.put("value", valueAsString) signableMetadata.put("subject", peer.publicKey.keyToHash().toHex()) val signableData = attestation.getHash() + signableMetadata.toString().toByteArray() diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/BonehExactAlgorithm.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/BonehExactAlgorithm.kt index 902868db..82742473 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/BonehExactAlgorithm.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/BonehExactAlgorithm.kt @@ -5,7 +5,6 @@ import nl.tudelft.ipv8.attestation.WalletAttestation import nl.tudelft.ipv8.attestation.wallet.cryptography.* import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.attestations.BonehAttestation import nl.tudelft.ipv8.messaging.* -import java.math.BigDecimal import java.math.BigInteger const val ALGORITHM_NAME = "bonehexact" @@ -49,7 +48,6 @@ class BonehExactAlgorithm(val idFormat: String, val formats: HashMap throw RuntimeException("Unknown hashing mode $hashMode") } - } override fun deserialize(serialized: ByteArray, idFormat: String): WalletAttestation { From 362286ba622873e872460c4a5bd691f11ef30ccb Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 26 Apr 2021 17:31:57 +0200 Subject: [PATCH 083/144] Fix default timeout type + add vaue to attestation presentation --- .../communication/CommunicationChannel.kt | 19 +++++++++++++++---- .../ipv8/attestation/identity/Metadata.kt | 4 ++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt index fd2beac6..d40e9265 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt @@ -23,7 +23,7 @@ import nl.tudelft.ipv8.util.toHex import nl.tudelft.ipv8.util.toKey import org.json.JSONObject -const val DEFAULT_TIME_OUT = 30_000 +const val DEFAULT_TIME_OUT = 30_000L private val logger = KotlinLogging.logger {} class CommunicationChannel( @@ -161,15 +161,18 @@ class CommunicationChannel( attestors += Pair(attestor, attestation.signature) } - val attributeHash = pseudonym.tree.elements[credential.metadata.tokenPointer.toKey()]!!.contentHash + val attributeHash = + pseudonym.tree.elements[credential.metadata.tokenPointer.toKey()]!!.contentHash val jsonMetadata = JSONObject(String(credential.metadata.serializedMetadata)) val attributeName = jsonMetadata.getString("name") + val attributeValue = jsonMetadata.getString("value") val idFormat = jsonMetadata.getString("schema") val signDate = jsonMetadata.getFloat("date") out += AttestationPresentation( attributeHash, attributeName, + attributeValue, idFormat, signDate, credential.metadata, @@ -215,7 +218,13 @@ class CommunicationChannel( val key = this.attestationOverlay.getIdAlgorithm(idFormat).generateSecretKey() this.attestationMetadata[AttributePointer(this.identityOverlay.myPeer, attributeName)] = metadata - this.attestationOverlay.requestAttestation(peer, attributeName, key, metadata, proposedValue) + this.attestationOverlay.requestAttestation( + peer, + attributeName, + key, + metadata, + proposedValue + ) } fun attest(peer: Peer, attributeName: String, value: ByteArray) { @@ -275,7 +284,8 @@ class CommunicationChannel( } if (!attestors.any { attestor -> - val authority = this.attestationOverlay.authorityManager.getAuthority(attestor.first) + val authority = + this.attestationOverlay.authorityManager.getAuthority(attestor.first) authority?.let { it.publicKey!!.verify(attestor.second, metadata.hash) } == true @@ -295,6 +305,7 @@ class CommunicationChannel( class AttestationPresentation( val attributeHash: ByteArray, val attributeName: String, + val attributeValue: String, val idFormat: String, val signDate: Float, val metadata: Metadata, diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt index 735ef3e7..81774dc6 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt @@ -60,9 +60,9 @@ class Metadata( fun fromDatabaseTuple( tokenPointer: ByteArray, signature: ByteArray?, - serializedJSONObject: ByteArray, + serializedMetadata: ByteArray, ): Metadata { - return Metadata(tokenPointer, serializedJSONObject, signature = signature) + return Metadata(tokenPointer, serializedMetadata, signature = signature) } } } From 38ee68d8459372ea57068b2e76fca4303306587f Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 26 Apr 2021 21:21:14 +0200 Subject: [PATCH 084/144] Add returns in local verification logic --- .../attestation/communication/CommunicationChannel.kt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt index d40e9265..9723dfef 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt @@ -168,7 +168,7 @@ class CommunicationChannel( val attributeName = jsonMetadata.getString("name") val attributeValue = jsonMetadata.getString("value") val idFormat = jsonMetadata.getString("schema") - val signDate = jsonMetadata.getFloat("date") + val signDate = jsonMetadata.getDouble("date").toFloat() out += AttestationPresentation( attributeHash, attributeName, @@ -277,22 +277,25 @@ class CommunicationChannel( if (!subjectKey.verify(challengePair.first, challengePair.second.toByteArray())) { logger.info("Not accepting ${attestationHash.toHex()}, challenge not valid!") + return false } if (!subjectKey.verify(metadata.signature, metadata.getPlaintext())) { logger.info("Not accepting ${attestationHash.toHex()}, metadata signature not valid!") + return false } + // Check if authority is recognized and the corresponding signature is correct. if (!attestors.any { attestor -> val authority = - this.attestationOverlay.authorityManager.getAuthority(attestor.first) + this.attestationOverlay.authorityManager.getTrustedAuthority(attestor.first) authority?.let { - it.publicKey!!.verify(attestor.second, metadata.hash) + it.publicKey?.verify(attestor.second, metadata.hash) } == true }) { logger.info("Not accepting ${attestationHash.toHex()}, no recognized authority or valid signature found.") + return false } - return true } From 6a3ef675894f448a6d3fdeff8638331932e7bcc7 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 29 Apr 2021 09:42:31 +0200 Subject: [PATCH 085/144] Remove signature from AttestationCommunity --- .../wallet/AttestationCommunity.kt | 193 +++++++++++------- 1 file changed, 117 insertions(+), 76 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt index 5811952e..dc064293 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt @@ -20,10 +20,11 @@ import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity.MessageId.VERIFY_ import nl.tudelft.ipv8.attestation.wallet.caches.* import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPrivateKey import nl.tudelft.ipv8.attestation.wallet.payloads.* -import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.messaging.EndpointAggregator import nl.tudelft.ipv8.messaging.Packet +import nl.tudelft.ipv8.messaging.deserializeVarLen import nl.tudelft.ipv8.messaging.payload.GlobalTimeDistributionPayload +import nl.tudelft.ipv8.messaging.serializeVarLen import nl.tudelft.ipv8.peerdiscovery.Network import nl.tudelft.ipv8.util.* import org.json.JSONObject @@ -36,7 +37,8 @@ import kotlin.random.nextUBytes private val logger = KotlinLogging.logger {} private const val CHUNK_SIZE = 800 -class AttestationCommunity(val authorityManager: AuthorityManager, val database: AttestationStore) : Community() { +class AttestationCommunity(val authorityManager: AuthorityManager, val database: AttestationStore) : + Community() { override lateinit var myPeer: Peer override lateinit var endpoint: EndpointAggregator @@ -63,11 +65,12 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val schemaManager = SchemaManager() private lateinit var attestationRequestCallback: (peer: Peer, attributeName: String, metaData: String, proposedValue: String?) -> Deferred - private lateinit var attestationRequestCompleteCallback: (forPeer: Peer, attributeName: String, attestation: WalletAttestation, attestationHash: ByteArray, idFormat: String, fromPeer: Peer?, value: ByteArray?, signature: ByteArray?) -> Unit + private lateinit var attestationRequestCompleteCallback: (forPeer: Peer, attributeName: String, attestation: WalletAttestation, attestationHash: ByteArray, idFormat: String, fromPeer: Peer?, value: ByteArray?) -> Unit private lateinit var verifyRequestCallback: (peer: Peer, attributeHash: ByteArray) -> Deferred private lateinit var attestationChunkCallback: (peer: Peer, sequenceNumber: Int) -> Unit - private val attestationKeys: MutableMap> = mutableMapOf() + private val attestationKeys: MutableMap> = + mutableMapOf() private val cachedAttestationBlobs = mutableMapOf() private val allowedAttestations = mutableMapOf>() @@ -81,7 +84,8 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val hash = att.attestationHash val key = att.key val idFormat = att.idFormat - this.attestationKeys[ByteArrayKey(hash)] = Pair(this.getIdAlgorithm(idFormat).loadSecretKey(key), idFormat) + this.attestationKeys[ByteArrayKey(hash)] = + Pair(this.getIdAlgorithm(idFormat).loadSecretKey(key), idFormat) } messageHandlers[VERIFY_ATTESTATION_REQUEST] = ::onVerifyAttestationRequestWrapper @@ -137,7 +141,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: this.attestationRequestCallback = f } - fun setAttestationRequestCompleteCallback(f: (forPeer: Peer, attributeName: String, attestation: WalletAttestation, attributeHash: ByteArray, idFormat: String, fromPeer: Peer?, value: ByteArray?, Signature: ByteArray?) -> Unit) { + fun setAttestationRequestCompleteCallback(f: (forPeer: Peer, attributeName: String, attestation: WalletAttestation, attributeHash: ByteArray, idFormat: String, fromPeer: Peer?, value: ByteArray?) -> Unit) { this.attestationRequestCompleteCallback = f } @@ -169,7 +173,10 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val metadataJson = JSONObject() metadataJson.put("attribute", attributeName) - metadataJson.put("public_key", defaultEncodingUtils.encodeBase64ToString(publicKey.serialize())) + metadataJson.put( + "public_key", + defaultEncodingUtils.encodeBase64ToString(publicKey.serialize()) + ) metadataJson.put("id_format", idFormat) // Will not be added if null. metadataJson.put("proposed_value", proposedValue) @@ -217,38 +224,27 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: var proposedValue: String? = null // We cannot cast null to string, hence member checking. if (metadata.has("proposed_value")) { - proposedValue = metadata.remove("proposed_value") as String + proposedValue = metadata.remove("proposed_value") as String } val metadataString = metadata.toString() val idAlgorithm = this.getIdAlgorithm(idFormat) - val value = this.attestationRequestCallback(peer, attribute, metadataString, proposedValue).await() + val value = + this.attestationRequestCallback(peer, attribute, metadataString, proposedValue).await() if (value == null) { logger.error("Failed to get value from callback") return } // Decode as UTF-8 ByteArray - val publicKey = idAlgorithm.loadPublicKey(defaultEncodingUtils.decodeBase64FromString(pubkeyEncoded)) + val publicKey = + idAlgorithm.loadPublicKey(defaultEncodingUtils.decodeBase64FromString(pubkeyEncoded)) val attestationBlob = idAlgorithm.attest(publicKey, value) val attestation = idAlgorithm.deserialize(attestationBlob, idFormat) - val valueAsString = when (idFormat) { - ID_METADATA_RANGE_18PLUS -> ID_METADATA_RANGE_18PLUS_PUBLIC_VALUE - ID_METADATA_RANGE_UNDERAGE -> ID_METADATA_RANGE_UNDERAGE_PUBLIC_VALUE - else -> String(value) - } - - val signableMetadata = JSONObject(metadataString) - signableMetadata.put("value", valueAsString) - signableMetadata.put("subject", peer.publicKey.keyToHash().toHex()) - - val signableData = attestation.getHash() + signableMetadata.toString().toByteArray() - val signature = (myPeer.key as PrivateKey).sign(signableData) - if (this::attestationRequestCompleteCallback.isInitialized) { this.attestationRequestCompleteCallback( peer, @@ -257,17 +253,14 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: attestation.getHash(), idFormat, null, - value, - signature, + value ) } this.sendAttestation( peer.address, - attestationBlob, + attestationBlob + serializeVarLen(value), dist.globalTime, - value, - signature ) } @@ -279,7 +272,6 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: attestationHash: ByteArray, idFormat: String, value: ByteArray? = null, - signature: ByteArray? = null, ) { this.attestationKeys[ByteArrayKey(attestationHash)] = Pair(privateKey, idFormat) this.database.insertAttestation( @@ -287,9 +279,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: attestationHash, privateKey, idFormat, - value?.let { String(it, Charsets.US_ASCII) }, - signature, - peer.publicKey + value ) if (this::attestationRequestCompleteCallback.isInitialized) { @@ -300,8 +290,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: attestationHash, idFormat, peer, - value, - signature + value ) } } @@ -319,7 +308,14 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: callback(attestationHash, values.map { algorithm.certainty(it, relativityMap) }) } - this.requestCache.add(ProvingAttestationCache(this, attestationHash, idFormat, onComplete = ::onComplete)) + this.requestCache.add( + ProvingAttestationCache( + this, + attestationHash, + idFormat, + onComplete = ::onComplete + ) + ) this.createVerifyAttestationRequest(socketAddress, attestationHash, idFormat) } @@ -356,7 +352,8 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: } val (privateKey, idFormat) = this.attestationKeys[ByteArrayKey(payload.hash)]!! - val privateAttestation = schemaManager.deserializePrivate(privateKey, attestationBlob, idFormat) + val privateAttestation = + schemaManager.deserializePrivate(privateKey, attestationBlob, idFormat) val publicAttestationBlob = privateAttestation.serialize() this.cachedAttestationBlobs[ByteArrayKey(payload.hash)] = privateAttestation this.sendAttestation(peer.address, publicAttestationBlob) @@ -366,8 +363,6 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: sockedAddress: IPv4Address, blob: ByteArray, globalTime: ULong? = null, - value: ByteArray? = null, - signature: ByteArray? = null, ) { var sequenceNumber = 0 for (i in blob.indices step CHUNK_SIZE) { @@ -376,19 +371,19 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val blobChunk = blob.copyOfRange(i, endIndex) logger.info("Sending attestation chunk $sequenceNumber to $sockedAddress") - // Only send metadata and signature on final package to reduce overhead. - val payload = - if (i + CHUNK_SIZE > blob.size) - AttestationChunkPayload(sha1(blob), sequenceNumber, blobChunk, value, signature) - else - AttestationChunkPayload(sha1(blob), sequenceNumber, blobChunk) - val packet = serializePacket(ATTESTATION, payload, prefix = this.prefix, timestamp = globalTime) + val payload = AttestationChunkPayload(sha1(blob), sequenceNumber, blobChunk) + val packet = + serializePacket(ATTESTATION, payload, prefix = this.prefix, timestamp = globalTime) this.endpoint.send(sockedAddress, packet) sequenceNumber += 1 } } - private fun onAttestationChunk(peer: Peer, dist: GlobalTimeDistributionPayload, payload: AttestationChunkPayload) { + private fun onAttestationChunk( + peer: Peer, + dist: GlobalTimeDistributionPayload, + payload: AttestationChunkPayload + ) { if (this::attestationChunkCallback.isInitialized) { this.attestationChunkCallback(peer, payload.sequenceNumber) } @@ -416,11 +411,11 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: } if (sha1(serialized).contentEquals(payload.hash)) { - val deserialized = schemaManager.deserialize(serialized, cache.idFormat) + val attestation = schemaManager.deserialize(serialized, cache.idFormat) this.requestCache.pop(prefix, number) this.onReceivedAttestation( peer, - deserialized, + attestation, payload.hash ) } @@ -430,14 +425,11 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: var handled = false for (peerId in peerIds) { if (this.requestCache.has(peerId.first, peerId.second)) { - var cache = this.requestCache.get(peerId.first, peerId.second) as ReceiveAttestationRequestCache + var cache = this.requestCache.get( + peerId.first, + peerId.second + ) as ReceiveAttestationRequestCache cache.attestationMap.add(Pair(payload.sequenceNumber, payload.data)) - if (payload.value != null) { - cache.value = payload.value - } - if (payload.signature != null) { - cache.signature = payload.signature - } var serialized = byteArrayOf() for ((_, chunk) in cache.attestationMap.sortedBy { attestation -> attestation.first }) { @@ -445,13 +437,30 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: } if (sha1(serialized).contentEquals(payload.hash)) { - val deserialized = - schemaManager.deserializePrivate(cache.privateKey, serialized, cache.idFormat) - cache = (this.requestCache.pop(peerId.first, peerId.second) as ReceiveAttestationRequestCache) - - this.allowedAttestations[peer.mid] = this.allowedAttestations[peer.mid]!!.mapNotNull { - if (!it.contentEquals(dist.globalTime.toString().toByteArray())) it else null - }.toTypedArray() + val attestation = + schemaManager.deserializePrivate( + cache.privateKey, + serialized, + cache.idFormat + ) + val value = deserializeVarLen( + serialized.copyOfRange( + attestation.serialize().size, + serialized.size + ) + ).first + cache = (this.requestCache.pop( + peerId.first, + peerId.second + ) as ReceiveAttestationRequestCache) + + this.allowedAttestations[peer.mid] = + this.allowedAttestations[peer.mid]!!.mapNotNull { + if (!it.contentEquals( + dist.globalTime.toString().toByteArray() + ) + ) it else null + }.toTypedArray() if (this.allowedAttestations[peer.mid].isNullOrEmpty()) { this.allowedAttestations.remove(peer.mid) } @@ -459,14 +468,13 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: // TODO: Verify received signature and value this.onAttestationComplete( - deserialized, + attestation, cache.privateKey, peer, cache.name, - deserialized.getHash(), + attestation.getHash(), cache.idFormat, - cache.value, - cache.signature + value, ) } @@ -515,7 +523,14 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: } remaining -= 1 - this.requestCache.add(PendingChallengesCache(this, sha1(challenge), cache, cache.idFormat)) + this.requestCache.add( + PendingChallengesCache( + this, + sha1(challenge), + cache, + cache.idFormat + ) + ) val payload = ChallengePayload(attestationHash, challenge) val packet = serializePacket(CHALLENGE, payload, prefix = this.prefix) @@ -547,7 +562,10 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: payload: ChallengeResponsePayload, ) { synchronized(receiveBlockLock) { - val (prefix, number) = HashCache.idFromHash(PENDING_CHALLENGES_PREFIX, payload.challengeHash) + val (prefix, number) = HashCache.idFromHash( + PENDING_CHALLENGES_PREFIX, + payload.challengeHash + ) if (this.requestCache.has(prefix, number)) { val cache = this.requestCache.pop(prefix, number) as PendingChallengesCache val provingCache = cache.provingCache @@ -558,12 +576,17 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: var challenge: ByteArray? = null // TODO: Come up with more elegant solution for ByteArray checking. - val hashElement = provingCache.hashedChallenges.find { x -> x.contentEquals(payload.challengeHash) } + val hashElement = + provingCache.hashedChallenges.find { x -> x.contentEquals(payload.challengeHash) } if (hashElement != null) { provingCache.hashedChallenges.remove(hashElement) for (c in provingCache.challenges) { if (sha1(c).contentEquals(payload.challengeHash)) { - provingCache.challenges.remove(provingCache.challenges.first { x -> x.contentEquals(c) }) + provingCache.challenges.remove(provingCache.challenges.first { x -> + x.contentEquals( + c + ) + }) challenge = c break } @@ -571,13 +594,24 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: } val algorithm = this.getIdAlgorithm(provingCache.idFormat) if (cache.honestyCheck < 0) { - algorithm.processChallengeResponse(provingCache.relativityMap, challenge, payload.response) - } else if (!algorithm.processHonestyChallenge(cache.honestyCheck, payload.response)) { + algorithm.processChallengeResponse( + provingCache.relativityMap, + challenge, + payload.response + ) + } else if (!algorithm.processHonestyChallenge( + cache.honestyCheck, + payload.response + ) + ) { logger.error("${peer.address} attempted to cheat in the ZKP!") if (this.requestCache.has(provingCachePrefix, provingCacheId)) { this.requestCache.pop(provingCachePrefix, provingCacheId) } - provingCache.attestationCallbacks(provingCache.cacheHash, algorithm.createCertaintyAggregate(null)) + provingCache.attestationCallbacks( + provingCache.cacheHash, + algorithm.createCertaintyAggregate(null) + ) } if (provingCache.hashedChallenges.isEmpty()) { @@ -586,10 +620,14 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: if (this.requestCache.has(provingCachePrefix, provingCacheId)) { this.requestCache.pop(provingCachePrefix, provingCacheId) } - provingCache.attestationCallbacks(provingCache.cacheHash, provingCache.relativityMap) + provingCache.attestationCallbacks( + provingCache.cacheHash, + provingCache.relativityMap + ) } else { // TODO: Add secure random. - val honestyCheck = algorithm.honestCheck && (Random.nextUBytes(1)[0].toInt() < 38) + val honestyCheck = + algorithm.honestCheck && (Random.nextUBytes(1)[0].toInt() < 38) var honestyCheckByte = if (honestyCheck) arrayOf(0, 1, 2).random() else -1 challenge = null if (honestyCheck) { @@ -600,7 +638,10 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: ) ) ) { - challenge = algorithm.createHonestyChallenge(provingCache.publicKey!!, honestyCheckByte) + challenge = algorithm.createHonestyChallenge( + provingCache.publicKey!!, + honestyCheckByte + ) } } if (!honestyCheck || (challenge != null && this.requestCache.has( From 232f7f30d4484ed31b4f8f01fca6a5d254576e1e Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 29 Apr 2021 09:42:56 +0200 Subject: [PATCH 086/144] Verify value in metadata --- .../communication/CommunicationChannel.kt | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt index 9723dfef..ea3e33ea 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt @@ -18,6 +18,9 @@ import nl.tudelft.ipv8.keyvault.defaultCryptoProvider import nl.tudelft.ipv8.util.ByteArrayKey import nl.tudelft.ipv8.util.SettableDeferred import nl.tudelft.ipv8.util.asMap +import nl.tudelft.ipv8.util.defaultEncodingUtils +import nl.tudelft.ipv8.util.sha3_256 +import nl.tudelft.ipv8.util.stripSHA1Padding import nl.tudelft.ipv8.util.toByteArray import nl.tudelft.ipv8.util.toHex import nl.tudelft.ipv8.util.toKey @@ -77,11 +80,10 @@ class CommunicationChannel( attributeHash: ByteArray, idFormat: String, fromPeer: Peer?, - value: ByteArray?, - Signature: ByteArray?, + value: ByteArray? ) { val metadata = this.attestationMetadata[AttributePointer(forPeer, attributeName)]!! - value?.let { metadata["value"] = String(it) } + value?.let { metadata["value"] = defaultEncodingUtils.encodeBase64ToString(sha3_256(it)) } if (forPeer == myPeer) { if (fromPeer == myPeer) { @@ -166,7 +168,10 @@ class CommunicationChannel( val jsonMetadata = JSONObject(String(credential.metadata.serializedMetadata)) val attributeName = jsonMetadata.getString("name") - val attributeValue = jsonMetadata.getString("value") + val attributeValue = + this.attestationOverlay.database.getValueByHash( + stripSHA1Padding(attributeHash) + )!! val idFormat = jsonMetadata.getString("schema") val signDate = jsonMetadata.getDouble("date").toFloat() out += AttestationPresentation( @@ -265,6 +270,7 @@ class CommunicationChannel( fun verifyLocally( attestationHash: ByteArray, + proposedAttestationValue: ByteArray, metadata: Metadata, subjectKey: PublicKey, challengePair: Pair, @@ -285,6 +291,15 @@ class CommunicationChannel( return false } + val parsedMD = JSONObject(String(metadata.serializedMetadata)) + val valueHash = parsedMD.getString("value") + val proposedHash = + defaultEncodingUtils.encodeBase64ToString(sha3_256(proposedAttestationValue)) + if (valueHash != proposedHash) { + logger.info("Not accepting ${attestationHash.toHex()}, value not valid!") + return false + } + // Check if authority is recognized and the corresponding signature is correct. if (!attestors.any { attestor -> val authority = @@ -308,7 +323,7 @@ class CommunicationChannel( class AttestationPresentation( val attributeHash: ByteArray, val attributeName: String, - val attributeValue: String, + val attributeValue: ByteArray, val idFormat: String, val signDate: Float, val metadata: Metadata, From 79efec495b15bda3317d4a60453e6c0287ea71c5 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 29 Apr 2021 09:43:57 +0200 Subject: [PATCH 087/144] Add debug log + change default value types --- .../nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt | 1 + .../java/nl/tudelft/ipv8/attestation/schema/SchemaManager.kt | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index abccc791..d1b527ed 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -142,6 +142,7 @@ class IdentityCommunity( val transaction = JSONObject(String(metadata.serializedMetadata)) val requestedKeys = transaction.keySet() if (!pseudonym.tree.elements.containsKey(metadata.tokenPointer.toKey())) { + logger.debug("Not signing $metadata, unknown token!") return false } val attributeHash = pseudonym.tree.elements[metadata.tokenPointer.toKey()]!!.contentHash diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/schema/SchemaManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/schema/SchemaManager.kt index 02ab688f..ef666d9e 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/schema/SchemaManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/schema/SchemaManager.kt @@ -21,9 +21,9 @@ const val ID_METADATA = "id_metadata" const val ID_METADATA_BIG = "id_metadata_big" const val ID_METADATA_HUGE = "id_metadata_huge" const val ID_METADATA_RANGE_18PLUS = "id_metadata_range_18plus" -const val ID_METADATA_RANGE_18PLUS_PUBLIC_VALUE = true +const val ID_METADATA_RANGE_18PLUS_PUBLIC_VALUE = "true" const val ID_METADATA_RANGE_UNDERAGE = "id_metadata_range_underage" -const val ID_METADATA_RANGE_UNDERAGE_PUBLIC_VALUE = true +const val ID_METADATA_RANGE_UNDERAGE_PUBLIC_VALUE = "true" class SchemaManager { From 734d3bbf8376fada2d406f7e4370b91f91b75c5b Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 29 Apr 2021 09:44:36 +0200 Subject: [PATCH 088/144] Remove signature from attestation logic --- .../wallet/AttestationSQLiteStore.kt | 22 ++++-------- .../attestation/wallet/AttestationStore.kt | 10 ++---- .../caches/ReceiveAttestationRequestCache.kt | 2 -- .../payloads/AttestationChunkPayload.kt | 34 ++++--------------- 4 files changed, 16 insertions(+), 52 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationSQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationSQLiteStore.kt index 226f2089..17670a7d 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationSQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationSQLiteStore.kt @@ -12,18 +12,14 @@ private val attestationMapper: ( ByteArray, ByteArray, String, - String?, ByteArray?, - ByteArray?, -) -> AttestationBlob = { hash, blob, key, id_format, value, signature, attestor_key -> +) -> AttestationBlob = { hash, blob, key, id_format, value -> AttestationBlob( hash, blob, key, id_format, - value, - signature, - attestor_key?.let { defaultCryptoProvider.keyFromPublicBin(it) } + value ) } @@ -41,9 +37,7 @@ class AttestationSQLiteStore(database: Database) : AttestationStore { attestationHash: ByteArray, privateKey: BonehPrivateKey, idFormat: String, - value: String?, - signature: ByteArray?, - attestorKey: PublicKey?, + value: ByteArray?, ) { val blob = attestation.serializePrivate(privateKey.publicKey()) dao.insertAttestation( @@ -51,9 +45,7 @@ class AttestationSQLiteStore(database: Database) : AttestationStore { blob, privateKey.serialize(), idFormat, - value, - signature, - attestorKey?.keyToBin() + value ) } @@ -61,10 +53,8 @@ class AttestationSQLiteStore(database: Database) : AttestationStore { return dao.getAttestationByHash(attestationHash).executeAsOneOrNull() } - override fun getValueAndSignatureByHash(attestationHash: ByteArray): Pair? { - val pair = - dao.getValueAndSignatureByHash(attestationHash).executeAsOneOrNull() ?: return null - return Pair(pair.value!!, pair.signature!!) + override fun getValueByHash(attestationHash: ByteArray): ByteArray? { + return dao.getValueByHash(attestationHash).executeAsOneOrNull()?.value } override fun deleteAttestationByHash(attestationHash: ByteArray) { diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationStore.kt index 2e575a8c..f530b2c9 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationStore.kt @@ -9,9 +9,7 @@ class AttestationBlob( val blob: ByteArray, val key: ByteArray, val idFormat: String, - val value: String?, - val signature: ByteArray?, - val attestorKey: PublicKey?, + val value: ByteArray?, ) interface AttestationStore { @@ -22,14 +20,12 @@ interface AttestationStore { attestationHash: ByteArray, privateKey: BonehPrivateKey, idFormat: String, - value: String? = null, - signature: ByteArray? = null, - attestorKey: PublicKey? = null, + value: ByteArray? = null, ) fun getAttestationBlobByHash(attestationHash: ByteArray): ByteArray? - fun getValueAndSignatureByHash(attestationHash: ByteArray): Pair? + fun getValueByHash(attestationHash: ByteArray): ByteArray? fun deleteAttestationByHash(attestationHash: ByteArray) } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/ReceiveAttestationRequestCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/ReceiveAttestationRequestCache.kt index d27e3a15..4081f21a 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/ReceiveAttestationRequestCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/ReceiveAttestationRequestCache.kt @@ -13,8 +13,6 @@ class ReceiveAttestationRequestCache( idFormat: String, ) : PeerCache(community.requestCache, ATTESTATION_REQUEST_PREFIX, mid, idFormat) { - var signature: ByteArray? = null - var value: ByteArray? = null val attestationMap: MutableSet> = mutableSetOf() } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/payloads/AttestationChunkPayload.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/payloads/AttestationChunkPayload.kt index 902330b4..f9405d24 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/payloads/AttestationChunkPayload.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/payloads/AttestationChunkPayload.kt @@ -6,19 +6,10 @@ class AttestationChunkPayload( val hash: ByteArray, val sequenceNumber: Int, val data: ByteArray, - val value: ByteArray? = null, - val signature: ByteArray? = null, ) : Serializable { - private val msgId = 2 override fun serialize(): ByteArray { - return ( - hash + serializeUInt(sequenceNumber.toUInt()) + serializeVarLen(data) + - ( - if (value != null && signature != null) serializeVarLen(value) + signature - else byteArrayOf() - ) - ) + return hash + serializeUInt(sequenceNumber.toUInt()) + serializeVarLen(data) } companion object Deserializer : Deserializable { @@ -28,8 +19,10 @@ class AttestationChunkPayload( ): Pair { var localoffset = 0 - val hash = buffer.copyOfRange(offset + localoffset, - offset + localoffset + SERIALIZED_SHA1_HASH_SIZE) + val hash = buffer.copyOfRange( + offset + localoffset, + offset + localoffset + SERIALIZED_SHA1_HASH_SIZE + ) localoffset += SERIALIZED_SHA1_HASH_SIZE val sequenceNumber = deserializeUInt(buffer, offset + localoffset) @@ -38,21 +31,8 @@ class AttestationChunkPayload( val (data, dataSize) = deserializeVarLen(buffer, offset + localoffset) localoffset += dataSize - return if (buffer.lastIndex > offset + localoffset) { - val (value, valueSize) = deserializeVarLen(buffer, offset + localoffset) - localoffset += valueSize - - val signature = buffer.copyOfRange(offset + localoffset, offset + localoffset + SIGNATURE_SIZE) - localoffset += SIGNATURE_SIZE - - val payload = AttestationChunkPayload(hash, sequenceNumber.toInt(), data, value, signature) - Pair(payload, localoffset) - } else { - val payload = AttestationChunkPayload(hash, sequenceNumber.toInt(), data) - Pair(payload, localoffset) - } - + val payload = AttestationChunkPayload(hash, sequenceNumber.toInt(), data) + return Pair(payload, localoffset) } - } } From b95f1962fa771f86b142232bedc87fed12898d72 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 29 Apr 2021 09:44:51 +0200 Subject: [PATCH 089/144] Remove signature and public key from attestation db --- .../nl/tudelft/ipv8/sqldelight/DbAttestation.sq | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAttestation.sq b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAttestation.sq index d8a4e89b..d8165542 100644 --- a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAttestation.sq +++ b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAttestation.sq @@ -3,9 +3,7 @@ CREATE TABLE attestations ( blob BLOB NOT NULL, key BLOB NOT NULL, id_format TEXT NOT NULL, - value TEXT, - signature BLOB, - attestor_key BLOB, + value BLOB, PRIMARY KEY(hash) ); @@ -13,13 +11,13 @@ getAllAttestations: SELECT * FROM attestations; insertAttestation: -INSERT INTO attestations (hash, blob, key, id_format, value, signature, attestor_key) VALUES(?, ?, ?, ?, ?, ?, ?); +INSERT INTO attestations (hash, blob, key, id_format, value) VALUES(?, ?, ?, ?, ?); getAttestationByHash: SELECT blob FROM attestations WHERE hash = ?; -getValueAndSignatureByHash: -SELECT value, signature FROM attestations WHERE hash = ?; +getValueByHash: +SELECT value FROM attestations WHERE hash = ?; deleteAttestationByHash: DELETE FROM attestations WHERE hash = ?; From 8f3dbaedb6ab7ab47a62d64fabe6a6a35937163c Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 29 Apr 2021 09:45:04 +0200 Subject: [PATCH 090/144] Change BonehAttestation serialization --- .../bonehexact/attestations/BonehAttestation.kt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/attestations/BonehAttestation.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/attestations/BonehAttestation.kt index f629eab2..94c2148e 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/attestations/BonehAttestation.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/attestations/BonehAttestation.kt @@ -3,6 +3,9 @@ package nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.attestations import nl.tudelft.ipv8.attestation.WalletAttestation import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPrivateKey import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPublicKey +import nl.tudelft.ipv8.messaging.SERIALIZED_USHORT_SIZE +import nl.tudelft.ipv8.messaging.deserializeUShort +import nl.tudelft.ipv8.messaging.serializeUShort class BonehAttestation( override val publicKey: BonehPublicKey, @@ -13,7 +16,7 @@ class BonehAttestation( override fun serialize(): ByteArray { var out = byteArrayOf() this.bitPairs.forEach { out += (it.serialize()) } - return this.publicKey.serialize() + out + return this.publicKey.serialize() + serializeUShort(this.bitPairs.size) + out } override fun deserialize(serialized: ByteArray, idFormat: String): WalletAttestation { @@ -25,12 +28,18 @@ class BonehAttestation( val publicKey = BonehPublicKey.deserialize(serialized)!! val bitPairs = arrayListOf() val pkSerialized = publicKey.serialize() - var rem = serialized.copyOfRange(pkSerialized.size, serialized.size) - while (rem.isNotEmpty()) { + + var offset = pkSerialized.size + val amountBitPairs = deserializeUShort(serialized, offset) + offset += SERIALIZED_USHORT_SIZE + + var rem = serialized.copyOfRange(offset, serialized.size) + for (i in 0 until amountBitPairs) { val attest = BitPairAttestation.deserialize(rem, publicKey.p) bitPairs.add(attest) rem = rem.copyOfRange(attest.serialize().size, rem.size) } + return BonehAttestation(publicKey, bitPairs, idFormat) } From 3fea5fbc630b467549c68bcae2e18ef8bdfbc9ec Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 29 Apr 2021 09:45:17 +0200 Subject: [PATCH 091/144] Create JSONArray toList method --- .../nl/tudelft/ipv8/util/EncodingUtils.kt | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/util/EncodingUtils.kt b/ipv8/src/main/java/nl/tudelft/ipv8/util/EncodingUtils.kt index 9c5b7f47..eac2612c 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/util/EncodingUtils.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/util/EncodingUtils.kt @@ -2,6 +2,7 @@ package nl.tudelft.ipv8.util import org.json.JSONArray import org.json.JSONObject +import java.util.ArrayList interface EncodingUtils { @@ -25,7 +26,7 @@ fun JSONObject.asMap(): Map { } else if (value1 is JSONObject) { value1.asMap() } else if (value1 is JSONArray) { - value1.toList() + value1.asList() } else { value1 } @@ -33,3 +34,20 @@ fun JSONObject.asMap(): Map { } return results } + +fun JSONArray.asList(): List { + val results: MutableList = ArrayList(this.length()) + for (i in 0 until this.length()) { + val element = this.get(i) + if (element == null || JSONObject.NULL == element) { + results.add(null) + } else if (element is JSONArray) { + results.add(element.asList()) + } else if (element is JSONObject) { + results.add(element.asMap()) + } else { + results.add(element) + } + } + return results +} From a8c4f6a5b4fdab65fa25c07ee7c54c7f5605b517 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 30 Apr 2021 09:19:52 +0200 Subject: [PATCH 092/144] Implement unload method in CommunicationManager --- .../messaging/bluetooth/BluetoothLeDiscovery.kt | 2 +- .../peerdiscovery/NetworkServiceDiscovery.kt | 2 +- ipv8/src/main/java/nl/tudelft/ipv8/IPv8.kt | 11 +++++++++++ .../communication/CommunicationChannel.kt | 3 +++ .../communication/CommunicationManager.kt | 13 ++++++++++--- .../peerdiscovery/strategy/DiscoveryStrategy.kt | 2 ++ .../peerdiscovery/strategy/PeriodicSimilarity.kt | 2 +- .../ipv8/peerdiscovery/strategy/RandomChurn.kt | 2 +- .../ipv8/peerdiscovery/strategy/RandomWalk.kt | 2 +- 9 files changed, 31 insertions(+), 8 deletions(-) diff --git a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/BluetoothLeDiscovery.kt b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/BluetoothLeDiscovery.kt index 740ac743..c1cbb01d 100644 --- a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/BluetoothLeDiscovery.kt +++ b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/messaging/bluetooth/BluetoothLeDiscovery.kt @@ -10,7 +10,7 @@ private val logger = KotlinLogging.logger {} * A strategy for selecting discovered Bluetooth peers we should connect to. */ class BluetoothLeDiscovery( - private val overlay: Overlay, + override val overlay: Overlay, private val peers: Int ) : DiscoveryStrategy { override fun takeStep() { diff --git a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/peerdiscovery/NetworkServiceDiscovery.kt b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/peerdiscovery/NetworkServiceDiscovery.kt index 47e39637..ea25a811 100644 --- a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/peerdiscovery/NetworkServiceDiscovery.kt +++ b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/peerdiscovery/NetworkServiceDiscovery.kt @@ -16,7 +16,7 @@ private val logger = KotlinLogging.logger {} */ class NetworkServiceDiscovery( private val nsdManager: NsdManager, - private val overlay: Overlay + override val overlay: Overlay ) : DiscoveryStrategy { private var serviceName: String? = null diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/IPv8.kt b/ipv8/src/main/java/nl/tudelft/ipv8/IPv8.kt index 7ef0d0b2..b3444b2a 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/IPv8.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/IPv8.kt @@ -110,6 +110,17 @@ class IPv8( } } + fun unloadSecondaryOverlayStrategy(serviceId: String) { + synchronized(overlayLock) { + val overlay = this.secondaryOverlays.remove(serviceId) + for (strategy in strategies) { + if (strategy.overlay == overlay) { + this.strategies.remove(strategy) + } + } + } + } + private fun onTick() { if (endpoint.isOpen()) { synchronized(overlayLock) { diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt index ea3e33ea..b20f9083 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt @@ -46,6 +46,9 @@ class CommunicationChannel( this.attestationOverlay.setVerifyRequestCallback(this::onVerifyRequestAsync) } + val publicKeyBin + get() = this.identityOverlay.myPeer.publicKey.keyToBin() + val peers get() = this.identityOverlay.getPeers() diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt index dd7d6840..a55357b9 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt @@ -88,9 +88,14 @@ class CommunicationManager( return this.nameToChannel[name]!! } - @Suppress("UNUSED_PARAMETER") fun unload(name: String) { - TODO() + if (this.nameToChannel.containsKey(name)) { + val communicationChannel = this.nameToChannel.remove(name)!! + this.channels.remove(communicationChannel.publicKeyBin.toKey()) + this.iPv8Instance.unloadSecondaryOverlayStrategy(communicationChannel.identityOverlay.serviceId) + communicationChannel.attestationOverlay.unload() + // TODO: Endpoint close? + } } fun listPseudonyms(): List { @@ -103,7 +108,9 @@ class CommunicationManager( } fun shutdown() { - TODO() + for (name in this.nameToChannel.keys) { + this.unload(name) + } } fun getAllPeers(): List { diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/peerdiscovery/strategy/DiscoveryStrategy.kt b/ipv8/src/main/java/nl/tudelft/ipv8/peerdiscovery/strategy/DiscoveryStrategy.kt index 26f60bec..0d893b6c 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/peerdiscovery/strategy/DiscoveryStrategy.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/peerdiscovery/strategy/DiscoveryStrategy.kt @@ -6,6 +6,8 @@ import nl.tudelft.ipv8.Overlay * Strategy for discovering peers in a network. */ interface DiscoveryStrategy { + val overlay: Overlay + /** * It is called when the IPv8 service is started. */ diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/peerdiscovery/strategy/PeriodicSimilarity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/peerdiscovery/strategy/PeriodicSimilarity.kt index 0c7cfdb4..79c570b6 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/peerdiscovery/strategy/PeriodicSimilarity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/peerdiscovery/strategy/PeriodicSimilarity.kt @@ -6,7 +6,7 @@ import nl.tudelft.ipv8.peerdiscovery.DiscoveryCommunity * On every step, it sends a similarity request to a random peer. */ class PeriodicSimilarity( - private val overlay: DiscoveryCommunity + override val overlay: DiscoveryCommunity ) : DiscoveryStrategy { override fun takeStep() { val peer = overlay.network.getRandomPeer() diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/peerdiscovery/strategy/RandomChurn.kt b/ipv8/src/main/java/nl/tudelft/ipv8/peerdiscovery/strategy/RandomChurn.kt index 25632140..402ac4c0 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/peerdiscovery/strategy/RandomChurn.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/peerdiscovery/strategy/RandomChurn.kt @@ -15,7 +15,7 @@ private val logger = KotlinLogging.logger {} * from the network graph. */ class RandomChurn( - private val overlay: PingOverlay, + override val overlay: PingOverlay, private val sampleSize: Int, private val pingInterval: Double, private val inactiveTime: Double, diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/peerdiscovery/strategy/RandomWalk.kt b/ipv8/src/main/java/nl/tudelft/ipv8/peerdiscovery/strategy/RandomWalk.kt index 2130d68f..c8f5ab30 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/peerdiscovery/strategy/RandomWalk.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/peerdiscovery/strategy/RandomWalk.kt @@ -12,7 +12,7 @@ private val logger = KotlinLogging.logger {} * an introduction to another community member. */ class RandomWalk( - private val overlay: Overlay, + override val overlay: Overlay, private val timeout: Double, private val windowSize: Int, private val resetChance: Int, From 20a10a856e59cf626c92edd9a8a9a8ef5679a62b Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 30 Apr 2021 09:20:58 +0200 Subject: [PATCH 093/144] Format IdentitySQLiteStore --- .../identity/database/IdentitySQLiteStore.kt | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt index 972d23d0..0f14940c 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt @@ -44,9 +44,18 @@ class IdentitySQLiteStore(database: Database) : IdentityStore { dao.insertMetadata(publicKey.keyToBin(), tokenPointer, signature, serializedMetadata) } - override fun insertAttestation(publicKey: PublicKey, authorityKey: PublicKey, attestation: IdentityAttestation) { + override fun insertAttestation( + publicKey: PublicKey, + authorityKey: PublicKey, + attestation: IdentityAttestation + ) { val (metadataPointer, signature) = attestation.toDatabaseTuple() - dao.insertIdentityAttestation(publicKey.keyToBin(), authorityKey.keyToBin(), metadataPointer, signature) + dao.insertIdentityAttestation( + publicKey.keyToBin(), + authorityKey.keyToBin(), + metadataPointer, + signature + ) } override fun getTokensFor(publicKey: PublicKey): List { @@ -58,15 +67,18 @@ class IdentitySQLiteStore(database: Database) : IdentityStore { } override fun getAttestationsFor(publicKey: PublicKey): Set { - return dao.getAttestationsFor(publicKey.keyToBin(), identityAttestationMapper).executeAsList().toSet() + return dao.getAttestationsFor(publicKey.keyToBin(), identityAttestationMapper) + .executeAsList().toSet() } override fun getAttestationsBy(publicKey: PublicKey): Set { - return dao.getAttestationsBy(publicKey.keyToBin(), identityAttestationMapper).executeAsList().toSet() + return dao.getAttestationsBy(publicKey.keyToBin(), identityAttestationMapper) + .executeAsList().toSet() } override fun getAttestationsOver(metadata: Metadata): Set { - return dao.getAttestationsOver(metadata.hash, identityAttestationMapper).executeAsList().toSet() + return dao.getAttestationsOver(metadata.hash, identityAttestationMapper).executeAsList() + .toSet() } override fun getAuthority(attestation: IdentityAttestation): ByteArray { @@ -82,6 +94,7 @@ class IdentitySQLiteStore(database: Database) : IdentityStore { } override fun getKnownIdentities(): List { - return dao.getKnownIdentities().executeAsList().map { defaultCryptoProvider.keyFromPublicBin(it) } + return dao.getKnownIdentities().executeAsList() + .map { defaultCryptoProvider.keyFromPublicBin(it) } } } From 0599cda39f7859621480cfd26c152e688419b4d2 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 30 Apr 2021 09:21:08 +0200 Subject: [PATCH 094/144] Fix equals method --- .../ipv8/attestation/communication/CommunicationChannel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt index b20f9083..8432342b 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt @@ -333,7 +333,7 @@ class AttestationPresentation( val attestors: List> ) { override fun equals(other: Any?): Boolean { - return other is AttestationPresentation && this.attributeHash.contentEquals(other.attributeHash) + return other is AttestationPresentation && this.attributeHash.contentEquals(other.attributeHash) && this.attestors.size == other.attestors.size } } From ab7273c9e5c77ebb5fa79a01304c3fa50c6ba864 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 3 May 2021 16:49:50 +0200 Subject: [PATCH 095/144] Format code + add method for fetching attestation signed by a peer --- .../ipv8/attestation/AuthorityManager.kt | 17 +++++++---- .../communication/CommunicationChannel.kt | 4 +++ .../attestation/identity/IdentityCommunity.kt | 4 +-- .../revocation/AuthoritySQLiteStore.kt | 28 ++++++++++++------- .../attestation/revocation/AuthorityStore.kt | 9 ++++-- .../ipv8/attestation/tokenTree/TokenTree.kt | 4 +-- 6 files changed, 44 insertions(+), 22 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt index 6af27135..e1925ccc 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt @@ -1,4 +1,4 @@ -package nl.tudelft.ipv8.attestation + package nl.tudelft.ipv8.attestation import nl.tudelft.ipv8.attestation.revocation.AuthorityStore import nl.tudelft.ipv8.attestation.revocation.RevocationBlob @@ -34,7 +34,12 @@ class AuthorityManager(val authorityDatabase: AuthorityStore) { } } - fun insertRevocations(publicKeyHash: ByteArray, versionNumber: Long, signature: ByteArray, revokedHashes: List) { + fun insertRevocations( + publicKeyHash: ByteArray, + versionNumber: Long, + signature: ByteArray, + revokedHashes: List + ) { authorityDatabase.insertRevocations(publicKeyHash, versionNumber, signature, revokedHashes) if (this.trustedAuthorities.containsKey(publicKeyHash.toKey())) { this.trustedAuthorities[publicKeyHash.toKey()]!!.version = versionNumber @@ -72,7 +77,7 @@ class AuthorityManager(val authorityDatabase: AuthorityStore) { if (!this.contains(hash)) { val localAuthority = authorityDatabase.getAuthorityByHash(hash) if (localAuthority == null) { - authorityDatabase.insertAuthority(publicKey) + authorityDatabase.insertTrustedAuthority(publicKey) synchronized(lock) { this.trustedAuthorities[hash.toKey()] = Authority(publicKey, hash) } @@ -97,7 +102,9 @@ class AuthorityManager(val authorityDatabase: AuthorityStore) { } fun getAuthority(hash: ByteArray): Authority? { - return this.trustedAuthorities.get(hash.toKey()) ?: authorityDatabase.getAuthorityByHash(hash) + return this.trustedAuthorities.get(hash.toKey()) ?: authorityDatabase.getAuthorityByHash( + hash + ) } fun deleteTrustedAuthority(publicKey: PublicKey) { @@ -107,6 +114,4 @@ class AuthorityManager(val authorityDatabase: AuthorityStore) { fun contains(hash: ByteArray): Boolean { return this.trustedAuthorities.containsKey(hash.toKey()) } - - } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt index 8432342b..6fd25e05 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt @@ -190,6 +190,10 @@ class CommunicationChannel( return out.sortedBy { it.attributeName } } + fun getAttestationsSignedBy(peer: Peer) { + this.identityOverlay.identityManager.database.getAttestationsBy(peer.publicKey) + } + @Deprecated("This should not be used.") fun getAttributes(peer: Peer): HashMap, List>> { val pseudonym = this.identityOverlay.identityManager.getPseudonym(peer.publicKey) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index d1b527ed..bf9108b8 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -209,8 +209,8 @@ class IdentityCommunity( } private fun receivedDisclosureForAttest(peer: Peer, disclosure: Disclosure) { - val solicited = this.knownAttestationHashes.values.filter { it.publicKey == peer.publicKey } - if (solicited.isNotEmpty()) { + val solicited = this.knownAttestationHashes.values.any { it.publicKey == peer.publicKey } + if (solicited) { val (correct, pseudonym) = this.identityManager.substantiate( peer.publicKey, disclosure.metadata, diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt index 56389303..0a6e9137 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt @@ -6,7 +6,6 @@ import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.keyvault.defaultCryptoProvider import nl.tudelft.ipv8.sqldelight.Database import nl.tudelft.ipv8.sqldelight.GetAllRevocations -import nl.tudelft.ipv8.util.toHex private val authorityMapper: ( ByteArray?, @@ -14,10 +13,12 @@ private val authorityMapper: ( Long?, Long?, ) -> Authority = { public_key, hash, version, recognized -> - Authority(public_key?.let { defaultCryptoProvider.keyFromPublicBin(it) }, + Authority( + public_key?.let { defaultCryptoProvider.keyFromPublicBin(it) }, hash, version ?: 0L, - recognized?.toInt() == 1) + recognized?.toInt() == 1 + ) } private val logger = KotlinLogging.logger {} @@ -49,6 +50,10 @@ class AuthoritySQLiteStore(database: Database) : AuthorityStore { return dao.insertAuthority(publicKey.keyToBin(), publicKey.keyToHash(), null, null) } + override fun insertTrustedAuthority(publicKey: PublicKey) { + return dao.insertAuthority(publicKey.keyToBin(), publicKey.keyToHash(), null, 1) + } + override fun insertAuthority(hash: ByteArray) { return dao.insertAuthority(null, hash, null, null) } @@ -67,19 +72,21 @@ class AuthoritySQLiteStore(database: Database) : AuthorityStore { if (version >= 2L) { val previousId = - dao.getVersionByAuthorityIDandVersionNumber(authorityId, version - 1L).executeAsOneOrNull()?.version_id + dao.getVersionByAuthorityIDandVersionNumber(authorityId, version - 1L) + .executeAsOneOrNull()?.version_id if (previousId == null) { logger.warn("Received revocations out of order, skipping!") return } - } var versionId = - dao.getVersionByAuthorityIDandVersionNumber(authorityId, version).executeAsOneOrNull()?.version_id + dao.getVersionByAuthorityIDandVersionNumber(authorityId, version) + .executeAsOneOrNull()?.version_id if (versionId == null) { dao.insertVersion(authorityId, version, signature) - versionId = dao.getVersionByAuthorityIDandVersionNumber(authorityId, version).executeAsOne().version_id + versionId = dao.getVersionByAuthorityIDandVersionNumber(authorityId, version) + .executeAsOne().version_id } revokedHashes.forEach { dao.insertRevocation(authorityId, versionId, it) } @@ -103,15 +110,16 @@ class AuthoritySQLiteStore(database: Database) : AuthorityStore { dao.getVersionsByAuthorityIDandVersionNumbers(authorityId, versions).executeAsList() return versionEntries.map { - RevocationBlob(publicKeyHash, it.version_number, + RevocationBlob( + publicKeyHash, it.version_number, it.signature, dao.getRevocationsByAuthorityIdAndVersionId(authorityId, it.version_id) - .executeAsList()) + .executeAsList() + ) } } override fun getAllRevocations(): List { return dao.getAllRevocations().executeAsList() } - } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt index 8ac5625c..9d06b9e4 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt @@ -5,7 +5,12 @@ import nl.tudelft.ipv8.attestation.Revocations import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.sqldelight.GetAllRevocations -class RevocationBlob(val publicKeyHash: ByteArray, val version: Long, val signature: ByteArray, val revocations: List) +class RevocationBlob( + val publicKeyHash: ByteArray, + val version: Long, + val signature: ByteArray, + val revocations: List +) interface AuthorityStore { @@ -14,6 +19,7 @@ interface AuthorityStore { fun getAuthorityByHash(hash: ByteArray): Authority? fun recognizeAuthority(hash: ByteArray) fun disregardAuthority(hash: ByteArray) + fun insertTrustedAuthority(publicKey: PublicKey) fun insertAuthority(publicKey: PublicKey) fun insertAuthority(hash: ByteArray) @@ -29,5 +35,4 @@ interface AuthorityStore { fun getVersionsSince(publicKeyHash: ByteArray, sinceVersion: Long): List fun getAllRevocations(): List - } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt index e0872cd1..c2c0d3d4 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt @@ -8,7 +8,7 @@ import nl.tudelft.ipv8.util.sha3_256 import nl.tudelft.ipv8.util.toKey const val UNCHAINED_MAX_SIZE = 100 -const val DEFAULT_CHUNK_SUZE = 64 +const val DEFAULT_CHUNK_SIZE = 64 private val logger = KotlinLogging.logger {} @@ -143,7 +143,7 @@ class TokenTree(publicKey: PublicKey? = null, privateKey: PrivateKey? = null) { fun deserializePublic(serialized: ByteArray): Boolean { val signatureLength = this.publicKey.getSignatureLength() - val chunkSize = DEFAULT_CHUNK_SUZE + signatureLength + val chunkSize = DEFAULT_CHUNK_SIZE + signatureLength var isCorrect = true for (i in serialized.indices step chunkSize) { isCorrect = isCorrect && this.gatherToken(Token.deserialize(serialized, this.publicKey, offset = i)) != null From ad095f08eaf79f5d570717d34e91e0194558bbc7 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 5 May 2021 15:01:03 +0200 Subject: [PATCH 096/144] Move RequestCache --- .../java/nl/tudelft/ipv8/attestation/{wallet => }/RequestCache.kt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/{wallet => }/RequestCache.kt (100%) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/RequestCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/RequestCache.kt similarity index 100% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/RequestCache.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/RequestCache.kt From 49a7b4402bd2d18f37d51658ff68abd67075c1f1 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 5 May 2021 15:01:45 +0200 Subject: [PATCH 097/144] Update RequestCache references --- .../src/main/java/nl/tudelft/ipv8/attestation/RequestCache.kt | 4 +--- .../revocation/caches/PendingRevocationUpdateCache.kt | 2 +- .../nl/tudelft/ipv8/attestation/wallet/caches/HashCache.kt | 3 +-- .../nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt | 2 +- .../nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt | 2 +- .../ipv8/attestation/wallet/caches/PendingChallengesCache.kt | 2 +- 6 files changed, 6 insertions(+), 9 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/RequestCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/RequestCache.kt index bb91d26e..242211b0 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/RequestCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/RequestCache.kt @@ -1,4 +1,4 @@ -package nl.tudelft.ipv8.attestation.wallet +package nl.tudelft.ipv8.attestation import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async @@ -7,8 +7,6 @@ import mu.KotlinLogging import nl.tudelft.ipv8.attestation.wallet.caches.NumberCache import java.math.BigInteger -private val logger = KotlinLogging.logger {} - class RequestCache { private val logger = KotlinLogging.logger {} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt index 9eee5794..571276b8 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt @@ -1,6 +1,6 @@ package nl.tudelft.ipv8.attestation.revocation.caches -import nl.tudelft.ipv8.attestation.wallet.RequestCache +import nl.tudelft.ipv8.attestation.RequestCache import nl.tudelft.ipv8.attestation.wallet.caches.HashCache import nl.tudelft.ipv8.attestation.wallet.caches.NumberCache import nl.tudelft.ipv8.util.sha1 diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/HashCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/HashCache.kt index 0eac7d00..8a0c66d1 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/HashCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/HashCache.kt @@ -1,7 +1,6 @@ package nl.tudelft.ipv8.attestation.wallet.caches -import nl.tudelft.ipv8.attestation.wallet.RequestCache -import nl.tudelft.ipv8.messaging.deserializeUChar +import nl.tudelft.ipv8.attestation.RequestCache import java.math.BigInteger open class HashCache(requestCache: RequestCache, prefix: String, cacheHash: ByteArray, val idFormat: String) : diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt index d96a7ddb..0d626a6a 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt @@ -2,7 +2,7 @@ package nl.tudelft.ipv8.attestation.wallet.caches import kotlinx.coroutines.* import mu.KotlinLogging -import nl.tudelft.ipv8.attestation.wallet.RequestCache +import nl.tudelft.ipv8.attestation.RequestCache import java.math.BigInteger private val logger = KotlinLogging.logger {} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt index 83bb4d93..e21b4a61 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt @@ -1,6 +1,6 @@ package nl.tudelft.ipv8.attestation.wallet.caches -import nl.tudelft.ipv8.attestation.wallet.RequestCache +import nl.tudelft.ipv8.attestation.RequestCache import java.math.BigInteger open class PeerCache(cache: RequestCache, prefix: String, val mid: String, val idFormat: String) : diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PendingChallengesCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PendingChallengesCache.kt index 9d402c73..9c77a895 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PendingChallengesCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PendingChallengesCache.kt @@ -7,7 +7,7 @@ const val PENDING_CHALLENGES_PREFIX = "proving-hash" class PendingChallengesCache( community: AttestationCommunity, - val cacheHash: ByteArray, + cacheHash: ByteArray, val provingCache: ProvingAttestationCache, idFormat: String, val honestyCheck: Int = -1, From 4035af5ad59f1e4ec7a67733b8c1382b8cc18787 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 5 May 2021 15:11:44 +0200 Subject: [PATCH 098/144] Add method for selecting all revocations --- .../attestation/revocation/AuthoritySQLiteStore.kt | 4 ++-- .../ipv8/attestation/revocation/AuthorityStore.kt | 2 +- .../nl/tudelft/ipv8/sqldelight/DbAuthority.sq | 13 ++++++++----- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt index 0a6e9137..04cd159e 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt @@ -119,7 +119,7 @@ class AuthoritySQLiteStore(database: Database) : AuthorityStore { } } - override fun getAllRevocations(): List { - return dao.getAllRevocations().executeAsList() + override fun getAllRevocations(): List { + return dao.getRevocations().executeAsList() } } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt index 9d06b9e4..3db11245 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt @@ -34,5 +34,5 @@ interface AuthorityStore { fun getVersionsSince(publicKeyHash: ByteArray, sinceVersion: Long): List - fun getAllRevocations(): List + fun getAllRevocations(): List } diff --git a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq index b7c74e10..32d4a4ad 100644 --- a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq +++ b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq @@ -1,7 +1,7 @@ CREATE TABLE revocations ( authority_id INTEGER NOT NULL, version_id INTEGER NOT NULL, - attestation_hash BLOB NOT NULL, + revoked_hash BLOB NOT NULL, FOREIGN KEY(authority_id) REFERENCES authorities(authority_id), FOREIGN KEY(version_id) REFERENCES versions(version_id) ); @@ -23,7 +23,7 @@ CREATE TABLE authorities ( ); insertRevocation: -INSERT INTO revocations (authority_id, version_id, attestation_hash) VALUES (?, ?, ?); +INSERT INTO revocations (authority_id, version_id, revoked_hash) VALUES (?, ?, ?); insertVersion: INSERT INTO versions (authority_id, version_number, signature) VALUES (?, ?, ?); @@ -50,10 +50,10 @@ disregardAuthority: UPDATE authorities SET recognized = 0 WHERE public_key_hash = ?; getRevocationsByAuthorityId: -SELECT attestation_hash FROM revocations WHERE authority_id = ?; +SELECT revoked_hash FROM revocations WHERE authority_id = ?; getRevocationsByAuthorityIdAndVersionId: -SELECT attestation_hash FROM revocations WHERE authority_id = ? AND version_id = ?; +SELECT revoked_hash FROM revocations WHERE authority_id = ? AND version_id = ?; updateVersionFor: UPDATE authorities SET latest_version_id = ? WHERE public_key_hash = ?; @@ -68,4 +68,7 @@ getVersionsSince: SELECT version_number FROM versions WHERE authority_id = ? AND version_number > ?; getAllRevocations: -SELECT authorities.public_key_hash, versions.version_number, versions.signature, revocations.attestation_hash FROM authorities LEFT JOIN versions ON authorities.latest_version_id = versions.version_id LEFT JOIN revocations ON authorities.authority_id = revocations.authority_id; +SELECT authorities.public_key_hash, versions.version_number, versions.signature, revocations.revoked_hash FROM authorities LEFT JOIN versions ON authorities.latest_version_id = versions.version_id LEFT JOIN revocations ON authorities.authority_id = revocations.authority_id; + +getRevocations: +SELECT revoked_hash FROM revocations; \ No newline at end of file From 45839dffac27f28c2e54832a4b3330dc72af4f8a Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 5 May 2021 15:12:08 +0200 Subject: [PATCH 099/144] Add method for fetching all known identities --- .../attestation/identity/database/IdentitySQLiteStore.kt | 5 +++++ .../ipv8/attestation/identity/database/IdentityStore.kt | 9 +++++++-- .../sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq | 3 +++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt index 0f14940c..4f0975f0 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt @@ -97,4 +97,9 @@ class IdentitySQLiteStore(database: Database) : IdentityStore { return dao.getKnownIdentities().executeAsList() .map { defaultCryptoProvider.keyFromPublicBin(it) } } + + override fun getKnownSubjects(): List { + return dao.getKnownSubjects().executeAsList() + .map { defaultCryptoProvider.keyFromPublicBin(it) } + } } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentityStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentityStore.kt index afab814e..f821fce3 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentityStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentityStore.kt @@ -11,7 +11,12 @@ interface IdentityStore { fun insertToken(publicKey: PublicKey, token: Token) fun insertMetadata(publicKey: PublicKey, metadata: Metadata) - fun insertAttestation(publicKey: PublicKey, authorityKey: PublicKey, attestation: IdentityAttestation) + fun insertAttestation( + publicKey: PublicKey, + authorityKey: PublicKey, + attestation: IdentityAttestation + ) + fun getTokensFor(publicKey: PublicKey): List fun getMetadataFor(publicKey: PublicKey): List fun getAttestationsFor(publicKey: PublicKey): Set @@ -21,5 +26,5 @@ interface IdentityStore { fun getCredentialOver(metadata: Metadata): Credential fun getCredentialsFor(publicKey: PublicKey): List fun getKnownIdentities(): List - + fun getKnownSubjects(): List } diff --git a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq index e3b792e1..15141b77 100644 --- a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq +++ b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq @@ -52,3 +52,6 @@ SELECT authority_key FROM identity_attestations WHERE signature = ?; getKnownIdentities: SELECT public_key FROM tokens; + +getKnownSubjects: +SELECT DISTINCT public_key FROM metadata; \ No newline at end of file From 62ee19c5eadd129eae20ce805b579868e89ac16a Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 5 May 2021 15:13:43 +0200 Subject: [PATCH 100/144] Chec for revocations when verifying signatures --- .../nl/tudelft/ipv8/attestation/AuthorityManager.kt | 10 +++++++++- .../attestation/communication/CommunicationChannel.kt | 11 +++++++++-- .../attestation/revocation/RevocationCommunity.kt | 6 +++--- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt index e1925ccc..6f1b5753 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt @@ -1,4 +1,4 @@ - package nl.tudelft.ipv8.attestation +package nl.tudelft.ipv8.attestation import nl.tudelft.ipv8.attestation.revocation.AuthorityStore import nl.tudelft.ipv8.attestation.revocation.RevocationBlob @@ -34,6 +34,10 @@ class AuthorityManager(val authorityDatabase: AuthorityStore) { } } + fun verify(signature: ByteArray): Boolean { + return !getAllRevocations().any { it.contentEquals(signature) } + } + fun insertRevocations( publicKeyHash: ByteArray, versionNumber: Long, @@ -60,6 +64,10 @@ class AuthorityManager(val authorityDatabase: AuthorityStore) { return authorityDatabase.getRevocations(publicKeyHash, versions) } + fun getAllRevocations(): List { + return authorityDatabase.getAllRevocations() + } + fun loadDefaultAuthorities() { TODO("Preinstalled Authorities yet to be designed.") } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt index 6fd25e05..6f343cb7 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt @@ -308,16 +308,23 @@ class CommunicationChannel( } // Check if authority is recognized and the corresponding signature is correct. - if (!attestors.any { attestor -> + if (attestors.any { attestor -> val authority = this.attestationOverlay.authorityManager.getTrustedAuthority(attestor.first) authority?.let { it.publicKey?.verify(attestor.second, metadata.hash) - } == true + } == false }) { logger.info("Not accepting ${attestationHash.toHex()}, no recognized authority or valid signature found.") return false } + + // Check if any authority has not revoked a signature + if (!this.attestationOverlay.authorityManager.verify(metadata.hash)) { + logger.info("Not accepting ${attestationHash.toHex()}, signature was revoked.") + return false + } + return true } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt index 9e16351a..87701bcd 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt @@ -11,7 +11,7 @@ import nl.tudelft.ipv8.attestation.revocation.caches.PendingRevocationUpdateCach import nl.tudelft.ipv8.attestation.revocation.payloads.RevocationUpdateChunkPayload import nl.tudelft.ipv8.attestation.revocation.payloads.RevocationUpdatePreviewPayload import nl.tudelft.ipv8.attestation.revocation.payloads.RevocationUpdateRequestPayload -import nl.tudelft.ipv8.attestation.wallet.RequestCache +import nl.tudelft.ipv8.attestation.RequestCache import nl.tudelft.ipv8.attestation.wallet.caches.PeerCache import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.messaging.* @@ -250,9 +250,9 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() val authority = this.authorityManager.getAuthority(revocationBlob.publicKeyHash) if (authority?.publicKey != null) { - var signable = serializeULong(revocationBlob.version.toULong()) + var signable = revocationBlob.version.toByteArray() revocationBlob.revocations.forEach { signable += it } - if (!authority.publicKey.verify(revocationBlob.signature, signable)) { + if (!authority.publicKey.verify(revocationBlob.signature, sha3_256(signable))) { logger.warn("Peer ${peer.mid} might have altered the revoked signatures, skipping!") } } else { From eb1913035d08747659a0f6dea18db61673a75b4b Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 6 May 2021 15:05:06 +0200 Subject: [PATCH 101/144] Add tokentree tests --- .../ipv8/attestation/tokenTree/TokenTest.kt | 83 +++++++++ .../attestation/tokenTree/TokenTreeTest.kt | 175 ++++++++++++++++++ 2 files changed, 258 insertions(+) create mode 100644 ipv8/src/test/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTest.kt create mode 100644 ipv8/src/test/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTreeTest.kt diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTest.kt new file mode 100644 index 00000000..b35bf571 --- /dev/null +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTest.kt @@ -0,0 +1,83 @@ +package nl.tudelft.ipv8.attestation.tokenTree + +import nl.tudelft.ipv8.keyvault.PrivateKey +import nl.tudelft.ipv8.keyvault.PublicKey +import nl.tudelft.ipv8.keyvault.defaultCryptoProvider +import org.junit.Assert.assertArrayEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test + +class TokenTest { + + private lateinit var privateKey: PrivateKey + private lateinit var testPublicKey: PublicKey + private lateinit var testData: ByteArray + private lateinit var testDataHash: ByteArray + private lateinit var testSignature: ByteArray + + @Before + fun init() { + privateKey = defaultCryptoProvider.generateKey() + testData = "1234567890abcdefghijklmnopqrstuvwxyz".repeat(69).toByteArray() + + val sk = defaultCryptoProvider.generateKey() + testPublicKey = sk.pub() + + val token = Token("test_previous_token_hash".toByteArray(), content = testData, privateKey = sk) + testDataHash = token.contentHash + testSignature = token.signature + } + + @Test + fun testCreatePrivateToken() { + val token = + Token("test_previous_token_hash".toByteArray(), content = this.testData, privateKey = this.privateKey) + assertArrayEquals("test_previous_token_hash".toByteArray(), token.previousTokenHash) + assertArrayEquals(this.testData, token.content) + assertArrayEquals(this.testDataHash, token.contentHash) + assertTrue(token.verify(this.privateKey.pub())) + } + + @Test + fun testVerifyTokenIllegal() { + val token = + Token("test_previous_token_hash".toByteArray(), contentHash = this.testData, signature = this.testSignature) + val otherKey = defaultCryptoProvider.generateKey().pub() + assertFalse(token.verify(otherKey)) + } + + @Test + fun testUpdatePublicToken() { + val token = Token( + "test_previous_token_hash".toByteArray(), + contentHash = this.testDataHash, + signature = this.testSignature + ) + val returnValue = token.receiveContent(this.testData) + + assertTrue(returnValue) + assertArrayEquals("test_previous_token_hash".toByteArray(), token.previousTokenHash) + assertArrayEquals(this.testData, token.content) + assertArrayEquals(this.testDataHash, token.contentHash) + assertTrue(token.verify(this.testPublicKey)) + } + + @Test + fun testUpdatePublicTokenIllegal() { + val token = Token( + "test_previous_token_hash".toByteArray(), + contentHash = this.testDataHash, + signature = this.testSignature + ) + val returnValue = token.receiveContent("some other data".toByteArray()) + + assertFalse(returnValue) + assertArrayEquals("test_previous_token_hash".toByteArray(), token.previousTokenHash) + assertNull(token.content) + assertArrayEquals(this.testDataHash, token.contentHash) + assertTrue(token.verify(this.testPublicKey)) + } +} diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTreeTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTreeTest.kt new file mode 100644 index 00000000..f838be15 --- /dev/null +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTreeTest.kt @@ -0,0 +1,175 @@ +package nl.tudelft.ipv8.attestation.tokenTree + +import nl.tudelft.ipv8.keyvault.PrivateKey +import nl.tudelft.ipv8.keyvault.PublicKey +import nl.tudelft.ipv8.keyvault.defaultCryptoProvider +import nl.tudelft.ipv8.util.hexToBytes +import org.junit.Assert.assertArrayEquals +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test + +class TokenTreeTest { + + private lateinit var privateKey: PrivateKey + private lateinit var publicKey: PublicKey + + @Before + fun init() { + privateKey = defaultCryptoProvider.generateKey() + publicKey = privateKey.pub() + } + + @Test + fun testCreateOwnEmpty() { + val tree = TokenTree(privateKey = privateKey) + assertEquals(0, tree.elements.size) + assertEquals(0, tree.unchained.size) + assertEquals(0, tree.getMissing().size) + } + + @Test + fun testCreateOtherEmpty() { + val tree = TokenTree(publicKey = publicKey) + assertEquals(0, tree.elements.size) + assertEquals(0, tree.unchained.size) + assertEquals(0, tree.getMissing().size) + } + + @Test + fun testOwnAdd() { + val tree = TokenTree(privateKey = privateKey) + val content = "test content".toByteArray() + val token = tree.add(content) + + assertEquals(1, tree.elements.size) + assertEquals(0, tree.unchained.size) + assertEquals(0, tree.getMissing().size) + assertTrue(tree.verify(token)) + assertArrayEquals(content, token.content) + } + + @Test + fun testOtherAddInSequence() { + val tree = TokenTree(privateKey = privateKey) + val actualToken = Token(tree.genesisHash, content = "some data".toByteArray(), privateKey = privateKey) + val publicToken = Token.deserialize(actualToken.getPlaintextSigned(), this.publicKey) + val token = tree.gatherToken(publicToken)!! + + assertEquals(1, tree.elements.size) + assertEquals(0, tree.unchained.size) + assertEquals(0, tree.getMissing().size) + assertTrue(tree.verify(publicToken)) + assertNull(token.content) + } + + @Test + fun testOtherAddOutSequence() { + val tree = TokenTree(publicKey = publicKey) + val actualToken = + Token("ab".repeat(16).toByteArray(), content = "some data".toByteArray(), privateKey = privateKey) + val publicToken = Token.deserialize(actualToken.getPlaintextSigned(), this.publicKey) + val token = tree.gatherToken(publicToken) + + assertEquals(0, tree.elements.size) + assertEquals(1, tree.unchained.size) + assertArrayEquals(arrayOf("ab".repeat(16).toByteArray()), tree.getMissing().toTypedArray()) + assertFalse(tree.verify(publicToken)) + assertNull(token) + } + + @Test + fun testOtherAddOutSequenceOverflow() { + val tree = TokenTree(publicKey = publicKey) + tree.unchainedLimit = 1 + + val realToken1 = + Token("ab".repeat(16).toByteArray(), content = "some data".toByteArray(), privateKey = privateKey) + val realToken2 = + Token("cd".repeat(16).toByteArray(), content = "some other data".toByteArray(), privateKey = privateKey) + val publicToken1 = Token.deserialize(realToken1.getPlaintextSigned(), this.publicKey) + val publicToken2 = Token.deserialize(realToken2.getPlaintextSigned(), this.publicKey) + tree.gatherToken(publicToken1) + tree.gatherToken(publicToken2) + + assertEquals(0, tree.elements.size) + assertEquals(1, tree.unchained.size) + assertArrayEquals(arrayOf("cd".repeat(16).toByteArray()), tree.getMissing().toTypedArray()) + assertFalse(tree.verify(publicToken1)) + assertFalse(tree.verify(publicToken2)) + } + + @Test + fun testOtherAddDuplicate() { + val tree = TokenTree(publicKey = publicKey) + val actualToken = Token(tree.genesisHash, content = "some data".toByteArray(), privateKey = privateKey) + val publicToken = Token.deserialize(actualToken.getPlaintextSigned(), this.publicKey) + val token = tree.gatherToken(publicToken)!! + + assertEquals(1, tree.elements.size) + assertEquals(0, tree.unchained.size) + assertEquals(0, tree.getMissing().size) + assertTrue(tree.verify(publicToken)) + assertNull(token.content) + } + + @Test + fun testOtherAddDuplicateContent() { + val tree = TokenTree(publicKey = publicKey) + val actualToken = Token(tree.genesisHash, content = "some data".toByteArray(), privateKey = privateKey) + val publicToken = Token.deserialize(actualToken.getPlaintextSigned(), this.publicKey) + val token = tree.gatherToken(publicToken)!! + tree.gatherToken(actualToken) + + assertEquals(1, tree.elements.size) + assertEquals(0, tree.unchained.size) + assertEquals(0, tree.getMissing().size) + assertTrue(tree.verify(publicToken)) + assertTrue(tree.verify(token)) + assertArrayEquals("some data".toByteArray(), token.content) + } + + @Test + fun testSerializePublic() { + val tree = TokenTree(privateKey = privateKey) + tree.add("data1".toByteArray()) + tree.add("data2".toByteArray()) + tree.add("data3".toByteArray()) + + assertEquals(128 * 3, tree.serializePublic().size) + } + + @Test + fun testSerializePublicPartial() { + val tree = TokenTree(privateKey = privateKey) + val token1 = tree.add("data1".toByteArray()) + val token2 = tree.add("data2".toByteArray(), token1) + tree.add("data3".toByteArray(), token2) + + assertEquals(128 * 2, tree.serializePublic(token2).size) + } + + @Test + fun testDeserializePublic() { + val publicKey = + defaultCryptoProvider.keyFromPublicBin("4c69624e61434c504b3ae2db18b81ae520ca5819d5a65c45edb3536ef7cbd86254145a5e96b6ceecd0779d6c7ab811bdb49e1d161b5c49fc29063b4684a0e2d987cd1c91a3fbdedf6005".hexToBytes()) + val serializedTree = + "c0332fa9b25cf0ae4f2456e9d1c38d41b990faae81e9a6a3610032e96a86ce01f3ab3ec93cbecf2ae8280f0d782111ab3202dfa6eef6797203b886e215fc7b6e3ce8676f8b395bd1e729fe2b2be9865c9d6b9dd7350989d85bf91e1522bc75b21574790b662b5cdcceb5168622707a3ba87fb60db8f89df5e089e7499cf89204c0332fa9b25cf0ae4f2456e9d1c38d41b990faae81e9a6a3610032e96a86ce011feff33a31fe7bd710f738ec96e95a8a8551a2047abd46309b7b2594e606359529e3b4d6f18432c4ac3a73c845a7c33a7d17f476b059689be65fe38bd59c48f4f108e3e4c32ab26e0deadd4fee83f2ff6ca1251fd6b2e0bbdef6fb4f8253260bc0332fa9b25cf0ae4f2456e9d1c38d41b990faae81e9a6a3610032e96a86ce014c75b310b769b0a0c8521a40968af43daf62cec5ab1a65dc658093192020897c82a3baf38bece1d113783a4aefc04e4baf40c8af53d23451823706857830b177db6980c9251072916445bab2b8430d917287d5f5f61496f30bd27dc6ce79d309".hexToBytes() + + val tree = TokenTree(publicKey = publicKey) + tree.deserializePublic(serializedTree) + + assertEquals(3, tree.elements.size) + + for (token in tree.elements.values) { + assertTrue(tree.verify(token)) + } + + for (content in listOf("data1".toByteArray(), "data2".toByteArray(), "data3".toByteArray())) { + assertTrue(tree.elements.values.any { it.receiveContent(content) }) + } + } +} From f1aaa0c8f964314d2695907c3c4f7a3f4b7aa353 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 6 May 2021 15:05:17 +0200 Subject: [PATCH 102/144] Add IdentityManagerTests --- .../identity/manager/IdentityManagerTest.kt | 208 ++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 ipv8/src/test/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManagerTest.kt diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManagerTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManagerTest.kt new file mode 100644 index 00000000..ae5da162 --- /dev/null +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManagerTest.kt @@ -0,0 +1,208 @@ +package nl.tudelft.ipv8.attestation.identity.manager + +import com.squareup.sqldelight.db.SqlDriver +import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver +import nl.tudelft.ipv8.attestation.identity.database.Credential +import nl.tudelft.ipv8.attestation.identity.database.IdentitySQLiteStore +import nl.tudelft.ipv8.keyvault.defaultCryptoProvider +import nl.tudelft.ipv8.sqldelight.Database +import org.json.JSONObject +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test + +class IdentityManagerTest { + + private val privateKey = defaultCryptoProvider.generateKey() + private val publicKey = privateKey.pub() + private val authorityPrivateKey = defaultCryptoProvider.generateKey() + private val authorityPublicKey = authorityPrivateKey.pub() + private val manager: IdentityManager + + private var driver: SqlDriver + + init { + driver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY) + Database.Schema.create(driver) + val database = Database(driver) + val store = IdentitySQLiteStore(database) + this.manager = IdentityManager(store) + } + + private fun forgetIdentities() { + this.manager.pseudonyms.clear() + driver.close() + driver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY) + Database.Schema.create(driver) + val database = Database(driver) + this.manager.database = IdentitySQLiteStore(database) + } + + @Test + fun testCreateIdentity() { + val pseudonym = this.manager.getPseudonym(this.privateKey) + assertEquals(listOf(), pseudonym.getCredentials()) + } + + @Test + fun testSubstantiateEmpty() { + val (correct, pseudonym) = this.manager.substantiate( + this.publicKey, + byteArrayOf(), + byteArrayOf(), + byteArrayOf(), + byteArrayOf() + ) + + assertTrue(correct) + assertEquals(listOf(), pseudonym.getCredentials()) + } + + @Test + fun testCreateCredential() { + val pseudonym = this.manager.getPseudonym(this.privateKey) + pseudonym.createCredential("ab".repeat(16).toByteArray(), hashMapOf("some_key" to "some_value")) + assertEquals(1, pseudonym.getCredentials().size) + assertEquals(0, pseudonym.getCredentials()[0].attestations.size) + val expectedMD = JSONObject() + expectedMD.put("some_key", "some_value") + assertEquals(expectedMD.toString(), String(pseudonym.getCredentials()[0].metadata.serializedMetadata)) + } + + @Test + fun testSubstantiateCredentialUpdate() { + val pseudonym = this.manager.getPseudonym(this.privateKey) + pseudonym.createCredential("ab".repeat(16).toByteArray(), hashMapOf("some_key" to "some_value")) + val (metadata, tokens, attestations, authorities) = pseudonym.discloseCredentials( + pseudonym.getCredentials(), + setOf() + ) + this.manager.pseudonyms.clear() + val (correct, publicPseudonym) = this.manager.substantiate( + pseudonym.publicKey, + metadata, + tokens, + attestations, + authorities + ) + + assertTrue(correct) + assertEquals(1, publicPseudonym.getCredentials().size) + assertEquals(0, publicPseudonym.getCredentials()[0].attestations.size) + val expectedMD = JSONObject() + expectedMD.put("some_key", "some_value") + assertEquals(expectedMD.toString(), String(publicPseudonym.getCredentials()[0].metadata.serializedMetadata)) + } + + @Test + fun testSubstantiateCredentialWithoutMetadata() { + val pseudonym = this.manager.getPseudonym(this.privateKey) + pseudonym.createCredential("ab".repeat(16).toByteArray(), hashMapOf("some_key" to "some_value")) + val (_, tokens, attestations, authorities) = pseudonym.discloseCredentials( + pseudonym.getCredentials(), + setOf() + ) + this.forgetIdentities() + val (correct, publicPseudonym) = this.manager.substantiate( + pseudonym.publicKey, + byteArrayOf(), + tokens, + attestations, + authorities + ) + + assertTrue(correct) + assertEquals(0, publicPseudonym.getCredentials().size) + assertEquals(1, publicPseudonym.tree.elements.size) + } + + @Test + fun testSubstantiateCredentialWithMetadata() { + val pseudonym = this.manager.getPseudonym(this.privateKey) + pseudonym.createCredential("ab".repeat(16).toByteArray(), hashMapOf("some_key" to "some_value")) + val (metadata, tokens, attestations, authorities) = pseudonym.discloseCredentials( + pseudonym.getCredentials(), + setOf() + ) + this.forgetIdentities() + val (correct, publicPseudonym) = this.manager.substantiate( + pseudonym.publicKey, + metadata, + tokens, + attestations, + authorities + ) + + assertTrue(correct) + assertEquals(1, publicPseudonym.getCredentials().size) + assertEquals(0, publicPseudonym.getCredentials()[0].attestations.size) + val expectedMD = JSONObject() + expectedMD.put("some_key", "some_value") + assertEquals(expectedMD.toString(), String(publicPseudonym.getCredentials()[0].metadata.serializedMetadata)) + } + + @Test + fun testSubstantiateCredentialFull() { + val pseudonym = this.manager.getPseudonym(this.privateKey) + pseudonym.createCredential("ab".repeat(16).toByteArray(), hashMapOf("some_key" to "some_value")) + + val attestation = pseudonym.createAttestation(pseudonym.getCredentials()[0].metadata, this.authorityPrivateKey) + pseudonym.addAttestation(this.authorityPublicKey, attestation) + + val (metadata, tokens, attestations, authorities) = pseudonym.discloseCredentials( + pseudonym.getCredentials(), + setOf(attestation.hash) + ) + this.forgetIdentities() + + val (correct, publicPseudonym) = this.manager.substantiate( + pseudonym.publicKey, + metadata, + tokens, + attestations, + authorities + ) + + assertTrue(correct) + assertEquals(1, publicPseudonym.getCredentials().size) + assertEquals(1, publicPseudonym.getCredentials()[0].attestations.size) + val expectedMD = JSONObject() + expectedMD.put("some_key", "some_value") + assertEquals(expectedMD.toString(), String(publicPseudonym.getCredentials()[0].metadata.serializedMetadata)) + } + + @Test + fun testSubstantiateCredentialPartial() { + val pseudonym = this.manager.getPseudonym(this.privateKey) + pseudonym.createCredential("ab".repeat(16).toByteArray(), hashMapOf("some_key" to "some_value")) + + val attestation = pseudonym.createAttestation(pseudonym.getCredentials()[0].metadata, this.authorityPrivateKey) + pseudonym.addAttestation(this.authorityPublicKey, attestation) + + val attestation2 = pseudonym.createAttestation(pseudonym.getCredentials()[0].metadata, this.privateKey) + pseudonym.addAttestation(this.publicKey, attestation2) + + val (metadata, tokens, attestations, authorities) = pseudonym.discloseCredentials( + pseudonym.getCredentials(), + setOf(attestation.hash) + ) + this.forgetIdentities() + + val (correct, publicPseudonym) = this.manager.substantiate( + pseudonym.publicKey, + metadata, + tokens, + attestations, + authorities + ) + + assertTrue(correct) + assertEquals(1, publicPseudonym.getCredentials().size) + assertEquals(1, publicPseudonym.getCredentials()[0].attestations.size) + val expectedMD = JSONObject() + expectedMD.put("some_key", "some_value") + assertEquals(expectedMD.toString(), String(publicPseudonym.getCredentials()[0].metadata.serializedMetadata)) + } +} + + From 6b09bad01d46c9f69d49f38b62c205dd617b6519 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 6 May 2021 21:10:17 +0200 Subject: [PATCH 103/144] Use correct hash in receive content method --- .../main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt index 6182716a..31184604 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt @@ -36,8 +36,8 @@ class Token( } fun receiveContent(content: ByteArray): Boolean { - contentHash = sha3_256(content) - if (this.contentHash.contentEquals(contentHash)) { + val contentHash = sha3_256(content) + if (contentHash.contentEquals(this.contentHash)) { this.content = content return true } From fa9bdb3dbfe5115cd87014361baef332d6917b5b Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 6 May 2021 21:10:42 +0200 Subject: [PATCH 104/144] Remove last unchained token instead of first --- .../nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt index c2c0d3d4..da500937 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt @@ -14,8 +14,10 @@ private val logger = KotlinLogging.logger {} class TokenTree(publicKey: PublicKey? = null, privateKey: PrivateKey? = null) { + var unchainedLimit = UNCHAINED_MAX_SIZE + val elements = hashMapOf() - val unchained = mutableMapOf() + val unchained = linkedMapOf() var publicKey: PublicKey var privateKey: PrivateKey? @@ -56,8 +58,8 @@ class TokenTree(publicKey: PublicKey? = null, privateKey: PrivateKey? = null) { token.previousTokenHash)) ) { this.unchained[token] = null - if (this.unchained.size > UNCHAINED_MAX_SIZE) { - this.unchained.remove(this.unchained.keys.last()) + if (this.unchained.size > unchainedLimit) { + this.unchained.remove(this.unchained.keys.first()) } logger.info("Delaying unchained token $token!") return null From 5b33ea4adfb6d309f1c2540237ff3a1d5380bb00 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 6 May 2021 21:11:15 +0200 Subject: [PATCH 105/144] Deserialize authorities correctly --- .../ipv8/attestation/identity/manager/IdentityManager.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt index 1f3afcd6..fbeda0a9 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt @@ -14,7 +14,7 @@ import nl.tudelft.ipv8.messaging.deserializeUShort import nl.tudelft.ipv8.util.ByteArrayKey import nl.tudelft.ipv8.util.toKey -class IdentityManager(internal val database: IdentityStore) { +class IdentityManager(internal var database: IdentityStore) { val pseudonyms = hashMapOf() @@ -57,7 +57,7 @@ class IdentityManager(internal val database: IdentityStore) { var attestationOffset = 0 var authorityOffset = 0 - while (authorityOffset < serializedAttestations.size) { + while (authorityOffset < serializedAuthorities.size) { val authoritySize = deserializeUShort(serializedAuthorities, authorityOffset) authorityOffset += SERIALIZED_USHORT_SIZE val authority = defaultCryptoProvider.keyFromPublicBin( From f61813baaef27efb89836d253461455050a68bc1 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 7 May 2021 10:58:39 +0200 Subject: [PATCH 106/144] Update RequestCache import in AttestationCommunity --- .../nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt index dc064293..0ec5145f 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt @@ -11,6 +11,7 @@ import nl.tudelft.ipv8.Peer import nl.tudelft.ipv8.attestation.WalletAttestation import nl.tudelft.ipv8.attestation.IdentityAlgorithm import nl.tudelft.ipv8.attestation.AuthorityManager +import nl.tudelft.ipv8.attestation.RequestCache import nl.tudelft.ipv8.attestation.schema.* import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity.MessageId.ATTESTATION import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity.MessageId.ATTESTATION_REQUEST From eea95a2b84e6fec9910551c9f3f892ab06ac554a Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 7 May 2021 10:59:38 +0200 Subject: [PATCH 107/144] Add AttestationPresentation logic --- .../communication/CommunicationChannel.kt | 274 ++++++++++++------ .../caches/DisclosureRequestCache.kt | 29 ++ .../communication/caches/TokenRequestCache.kt | 19 ++ .../attestation/identity/IdentityCommunity.kt | 215 +++++++++++--- .../identity/payloads/DisclosePayload.kt | 19 +- .../payloads/MissingResponsePayload.kt | 8 +- .../payloads/RequestMissingPayload.kt | 8 +- 7 files changed, 424 insertions(+), 148 deletions(-) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/caches/DisclosureRequestCache.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/caches/TokenRequestCache.kt diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt index 6f343cb7..d63b5da5 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt @@ -12,6 +12,8 @@ import nl.tudelft.ipv8.attestation.WalletAttestation import nl.tudelft.ipv8.attestation.identity.IdentityCommunity import nl.tudelft.ipv8.attestation.identity.Metadata import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity +import nl.tudelft.ipv8.attestation.communication.caches.DisclosureRequestCache +import nl.tudelft.ipv8.attestation.identity.IdentityAttestation import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.keyvault.defaultCryptoProvider @@ -25,6 +27,7 @@ import nl.tudelft.ipv8.util.toByteArray import nl.tudelft.ipv8.util.toHex import nl.tudelft.ipv8.util.toKey import org.json.JSONObject +import java.util.UUID const val DEFAULT_TIME_OUT = 30_000L private val logger = KotlinLogging.logger {} @@ -33,7 +36,6 @@ class CommunicationChannel( val attestationOverlay: AttestationCommunity, val identityOverlay: IdentityCommunity ) { - val attestationRequests = hashMapOf, String, String?>>() val verifyRequests = hashMapOf>() @@ -44,6 +46,7 @@ class CommunicationChannel( this.attestationOverlay.setAttestationRequestCallback(this::onRequestAttestationAsync) this.attestationOverlay.setAttestationRequestCompleteCallback(this::onAttestationComplete) this.attestationOverlay.setVerifyRequestCallback(this::onVerifyRequestAsync) + this.identityOverlay.setAttestationPresentationCallback(this::onAttestationPresentationComplete) } val publicKeyBin @@ -58,6 +61,9 @@ class CommunicationChannel( val schemas get() = this.attestationOverlay.schemaManager.getSchemaNames() + val authorityManager + get() = this.attestationOverlay.authorityManager + private fun onRequestAttestationAsync( peer: Peer, attributeName: String, @@ -97,7 +103,7 @@ class CommunicationChannel( ) } else { @Suppress("UNCHECKED_CAST") - this.identityOverlay.requestAttestationAdvertisement( + this.identityOverlay.advertiseAttestation( fromPeer!!, attributeHash, attributeName, idFormat, metadata as HashMap? ) @@ -135,6 +141,20 @@ class CommunicationChannel( } } + @Suppress("UNUSED_PARAMETER") + private fun onAttestationPresentationComplete( + peer: Peer, + attributeHash: ByteArray, + value: ByteArray, + metadata: Metadata, + attestations: List + ) { + logger.info("Received correct attestation presentation with hash ${attributeHash.toHex()}.") + val parsedMD = JSONObject(metadata.serializedMetadata) + val idFormat = parsedMD.getString("schema") + this.verify(peer, attributeHash, listOf(value), idFormat) + } + private fun dropIdentityTableData() { TODO("") } @@ -147,79 +167,6 @@ class CommunicationChannel( TODO("") } - fun getOfflineVerifiableAttributes(): List { - val out = mutableListOf() - val peer = this.myPeer - val pseudonym = this.identityOverlay.identityManager.getPseudonym(peer.publicKey) - - for (credential in pseudonym.getCredentials()) { - val attestations = credential.attestations.toList() - - val attestors = mutableListOf>() - - for (attestation in attestations) { - val attestor = defaultCryptoProvider.keyFromPublicBin( - this.identityOverlay.identityManager.database.getAuthority( - attestation - ) - ).keyToHash() - attestors += Pair(attestor, attestation.signature) - } - - val attributeHash = - pseudonym.tree.elements[credential.metadata.tokenPointer.toKey()]!!.contentHash - val jsonMetadata = JSONObject(String(credential.metadata.serializedMetadata)) - - val attributeName = jsonMetadata.getString("name") - val attributeValue = - this.attestationOverlay.database.getValueByHash( - stripSHA1Padding(attributeHash) - )!! - val idFormat = jsonMetadata.getString("schema") - val signDate = jsonMetadata.getDouble("date").toFloat() - out += AttestationPresentation( - attributeHash, - attributeName, - attributeValue, - idFormat, - signDate, - credential.metadata, - attestors - ) - } - return out.sortedBy { it.attributeName } - } - - fun getAttestationsSignedBy(peer: Peer) { - this.identityOverlay.identityManager.database.getAttestationsBy(peer.publicKey) - } - - @Deprecated("This should not be used.") - fun getAttributes(peer: Peer): HashMap, List>> { - val pseudonym = this.identityOverlay.identityManager.getPseudonym(peer.publicKey) - val out: HashMap, List>> = - hashMapOf() - - for (credential in pseudonym.getCredentials()) { - val attestations = credential.attestations.toList() - val attestors = mutableListOf() - - for (attestation in attestations) { - attestors += this.identityOverlay.identityManager.database.getAuthority(attestation) - } - val attributeHash = - pseudonym.tree.elements[credential.metadata.tokenPointer.toKey()]!!.contentHash - val jsonMetadata = JSONObject(String(credential.metadata.serializedMetadata)) - out[attributeHash.toKey()] = - Triple( - jsonMetadata.getString("name"), - jsonMetadata.asMap() as HashMap, - attestors - ) - } - return out - } - fun requestAttestation( peer: Peer, attributeName: String, @@ -259,6 +206,20 @@ class CommunicationChannel( GlobalScope.launch { outstanding.setResult(false) } } + fun generateDisclosureRequest( + attributeName: String + ): String { + val id = UUID.randomUUID().toString() + this.identityOverlay.requestCache.add( + DisclosureRequestCache( + this.identityOverlay.requestCache, + id, + DisclosureRequest(attributeName), + ) + ) + return id + } + fun verify( peer: Peer, attestationHash: ByteArray, @@ -275,6 +236,19 @@ class CommunicationChannel( ) } + fun revoke(signature: ByteArray) { + return revoke(listOf(signature)) + } + + fun revoke(signatures: List) { + val keyHash = myPeer.publicKey.keyToHash() + val latestVersion = authorityManager.getAuthority(keyHash)?.version?.plus(1) ?: 1L + var signableData = latestVersion.toByteArray() + signatures.forEach { signableData += it } + val versionSignature = (myPeer.key as PrivateKey).sign(sha3_256(signableData)) + authorityManager.insertRevocations(myPeer.publicKey.keyToHash(), latestVersion, versionSignature, signatures) + } + fun verifyLocally( attestationHash: ByteArray, proposedAttestationValue: ByteArray, @@ -332,9 +306,123 @@ class CommunicationChannel( val timestamp = System.currentTimeMillis() return Pair(timestamp, (this.myPeer.key as PrivateKey).sign(timestamp.toByteArray())) } + + fun getOfflineVerifiableAttributes(publicKey: PublicKey = this.myPeer.publicKey): List { + val out = mutableListOf() + val pseudonym = this.identityOverlay.identityManager.getPseudonym(publicKey) + + for (credential in pseudonym.getCredentials()) { + val attestations = credential.attestations.toList() + + val attestors = mutableListOf>() + + for (attestation in attestations) { + val attestor = defaultCryptoProvider.keyFromPublicBin( + this.identityOverlay.identityManager.database.getAuthority( + attestation + ) + ).keyToHash() + attestors += Pair(attestor, attestation.signature) + } + + val attributeHash = + pseudonym.tree.elements[credential.metadata.tokenPointer.toKey()]!!.contentHash + val jsonMetadata = JSONObject(String(credential.metadata.serializedMetadata)) + + val attributeName = jsonMetadata.getString("name") + val attributeValue = + this.attestationOverlay.database.getValueByHash( + stripSHA1Padding(attributeHash) + )!! + val idFormat = jsonMetadata.getString("schema") + val signDate = jsonMetadata.getDouble("date").toFloat() + out += AttestationPresentation( + publicKey, + attributeHash, + attributeName, + attributeValue, + idFormat, + signDate, + credential.metadata, + attestors + ) + } + return out.sortedBy { it.attributeName } + } + + fun getAttributesSignedBy(peer: Peer): List { + val db = this.identityOverlay.identityManager.database + // Exclude own public key + val subjects = db.getKnownSubjects() - peer.publicKey + val out = mutableListOf() + for (subject in subjects) { + val mdList = db.getMetadataFor(subject) + for (metadata in mdList) { + val md = JSONObject(String(metadata.serializedMetadata)) + out.add( + SubjectAttestationPresentation( + subject, + metadata.hash, + metadata, + md.getString("name"), + md.getDouble("date").toFloat() + ) + ) + } + } + return out.sortedBy { it.publicKey.keyToHash().toHex() } + } + + @Deprecated("This should not be used.") + fun getAttributes(peer: Peer): HashMap, List>> { + val pseudonym = this.identityOverlay.identityManager.getPseudonym(peer.publicKey) + val out: HashMap, List>> = + hashMapOf() + + for (credential in pseudonym.getCredentials()) { + val attestations = credential.attestations.toList() + val attestors = mutableListOf() + + for (attestation in attestations) { + attestors += this.identityOverlay.identityManager.database.getAuthority(attestation) + } + val attributeHash = + pseudonym.tree.elements[credential.metadata.tokenPointer.toKey()]!!.contentHash + val jsonMetadata = JSONObject(String(credential.metadata.serializedMetadata)) + out[attributeHash.toKey()] = + Triple( + jsonMetadata.getString("name"), + jsonMetadata.asMap() as HashMap, + attestors + ) + } + return out + } +} + +class SubjectAttestationPresentation( + val publicKey: PublicKey, + val metadataHash: ByteArray, + val metadata: Metadata, + val attributeName: String, + val signDate: Float, +) { + override fun equals(other: Any?): Boolean { + return other is SubjectAttestationPresentation && this.publicKey == other.publicKey && this.metadata == other.metadata + } + + override fun hashCode(): Int { + var result = publicKey.hashCode() + result = 31 * result + metadataHash.contentHashCode() + result = 31 * result + metadata.hashCode() + result = 31 * result + attributeName.hashCode() + result = 31 * result + signDate.hashCode() + return result + } } class AttestationPresentation( + val publicKey: PublicKey, val attributeHash: ByteArray, val attributeName: String, val attributeValue: ByteArray, @@ -344,24 +432,24 @@ class AttestationPresentation( val attestors: List> ) { override fun equals(other: Any?): Boolean { - return other is AttestationPresentation && this.attributeHash.contentEquals(other.attributeHash) && this.attestors.size == other.attestors.size + return other is AttestationPresentation && this.publicKey == other.publicKey && this.attributeHash.contentEquals( + other.attributeHash + ) && this.attestors.size == other.attestors.size + } + + override fun hashCode(): Int { + var result = publicKey.hashCode() + result = 31 * result + attributeHash.contentHashCode() + result = 31 * result + attributeName.hashCode() + result = 31 * result + attributeValue.contentHashCode() + result = 31 * result + idFormat.hashCode() + result = 31 * result + signDate.hashCode() + result = 31 * result + metadata.hashCode() + result = 31 * result + attestors.hashCode() + return result } } -// class PrivateAttestationBlob( -// val attributeName: String, -// val attributeHash: ByteArray, -// val metadataString: String, -// val idFormat: String, -// val attributeValue: String, -// val signature: ByteArray, -// val attestorKeys: List -// ) { -// override fun equals(other: Any?): Boolean { -// return other is PrivateAttestationBlob && this.attributeName == other.attributeName && this.attributeHash.contentEquals( -// other.attributeHash -// ) && this.metadataString == other.metadataString && this.idFormat == other.idFormat && this.attributeValue == other.attributeValue && this.signature.contentEquals( -// other.signature -// ) && this.attestorKeys == other.attestorKeys -// } -// } +class DisclosureRequest( + val attributeName: String +) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/caches/DisclosureRequestCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/caches/DisclosureRequestCache.kt new file mode 100644 index 00000000..44ccb41a --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/caches/DisclosureRequestCache.kt @@ -0,0 +1,29 @@ +package nl.tudelft.ipv8.attestation.communication.caches + +import nl.tudelft.ipv8.attestation.RequestCache +import nl.tudelft.ipv8.attestation.communication.DisclosureRequest +import nl.tudelft.ipv8.attestation.wallet.caches.DEFAULT_TIMEOUT +import nl.tudelft.ipv8.attestation.wallet.caches.HashCache +import nl.tudelft.ipv8.attestation.wallet.caches.NumberCache +import java.math.BigInteger + +const val DISCLOSURE_REQUEST_PREFIX = "disclosure-request" + +class DisclosureRequestCache( + requestCache: RequestCache, + id: String, + val disclosureRequest: DisclosureRequest, + timeout: Int = DEFAULT_TIMEOUT +) : NumberCache( + requestCache, DISCLOSURE_REQUEST_PREFIX, + idFromUUID(id).second, timeout +) { + + + + companion object { + fun idFromUUID(id: String): Pair { + return HashCache.idFromHash(DISCLOSURE_REQUEST_PREFIX, id.toByteArray()) + } + } +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/caches/TokenRequestCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/caches/TokenRequestCache.kt new file mode 100644 index 00000000..539a90ed --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/caches/TokenRequestCache.kt @@ -0,0 +1,19 @@ +package nl.tudelft.ipv8.attestation.communication.caches + +import nl.tudelft.ipv8.attestation.RequestCache +import nl.tudelft.ipv8.attestation.wallet.caches.HashCache +import nl.tudelft.ipv8.attestation.wallet.caches.NumberCache +import java.math.BigInteger + +const val TOKEN_REQUEST_CACHE = "token-request" + +// TODO: add second parameter for uniqueness. +class TokenRequestCache(cache: RequestCache, mid: String, val requestedAttributeName: String, val disclosureInformation: String) : + NumberCache(cache, TOKEN_REQUEST_CACHE, generateId(mid).second) { + + companion object { + fun generateId(mid: String): Pair { + return HashCache.idFromHash(TOKEN_REQUEST_CACHE, mid.toByteArray()) + } + } +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index bf9108b8..b282cc2b 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -2,6 +2,9 @@ package nl.tudelft.ipv8.attestation.identity import mu.KotlinLogging import nl.tudelft.ipv8.* +import nl.tudelft.ipv8.attestation.RequestCache +import nl.tudelft.ipv8.attestation.communication.caches.DisclosureRequestCache +import nl.tudelft.ipv8.attestation.communication.caches.TokenRequestCache import nl.tudelft.ipv8.attestation.identity.database.Credential import nl.tudelft.ipv8.attestation.identity.database.IdentityStore import nl.tudelft.ipv8.attestation.identity.manager.Disclosure @@ -20,6 +23,7 @@ import nl.tudelft.ipv8.peerdiscovery.Network import nl.tudelft.ipv8.peerdiscovery.strategy.RandomWalk import nl.tudelft.ipv8.util.ByteArrayKey import nl.tudelft.ipv8.util.asMap +import nl.tudelft.ipv8.util.hexToBytes import nl.tudelft.ipv8.util.padSHA1Hash import nl.tudelft.ipv8.util.toHex import nl.tudelft.ipv8.util.toKey @@ -56,6 +60,10 @@ class IdentityCommunity( ) : Community() { var identityManager: IdentityManager = identityManager ?: IdentityManager(database) + val requestCache = RequestCache() + + private lateinit var attestationPresentationCallback: (peer: Peer, attributeHash: ByteArray, value: ByteArray, metadata: Metadata, attestations: List) -> Unit + private val knownAttestationHashes = hashMapOf() private val pseudonymManager = this.identityManager.getPseudonym(this.myPeer.key) @@ -90,9 +98,13 @@ class IdentityCommunity( messageHandlers[MISSING_RESPONSE_PAYLOAD] = ::onMissingResponseWrapper } + fun setAttestationPresentationCallback(f: (peer: Peer, attributeHash: ByteArray, value: ByteArray, metadata: Metadata, attestations: List) -> Unit) { + this.attestationPresentationCallback = f + } + private fun onDisclosureWrapper(packet: Packet) { val (peer, payload) = packet.getAuthPayload(DisclosePayload.Deserializer) - logger.info("Received Disclose payload from ${peer.mid}.") + logger.info(" Disclose payload from ${peer.mid}.") this.onDisclosure(peer, payload) } @@ -209,60 +221,127 @@ class IdentityCommunity( } private fun receivedDisclosureForAttest(peer: Peer, disclosure: Disclosure) { - val solicited = this.knownAttestationHashes.values.any { it.publicKey == peer.publicKey } - if (solicited) { - val (correct, pseudonym) = this.identityManager.substantiate( - peer.publicKey, - disclosure.metadata, - disclosure.tokens, - disclosure.attestations, - disclosure.authorities - ) - val requiredAttributes = - this.knownAttestationHashes.filter { it.value.publicKey == peer.publicKey }.keys.toTypedArray() - val knownAttributes: List = - pseudonym.tree.elements.values.map { ByteArrayKey(it.contentHash) } - - if (correct && requiredAttributes.any { knownAttributes.contains(it) }) { - for (credential in pseudonym.getCredentials()) { - if (shouldSign(pseudonym, credential.metadata)) { - logger.info("Attesting to ${credential.metadata}.") - val myPrivateKey = this.myPeer.key as PrivateKey - val attestation = pseudonym.createAttestation( - credential.metadata, - myPrivateKey - ) - pseudonym.addAttestation(this.myPeer.publicKey, attestation) - val payload = AttestPayload(attestation.getPlaintextSigned()) - this.endpoint.send(peer, serializePacket(ATTEST_PAYLOAD, payload)) - } + val (correct, pseudonym) = this.identityManager.substantiate( + peer.publicKey, + disclosure.metadata, + disclosure.tokens, + disclosure.attestations, + disclosure.authorities + ) + val requiredAttributes = + this.knownAttestationHashes.filter { it.value.publicKey == peer.publicKey }.keys.toTypedArray() + val knownAttributes: List = + pseudonym.tree.elements.values.map { ByteArrayKey(it.contentHash) } + + if (correct && requiredAttributes.any { knownAttributes.contains(it) }) { + for (credential in pseudonym.getCredentials()) { + if (shouldSign(pseudonym, credential.metadata)) { + logger.info("Attesting to ${credential.metadata}.") + val myPrivateKey = this.myPeer.key as PrivateKey + val attestation = pseudonym.createAttestation( + credential.metadata, + myPrivateKey + ) + pseudonym.addAttestation(this.myPeer.publicKey, attestation) + val payload = AttestPayload(attestation.getPlaintextSigned()) + this.endpoint.send(peer, serializePacket(ATTEST_PAYLOAD, payload)) } } + } + + for (attributeHash in requiredAttributes) { + if (!knownAttributes.contains(attributeHash)) { + logger.info("Missing information for attestation ${attributeHash.bytes.toHex()}, requesting more.") + val payload = RequestMissingPayload(pseudonym.tree.elements.size) + this.endpoint.send(peer, serializePacket(REQUEST_MISSING_PAYLOAD, payload)) + } + } + } + + // TODO: remove parameters from disclosureInformation. + private fun receivedDisclosureForPresentation( + peer: Peer, + disclosure: Disclosure, + attributeName: String, + disclosureInformation: String + ) { + val (correct, pseudonym) = this.identityManager.substantiate( + peer.publicKey, + disclosure.metadata, + disclosure.tokens, + disclosure.attestations, + disclosure.authorities + ) - for (attributeHash in requiredAttributes) { - if (!knownAttributes.contains(attributeHash)) { - logger.info("Missing information for attestation ${attributeHash.bytes.toHex()}, requesting more.") - val payload = RequestMissingPayload(pseudonym.tree.elements.size) - this.endpoint.send(peer, serializePacket(REQUEST_MISSING_PAYLOAD, payload)) + val disclosureJSON = JSONObject(disclosureInformation) + val requiredAttributes = listOf(disclosureJSON.getString("attributeHash").hexToBytes().toKey()) + val knownAttributes: List = + pseudonym.tree.elements.values.map { ByteArrayKey(it.contentHash) } + + if (correct && requiredAttributes.any { knownAttributes.contains(it) }) { + for (credential in pseudonym.getCredentials()) { + if (shouldSign(pseudonym, credential.metadata)) { + val presentedAttributeName = + JSONObject(String(credential.metadata.serializedMetadata)).getString("name") + if (presentedAttributeName != attributeName) { + logger.warn("Client sent wrong attestation. Requested: $attributeName, received: $presentedAttributeName") + return + } + logger.info("Received valid attestation presentation ${String(credential.metadata.serializedMetadata)}") + val value = disclosureJSON.getString("value").hexToBytes() + this.attestationPresentationCallback( + peer, requiredAttributes[0].bytes, value, credential.metadata, + credential.attestations.toList() + ) } } - } else { - logger.warn("Received unsolicited disclosure from $peer, dropping.") + } + + for (attributeHash in requiredAttributes) { + if (!knownAttributes.contains(attributeHash)) { + logger.info("Missing information for attestation ${attributeHash.bytes.toHex()}, requesting more.") + // TODO: add second parameter for uniqueness. + requestCache.add(TokenRequestCache(requestCache, peer.mid, attributeName, disclosureInformation)) + val payload = RequestMissingPayload(pseudonym.tree.elements.size) + this.endpoint.send(peer, serializePacket(REQUEST_MISSING_PAYLOAD, payload)) + } } } - fun requestAttestationAdvertisement( + fun presentAttestationAdvertisement( + peer: Peer, + requestId: String, + attributeHash: ByteArray, + attributeName: String, + attributeValue: ByteArray, + blockType: String = ID_METADATA, + metadata: HashMap? + ) { + val credential = this.selfAdvertise(attributeHash, attributeName, blockType, metadata) + this.permissions[peer] = this.tokenChain.size + val disclosure = this.pseudonymManager.discloseCredentials(listOf(credential), setOf()) + val (metadataObj, tokens, attestations, authorities) = this.fitDisclosure(disclosure) + val presentationMetadata = JSONObject() + presentationMetadata.put("id", requestId) + presentationMetadata.put("attestationHash", attributeHash) + presentationMetadata.put("value", attributeValue) + val payload = DisclosePayload(metadataObj, tokens, attestations, authorities, presentationMetadata.toString()) + this.endpoint.send(peer, serializePacket(DISCLOSURE_PAYLOAD, payload)) + } + + fun advertiseAttestation( peer: Peer, attributeHash: ByteArray, name: String, blockType: String = ID_METADATA, metadata: HashMap?, + advertisementInformation: String? = null, ) { val credential = this.selfAdvertise(attributeHash, name, blockType, metadata) this.permissions[peer] = this.tokenChain.size val disclosure = this.pseudonymManager.discloseCredentials(listOf(credential), setOf()) val (metadataObj, tokens, attestations, authorities) = this.fitDisclosure(disclosure) - val payload = DisclosePayload(metadataObj, tokens, attestations, authorities) + val payload = DisclosePayload(metadataObj, tokens, attestations, authorities, advertisementInformation) this.endpoint.send(peer, serializePacket(DISCLOSURE_PAYLOAD, payload)) } @@ -298,10 +377,33 @@ class IdentityCommunity( } private fun onDisclosure(peer: Peer, payload: DisclosePayload) { - this.receivedDisclosureForAttest( - peer, - Disclosure(payload.metadata, payload.tokens, payload.attestations, payload.authorities) - ) + val isAttestationRequest = this.knownAttestationHashes.values.any { it.publicKey == peer.publicKey } + val disclosureMD = JSONObject(payload.advertisementInformation ?: "{}") + val id = disclosureMD.optString("id") + val idPair = DisclosureRequestCache.idFromUUID(id) + val isAttestationPresentation = this.requestCache.has(idPair) + + when { + // Presentation takes precedence, as id should not be set otherwise. + isAttestationPresentation -> { + val cache = this.requestCache.pop(idPair)!! as DisclosureRequestCache + this.receivedDisclosureForPresentation( + peer, + Disclosure(payload.metadata, payload.tokens, payload.attestations, payload.authorities), + cache.disclosureRequest.attributeName, + payload.advertisementInformation!! + ) + } + isAttestationRequest -> { + this.receivedDisclosureForAttest( + peer, + Disclosure(payload.metadata, payload.tokens, payload.attestations, payload.authorities) + ) + } + else -> { + logger.warn("Received unsolicited disclosure from $peer, dropping.") + } + } } private fun onAttest(peer: Peer, payload: AttestPayload) { @@ -325,15 +427,38 @@ class IdentityCommunity( out += serialized } } + val responsePayload = MissingResponsePayload(out) this.endpoint.send(peer, serializePacket(MISSING_RESPONSE_PAYLOAD, responsePayload)) } private fun onMissingResponse(peer: Peer, payload: MissingResponsePayload) { - this.receivedDisclosureForAttest( - peer, - Disclosure(byteArrayOf(), payload.tokens, byteArrayOf(), byteArrayOf()) - ) + val solicitedAttestationRequest = this.knownAttestationHashes.values.any { it.publicKey == peer.publicKey } + val idPair = TokenRequestCache.generateId(peer.mid) + val solicitedAttestationPresentation = this.requestCache.has(idPair) + + when { + solicitedAttestationPresentation -> { + val cache = (this.requestCache.get(idPair)!! as TokenRequestCache) + val disclosureMD = JSONObject(cache.disclosureInformation) + this.receivedDisclosureForPresentation( + peer, + Disclosure(byteArrayOf(), payload.tokens, byteArrayOf(), byteArrayOf()), + cache.requestedAttributeName, + cache.disclosureInformation + ) + } + solicitedAttestationRequest -> { + this.receivedDisclosureForAttest( + peer, + Disclosure(byteArrayOf(), payload.tokens, byteArrayOf(), byteArrayOf()) + ) + } + + else -> { + logger.warn("Received unsolicited disclosure from $peer, dropping.") + } + } } override fun equals(other: Any?): Boolean { diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/DisclosePayload.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/DisclosePayload.kt index b4e16844..fa171079 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/DisclosePayload.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/DisclosePayload.kt @@ -7,10 +7,12 @@ class DisclosePayload( val tokens: ByteArray, val attestations: ByteArray, val authorities: ByteArray, + val advertisementInformation: String? = null, ) : Serializable { override fun serialize(): ByteArray { - return serializeVarLen(metadata) + serializeVarLen(tokens) + serializeVarLen(attestations) + serializeVarLen( - authorities) + return serializeVarLen(metadata) + serializeVarLen(tokens) + serializeVarLen(attestations) + + serializeVarLen(authorities) + if (advertisementInformation != null) + serializeVarLen(advertisementInformation.toByteArray()) else byteArrayOf() } companion object Deserializer : Deserializable { @@ -28,8 +30,17 @@ class DisclosePayload( val (authorities, offset4) = deserializeVarLen(buffer, localOffset) localOffset += offset4 - return Pair(DisclosePayload(metadata, tokens, attestations, authorities), localOffset) + var disclosureMetadata: String? = null + if (buffer.size > localOffset) { + val deserializedMetadataPair = deserializeVarLen(buffer, localOffset) + disclosureMetadata = String(deserializedMetadataPair.first) + localOffset += deserializedMetadataPair.second + } + + return Pair( + DisclosePayload(metadata, tokens, attestations, authorities, disclosureMetadata), + localOffset + ) } } - } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/MissingResponsePayload.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/MissingResponsePayload.kt index 4eb2ff7a..b18d6df7 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/MissingResponsePayload.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/MissingResponsePayload.kt @@ -11,9 +11,11 @@ class MissingResponsePayload( companion object Deserializer : Deserializable { override fun deserialize(buffer: ByteArray, offset: Int): Pair { - val (tokens, localOffset) = deserializeRaw(buffer, offset) - return Pair(MissingResponsePayload(tokens), offset + localOffset) + var localOffset = offset + val (tokens, localOffset1) = deserializeRaw(buffer, localOffset) + localOffset += localOffset1 + + return Pair(MissingResponsePayload(tokens), localOffset) } } - } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/RequestMissingPayload.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/RequestMissingPayload.kt index 1defcd47..6e14ae3c 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/RequestMissingPayload.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/payloads/RequestMissingPayload.kt @@ -11,9 +11,11 @@ class RequestMissingPayload( companion object Deserializer : Deserializable { override fun deserialize(buffer: ByteArray, offset: Int): Pair { - val known = deserializeUInt(buffer, offset) - return Pair(RequestMissingPayload(known.toInt()), offset + SERIALIZED_UINT_SIZE) + var localOffset = offset + val known = deserializeUInt(buffer, localOffset) + localOffset += SERIALIZED_UINT_SIZE + + return Pair(RequestMissingPayload(known.toInt()), localOffset) } } - } From ed8643107760b2b7b79f3706a9c47f97f226d492 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 10 May 2021 13:25:15 +0200 Subject: [PATCH 108/144] Add disclosure information to callback + make checks optional in verification method --- .../attestation/identity/IdentityCommunity.kt | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index b282cc2b..106eb733 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -62,7 +62,7 @@ class IdentityCommunity( var identityManager: IdentityManager = identityManager ?: IdentityManager(database) val requestCache = RequestCache() - private lateinit var attestationPresentationCallback: (peer: Peer, attributeHash: ByteArray, value: ByteArray, metadata: Metadata, attestations: List) -> Unit + private lateinit var attestationPresentationCallback: (peer: Peer, attributeHash: ByteArray, value: ByteArray, metadata: Metadata, attestations: List, disclosureInformation: String) -> Unit private val knownAttestationHashes = hashMapOf() private val pseudonymManager = this.identityManager.getPseudonym(this.myPeer.key) @@ -98,7 +98,7 @@ class IdentityCommunity( messageHandlers[MISSING_RESPONSE_PAYLOAD] = ::onMissingResponseWrapper } - fun setAttestationPresentationCallback(f: (peer: Peer, attributeHash: ByteArray, value: ByteArray, metadata: Metadata, attestations: List) -> Unit) { + fun setAttestationPresentationCallback(f: (peer: Peer, attributeHash: ByteArray, value: ByteArray, metadata: Metadata, attestations: List, disclosureInformation: String) -> Unit) { this.attestationPresentationCallback = f } @@ -150,7 +150,7 @@ class IdentityCommunity( return null } - private fun shouldSign(pseudonym: PseudonymManager, metadata: Metadata): Boolean { + private fun shouldSign(pseudonym: PseudonymManager, metadata: Metadata, isVerification: Boolean = false): Boolean { val transaction = JSONObject(String(metadata.serializedMetadata)) val requestedKeys = transaction.keySet() if (!pseudonym.tree.elements.containsKey(metadata.tokenPointer.toKey())) { @@ -173,7 +173,7 @@ class IdentityCommunity( return false } // Refuse to sign blocks older than 5 minutes - if (System.currentTimeMillis() / 1000F > this.knownAttestationHashes[attributeHash.toKey()]?.time?.plus( + if (!isVerification && System.currentTimeMillis() / 1000F > this.knownAttestationHashes[attributeHash.toKey()]?.time?.plus( (DEFAULT_TIME_OUT) ) ?: 0F ) { @@ -192,12 +192,14 @@ class IdentityCommunity( logger.debug("Not signing $metadata, metadata does not match!") return false } - for (attestation in pseudonym.database.getAttestationsOver(metadata)) { - if (this.myPeer.publicKey.keyToBin() - .contentEquals(pseudonym.database.getAuthority(attestation)) - ) { - logger.debug("Not signing $metadata, already attested!") - return false + if (!isVerification) { + for (attestation in pseudonym.database.getAttestationsOver(metadata)) { + if (this.myPeer.publicKey.keyToBin() + .contentEquals(pseudonym.database.getAuthority(attestation)) + ) { + logger.debug("Not signing $metadata, already attested!") + return false + } } } return true @@ -274,12 +276,21 @@ class IdentityCommunity( ) val disclosureJSON = JSONObject(disclosureInformation) - val requiredAttributes = listOf(disclosureJSON.getString("attributeHash").hexToBytes().toKey()) + val requiredAttributes = listOf(disclosureJSON.getString("attestationHash").hexToBytes().toKey()) val knownAttributes: List = pseudonym.tree.elements.values.map { ByteArrayKey(it.contentHash) } if (correct && requiredAttributes.any { knownAttributes.contains(it) }) { for (credential in pseudonym.getCredentials()) { + val value = disclosureJSON.getString("value").hexToBytes() + @Suppress("UNCHECKED_CAST") + this.addKnownHash( + requiredAttributes[0].bytes, + attributeName, + value, + peer.publicKey, + JSONObject(String(credential.metadata.serializedMetadata)).toMap() as HashMap + ) if (shouldSign(pseudonym, credential.metadata)) { val presentedAttributeName = JSONObject(String(credential.metadata.serializedMetadata)).getString("name") @@ -288,10 +299,11 @@ class IdentityCommunity( return } logger.info("Received valid attestation presentation ${String(credential.metadata.serializedMetadata)}") - val value = disclosureJSON.getString("value").hexToBytes() + this.attestationPresentationCallback( peer, requiredAttributes[0].bytes, value, credential.metadata, - credential.attestations.toList() + credential.attestations.toList(), + disclosureInformation ) } } @@ -439,8 +451,7 @@ class IdentityCommunity( when { solicitedAttestationPresentation -> { - val cache = (this.requestCache.get(idPair)!! as TokenRequestCache) - val disclosureMD = JSONObject(cache.disclosureInformation) + val cache = (this.requestCache.pop(idPair)!! as TokenRequestCache) this.receivedDisclosureForPresentation( peer, Disclosure(byteArrayOf(), payload.tokens, byteArrayOf(), byteArrayOf()), From 63d60c21746324a0530c453f4fe3e296aa94e0b5 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 10 May 2021 13:25:43 +0200 Subject: [PATCH 109/144] Strip sha1 padding + update callback --- .../ipv8/attestation/communication/CommunicationChannel.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt index d63b5da5..a0eaf696 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt @@ -147,12 +147,13 @@ class CommunicationChannel( attributeHash: ByteArray, value: ByteArray, metadata: Metadata, - attestations: List + attestations: List, + disclosureInformation: String, ) { logger.info("Received correct attestation presentation with hash ${attributeHash.toHex()}.") - val parsedMD = JSONObject(metadata.serializedMetadata) + val parsedMD = JSONObject(String(metadata.serializedMetadata)) val idFormat = parsedMD.getString("schema") - this.verify(peer, attributeHash, listOf(value), idFormat) + this.verify(peer, stripSHA1Padding(attributeHash), listOf(value), idFormat) } private fun dropIdentityTableData() { From 2ce08500ffcf0419eff7b1d13d6a26c3958d61da Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 10 May 2021 13:27:11 +0200 Subject: [PATCH 110/144] Add method for presentation + add method for fetching attributes by name --- .../communication/CommunicationChannel.kt | 61 +++++++++++++++++-- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt index d63b5da5..4cebe2dd 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt @@ -14,6 +14,8 @@ import nl.tudelft.ipv8.attestation.identity.Metadata import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity import nl.tudelft.ipv8.attestation.communication.caches.DisclosureRequestCache import nl.tudelft.ipv8.attestation.identity.IdentityAttestation +import nl.tudelft.ipv8.attestation.identity.database.Credential +import nl.tudelft.ipv8.attestation.schema.ID_METADATA import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.keyvault.defaultCryptoProvider @@ -27,6 +29,7 @@ import nl.tudelft.ipv8.util.toByteArray import nl.tudelft.ipv8.util.toHex import nl.tudelft.ipv8.util.toKey import org.json.JSONObject +import java.util.Locale import java.util.UUID const val DEFAULT_TIME_OUT = 30_000L @@ -206,7 +209,7 @@ class CommunicationChannel( GlobalScope.launch { outstanding.setResult(false) } } - fun generateDisclosureRequest( + fun generateAttestationPresentationRequest( attributeName: String ): String { val id = UUID.randomUUID().toString() @@ -220,6 +223,25 @@ class CommunicationChannel( return id } + fun presentAttestation( + peer: Peer, + requestId: String, + attributeHash: ByteArray, + attributeValue: ByteArray, + credential: Credential, + ) { + val presentationMetadata = JSONObject() + presentationMetadata.put("id", requestId) + presentationMetadata.put("attestationHash", attributeHash.toHex()) + presentationMetadata.put("value", attributeValue.toHex()) + + this.identityOverlay.presentAttestationAdvertisement( + peer, + credential, + presentationMetadata.toString(), + ) + } + fun verify( peer: Peer, attestationHash: ByteArray, @@ -246,7 +268,12 @@ class CommunicationChannel( var signableData = latestVersion.toByteArray() signatures.forEach { signableData += it } val versionSignature = (myPeer.key as PrivateKey).sign(sha3_256(signableData)) - authorityManager.insertRevocations(myPeer.publicKey.keyToHash(), latestVersion, versionSignature, signatures) + authorityManager.insertRevocations( + myPeer.publicKey.keyToHash(), + latestVersion, + versionSignature, + signatures + ) } fun verifyLocally( @@ -282,12 +309,12 @@ class CommunicationChannel( } // Check if authority is recognized and the corresponding signature is correct. - if (attestors.any { attestor -> + if (!attestors.any { attestor -> val authority = this.attestationOverlay.authorityManager.getTrustedAuthority(attestor.first) authority?.let { it.publicKey?.verify(attestor.second, metadata.hash) - } == false + } == true }) { logger.info("Not accepting ${attestationHash.toHex()}, no recognized authority or valid signature found.") return false @@ -307,6 +334,32 @@ class CommunicationChannel( return Pair(timestamp, (this.myPeer.key as PrivateKey).sign(timestamp.toByteArray())) } + // Hash, Metadata, Value + fun getAttributeByName(attributeName: String): Triple? { + val pseudonym = this.identityOverlay.identityManager.getPseudonym(myPeer.publicKey) + + for (credential in pseudonym.getCredentials()) { + val attestations = credential.attestations.toList() + val attestors = mutableListOf() + + for (attestation in attestations) { + attestors += this.identityOverlay.identityManager.database.getAuthority(attestation) + } + val attributeHash = + pseudonym.tree.elements[credential.metadata.tokenPointer.toKey()]!!.contentHash + val jsonMetadata = JSONObject(String(credential.metadata.serializedMetadata)) + val attributeValue = + this.attestationOverlay.database.getValueByHash( + stripSHA1Padding(attributeHash) + )!! + + if (jsonMetadata.getString("name").equals(attributeName, ignoreCase = true)) { + return Triple(attributeHash, credential, attributeValue) + } + } + return null + } + fun getOfflineVerifiableAttributes(publicKey: PublicKey = this.myPeer.publicKey): List { val out = mutableListOf() val pseudonym = this.identityOverlay.identityManager.getPseudonym(publicKey) From 25d92c35e9a9c208ac99ff7e91445521c1db9193 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 10 May 2021 13:27:49 +0200 Subject: [PATCH 111/144] Clean up presentation method + strip sha1 padding --- .../attestation/identity/IdentityCommunity.kt | 21 ++++++------------- .../wallet/AttestationCommunity.kt | 13 ++++++------ 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index b282cc2b..bd954cd8 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -310,22 +310,14 @@ class IdentityCommunity( fun presentAttestationAdvertisement( peer: Peer, - requestId: String, - attributeHash: ByteArray, - attributeName: String, - attributeValue: ByteArray, - blockType: String = ID_METADATA, - metadata: HashMap? + credential: Credential, + presentationMetadata: String, ) { - val credential = this.selfAdvertise(attributeHash, attributeName, blockType, metadata) + // val credential = this.selfAdvertise(attributeHash, attributeName, blockType, metadata) this.permissions[peer] = this.tokenChain.size val disclosure = this.pseudonymManager.discloseCredentials(listOf(credential), setOf()) val (metadataObj, tokens, attestations, authorities) = this.fitDisclosure(disclosure) - val presentationMetadata = JSONObject() - presentationMetadata.put("id", requestId) - presentationMetadata.put("attestationHash", attributeHash) - presentationMetadata.put("value", attributeValue) - val payload = DisclosePayload(metadataObj, tokens, attestations, authorities, presentationMetadata.toString()) + val payload = DisclosePayload(metadataObj, tokens, attestations, authorities, presentationMetadata) this.endpoint.send(peer, serializePacket(DISCLOSURE_PAYLOAD, payload)) } @@ -335,13 +327,12 @@ class IdentityCommunity( name: String, blockType: String = ID_METADATA, metadata: HashMap?, - advertisementInformation: String? = null, ) { val credential = this.selfAdvertise(attributeHash, name, blockType, metadata) this.permissions[peer] = this.tokenChain.size val disclosure = this.pseudonymManager.discloseCredentials(listOf(credential), setOf()) val (metadataObj, tokens, attestations, authorities) = this.fitDisclosure(disclosure) - val payload = DisclosePayload(metadataObj, tokens, attestations, authorities, advertisementInformation) + val payload = DisclosePayload(metadataObj, tokens, attestations, authorities) this.endpoint.send(peer, serializePacket(DISCLOSURE_PAYLOAD, payload)) } @@ -416,6 +407,7 @@ class IdentityCommunity( } private fun onRequestMissing(peer: Peer, payload: RequestMissingPayload) { + logger.info("Received missing request from ${peer.mid} for ${payload.known} tokens") var out = byteArrayOf() val permitted = this.tokenChain.subList(0, this.permissions.get(peer) ?: 0) permitted.forEachIndexed { index, token -> @@ -440,7 +432,6 @@ class IdentityCommunity( when { solicitedAttestationPresentation -> { val cache = (this.requestCache.get(idPair)!! as TokenRequestCache) - val disclosureMD = JSONObject(cache.disclosureInformation) this.receivedDisclosureForPresentation( peer, Disclosure(byteArrayOf(), payload.tokens, byteArrayOf(), byteArrayOf()), diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt index 0ec5145f..90d1c3a2 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt @@ -336,27 +336,28 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: peer: Peer, payload: VerifyAttestationRequestPayload, ) { - val attestationBlob = this.database.getAttestationBlobByHash(payload.hash) + val hash = stripSHA1Padding(payload.hash) + val attestationBlob = this.database.getAttestationBlobByHash(hash) if (attestationBlob == null) { - logger.warn("Dropping verification request of unknown hash ${payload.hash}!") + logger.warn("Dropping verification request of unknown hash ${payload.hash.toHex()}!") return } if (attestationBlob.isEmpty()) { - logger.warn("Attestation blob for verification is empty: ${payload.hash}!") + logger.warn("Attestation blob for verification is empty: ${payload.hash.toHex()}!") } - val value = verifyRequestCallback(peer, payload.hash).await() + val value = verifyRequestCallback(peer, hash).await() if (value == null || !value) { logger.info("Verify request callback returned false for $peer, ${payload.hash}") return } - val (privateKey, idFormat) = this.attestationKeys[ByteArrayKey(payload.hash)]!! + val (privateKey, idFormat) = this.attestationKeys[ByteArrayKey(hash)]!! val privateAttestation = schemaManager.deserializePrivate(privateKey, attestationBlob, idFormat) val publicAttestationBlob = privateAttestation.serialize() - this.cachedAttestationBlobs[ByteArrayKey(payload.hash)] = privateAttestation + this.cachedAttestationBlobs[ByteArrayKey(hash)] = privateAttestation this.sendAttestation(peer.address, publicAttestationBlob) } From 88e31328c41c7d5caca5dd8353a2173099e2c16d Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 10 May 2021 14:23:24 +0200 Subject: [PATCH 112/144] Cleanup attestation community --- .../wallet/AttestationCommunity.kt | 234 +++++++++--------- 1 file changed, 122 insertions(+), 112 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt index 90d1c3a2..e1a16bac 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt @@ -38,11 +38,21 @@ import kotlin.random.nextUBytes private val logger = KotlinLogging.logger {} private const val CHUNK_SIZE = 800 +/** + * Community for signing and verifying attestations. + */ class AttestationCommunity(val authorityManager: AuthorityManager, val database: AttestationStore) : Community() { + override val serviceId = "e5d116f803a916a84850b9057cc0f662163f71f5" + + @Suppress("JoinDeclarationAndAssignment", "JoinDeclarationAndAssignment", "LateinitVarOverridesLateinitVar") override lateinit var myPeer: Peer + + @Suppress("JoinDeclarationAndAssignment", "JoinDeclarationAndAssignment", "LateinitVarOverridesLateinitVar") override lateinit var endpoint: EndpointAggregator + + @Suppress("JoinDeclarationAndAssignment", "JoinDeclarationAndAssignment", "LateinitVarOverridesLateinitVar") override lateinit var network: Network constructor( @@ -60,8 +70,6 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: this.network = network } - override val serviceId = "e5d116f803a916a84850b9057cc0f662163f71f5" - private val receiveBlockLock = ReentrantLock() val schemaManager = SchemaManager() @@ -73,8 +81,8 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: private val attestationKeys: MutableMap> = mutableMapOf() - private val cachedAttestationBlobs = mutableMapOf() - private val allowedAttestations = mutableMapOf>() + private val cachedAttestationBlobs: MutableMap = mutableMapOf() + private val allowedAttestations: MutableMap> = mutableMapOf() val requestCache = RequestCache() @@ -85,7 +93,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val hash = att.attestationHash val key = att.key val idFormat = att.idFormat - this.attestationKeys[ByteArrayKey(hash)] = + this.attestationKeys[hash.toKey()] = Pair(this.getIdAlgorithm(idFormat).loadSecretKey(key), idFormat) } @@ -96,70 +104,11 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: messageHandlers[ATTESTATION_REQUEST] = ::onRequestAttestationWrapper } - private fun onRequestAttestationWrapper(packet: Packet) { - val (peer, dist, payload) = packet.getAuthPayloadWithDist(RequestAttestationPayload.Deserializer) - logger.info("Received RequestAttestation from ${peer.mid} for metadata ${payload.metadata}.") - GlobalScope.launch { onRequestAttestation(peer, dist, payload) } - } - - private fun onChallengeResponseWrapper(packet: Packet) { - val (peer, payload) = packet.getAuthPayload(ChallengeResponsePayload.Deserializer) - logger.info( - "Received ChallengeResponse from ${peer.mid} for hash ${String(payload.challengeHash)} with response ${ - String(payload.response) - }." - ) - this.onChallengeResponse(peer, payload) - } - - private fun onChallengeWrapper(packet: Packet) { - val (peer, payload) = packet.getAuthPayload(ChallengePayload.Deserializer) - logger.info( - "Received Challenge from ${peer.mid} for hash ${String(payload.attestationHash)} with challenge ${ - String(payload.challenge) - }." - ) - this.onChallenge(peer, payload) - } - - private fun onAttestationChunkWrapper(packet: Packet) { - val (peer, dist, payload) = packet.getAuthPayloadWithDist(AttestationChunkPayload.Deserializer) - logger.info("Received AttestationChunk from ${peer.mid} with sequence number ${payload.sequenceNumber}, data ${payload.data.size} bytes, hash ${payload.hash.toHex()}.") - this.onAttestationChunk(peer, dist, payload) - } - - private fun onVerifyAttestationRequestWrapper(packet: Packet) { - val (peer, payload) = packet.getAuthPayload(VerifyAttestationRequestPayload.Deserializer) - logger.info("Received VerifyAttestationRequest from ${peer.mid} for hash ${String(payload.hash)}.") - GlobalScope.launch { onVerifyAttestationRequest(peer, payload) } - } - - fun getIdAlgorithm(idFormat: String): IdentityAlgorithm { - return this.schemaManager.getAlgorithmInstance(idFormat) - } - - fun setAttestationRequestCallback(f: (peer: Peer, attributeName: String, metaData: String, proposedValue: String?) -> Deferred) { - this.attestationRequestCallback = f - } - - fun setAttestationRequestCompleteCallback(f: (forPeer: Peer, attributeName: String, attestation: WalletAttestation, attributeHash: ByteArray, idFormat: String, fromPeer: Peer?, value: ByteArray?) -> Unit) { - this.attestationRequestCompleteCallback = f - } - - fun setVerifyRequestCallback(f: (attributeName: Peer, attributeHash: ByteArray) -> Deferred) { - this.verifyRequestCallback = f - } - - fun setAttestationChunkCallback(f: (peer: Peer, sequenceNumber: Int) -> Unit) { - this.attestationChunkCallback = f - } - - @Suppress("UNUSED_PARAMETER") - fun dumbBlob(attributeName: String, idFormat: String, blob: ByteArray, metaData: String = "") { - // TODO: Implement this method. - throw NotImplementedError() - } - + /** + * Method for requesting attestation with name [attributeName] from peer [peer] with additional metadata [metadata]. + * The attestation will be signed for the public-key belong to [privateKey]. + * An additional proposed value [proposedValue] can also be specified. + */ fun requestAttestation( peer: Peer, attributeName: String, @@ -200,7 +149,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: ) ) this.allowedAttestations[peer.mid] = - (this.allowedAttestations[peer.mid] ?: emptyArray()) + arrayOf(gTimeStr) + (this.allowedAttestations[peer.mid] ?: emptyList()) + listOf(gTimeStr) val packet = serializePacket( @@ -212,6 +161,35 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: endpoint.send(peer, packet) } + /** + * Method for verifying an attestation with hash [attestationHash] belonging to a peer listening on the + * address [socketAddress]. The value we believe the attestation has is incorporated in [values], with the + * used schema [idFormat]. After verification [callback] is called. + */ + fun verifyAttestationValues( + socketAddress: IPv4Address, + attestationHash: ByteArray, + values: List, + callback: ((ByteArray, List) -> Unit), + idFormat: String, + ) { + val algorithm = this.getIdAlgorithm(idFormat) + + fun onComplete(attestationHash: ByteArray, relativityMap: HashMap) { + callback(attestationHash, values.map { algorithm.certainty(it, relativityMap) }) + } + + this.requestCache.add( + ProvingAttestationCache( + this, + attestationHash, + idFormat, + onComplete = ::onComplete + ) + ) + this.createVerifyAttestationRequest(socketAddress, attestationHash, idFormat) + } + private suspend fun onRequestAttestation( peer: Peer, dist: GlobalTimeDistributionPayload, @@ -220,7 +198,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val metadata = JSONObject(payload.metadata) val attribute = metadata.remove("attribute") as String - val pubkeyEncoded = metadata.remove("public_key") as String + val encodedPK = metadata.remove("public_key") as String val idFormat = metadata.remove("id_format") as String var proposedValue: String? = null // We cannot cast null to string, hence member checking. @@ -240,7 +218,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: // Decode as UTF-8 ByteArray val publicKey = - idAlgorithm.loadPublicKey(defaultEncodingUtils.decodeBase64FromString(pubkeyEncoded)) + idAlgorithm.loadPublicKey(defaultEncodingUtils.decodeBase64FromString(encodedPK)) val attestationBlob = idAlgorithm.attest(publicKey, value) val attestation = @@ -274,7 +252,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: idFormat: String, value: ByteArray? = null, ) { - this.attestationKeys[ByteArrayKey(attestationHash)] = Pair(privateKey, idFormat) + this.attestationKeys[attestationHash.toKey()] = Pair(privateKey, idFormat) this.database.insertAttestation( deserialized, attestationHash, @@ -296,30 +274,6 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: } } - fun verifyAttestationValues( - socketAddress: IPv4Address, - attestationHash: ByteArray, - values: List, - callback: ((ByteArray, List) -> Unit), - idFormat: String, - ) { - val algorithm = this.getIdAlgorithm(idFormat) - - fun onComplete(attestationHash: ByteArray, relativityMap: HashMap) { - callback(attestationHash, values.map { algorithm.certainty(it, relativityMap) }) - } - - this.requestCache.add( - ProvingAttestationCache( - this, - attestationHash, - idFormat, - onComplete = ::onComplete - ) - ) - this.createVerifyAttestationRequest(socketAddress, attestationHash, idFormat) - } - private fun createVerifyAttestationRequest( socketAddress: IPv4Address, attestationHash: ByteArray, @@ -353,11 +307,11 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: return } - val (privateKey, idFormat) = this.attestationKeys[ByteArrayKey(hash)]!! + val (privateKey, idFormat) = this.attestationKeys[hash.toKey()]!! val privateAttestation = schemaManager.deserializePrivate(privateKey, attestationBlob, idFormat) val publicAttestationBlob = privateAttestation.serialize() - this.cachedAttestationBlobs[ByteArrayKey(hash)] = privateAttestation + this.cachedAttestationBlobs[hash.toKey()] = privateAttestation this.sendAttestation(peer.address, publicAttestationBlob) } @@ -390,9 +344,8 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: this.attestationChunkCallback(peer, payload.sequenceNumber) } val hashId = HashCache.idFromHash(ATTESTATION_VERIFY_PREFIX, payload.hash) - val (prefix, number) = hashId - val peerIds = arrayListOf>() - val allowedGlobs = this.allowedAttestations.get(peer.mid) ?: arrayOf() + val peerIds = mutableListOf>() + val allowedGlobs = this.allowedAttestations[peer.mid] ?: listOf() allowedGlobs.forEach { if (it.contentEquals(dist.globalTime.toString().toByteArray())) { peerIds.add( @@ -403,8 +356,8 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: ) } } - if (this.requestCache.has(prefix, number)) { - val cache = this.requestCache.get(prefix, number) as ReceiveAttestationVerifyCache + if (this.requestCache.has(hashId)) { + val cache = this.requestCache.get(hashId) as ReceiveAttestationVerifyCache cache.attestationMap.add(Pair(payload.sequenceNumber, payload.data)) var serialized = byteArrayOf() @@ -414,7 +367,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: if (sha1(serialized).contentEquals(payload.hash)) { val attestation = schemaManager.deserialize(serialized, cache.idFormat) - this.requestCache.pop(prefix, number) + this.requestCache.pop(hashId) this.onReceivedAttestation( peer, attestation, @@ -462,13 +415,11 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: dist.globalTime.toString().toByteArray() ) ) it else null - }.toTypedArray() + } if (this.allowedAttestations[peer.mid].isNullOrEmpty()) { this.allowedAttestations.remove(peer.mid) } - // TODO: Verify received signature and value - this.onAttestationComplete( attestation, cache.privateKey, @@ -541,15 +492,15 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: } private fun onChallenge(peer: Peer, payload: ChallengePayload) { - if (!this.attestationKeys.containsKey(ByteArrayKey(payload.attestationHash))) { + if (!this.attestationKeys.containsKey(payload.attestationHash.toKey())) { logger.error("Received ChallengePayload $payload for unknown attestation hash ${payload.attestationHash}.") return } - val (privateKey, idFormat) = this.attestationKeys[ByteArrayKey(payload.attestationHash)]!! + val (privateKey, idFormat) = this.attestationKeys[payload.attestationHash.toKey()]!! val challengeHash = sha1(payload.challenge) val algorithm = this.getIdAlgorithm(idFormat) - val attestation = this.cachedAttestationBlobs[ByteArrayKey(payload.attestationHash)]!! + val attestation = this.cachedAttestationBlobs[payload.attestationHash.toKey()]!! val outGoingPayload = ChallengeResponsePayload( challengeHash, @@ -668,7 +619,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: } } if (challenge == null) { - logger.info("No more bitpairs to challenge!") + logger.info("No more bit-pairs to challenge!") return } } @@ -691,6 +642,65 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: } } + private fun onRequestAttestationWrapper(packet: Packet) { + val (peer, dist, payload) = packet.getAuthPayloadWithDist(RequestAttestationPayload.Deserializer) + logger.info("Received RequestAttestation from ${peer.mid} for metadata ${payload.metadata}.") + GlobalScope.launch { onRequestAttestation(peer, dist, payload) } + } + + private fun onChallengeResponseWrapper(packet: Packet) { + val (peer, payload) = packet.getAuthPayload(ChallengeResponsePayload.Deserializer) + logger.info( + "Received ChallengeResponse from ${peer.mid} for hash ${String(payload.challengeHash)} with response ${ + String(payload.response) + }." + ) + this.onChallengeResponse(peer, payload) + } + + private fun onChallengeWrapper(packet: Packet) { + val (peer, payload) = packet.getAuthPayload(ChallengePayload.Deserializer) + logger.info( + "Received Challenge from ${peer.mid} for hash ${String(payload.attestationHash)} with challenge ${ + String(payload.challenge) + }." + ) + this.onChallenge(peer, payload) + } + + private fun onAttestationChunkWrapper(packet: Packet) { + val (peer, dist, payload) = packet.getAuthPayloadWithDist(AttestationChunkPayload.Deserializer) + logger.info("Received AttestationChunk from ${peer.mid} with sequence number ${payload.sequenceNumber}, data ${payload.data.size} bytes, hash ${payload.hash.toHex()}.") + this.onAttestationChunk(peer, dist, payload) + } + + private fun onVerifyAttestationRequestWrapper(packet: Packet) { + val (peer, payload) = packet.getAuthPayload(VerifyAttestationRequestPayload.Deserializer) + logger.info("Received VerifyAttestationRequest from ${peer.mid} for hash ${String(payload.hash)}.") + GlobalScope.launch { onVerifyAttestationRequest(peer, payload) } + } + + fun setAttestationRequestCallback(f: (peer: Peer, attributeName: String, metaData: String, proposedValue: String?) -> Deferred) { + this.attestationRequestCallback = f + } + + fun setAttestationRequestCompleteCallback(f: (forPeer: Peer, attributeName: String, attestation: WalletAttestation, attributeHash: ByteArray, idFormat: String, fromPeer: Peer?, value: ByteArray?) -> Unit) { + this.attestationRequestCompleteCallback = f + } + + fun setVerifyRequestCallback(f: (attributeName: Peer, attributeHash: ByteArray) -> Deferred) { + this.verifyRequestCallback = f + } + + @Suppress("unused") + fun setAttestationChunkCallback(f: (peer: Peer, sequenceNumber: Int) -> Unit) { + this.attestationChunkCallback = f + } + + fun getIdAlgorithm(idFormat: String): IdentityAlgorithm { + return this.schemaManager.getAlgorithmInstance(idFormat) + } + object MessageId { const val VERIFY_ATTESTATION_REQUEST = 1 const val ATTESTATION = 2 From 182df8675835aaca02238370837dbc91d2e8b67e Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 10 May 2021 17:40:47 +0200 Subject: [PATCH 113/144] Improve code structures + replace strings with consts --- .../{ => common}/AuthorityManager.kt | 2 +- .../attestation/{ => common}/RequestCache.kt | 2 +- .../{schema => common}/SchemaManager.kt | 64 +++-- .../common/consts/SchemaConstants.kt | 17 ++ .../communication/CommunicationChannel.kt | 10 +- .../communication/CommunicationManager.kt | 6 +- .../caches/DisclosureRequestCache.kt | 2 +- .../communication/caches/TokenRequestCache.kt | 2 +- .../attestation/identity/IdentityCommunity.kt | 206 +++++++------- .../identity/consts/MetadataConsts.kt | 9 + .../identity/consts/PayloadConsts.kt | 8 + .../IdentityAttestation.kt | 3 +- .../identity/{ => datastructures}/Metadata.kt | 5 +- .../datastructures}/SignedObject.kt | 3 +- .../datastructures}/tokenTree/Token.kt | 4 +- .../datastructures}/tokenTree/TokenTree.kt | 2 +- .../identity/manager/IdentityManager.kt | 6 +- .../identity/manager/PseudonymManager.kt | 12 +- .../IdentitySQLiteStore.kt | 8 +- .../{database => store}/IdentityStore.kt | 8 +- .../revocation/AuthoritySQLiteStore.kt | 3 +- .../attestation/revocation/AuthorityStore.kt | 4 +- .../revocation/RevocationCommunity.kt | 4 +- .../caches/PendingRevocationUpdateCache.kt | 2 +- .../wallet/AttestationCommunity.kt | 70 +++-- .../attestation/wallet/caches/HashCache.kt | 2 +- .../attestation/wallet/caches/NumberCache.kt | 2 +- .../attestation/wallet/caches/PeerCache.kt | 2 +- .../wallet/consts/MetadataConsts.kt | 8 + .../wallet/consts/PayloadConsts.kt | 9 + .../cryptography/IdentityAlgorithm.kt} | 35 +-- .../wallet/cryptography/WalletAttestation.kt | 36 +++ .../bonehexact/BonehExactAlgorithm.kt | 5 +- .../cryptography/bonehexact/BonehExactKeys.kt | 4 +- .../bonehexact/PrimitiveFunctions.kt | 4 +- .../attestations/BitPairAttestation.kt | 2 +- .../attestations/BonehAttestation.kt | 2 +- .../cryptography/pengbaorange/Boudot.kt | 170 ------------ .../cryptography/pengbaorange/PengBao.kt | 55 ++-- .../pengbaorange/PrimitiveFunctions.kt | 16 +- .../cryptography/pengbaorange/Structs.kt | 261 ------------------ .../attestations/PengBaoAttestation.kt | 60 ++++ .../cryptography/pengbaorange/boudot/Util.kt | 48 ++++ .../pengbaorange/boudot/primitives/EL.kt | 85 ++++++ .../pengbaorange/boudot/primitives/SQR.kt | 58 ++++ .../commitments/PengBaoCommitment.kt | 57 ++++ .../commitments/PrivatePengBaoCommitment.kt | 95 +++++++ .../commitments/PublicPengBaoCommitment.kt | 75 +++++ .../{ => cryptography}/primitives/EC.kt | 2 +- .../{ => cryptography}/primitives/FP2Value.kt | 2 +- .../{ => util}/AttestationHelperFunctions.kt | 4 +- .../wallet/cryptography/util/Serialization.kt | 21 ++ .../{ => store}/AttestationSQLiteStore.kt | 9 +- .../wallet/{ => store}/AttestationStore.kt | 5 +- .../datastructures}/tokenTree/TokenTest.kt | 2 +- .../tokenTree/TokenTreeTest.kt | 2 +- .../identity/manager/IdentityManagerTest.kt | 4 +- .../cryptography/bonehexact/TestBoneh.kt | 2 +- .../cryptography/bonehexact/TestKeys.kt | 2 +- .../cryptography/pengbaorange/TestBoudot.kt | 4 +- .../wallet/cryptography/primitives/TestEc.kt | 3 - 61 files changed, 865 insertions(+), 750 deletions(-) rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/{ => common}/AuthorityManager.kt (98%) rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/{ => common}/RequestCache.kt (97%) rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/{schema => common}/SchemaManager.kt (68%) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/consts/SchemaConstants.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/consts/MetadataConsts.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/consts/PayloadConsts.kt rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/{ => datastructures}/IdentityAttestation.kt (94%) rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/{ => datastructures}/Metadata.kt (93%) rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/{ => identity/datastructures}/SignedObject.kt (95%) rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/{ => identity/datastructures}/tokenTree/Token.kt (95%) rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/{ => identity/datastructures}/tokenTree/TokenTree.kt (98%) rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/{database => store}/IdentitySQLiteStore.kt (93%) rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/{database => store}/IdentityStore.kt (79%) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/consts/MetadataConsts.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/consts/PayloadConsts.kt rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/{IdentityFormats.kt => wallet/cryptography/IdentityAlgorithm.kt} (67%) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/WalletAttestation.kt delete mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/Boudot.kt delete mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/Structs.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/attestations/PengBaoAttestation.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/boudot/Util.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/boudot/primitives/EL.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/boudot/primitives/SQR.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/commitments/PengBaoCommitment.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/commitments/PrivatePengBaoCommitment.kt create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/commitments/PublicPengBaoCommitment.kt rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/{ => cryptography}/primitives/EC.kt (98%) rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/{ => cryptography}/primitives/FP2Value.kt (99%) rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/{ => util}/AttestationHelperFunctions.kt (98%) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/util/Serialization.kt rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/{ => store}/AttestationSQLiteStore.kt (85%) rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/{ => store}/AttestationStore.kt (84%) rename ipv8/src/test/java/nl/tudelft/ipv8/attestation/{ => identity/datastructures}/tokenTree/TokenTest.kt (97%) rename ipv8/src/test/java/nl/tudelft/ipv8/attestation/{ => identity/datastructures}/tokenTree/TokenTreeTest.kt (99%) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/AuthorityManager.kt similarity index 98% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/AuthorityManager.kt index 6f1b5753..228b8323 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/AuthorityManager.kt @@ -1,4 +1,4 @@ -package nl.tudelft.ipv8.attestation +package nl.tudelft.ipv8.attestation.common import nl.tudelft.ipv8.attestation.revocation.AuthorityStore import nl.tudelft.ipv8.attestation.revocation.RevocationBlob diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/RequestCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/RequestCache.kt similarity index 97% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/RequestCache.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/RequestCache.kt index 242211b0..e8a76a20 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/RequestCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/RequestCache.kt @@ -1,4 +1,4 @@ -package nl.tudelft.ipv8.attestation +package nl.tudelft.ipv8.attestation.common import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/schema/SchemaManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/SchemaManager.kt similarity index 68% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/schema/SchemaManager.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/SchemaManager.kt index ef666d9e..649dba5a 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/schema/SchemaManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/SchemaManager.kt @@ -1,13 +1,20 @@ -package nl.tudelft.ipv8.attestation.schema - -import nl.tudelft.ipv8.attestation.IdentityAlgorithm -import nl.tudelft.ipv8.attestation.WalletAttestation +package nl.tudelft.ipv8.attestation.common + +import nl.tudelft.ipv8.attestation.common.consts.AlgorithmNames.BONEH_EXACT +import nl.tudelft.ipv8.attestation.common.consts.AlgorithmNames.IRMA_EXACT +import nl.tudelft.ipv8.attestation.common.consts.AlgorithmNames.PENG_BAO_RANGE +import nl.tudelft.ipv8.attestation.common.consts.SchemaConstants.ID_METADATA +import nl.tudelft.ipv8.attestation.common.consts.SchemaConstants.ID_METADATA_BIG +import nl.tudelft.ipv8.attestation.common.consts.SchemaConstants.ID_METADATA_HUGE +import nl.tudelft.ipv8.attestation.common.consts.SchemaConstants.ID_METADATA_RANGE_18PLUS +import nl.tudelft.ipv8.attestation.common.consts.SchemaConstants.ID_METADATA_RANGE_UNDERAGE +import nl.tudelft.ipv8.attestation.wallet.cryptography.IdentityAlgorithm +import nl.tudelft.ipv8.attestation.wallet.cryptography.WalletAttestation import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehExactAlgorithm import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPrivateKey import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.attestations.BonehAttestation -import nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.PengBaoAttestation -import nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.Pengbaorange - +import nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.PengBaoRange +import nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.attestations.PengBaoAttestation class AlgorithmScheme( val schemaName: String, val algorithmName: String, @@ -17,28 +24,19 @@ class AlgorithmScheme( val max: Int? = null, ) -const val ID_METADATA = "id_metadata" -const val ID_METADATA_BIG = "id_metadata_big" -const val ID_METADATA_HUGE = "id_metadata_huge" -const val ID_METADATA_RANGE_18PLUS = "id_metadata_range_18plus" -const val ID_METADATA_RANGE_18PLUS_PUBLIC_VALUE = "true" -const val ID_METADATA_RANGE_UNDERAGE = "id_metadata_range_underage" -const val ID_METADATA_RANGE_UNDERAGE_PUBLIC_VALUE = "true" - - class SchemaManager { private val formats = HashMap>() fun deserialize(serialized: ByteArray, idFormat: String): WalletAttestation { return when (val algorithmName = getAlgorithmName(idFormat)) { - "bonehexact" -> { + BONEH_EXACT -> { BonehAttestation.deserialize(serialized, idFormat) } - "pengbaorange" -> { + PENG_BAO_RANGE -> { PengBaoAttestation.deserialize(serialized, idFormat) } - "irmaexact" -> { + IRMA_EXACT -> { TODO("Not yet implemented.") } else -> { @@ -53,13 +51,13 @@ class SchemaManager { idFormat: String, ): WalletAttestation { return when (val algorithmName = getAlgorithmName(idFormat)) { - "bonehexact" -> { + BONEH_EXACT -> { BonehAttestation.deserializePrivate(privateKey, serialized, idFormat) } - "pengbaorange" -> { + PENG_BAO_RANGE -> { PengBaoAttestation.deserializePrivate(privateKey, serialized, idFormat) } - "irmaexact" -> { + IRMA_EXACT -> { TODO("Not yet implemented.") } else -> { @@ -82,11 +80,11 @@ class SchemaManager { // TODO: Read in default schemas. fun registerDefaultSchemas() { val defaultSchemas = arrayListOf() - defaultSchemas.add(AlgorithmScheme(ID_METADATA, "bonehexact", 32, "sha256_4")) - defaultSchemas.add(AlgorithmScheme(ID_METADATA_BIG, "bonehexact", 64, "sha256")) - defaultSchemas.add(AlgorithmScheme(ID_METADATA_HUGE, "bonehexact", 96, "sha512")) - defaultSchemas.add(AlgorithmScheme(ID_METADATA_RANGE_18PLUS, "pengbaorange", 32, min = 18, max = 200)) - defaultSchemas.add(AlgorithmScheme(ID_METADATA_RANGE_UNDERAGE, "pengbaorange", 32, min = 0, max = 17)) + defaultSchemas.add(AlgorithmScheme(ID_METADATA, BONEH_EXACT, 32, "sha256_4")) + defaultSchemas.add(AlgorithmScheme(ID_METADATA_BIG, BONEH_EXACT, 64, "sha256")) + defaultSchemas.add(AlgorithmScheme(ID_METADATA_HUGE, BONEH_EXACT, 96, "sha512")) + defaultSchemas.add(AlgorithmScheme(ID_METADATA_RANGE_18PLUS, PENG_BAO_RANGE, 32, min = 18, max = 200)) + defaultSchemas.add(AlgorithmScheme(ID_METADATA_RANGE_UNDERAGE, PENG_BAO_RANGE, 32, min = 0, max = 17)) defaultSchemas.forEach { val params = hashMapOf("key_size" to it.keySize) @@ -98,7 +96,8 @@ class SchemaManager { params["max"] = it.max } - this.registerSchema(it.schemaName, + this.registerSchema( + it.schemaName, it.algorithmName, params ) @@ -107,13 +106,13 @@ class SchemaManager { fun getAlgorithmInstance(idFormat: String): IdentityAlgorithm { return when (val algorithmName = getAlgorithmName(idFormat)) { - "bonehexact" -> { + BONEH_EXACT -> { BonehExactAlgorithm(idFormat, this.formats) } - "pengbaorange" -> { - Pengbaorange(idFormat, this.formats) + PENG_BAO_RANGE -> { + PengBaoRange(idFormat, this.formats) } - "irmaexact" -> { + IRMA_EXACT -> { TODO("Not yet implemented.") } else -> { @@ -129,5 +128,4 @@ class SchemaManager { fun getSchemaNames(): List { return this.formats.keys.toList() } - } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/consts/SchemaConstants.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/consts/SchemaConstants.kt new file mode 100644 index 00000000..b64dea04 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/consts/SchemaConstants.kt @@ -0,0 +1,17 @@ +package nl.tudelft.ipv8.attestation.common.consts + +object SchemaConstants { + const val ID_METADATA = "id_metadata" + const val ID_METADATA_BIG = "id_metadata_big" + const val ID_METADATA_HUGE = "id_metadata_huge" + const val ID_METADATA_RANGE_18PLUS = "id_metadata_range_18plus" + const val ID_METADATA_RANGE_18PLUS_PUBLIC_VALUE = "true" + const val ID_METADATA_RANGE_UNDERAGE = "id_metadata_range_underage" + const val ID_METADATA_RANGE_UNDERAGE_PUBLIC_VALUE = "true" +} + +object AlgorithmNames { + const val BONEH_EXACT = "bonehexact" + const val PENG_BAO_RANGE = "pengbaorange" + const val IRMA_EXACT = "irmaexact" +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt index d5e3a6bf..44193094 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt @@ -8,14 +8,13 @@ import kotlinx.coroutines.async import kotlinx.coroutines.launch import mu.KotlinLogging import nl.tudelft.ipv8.Peer -import nl.tudelft.ipv8.attestation.WalletAttestation import nl.tudelft.ipv8.attestation.identity.IdentityCommunity -import nl.tudelft.ipv8.attestation.identity.Metadata +import nl.tudelft.ipv8.attestation.identity.datastructures.Metadata import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity import nl.tudelft.ipv8.attestation.communication.caches.DisclosureRequestCache -import nl.tudelft.ipv8.attestation.identity.IdentityAttestation -import nl.tudelft.ipv8.attestation.identity.database.Credential -import nl.tudelft.ipv8.attestation.schema.ID_METADATA +import nl.tudelft.ipv8.attestation.identity.datastructures.IdentityAttestation +import nl.tudelft.ipv8.attestation.identity.store.Credential +import nl.tudelft.ipv8.attestation.wallet.cryptography.WalletAttestation import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.keyvault.defaultCryptoProvider @@ -29,7 +28,6 @@ import nl.tudelft.ipv8.util.toByteArray import nl.tudelft.ipv8.util.toHex import nl.tudelft.ipv8.util.toKey import org.json.JSONObject -import java.util.Locale import java.util.UUID const val DEFAULT_TIME_OUT = 30_000L diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt index a55357b9..f24023e0 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt @@ -3,13 +3,13 @@ package nl.tudelft.ipv8.attestation.communication import mu.KotlinLogging import nl.tudelft.ipv8.IPv8 import nl.tudelft.ipv8.Peer -import nl.tudelft.ipv8.attestation.AuthorityManager +import nl.tudelft.ipv8.attestation.common.AuthorityManager import nl.tudelft.ipv8.attestation.identity.IdentityCommunity import nl.tudelft.ipv8.attestation.identity.createCommunity -import nl.tudelft.ipv8.attestation.identity.database.IdentityStore +import nl.tudelft.ipv8.attestation.identity.store.IdentityStore import nl.tudelft.ipv8.attestation.identity.manager.IdentityManager import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity -import nl.tudelft.ipv8.attestation.wallet.AttestationStore +import nl.tudelft.ipv8.attestation.wallet.store.AttestationStore import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.defaultCryptoProvider import nl.tudelft.ipv8.util.* diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/caches/DisclosureRequestCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/caches/DisclosureRequestCache.kt index 44ccb41a..fc23c26a 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/caches/DisclosureRequestCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/caches/DisclosureRequestCache.kt @@ -1,6 +1,6 @@ package nl.tudelft.ipv8.attestation.communication.caches -import nl.tudelft.ipv8.attestation.RequestCache +import nl.tudelft.ipv8.attestation.common.RequestCache import nl.tudelft.ipv8.attestation.communication.DisclosureRequest import nl.tudelft.ipv8.attestation.wallet.caches.DEFAULT_TIMEOUT import nl.tudelft.ipv8.attestation.wallet.caches.HashCache diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/caches/TokenRequestCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/caches/TokenRequestCache.kt index 539a90ed..93ad3325 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/caches/TokenRequestCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/caches/TokenRequestCache.kt @@ -1,6 +1,6 @@ package nl.tudelft.ipv8.attestation.communication.caches -import nl.tudelft.ipv8.attestation.RequestCache +import nl.tudelft.ipv8.attestation.common.RequestCache import nl.tudelft.ipv8.attestation.wallet.caches.HashCache import nl.tudelft.ipv8.attestation.wallet.caches.NumberCache import java.math.BigInteger diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index 5a40fc5e..5859680b 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -2,11 +2,23 @@ package nl.tudelft.ipv8.attestation.identity import mu.KotlinLogging import nl.tudelft.ipv8.* -import nl.tudelft.ipv8.attestation.RequestCache +import nl.tudelft.ipv8.attestation.common.RequestCache +import nl.tudelft.ipv8.attestation.common.consts.SchemaConstants.ID_METADATA import nl.tudelft.ipv8.attestation.communication.caches.DisclosureRequestCache import nl.tudelft.ipv8.attestation.communication.caches.TokenRequestCache -import nl.tudelft.ipv8.attestation.identity.database.Credential -import nl.tudelft.ipv8.attestation.identity.database.IdentityStore +import nl.tudelft.ipv8.attestation.identity.consts.Metadata.DATE +import nl.tudelft.ipv8.attestation.identity.consts.Metadata.ID +import nl.tudelft.ipv8.attestation.identity.consts.Metadata.NAME +import nl.tudelft.ipv8.attestation.identity.consts.Metadata.SCHEMA +import nl.tudelft.ipv8.attestation.identity.consts.Metadata.VALUE +import nl.tudelft.ipv8.attestation.identity.consts.PayloadIds.ATTEST_PAYLOAD +import nl.tudelft.ipv8.attestation.identity.consts.PayloadIds.DISCLOSURE_PAYLOAD +import nl.tudelft.ipv8.attestation.identity.consts.PayloadIds.MISSING_RESPONSE_PAYLOAD +import nl.tudelft.ipv8.attestation.identity.consts.PayloadIds.REQUEST_MISSING_PAYLOAD +import nl.tudelft.ipv8.attestation.identity.datastructures.IdentityAttestation +import nl.tudelft.ipv8.attestation.identity.datastructures.Metadata +import nl.tudelft.ipv8.attestation.identity.store.Credential +import nl.tudelft.ipv8.attestation.identity.store.IdentityStore import nl.tudelft.ipv8.attestation.identity.manager.Disclosure import nl.tudelft.ipv8.attestation.identity.manager.IdentityManager import nl.tudelft.ipv8.attestation.identity.manager.PseudonymManager @@ -14,8 +26,7 @@ import nl.tudelft.ipv8.attestation.identity.payloads.AttestPayload import nl.tudelft.ipv8.attestation.identity.payloads.DisclosePayload import nl.tudelft.ipv8.attestation.identity.payloads.MissingResponsePayload import nl.tudelft.ipv8.attestation.identity.payloads.RequestMissingPayload -import nl.tudelft.ipv8.attestation.schema.ID_METADATA -import nl.tudelft.ipv8.attestation.tokenTree.Token +import nl.tudelft.ipv8.attestation.identity.datastructures.tokenTree.Token import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.messaging.Packet @@ -34,12 +45,7 @@ const val SAFE_UDP_PACKET_LENGTH = 1296 const val DEFAULT_TIME_OUT = 300 const val TOKEN_SIZE = 64 -const val DISCLOSURE_PAYLOAD = 1 -const val ATTEST_PAYLOAD = 2 -const val REQUEST_MISSING_PAYLOAD = 3 -const val MISSING_RESPONSE_PAYLOAD = 4 - -val DEFAULT_METADATA = arrayOf("name", "date", "schema") +val DEFAULT_METADATA = listOf(NAME, DATE, SCHEMA) class HashInformation( val name: String, @@ -51,6 +57,9 @@ class HashInformation( private val logger = KotlinLogging.logger {} +/** + * Community for signing metadata over attestations, allowing for chains of attestations. + */ class IdentityCommunity( override var myPeer: Peer, identityManager: IdentityManager? = null, @@ -98,32 +107,62 @@ class IdentityCommunity( messageHandlers[MISSING_RESPONSE_PAYLOAD] = ::onMissingResponseWrapper } - fun setAttestationPresentationCallback(f: (peer: Peer, attributeHash: ByteArray, value: ByteArray, metadata: Metadata, attestations: List, disclosureInformation: String) -> Unit) { - this.attestationPresentationCallback = f + fun presentAttestationAdvertisement( + peer: Peer, + credential: Credential, + presentationMetadata: String, + ) { + this.permissions[peer] = this.tokenChain.size + val disclosure = this.pseudonymManager.discloseCredentials(listOf(credential), setOf()) + val (metadataObj, tokens, attestations, authorities) = this.fitDisclosure(disclosure) + val payload = DisclosePayload(metadataObj, tokens, attestations, authorities, presentationMetadata) + this.endpoint.send(peer, serializePacket(DISCLOSURE_PAYLOAD, payload)) } - private fun onDisclosureWrapper(packet: Packet) { - val (peer, payload) = packet.getAuthPayload(DisclosePayload.Deserializer) - logger.info(" Disclose payload from ${peer.mid}.") - this.onDisclosure(peer, payload) + fun advertiseAttestation( + peer: Peer, + attributeHash: ByteArray, + name: String, + blockType: String = ID_METADATA, + metadata: HashMap?, + ) { + val credential = this.selfAdvertise(attributeHash, name, blockType, metadata) + this.permissions[peer] = this.tokenChain.size + val disclosure = this.pseudonymManager.discloseCredentials(listOf(credential), setOf()) + val (metadataObj, tokens, attestations, authorities) = this.fitDisclosure(disclosure) + val payload = DisclosePayload(metadataObj, tokens, attestations, authorities) + this.endpoint.send(peer, serializePacket(DISCLOSURE_PAYLOAD, payload)) } - private fun onAttestWrapper(packet: Packet) { - val (peer, payload) = packet.getAuthPayload(AttestPayload.Deserializer) - logger.info("Received Attest payload from ${peer.mid}.") - this.onAttest(peer, payload) - } + fun selfAdvertise( + attributeHash: ByteArray, + name: String, + blockType: String, + metadata: HashMap?, + ): Credential { + val hash = if (attributeHash.size == 20) padSHA1Hash(attributeHash) else attributeHash - private fun onRequestMissingWrapper(packet: Packet) { - val (peer, payload) = packet.getAuthPayload(RequestMissingPayload.Deserializer) - logger.info("Received Request Missing payload from ${peer.mid}.") - this.onRequestMissing(peer, payload) - } + val extendedMetadata = + hashMapOf( + NAME to name, + SCHEMA to blockType, + DATE to System.currentTimeMillis() / 1000F + ) + if (metadata != null) { + extendedMetadata.putAll(metadata) + } - private fun onMissingResponseWrapper(packet: Packet) { - val (peer, payload) = packet.getAuthPayload(MissingResponsePayload.Deserializer) - logger.info("Received Missing Response payload from ${peer.mid}.") - this.onMissingResponse(peer, payload) + val credential = this.pseudonymManager.createCredential( + hash, + extendedMetadata, + if (this.metadataChain.isNotEmpty()) this.metadataChain.last() else null + ) + + this.attestationChain += credential.attestations + this.metadataChain += credential.metadata + this.tokenChain += this.pseudonymManager.tree.elements[credential.metadata.tokenPointer.toKey()]!! + + return credential } fun addKnownHash( @@ -142,7 +181,7 @@ class IdentityCommunity( val hash = if (attributeHash.size == 20) padSHA1Hash(attributeHash) else attributeHash for (credential in this.pseudonymManager.getCredentials()) { val token = - this.pseudonymManager.tree.elements.get(ByteArrayKey(credential.metadata.tokenPointer)) + this.pseudonymManager.tree.elements[ByteArrayKey(credential.metadata.tokenPointer)] if (token?.contentHash.contentEquals(hash)) { return credential.metadata } @@ -158,7 +197,7 @@ class IdentityCommunity( return false } val attributeHash = pseudonym.tree.elements[metadata.tokenPointer.toKey()]!!.contentHash - if ("name" !in requestedKeys || "date" !in requestedKeys || "schema" !in requestedKeys) { + if (NAME !in requestedKeys || DATE !in requestedKeys || SCHEMA !in requestedKeys) { logger.debug("Not signing $metadata, it doesn't include the required fields!") return false } @@ -180,7 +219,7 @@ class IdentityCommunity( logger.debug("Not signing $metadata, timed out!") return false } - if (transaction["name"] != this.knownAttestationHashes[attributeHash.toKey()]?.name) { + if (transaction[NAME] != this.knownAttestationHashes[attributeHash.toKey()]?.name) { logger.debug("Not signing $metadata, name does not match!") return false } @@ -282,7 +321,7 @@ class IdentityCommunity( if (correct && requiredAttributes.any { knownAttributes.contains(it) }) { for (credential in pseudonym.getCredentials()) { - val value = disclosureJSON.getString("value").hexToBytes() + val value = disclosureJSON.getString(VALUE).hexToBytes() @Suppress("UNCHECKED_CAST") this.addKnownHash( requiredAttributes[0].bytes, @@ -293,7 +332,7 @@ class IdentityCommunity( ) if (shouldSign(pseudonym, credential.metadata)) { val presentedAttributeName = - JSONObject(String(credential.metadata.serializedMetadata)).getString("name") + JSONObject(String(credential.metadata.serializedMetadata)).getString(NAME) if (presentedAttributeName != attributeName) { logger.warn("Client sent wrong attestation. Requested: $attributeName, received: $presentedAttributeName") return @@ -320,69 +359,10 @@ class IdentityCommunity( } } - fun presentAttestationAdvertisement( - peer: Peer, - credential: Credential, - presentationMetadata: String, - ) { - // val credential = this.selfAdvertise(attributeHash, attributeName, blockType, metadata) - this.permissions[peer] = this.tokenChain.size - val disclosure = this.pseudonymManager.discloseCredentials(listOf(credential), setOf()) - val (metadataObj, tokens, attestations, authorities) = this.fitDisclosure(disclosure) - val payload = DisclosePayload(metadataObj, tokens, attestations, authorities, presentationMetadata) - this.endpoint.send(peer, serializePacket(DISCLOSURE_PAYLOAD, payload)) - } - - fun advertiseAttestation( - peer: Peer, - attributeHash: ByteArray, - name: String, - blockType: String = ID_METADATA, - metadata: HashMap?, - ) { - val credential = this.selfAdvertise(attributeHash, name, blockType, metadata) - this.permissions[peer] = this.tokenChain.size - val disclosure = this.pseudonymManager.discloseCredentials(listOf(credential), setOf()) - val (metadataObj, tokens, attestations, authorities) = this.fitDisclosure(disclosure) - val payload = DisclosePayload(metadataObj, tokens, attestations, authorities) - this.endpoint.send(peer, serializePacket(DISCLOSURE_PAYLOAD, payload)) - } - - fun selfAdvertise( - attributeHash: ByteArray, - name: String, - blockType: String, - metadata: HashMap?, - ): Credential { - val hash = if (attributeHash.size == 20) padSHA1Hash(attributeHash) else attributeHash - - val extendedMetadata = - hashMapOf( - "name" to name, - "schema" to blockType, - "date" to System.currentTimeMillis() / 1000F - ) - if (metadata != null) { - extendedMetadata.putAll(metadata) - } - - val credential = this.pseudonymManager.createCredential( - hash, - extendedMetadata, - if (this.metadataChain.isNotEmpty()) this.metadataChain.last() else null - ) - - this.attestationChain += credential.attestations - this.metadataChain += credential.metadata - this.tokenChain += this.pseudonymManager.tree.elements[credential.metadata.tokenPointer.toKey()]!! - - return credential - } - private fun onDisclosure(peer: Peer, payload: DisclosePayload) { val isAttestationRequest = this.knownAttestationHashes.values.any { it.publicKey == peer.publicKey } val disclosureMD = JSONObject(payload.advertisementInformation ?: "{}") - val id = disclosureMD.optString("id") + val id = disclosureMD.optString(ID) val idPair = DisclosureRequestCache.idFromUUID(id) val isAttestationPresentation = this.requestCache.has(idPair) @@ -404,7 +384,7 @@ class IdentityCommunity( ) } else -> { - logger.warn("Received unsolicited disclosure from $peer, dropping.") + logger.warn("Received unsolicited disclosure from ${peer.mid}, dropping.") } } } @@ -419,9 +399,9 @@ class IdentityCommunity( } private fun onRequestMissing(peer: Peer, payload: RequestMissingPayload) { - logger.info("Received missing request from ${peer.mid} for ${payload.known} tokens") + logger.info("Received missing request from ${peer.mid} for ${payload.known} tokens.") var out = byteArrayOf() - val permitted = this.tokenChain.subList(0, this.permissions.get(peer) ?: 0) + val permitted = this.tokenChain.subList(0, this.permissions[peer] ?: 0) permitted.forEachIndexed { index, token -> if (index >= payload.known) { val serialized = token.getPlaintextSigned() @@ -464,6 +444,34 @@ class IdentityCommunity( } } + fun setAttestationPresentationCallback(f: (peer: Peer, attributeHash: ByteArray, value: ByteArray, metadata: Metadata, attestations: List, disclosureInformation: String) -> Unit) { + this.attestationPresentationCallback = f + } + + private fun onDisclosureWrapper(packet: Packet) { + val (peer, payload) = packet.getAuthPayload(DisclosePayload.Deserializer) + logger.info(" Disclose payload from ${peer.mid}.") + this.onDisclosure(peer, payload) + } + + private fun onAttestWrapper(packet: Packet) { + val (peer, payload) = packet.getAuthPayload(AttestPayload.Deserializer) + logger.info("Received Attest payload from ${peer.mid}.") + this.onAttest(peer, payload) + } + + private fun onRequestMissingWrapper(packet: Packet) { + val (peer, payload) = packet.getAuthPayload(RequestMissingPayload.Deserializer) + logger.info("Received Request Missing payload from ${peer.mid}.") + this.onRequestMissing(peer, payload) + } + + private fun onMissingResponseWrapper(packet: Packet) { + val (peer, payload) = packet.getAuthPayload(MissingResponsePayload.Deserializer) + logger.info("Received Missing Response payload from ${peer.mid}.") + this.onMissingResponse(peer, payload) + } + override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/consts/MetadataConsts.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/consts/MetadataConsts.kt new file mode 100644 index 00000000..c35d26f1 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/consts/MetadataConsts.kt @@ -0,0 +1,9 @@ +package nl.tudelft.ipv8.attestation.identity.consts + +object Metadata { + const val NAME = "name" + const val SCHEMA = "schema" + const val DATE = "date" + const val VALUE = "value" + const val ID = "id" +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/consts/PayloadConsts.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/consts/PayloadConsts.kt new file mode 100644 index 00000000..27dee285 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/consts/PayloadConsts.kt @@ -0,0 +1,8 @@ +package nl.tudelft.ipv8.attestation.identity.consts + +object PayloadIds { + const val DISCLOSURE_PAYLOAD = 1 + const val ATTEST_PAYLOAD = 2 + const val REQUEST_MISSING_PAYLOAD = 3 + const val MISSING_RESPONSE_PAYLOAD = 4 +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/datastructures/IdentityAttestation.kt similarity index 94% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/datastructures/IdentityAttestation.kt index 875d7340..c29e93cc 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityAttestation.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/datastructures/IdentityAttestation.kt @@ -1,6 +1,5 @@ -package nl.tudelft.ipv8.attestation.identity +package nl.tudelft.ipv8.attestation.identity.datastructures -import nl.tudelft.ipv8.attestation.SignedObject import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.util.toHex diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/datastructures/Metadata.kt similarity index 93% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/datastructures/Metadata.kt index 81774dc6..b9e0c2bd 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/Metadata.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/datastructures/Metadata.kt @@ -1,7 +1,6 @@ -package nl.tudelft.ipv8.attestation.identity +package nl.tudelft.ipv8.attestation.identity.datastructures -import nl.tudelft.ipv8.attestation.SignedObject -import nl.tudelft.ipv8.attestation.tokenTree.Token +import nl.tudelft.ipv8.attestation.identity.datastructures.tokenTree.Token import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.util.toHex diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/SignedObject.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/datastructures/SignedObject.kt similarity index 95% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/SignedObject.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/datastructures/SignedObject.kt index d886b32a..549519ec 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/SignedObject.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/datastructures/SignedObject.kt @@ -1,4 +1,4 @@ -package nl.tudelft.ipv8.attestation +package nl.tudelft.ipv8.attestation.identity.datastructures import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.PublicKey @@ -10,7 +10,6 @@ abstract class SignedObject(val privateKey: PrivateKey? = null, private val know var hash = byteArrayOf() open lateinit var signature: ByteArray - private val crypto = defaultCryptoProvider fun init() { this.sign(privateKey, knownSignature) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/datastructures/tokenTree/Token.kt similarity index 95% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/datastructures/tokenTree/Token.kt index 31184604..d68d03c8 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/Token.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/datastructures/tokenTree/Token.kt @@ -1,6 +1,6 @@ -package nl.tudelft.ipv8.attestation.tokenTree +package nl.tudelft.ipv8.attestation.identity.datastructures.tokenTree -import nl.tudelft.ipv8.attestation.SignedObject +import nl.tudelft.ipv8.attestation.identity.datastructures.SignedObject import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.util.sha3_256 diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/datastructures/tokenTree/TokenTree.kt similarity index 98% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/datastructures/tokenTree/TokenTree.kt index da500937..ee0157a9 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/datastructures/tokenTree/TokenTree.kt @@ -1,4 +1,4 @@ -package nl.tudelft.ipv8.attestation.tokenTree +package nl.tudelft.ipv8.attestation.identity.datastructures.tokenTree import mu.KotlinLogging import nl.tudelft.ipv8.keyvault.PrivateKey diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt index fbeda0a9..ebd18486 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt @@ -1,8 +1,8 @@ package nl.tudelft.ipv8.attestation.identity.manager -import nl.tudelft.ipv8.attestation.identity.IdentityAttestation -import nl.tudelft.ipv8.attestation.identity.Metadata -import nl.tudelft.ipv8.attestation.identity.database.IdentityStore +import nl.tudelft.ipv8.attestation.identity.datastructures.IdentityAttestation +import nl.tudelft.ipv8.attestation.identity.datastructures.Metadata +import nl.tudelft.ipv8.attestation.identity.store.IdentityStore import nl.tudelft.ipv8.keyvault.Key import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.PublicKey diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt index 7cca3f3f..248515d6 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt @@ -1,12 +1,12 @@ package nl.tudelft.ipv8.attestation.identity.manager import mu.KotlinLogging -import nl.tudelft.ipv8.attestation.identity.IdentityAttestation -import nl.tudelft.ipv8.attestation.identity.Metadata -import nl.tudelft.ipv8.attestation.identity.database.Credential -import nl.tudelft.ipv8.attestation.identity.database.IdentityStore -import nl.tudelft.ipv8.attestation.tokenTree.Token -import nl.tudelft.ipv8.attestation.tokenTree.TokenTree +import nl.tudelft.ipv8.attestation.identity.datastructures.IdentityAttestation +import nl.tudelft.ipv8.attestation.identity.datastructures.Metadata +import nl.tudelft.ipv8.attestation.identity.store.Credential +import nl.tudelft.ipv8.attestation.identity.store.IdentityStore +import nl.tudelft.ipv8.attestation.identity.datastructures.tokenTree.Token +import nl.tudelft.ipv8.attestation.identity.datastructures.tokenTree.TokenTree import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.messaging.serializeUInt diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/store/IdentitySQLiteStore.kt similarity index 93% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/store/IdentitySQLiteStore.kt index 4f0975f0..447e4f6f 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentitySQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/store/IdentitySQLiteStore.kt @@ -1,8 +1,8 @@ -package nl.tudelft.ipv8.attestation.identity.database +package nl.tudelft.ipv8.attestation.identity.store -import nl.tudelft.ipv8.attestation.identity.IdentityAttestation -import nl.tudelft.ipv8.attestation.identity.Metadata -import nl.tudelft.ipv8.attestation.tokenTree.Token +import nl.tudelft.ipv8.attestation.identity.datastructures.IdentityAttestation +import nl.tudelft.ipv8.attestation.identity.datastructures.Metadata +import nl.tudelft.ipv8.attestation.identity.datastructures.tokenTree.Token import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.keyvault.defaultCryptoProvider import nl.tudelft.ipv8.sqldelight.Database diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentityStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/store/IdentityStore.kt similarity index 79% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentityStore.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/store/IdentityStore.kt index f821fce3..f09742f7 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/database/IdentityStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/store/IdentityStore.kt @@ -1,8 +1,8 @@ -package nl.tudelft.ipv8.attestation.identity.database +package nl.tudelft.ipv8.attestation.identity.store -import nl.tudelft.ipv8.attestation.identity.IdentityAttestation -import nl.tudelft.ipv8.attestation.identity.Metadata -import nl.tudelft.ipv8.attestation.tokenTree.Token +import nl.tudelft.ipv8.attestation.identity.datastructures.IdentityAttestation +import nl.tudelft.ipv8.attestation.identity.datastructures.Metadata +import nl.tudelft.ipv8.attestation.identity.datastructures.tokenTree.Token import nl.tudelft.ipv8.keyvault.PublicKey class Credential(val metadata: Metadata, val attestations: Set) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt index 04cd159e..37ecc0fc 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt @@ -1,11 +1,10 @@ package nl.tudelft.ipv8.attestation.revocation import mu.KotlinLogging -import nl.tudelft.ipv8.attestation.Authority +import nl.tudelft.ipv8.attestation.common.Authority import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.keyvault.defaultCryptoProvider import nl.tudelft.ipv8.sqldelight.Database -import nl.tudelft.ipv8.sqldelight.GetAllRevocations private val authorityMapper: ( ByteArray?, diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt index 3db11245..5fe23493 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt @@ -1,9 +1,7 @@ package nl.tudelft.ipv8.attestation.revocation -import nl.tudelft.ipv8.attestation.Authority -import nl.tudelft.ipv8.attestation.Revocations +import nl.tudelft.ipv8.attestation.common.Authority import nl.tudelft.ipv8.keyvault.PublicKey -import nl.tudelft.ipv8.sqldelight.GetAllRevocations class RevocationBlob( val publicKeyHash: ByteArray, diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt index 87701bcd..7f562fdd 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt @@ -5,13 +5,13 @@ import mu.KotlinLogging import nl.tudelft.ipv8.Community import nl.tudelft.ipv8.Overlay import nl.tudelft.ipv8.Peer -import nl.tudelft.ipv8.attestation.AuthorityManager +import nl.tudelft.ipv8.attestation.common.AuthorityManager import nl.tudelft.ipv8.attestation.revocation.caches.PENDING_REVOCATION_UPDATE_CACHE_PREFIX import nl.tudelft.ipv8.attestation.revocation.caches.PendingRevocationUpdateCache import nl.tudelft.ipv8.attestation.revocation.payloads.RevocationUpdateChunkPayload import nl.tudelft.ipv8.attestation.revocation.payloads.RevocationUpdatePreviewPayload import nl.tudelft.ipv8.attestation.revocation.payloads.RevocationUpdateRequestPayload -import nl.tudelft.ipv8.attestation.RequestCache +import nl.tudelft.ipv8.attestation.common.RequestCache import nl.tudelft.ipv8.attestation.wallet.caches.PeerCache import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.messaging.* diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt index 571276b8..a380ddef 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt @@ -1,6 +1,6 @@ package nl.tudelft.ipv8.attestation.revocation.caches -import nl.tudelft.ipv8.attestation.RequestCache +import nl.tudelft.ipv8.attestation.common.RequestCache import nl.tudelft.ipv8.attestation.wallet.caches.HashCache import nl.tudelft.ipv8.attestation.wallet.caches.NumberCache import nl.tudelft.ipv8.util.sha1 diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt index e1a16bac..778ae474 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt @@ -8,19 +8,25 @@ import nl.tudelft.ipv8.Community import nl.tudelft.ipv8.IPv4Address import nl.tudelft.ipv8.Overlay import nl.tudelft.ipv8.Peer -import nl.tudelft.ipv8.attestation.WalletAttestation -import nl.tudelft.ipv8.attestation.IdentityAlgorithm -import nl.tudelft.ipv8.attestation.AuthorityManager -import nl.tudelft.ipv8.attestation.RequestCache -import nl.tudelft.ipv8.attestation.schema.* -import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity.MessageId.ATTESTATION -import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity.MessageId.ATTESTATION_REQUEST -import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity.MessageId.CHALLENGE -import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity.MessageId.CHALLENGE_RESPONSE -import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity.MessageId.VERIFY_ATTESTATION_REQUEST +import nl.tudelft.ipv8.attestation.wallet.cryptography.IdentityAlgorithm +import nl.tudelft.ipv8.attestation.common.AuthorityManager +import nl.tudelft.ipv8.attestation.common.RequestCache +import nl.tudelft.ipv8.attestation.common.SchemaManager +import nl.tudelft.ipv8.attestation.common.consts.SchemaConstants.ID_METADATA import nl.tudelft.ipv8.attestation.wallet.caches.* +import nl.tudelft.ipv8.attestation.wallet.consts.Metadata.ATTRIBUTE +import nl.tudelft.ipv8.attestation.wallet.consts.Metadata.ID_FORMAT +import nl.tudelft.ipv8.attestation.wallet.consts.Metadata.PROPOSED_VALUE +import nl.tudelft.ipv8.attestation.wallet.consts.Metadata.PUBLIC_KEY import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPrivateKey import nl.tudelft.ipv8.attestation.wallet.payloads.* +import nl.tudelft.ipv8.attestation.wallet.consts.PayloadIds.ATTESTATION +import nl.tudelft.ipv8.attestation.wallet.consts.PayloadIds.ATTESTATION_REQUEST +import nl.tudelft.ipv8.attestation.wallet.consts.PayloadIds.CHALLENGE +import nl.tudelft.ipv8.attestation.wallet.consts.PayloadIds.CHALLENGE_RESPONSE +import nl.tudelft.ipv8.attestation.wallet.consts.PayloadIds.VERIFY_ATTESTATION_REQUEST +import nl.tudelft.ipv8.attestation.wallet.cryptography.WalletAttestation +import nl.tudelft.ipv8.attestation.wallet.store.AttestationStore import nl.tudelft.ipv8.messaging.EndpointAggregator import nl.tudelft.ipv8.messaging.Packet import nl.tudelft.ipv8.messaging.deserializeVarLen @@ -119,17 +125,17 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: logger.info("Sending attestation request $attributeName to peer ${peer.mid}.") val publicKey = privateKey.publicKey() val inputMetadata = JSONObject(metadata) - val idFormat = (inputMetadata.remove("id_format") ?: ID_METADATA) as String + val idFormat = (inputMetadata.remove(ID_FORMAT) ?: ID_METADATA) as String val metadataJson = JSONObject() - metadataJson.put("attribute", attributeName) + metadataJson.put(ATTRIBUTE, attributeName) metadataJson.put( - "public_key", + PUBLIC_KEY, defaultEncodingUtils.encodeBase64ToString(publicKey.serialize()) ) - metadataJson.put("id_format", idFormat) + metadataJson.put(ID_FORMAT, idFormat) // Will not be added if null. - metadataJson.put("proposed_value", proposedValue) + metadataJson.put(PROPOSED_VALUE, proposedValue) inputMetadata.keys().forEach { metadataJson.put(it, inputMetadata.get(it)) @@ -197,13 +203,13 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: ) { val metadata = JSONObject(payload.metadata) - val attribute = metadata.remove("attribute") as String - val encodedPK = metadata.remove("public_key") as String - val idFormat = metadata.remove("id_format") as String + val attribute = metadata.remove(ATTRIBUTE) as String + val encodedPK = metadata.remove(PUBLIC_KEY) as String + val idFormat = metadata.remove(ID_FORMAT) as String var proposedValue: String? = null // We cannot cast null to string, hence member checking. - if (metadata.has("proposed_value")) { - proposedValue = metadata.remove("proposed_value") as String + if (metadata.has(PROPOSED_VALUE)) { + proposedValue = metadata.remove(PROPOSED_VALUE) as String } val metadataString = metadata.toString() @@ -303,7 +309,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val value = verifyRequestCallback(peer, hash).await() if (value == null || !value) { - logger.info("Verify request callback returned false for $peer, ${payload.hash}") + logger.info("Verify request callback returned false for $peer, ${payload.hash.toHex()}") return } @@ -375,7 +381,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: ) } - logger.info("Received attestation chunk ${payload.sequenceNumber} for proving by $peer") + logger.info("Received attestation chunk ${payload.sequenceNumber} for proving by ${peer.mid}") } else { var handled = false for (peerId in peerIds) { @@ -464,7 +470,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: cache.relativityMap = relativityMap cache.hashedChallenges = hashedChallenges cache.challenges = challenges - logger.info("Sending ${challenges.size} challenges to $peer.") + logger.info("Sending ${challenges.size} challenges to ${peer.mid}.") var remaining = 10 for (challenge in challenges) { @@ -493,7 +499,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: private fun onChallenge(peer: Peer, payload: ChallengePayload) { if (!this.attestationKeys.containsKey(payload.attestationHash.toKey())) { - logger.error("Received ChallengePayload $payload for unknown attestation hash ${payload.attestationHash}.") + logger.error("Received ChallengePayload $payload for unknown attestation hash ${payload.attestationHash.toHex()}.") return } @@ -568,7 +574,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: } if (provingCache.hashedChallenges.isEmpty()) { - logger.info("Completed attestation verification") + logger.info("Completed attestation verification.") // TODO: We can most likely directly call pop. if (this.requestCache.has(provingCachePrefix, provingCacheId)) { this.requestCache.pop(provingCachePrefix, provingCacheId) @@ -651,7 +657,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: private fun onChallengeResponseWrapper(packet: Packet) { val (peer, payload) = packet.getAuthPayload(ChallengeResponsePayload.Deserializer) logger.info( - "Received ChallengeResponse from ${peer.mid} for hash ${String(payload.challengeHash)} with response ${ + "Received ChallengeResponse from ${peer.mid} for hash ${payload.challengeHash.toHex()} with response ${ String(payload.response) }." ) @@ -661,7 +667,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: private fun onChallengeWrapper(packet: Packet) { val (peer, payload) = packet.getAuthPayload(ChallengePayload.Deserializer) logger.info( - "Received Challenge from ${peer.mid} for hash ${String(payload.attestationHash)} with challenge ${ + "Received Challenge from ${peer.mid} for hash ${payload.attestationHash.toHex()} with challenge ${ String(payload.challenge) }." ) @@ -676,7 +682,7 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: private fun onVerifyAttestationRequestWrapper(packet: Packet) { val (peer, payload) = packet.getAuthPayload(VerifyAttestationRequestPayload.Deserializer) - logger.info("Received VerifyAttestationRequest from ${peer.mid} for hash ${String(payload.hash)}.") + logger.info("Received VerifyAttestationRequest from ${peer.mid} for hash ${payload.hash.toHex()}.") GlobalScope.launch { onVerifyAttestationRequest(peer, payload) } } @@ -701,14 +707,6 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: return this.schemaManager.getAlgorithmInstance(idFormat) } - object MessageId { - const val VERIFY_ATTESTATION_REQUEST = 1 - const val ATTESTATION = 2 - const val CHALLENGE = 3 - const val CHALLENGE_RESPONSE = 4 - const val ATTESTATION_REQUEST = 5 - } - class Factory( private val authorityManager: AuthorityManager, private val database: AttestationStore, diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/HashCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/HashCache.kt index 8a0c66d1..d2eee63c 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/HashCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/HashCache.kt @@ -1,6 +1,6 @@ package nl.tudelft.ipv8.attestation.wallet.caches -import nl.tudelft.ipv8.attestation.RequestCache +import nl.tudelft.ipv8.attestation.common.RequestCache import java.math.BigInteger open class HashCache(requestCache: RequestCache, prefix: String, cacheHash: ByteArray, val idFormat: String) : diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt index 0d626a6a..47195c89 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt @@ -2,7 +2,7 @@ package nl.tudelft.ipv8.attestation.wallet.caches import kotlinx.coroutines.* import mu.KotlinLogging -import nl.tudelft.ipv8.attestation.RequestCache +import nl.tudelft.ipv8.attestation.common.RequestCache import java.math.BigInteger private val logger = KotlinLogging.logger {} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt index e21b4a61..06277166 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/PeerCache.kt @@ -1,6 +1,6 @@ package nl.tudelft.ipv8.attestation.wallet.caches -import nl.tudelft.ipv8.attestation.RequestCache +import nl.tudelft.ipv8.attestation.common.RequestCache import java.math.BigInteger open class PeerCache(cache: RequestCache, prefix: String, val mid: String, val idFormat: String) : diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/consts/MetadataConsts.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/consts/MetadataConsts.kt new file mode 100644 index 00000000..e31cb492 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/consts/MetadataConsts.kt @@ -0,0 +1,8 @@ +package nl.tudelft.ipv8.attestation.wallet.consts + +object Metadata { + const val ID_FORMAT = "id_format" + const val ATTRIBUTE = "attribute" + const val PUBLIC_KEY = "public_key" + const val PROPOSED_VALUE = "proposed_value" +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/consts/PayloadConsts.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/consts/PayloadConsts.kt new file mode 100644 index 00000000..074f2751 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/consts/PayloadConsts.kt @@ -0,0 +1,9 @@ +package nl.tudelft.ipv8.attestation.wallet.consts + +object PayloadIds { + const val VERIFY_ATTESTATION_REQUEST = 1 + const val ATTESTATION = 2 + const val CHALLENGE = 3 + const val CHALLENGE_RESPONSE = 4 + const val ATTESTATION_REQUEST = 5 +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/IdentityFormats.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/IdentityAlgorithm.kt similarity index 67% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/IdentityFormats.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/IdentityAlgorithm.kt index 3877f2ae..d8643121 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/IdentityFormats.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/IdentityAlgorithm.kt @@ -1,9 +1,7 @@ -package nl.tudelft.ipv8.attestation +package nl.tudelft.ipv8.attestation.wallet.cryptography import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPrivateKey import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPublicKey -import nl.tudelft.ipv8.util.sha1 -import java.math.BigDecimal abstract class IdentityAlgorithm(idFormat: String, formats: HashMap>) { var honestCheck = false @@ -52,34 +50,3 @@ abstract class IdentityAlgorithm(idFormat: String, formats: HashMap { this.attestationFunction = ::attestSHA256 this.aggregateReference = ::binaryRelativitySHA256 diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/BonehExactKeys.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/BonehExactKeys.kt index 5ceb7474..f97ac5af 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/BonehExactKeys.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/BonehExactKeys.kt @@ -1,8 +1,6 @@ package nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact -import nl.tudelft.ipv8.attestation.wallet.primitives.FP2Value -import nl.tudelft.ipv8.messaging.SERIALIZED_UINT_SIZE -import nl.tudelft.ipv8.messaging.deserializeUInt +import nl.tudelft.ipv8.attestation.wallet.cryptography.primitives.FP2Value import nl.tudelft.ipv8.messaging.deserializeVarLen import nl.tudelft.ipv8.messaging.serializeVarLen import java.math.BigInteger diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/PrimitiveFunctions.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/PrimitiveFunctions.kt index 37e3c3bb..05e0d245 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/PrimitiveFunctions.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/PrimitiveFunctions.kt @@ -1,7 +1,7 @@ package nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact -import nl.tudelft.ipv8.attestation.wallet.primitives.FP2Value -import nl.tudelft.ipv8.attestation.wallet.primitives.weilParing +import nl.tudelft.ipv8.attestation.wallet.cryptography.primitives.FP2Value +import nl.tudelft.ipv8.attestation.wallet.cryptography.primitives.weilParing import java.math.BigInteger import java.security.KeyPairGenerator import java.security.SecureRandom diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/attestations/BitPairAttestation.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/attestations/BitPairAttestation.kt index 3c1d4bad..e40717e5 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/attestations/BitPairAttestation.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/attestations/BitPairAttestation.kt @@ -1,6 +1,6 @@ package nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.attestations -import nl.tudelft.ipv8.attestation.wallet.primitives.FP2Value +import nl.tudelft.ipv8.attestation.wallet.cryptography.primitives.FP2Value import nl.tudelft.ipv8.messaging.deserializeVarLen import nl.tudelft.ipv8.messaging.serializeVarLen import java.math.BigInteger diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/attestations/BonehAttestation.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/attestations/BonehAttestation.kt index 94c2148e..d3518fd9 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/attestations/BonehAttestation.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/attestations/BonehAttestation.kt @@ -1,6 +1,6 @@ package nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.attestations -import nl.tudelft.ipv8.attestation.WalletAttestation +import nl.tudelft.ipv8.attestation.wallet.cryptography.WalletAttestation import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPrivateKey import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPublicKey import nl.tudelft.ipv8.messaging.SERIALIZED_USHORT_SIZE diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/Boudot.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/Boudot.kt deleted file mode 100644 index 4ddda52c..00000000 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/Boudot.kt +++ /dev/null @@ -1,170 +0,0 @@ -package nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange - -import nl.tudelft.ipv8.attestation.wallet.primitives.FP2Value -import nl.tudelft.ipv8.messaging.* -import nl.tudelft.ipv8.util.sha256AsBigInt -import java.math.BigInteger -import java.security.SecureRandom -import kotlin.math.ceil -import kotlin.math.log - -fun secureRandomNumber(min: BigInteger, max: BigInteger): BigInteger { - val normalizedRange = max - min - // TODO: We lose precision due to double conversion. - val n = ceil(log(normalizedRange.toDouble(), 2.toDouble())) - val returnBytes = BigInteger(n.toInt(), SecureRandom()) - val returnValue = min + (returnBytes.mod(normalizedRange)) - return if (returnValue >= min && returnValue < max) returnValue else secureRandomNumber(min, max) -} - - -private fun pack(vararg numbers: BigInteger): ByteArray { - var signByte = 0 - var packed = byteArrayOf() - - for (n in numbers) { - signByte = signByte shl 1 - signByte = signByte or (if (n < BigInteger.ZERO) 1 else 0) - packed = serializeVarLen(if (n < BigInteger.ZERO) (-n).toByteArray() else n.toByteArray()) + packed - } - - return serializeUChar(signByte.toUByte()) + packed -} - -private fun unpack(serialized: ByteArray, amount: Int): Pair, ByteArray> { - val buffer = serialized.copyOfRange(1, serialized.size) - var offset = 0 - val numbers = arrayListOf() - var signByte = deserializeUChar(serialized.copyOfRange(0, 1)).toInt() - - while (offset <= buffer.size && numbers.size < amount) { - val (deserializedValue, localOffset) = deserializeVarLen(buffer, offset) - offset += localOffset - val value = BigInteger(deserializedValue) - val isNegative = ((signByte and 0x01) == 1) - signByte = signByte shr 1 - numbers.add(if (isNegative) -value else value) - } - return Pair(numbers.reversed(), buffer.copyOfRange(offset, buffer.size)) -} - -const val NUM_PARAMS = 4 - -class EL(val c: BigInteger, val d: BigInteger, val d1: BigInteger, val d2: BigInteger) { - - fun check(g1: FP2Value, h1: FP2Value, g2: FP2Value, h2: FP2Value, y1: FP2Value, y2: FP2Value): Boolean { - var cW1 = g1.bigIntPow(this.d) * h1.bigIntPow(this.d1) * y1.bigIntPow(-this.c) - var cW2 = g2.bigIntPow(this.d) * h2.bigIntPow(this.d2) * y2.bigIntPow(-this.c) - cW1 = (cW1.wpNominator() * cW1.wpDenomInverse()).normalize() - cW2 = (cW2.wpNominator() * cW2.wpDenomInverse()).normalize() - - return this.c == (sha256AsBigInt(cW1.a.toString().toByteArray() + cW1.b.toString() - .toByteArray() + cW2.a.toString().toByteArray() + cW2.b.toString().toByteArray())) - } - - fun serialize(): ByteArray { - return pack(this.c, this.d, this.d1, this.d2) - } - - companion object { - fun create( - x: BigInteger, - r1: BigInteger, - r2: BigInteger, - g1: FP2Value, - h1: FP2Value, - g2: FP2Value, - h2: FP2Value, - b: Int, - bitSpace: Int, - t: Int = 80, - l: Int = 40, - ): EL { - val maxRangeW = 2 xor (l + t) * b - 1 - val maxRangeN = BigInteger("2") xor (l + t + bitSpace).toBigInteger() * g1.mod - BigInteger.ONE - val w = secureRandomNumber(BigInteger.ONE, maxRangeW.toBigInteger()) - val n1 = secureRandomNumber(BigInteger.ONE, maxRangeN) - val n2 = secureRandomNumber(BigInteger.ONE, maxRangeN) - val w1 = g1.bigIntPow(w) * h1.bigIntPow(n1) - val w2 = g2.bigIntPow(w) * h2.bigIntPow(n2) - val cW1 = (w1.wpNominator() * w1.wpDenomInverse()).normalize() - val cW2 = (w2.wpNominator() * w2.wpDenomInverse()).normalize() - - val c = - sha256AsBigInt(cW1.a.toString().toByteArray() + cW1.b.toString().toByteArray() + cW2.a.toString() - .toByteArray() + cW2.b.toString().toByteArray()) - - val d = w + c * x - val d1 = n1 + c * r1 - val d2 = n2 + c * r2 - - return EL(c, d, d1, d2) - } - - fun deserialize(serialized: ByteArray): Pair { - val (values, remainder) = unpack(serialized, NUM_PARAMS) - return Pair(EL(values[0], values[1], values[2], values[3]), remainder) - } - } - - override fun equals(other: Any?): Boolean { - if (other !is EL) - return false - return (this.c == other.c && this.d == other.d && this.d1 == other.d1 && this.d2 == other.d2) - } - - override fun hashCode(): Int { - return 6976 - } - - override fun toString(): String { - return "EL<$c,$d,$d1,$d2>" - } -} - -class SQR(val f: FP2Value, val el: EL) { - - fun check(g: FP2Value, h: FP2Value, y: FP2Value): Boolean { - return this.el.check(g, h, this.f, h, this.f, y) - } - - fun serialize(): ByteArray { - val minF = this.f.wpCompress() - return serializeVarLen(minF.mod.toByteArray()) + serializeVarLen(minF.a.toByteArray()) + serializeVarLen(minF.b.toByteArray()) + serializeVarLen( - this.el.serialize()) - } - - companion object { - fun create(x: BigInteger, r1: BigInteger, g: FP2Value, h: FP2Value, b: Int, bitSpace: Int): SQR { - val r2 = secureRandomNumber(-BigInteger("2") xor bitSpace.toBigInteger() * g.mod + BigInteger.ONE, - BigInteger("2") xor bitSpace.toBigInteger() * g.mod - BigInteger.ONE) - val f = g.bigIntPow(x) * h.bigIntPow(r2) - val r3 = r1 - r2 * x - return SQR(f, EL.create(x, r2, r3, g, h, f, h, b, bitSpace)) - } - - fun deserialize(serialized: ByteArray): Pair { - val (deserialized, rem) = deserializeAmount(serialized, NUM_PARAMS) - val mod = BigInteger(deserialized[0]) - val a = BigInteger(deserialized[1]) - val b = BigInteger(deserialized[2]) - val (el, _) = EL.deserialize(deserialized[3]) - return Pair(SQR(FP2Value(mod, a, b), el), rem) - - } - } - - override fun equals(other: Any?): Boolean { - if (other !is SQR) - return false - return (this.f == other.f && this.el == other.el) - } - - override fun hashCode(): Int { - return 838182 - } - - override fun toString(): String { - return "SQR<$f,$el>" - } -} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/PengBao.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/PengBao.kt index aabc8378..fe48718a 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/PengBao.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/PengBao.kt @@ -1,10 +1,12 @@ package nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange -import nl.tudelft.ipv8.attestation.IdentityAlgorithm -import nl.tudelft.ipv8.attestation.WalletAttestation +import nl.tudelft.ipv8.attestation.common.consts.AlgorithmNames.PENG_BAO_RANGE +import nl.tudelft.ipv8.attestation.wallet.cryptography.IdentityAlgorithm +import nl.tudelft.ipv8.attestation.wallet.cryptography.WalletAttestation import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPrivateKey import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPublicKey import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.generateKeypair +import nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.attestations.PengBaoAttestation import nl.tudelft.ipv8.messaging.deserializeBool import nl.tudelft.ipv8.messaging.deserializeRecursively import nl.tudelft.ipv8.messaging.serializeVarLen @@ -15,21 +17,7 @@ import java.security.SecureRandom const val LARGE_INTEGER = 32765 -private fun safeRandomNumber(keySize: Int, mod: BigInteger): BigInteger { - val random = SecureRandom() - val largeBigInteger = LARGE_INTEGER.toBigInteger() - fun randomNumber(): BigInteger { - return BigInteger(keySize, random).mod(mod) - } - - var out = randomNumber() - while (out < largeBigInteger) { - out = randomNumber() - } - return out -} - -class Pengbaorange(idFormat: String, formats: HashMap>) : +class PengBaoRange(idFormat: String, formats: HashMap>) : IdentityAlgorithm(idFormat, formats) { private val keySize: Int @@ -37,22 +25,22 @@ class Pengbaorange(idFormat: String, formats: HashMap 512) { throw RuntimeException("Illegal key size specified.") } - a = format.get("min") as Int - b = format.get("max") as Int + a = format["min"] as Int + b = format["max"] as Int } override fun generateSecretKey(): BonehPrivateKey { @@ -85,9 +73,11 @@ class Pengbaorange(idFormat: String, formats: HashMap { val mod = publicKey.g.mod - BigInteger.ONE - return arrayListOf(serializeVarLen(safeRandomNumber(this.keySize, mod).toByteArray()) + serializeVarLen( - safeRandomNumber(this.keySize, mod).toByteArray())) - + return arrayListOf( + serializeVarLen(safeRandomNumber(this.keySize, mod).toByteArray()) + serializeVarLen( + safeRandomNumber(this.keySize, mod).toByteArray() + ) + ) } override fun createChallengeResponse( @@ -118,7 +108,6 @@ class Pengbaorange(idFormat: String, formats: HashMap } - override fun processChallengeResponse( aggregate: HashMap, challenge: ByteArray?, @@ -132,7 +121,6 @@ class Pengbaorange(idFormat: String, formats: HashMap { - val (deserialized, rem) = deserializeAmount(serialized, 2) - val a = BigInteger(deserialized[0]) - val b = BigInteger(deserialized[1]) - return Pair(FP2Value(mod, a, b), rem) -} - -const val PENG_BAO_COMMITMENT_NUM_PARAMS = 8 -const val PENG_BAO_PRIVATE_COMMITMENT_NUM_PARAMS = 6 - -class PengBaoCommitment( - val c: FP2Value, - val c1: FP2Value, - val c2: FP2Value, - val ca: FP2Value, - val ca1: FP2Value, - val ca2: FP2Value, - val ca3: FP2Value, - val caa: FP2Value, -) { - - fun serialize(): ByteArray { - return ( - serializeVarLen(this.c.mod.toByteArray()) + serializeFP2Value(this.c) + serializeFP2Value(this.c1) - + serializeFP2Value(this.c2) + serializeFP2Value(this.ca) + serializeFP2Value(this.ca1) - + serializeFP2Value(this.ca2) + serializeFP2Value(this.ca3) + serializeFP2Value(this.caa) - ) - } - - companion object { - fun deserialize(serialized: ByteArray): Pair { - val (deserializedMod, localOffset) = deserializeVarLen(serialized) - val mod = BigInteger(deserializedMod) - - var buffer = serialized.copyOfRange(localOffset, serialized.size) - val params = arrayListOf() - for (i in 0 until PENG_BAO_COMMITMENT_NUM_PARAMS) { - val (param, rem) = deserializeFP2Value(mod, buffer) - params.add(param) - buffer = rem - } - - return Pair(PengBaoCommitment(params[0], - params[1], - params[2], - params[3], - params[4], - params[5], - params[6], - params[7]), buffer) - - } - } -} - -class PengBaoCommitmentPrivate( - val m1: BigInteger, - val m2: BigInteger, - val m3: BigInteger, - val r1: BigInteger, - val r2: BigInteger, - val r3: BigInteger, -) { - - - fun generateResponse(s: BigInteger, t: BigInteger): List { - return listOf(s * this.m1 + this.m2 + this.m3, - this.m1 + t * this.m2 + this.m3, - s * this.r1 + this.r2 + this.r3, - this.r1 + t * this.r2 + this.r3) - } - - fun serialize(): ByteArray { - return serializeVarLen(this.m1.toByteArray()) + serializeVarLen(this.m2.toByteArray()) + serializeVarLen(this.m3.toByteArray()) + serializeVarLen( - this.r1.toByteArray()) + serializeVarLen(this.r2.toByteArray()) + serializeVarLen(this.r3.toByteArray()) - } - - fun encode(publicKey: BonehPublicKey): ByteArray { - val serialized = this.serialize() - val hexSerialized = serialized.toHex() - var serializedEncodings = serializeUChar((hexSerialized.length / 2).toUByte()) - for (i in hexSerialized.indices step 2) { - val intValue = Integer.parseInt(hexSerialized.substring(i, i + 2), 16) - serializedEncodings += serializeFP2Value(encode(publicKey, intValue.toBigInteger())) - } - return serializedEncodings - } - - companion object { - val MSG_SPACE = (0 until 256).toList().toTypedArray() - - fun deserialize(serialized: ByteArray): Pair { - val (values, rem) = deserializeAmount(serialized, PENG_BAO_PRIVATE_COMMITMENT_NUM_PARAMS) - val m1 = BigInteger(values[0]) - val m2 = BigInteger(values[1]) - val m3 = BigInteger(values[2]) - val r1 = BigInteger(values[3]) - val r2 = BigInteger(values[4]) - val r3 = BigInteger(values[5]) - - return Pair(PengBaoCommitmentPrivate(m1, m2, m3, r1, r2, r3), rem) - } - - fun decode(privateKey: BonehPrivateKey, serialized: ByteArray): PengBaoCommitmentPrivate { - var serialization = byteArrayOf() - val length = deserializeUChar(serialized.copyOfRange(0, 1)).toInt() - var rem = serialized.copyOfRange(1, serialized.size) - for (i in 0 until length) { - val (deserialized, localRem) = deserializeFP2Value(privateKey.g.mod, rem) - rem = localRem - var hexedRaw = decode(privateKey, MSG_SPACE, deserialized)!! - var hexed = hexedRaw.toString(16) - if (hexed.endsWith("L", true)) { - hexed = hexed.substring(0, hexed.lastIndex) - } - if (hexed.length % 2 == 1) { - hexed = "0$hexed" - } - serialization += hexed.hexToBytes() - } - return deserialize(serialization).first - } - } - -} - -class PengBaoPublicData( - val publicKey: BonehPublicKey, - val bitSpace: Int, - val commitment: PengBaoCommitment, - val el: EL, - val sqr1: SQR, - val sqr2: SQR, -) { - - fun check( - a: Int, - b: Int, - s: BigInteger, - t: BigInteger, - x: BigInteger, - y: BigInteger, - u: BigInteger, - v: BigInteger, - ): Boolean { - var out = this.el.check(this.publicKey.g, - this.publicKey.h, - this.commitment.c1, - this.publicKey.h, - this.commitment.c2, - this.commitment.ca) - out = out && this.sqr1.check(this.commitment.ca, this.publicKey.h, this.commitment.caa) - out = out && this.sqr2.check(this.publicKey.g, this.publicKey.h, this.commitment.ca3) - out = - out && this.commitment.c1 == this.commitment.c / this.publicKey.g.bigIntPow(a.toBigInteger() - BigInteger.ONE) - out = - out && this.commitment.c2 == this.publicKey.g.bigIntPow(b.toBigInteger() + BigInteger.ONE) / this.commitment.c - out = out && this.commitment.caa == this.commitment.ca1 * this.commitment.ca2 * this.commitment.ca3 - out = out && (this.publicKey.g.bigIntPow(x) * this.publicKey.h.bigIntPow(u) - == (this.commitment.ca1.bigIntPow(s) * this.commitment.ca2 * this.commitment.ca3)) - out = out && ((this.publicKey.g.bigIntPow(y) * this.publicKey.h.bigIntPow(v)) - == (this.commitment.ca1 * this.commitment.ca2.bigIntPow(t) * this.commitment.ca3)) - - return out && x > BigInteger.ZERO && y > BigInteger.ZERO - } - - fun serialize(): ByteArray { - return (this.publicKey.serialize() + serializeUChar(this.bitSpace.toUByte()) + this.commitment.serialize() - + this.el.serialize() + this.sqr1.serialize() + this.sqr2.serialize()) - } - - companion object { - fun deserialize(serialized: ByteArray): Pair { - val publicKey = BonehPublicKey.deserialize(serialized)!! - var rem = serialized.copyOfRange(publicKey.serialize().size, serialized.size) - val bitSpace = deserializeUChar(rem.copyOfRange(0, 1)).toInt() - rem = rem.copyOfRange(1, rem.size) - val (commitment, localRem) = PengBaoCommitment.deserialize(rem) - rem = localRem - val (el, localRem2) = EL.deserialize(rem) - rem = localRem2 - val (sqr1, localRem3) = SQR.deserialize(rem) - rem = localRem3 - val (sqr2, localRem4) = SQR.deserialize(rem) - rem = localRem4 - - return Pair(PengBaoPublicData(publicKey, bitSpace, commitment, el, sqr1, sqr2), rem) - } - } -} - -class PengBaoAttestation( - val publicData: PengBaoPublicData, - val privateData: PengBaoCommitmentPrivate?, - override val idFormat: String? = null, -) : WalletAttestation() { - - override val publicKey = publicData.publicKey - - override fun serialize(): ByteArray { - return this.publicData.serialize() - } - - override fun deserialize(serialized: ByteArray, idFormat: String): WalletAttestation { - return PengBaoAttestation.deserialize(serialized, idFormat) - } - - override fun serializePrivate(publicKey: BonehPublicKey): ByteArray { - return if (this.privateData != null) { - val publicData = this.publicData.serialize() - val privateData = this.privateData.encode(publicKey) - publicData + privateData - } else { - throw RuntimeException("Private data was null.") - } - } - - override fun deserializePrivate( - privateKey: BonehPrivateKey, - serialized: ByteArray, - idFormat: String?, - ): WalletAttestation { - return PengBaoAttestation.deserializePrivate(privateKey, serialized, idFormat) - } - - companion object { - fun deserialize(serialized: ByteArray, idFormat: String? = null): PengBaoAttestation { - val (pubicData, _) = PengBaoPublicData.deserialize(serialized) - return PengBaoAttestation(pubicData, null, idFormat) - } - - fun deserializePrivate( - privateKey: BonehPrivateKey, - serialized: ByteArray, - idFormat: String? = null, - ): PengBaoAttestation { - val (publicData, rem) = PengBaoPublicData.deserialize(serialized) - val privateData = PengBaoCommitmentPrivate.decode(privateKey, rem) - - return PengBaoAttestation(publicData, privateData, idFormat) - } - } -} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/attestations/PengBaoAttestation.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/attestations/PengBaoAttestation.kt new file mode 100644 index 00000000..82e7ed88 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/attestations/PengBaoAttestation.kt @@ -0,0 +1,60 @@ +package nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.attestations + +import nl.tudelft.ipv8.attestation.wallet.cryptography.WalletAttestation +import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPrivateKey +import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPublicKey +import nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.commitments.PengBaoPrivateData +import nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.commitments.PengBaoPublicData + +class PengBaoAttestation( + val publicData: PengBaoPublicData, + val privateData: PengBaoPrivateData?, + override val idFormat: String? = null, +) : WalletAttestation() { + + override val publicKey = publicData.publicKey + + override fun serialize(): ByteArray { + return this.publicData.serialize() + } + + override fun deserialize(serialized: ByteArray, idFormat: String): WalletAttestation { + return PengBaoAttestation.deserialize(serialized, idFormat) + } + + override fun serializePrivate(publicKey: BonehPublicKey): ByteArray { + return if (this.privateData != null) { + val publicData = this.publicData.serialize() + val privateData = this.privateData.encode(publicKey) + publicData + privateData + } else { + throw RuntimeException("Private data was null.") + } + } + + override fun deserializePrivate( + privateKey: BonehPrivateKey, + serialized: ByteArray, + idFormat: String?, + ): WalletAttestation { + return PengBaoAttestation.deserializePrivate(privateKey, serialized, idFormat) + } + + companion object { + fun deserialize(serialized: ByteArray, idFormat: String? = null): PengBaoAttestation { + val (pubicData, _) = PengBaoPublicData.deserialize(serialized) + return PengBaoAttestation(pubicData, null, idFormat) + } + + fun deserializePrivate( + privateKey: BonehPrivateKey, + serialized: ByteArray, + idFormat: String? = null, + ): PengBaoAttestation { + val (publicData, rem) = PengBaoPublicData.deserialize(serialized) + val privateData = PengBaoPrivateData.decode(privateKey, rem) + + return PengBaoAttestation(publicData, privateData, idFormat) + } + } +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/boudot/Util.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/boudot/Util.kt new file mode 100644 index 00000000..d736cf02 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/boudot/Util.kt @@ -0,0 +1,48 @@ +package nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.boudot + +import nl.tudelft.ipv8.messaging.* +import java.math.BigInteger +import java.security.SecureRandom +import kotlin.math.ceil +import kotlin.math.log + +const val NUM_PARAMS = 4 + +fun secureRandomNumber(min: BigInteger, max: BigInteger): BigInteger { + val normalizedRange = max - min + // TODO: We lose precision due to double conversion. + val n = ceil(log(normalizedRange.toDouble(), 2.toDouble())) + val returnBytes = BigInteger(n.toInt(), SecureRandom()) + val returnValue = min + (returnBytes.mod(normalizedRange)) + return if (returnValue >= min && returnValue < max) returnValue else secureRandomNumber(min, max) +} + +fun pack(vararg numbers: BigInteger): ByteArray { + var signByte = 0 + var packed = byteArrayOf() + + for (n in numbers) { + signByte = signByte shl 1 + signByte = signByte or (if (n < BigInteger.ZERO) 1 else 0) + packed = serializeVarLen(if (n < BigInteger.ZERO) (-n).toByteArray() else n.toByteArray()) + packed + } + + return serializeUChar(signByte.toUByte()) + packed +} + +fun unpack(serialized: ByteArray, amount: Int): Pair, ByteArray> { + val buffer = serialized.copyOfRange(1, serialized.size) + var offset = 0 + val numbers = arrayListOf() + var signByte = deserializeUChar(serialized.copyOfRange(0, 1)).toInt() + + while (offset <= buffer.size && numbers.size < amount) { + val (deserializedValue, localOffset) = deserializeVarLen(buffer, offset) + offset += localOffset + val value = BigInteger(deserializedValue) + val isNegative = ((signByte and 0x01) == 1) + signByte = signByte shr 1 + numbers.add(if (isNegative) -value else value) + } + return Pair(numbers.reversed(), buffer.copyOfRange(offset, buffer.size)) +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/boudot/primitives/EL.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/boudot/primitives/EL.kt new file mode 100644 index 00000000..9bb890f9 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/boudot/primitives/EL.kt @@ -0,0 +1,85 @@ +package nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.boudot.primitives + +import nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.boudot.NUM_PARAMS +import nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.boudot.pack +import nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.boudot.secureRandomNumber +import nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.boudot.unpack +import nl.tudelft.ipv8.attestation.wallet.cryptography.primitives.FP2Value +import nl.tudelft.ipv8.util.sha256AsBigInt +import java.math.BigInteger + +class EL(val c: BigInteger, val d: BigInteger, val d1: BigInteger, val d2: BigInteger) { + + fun check(g1: FP2Value, h1: FP2Value, g2: FP2Value, h2: FP2Value, y1: FP2Value, y2: FP2Value): Boolean { + var cW1 = g1.bigIntPow(this.d) * h1.bigIntPow(this.d1) * y1.bigIntPow(-this.c) + var cW2 = g2.bigIntPow(this.d) * h2.bigIntPow(this.d2) * y2.bigIntPow(-this.c) + cW1 = (cW1.wpNominator() * cW1.wpDenomInverse()).normalize() + cW2 = (cW2.wpNominator() * cW2.wpDenomInverse()).normalize() + + return this.c == (sha256AsBigInt( + cW1.a.toString().toByteArray() + cW1.b.toString() + .toByteArray() + cW2.a.toString().toByteArray() + cW2.b.toString().toByteArray() + )) + } + + fun serialize(): ByteArray { + return pack(this.c, this.d, this.d1, this.d2) + } + + companion object { + fun create( + x: BigInteger, + r1: BigInteger, + r2: BigInteger, + g1: FP2Value, + h1: FP2Value, + g2: FP2Value, + h2: FP2Value, + b: Int, + bitSpace: Int, + t: Int = 80, + l: Int = 40, + ): EL { + val maxRangeW = 2 xor (l + t) * b - 1 + val maxRangeN = BigInteger("2") xor (l + t + bitSpace).toBigInteger() * g1.mod - BigInteger.ONE + val w = secureRandomNumber(BigInteger.ONE, maxRangeW.toBigInteger()) + val n1 = secureRandomNumber(BigInteger.ONE, maxRangeN) + val n2 = secureRandomNumber(BigInteger.ONE, maxRangeN) + val w1 = g1.bigIntPow(w) * h1.bigIntPow(n1) + val w2 = g2.bigIntPow(w) * h2.bigIntPow(n2) + val cW1 = (w1.wpNominator() * w1.wpDenomInverse()).normalize() + val cW2 = (w2.wpNominator() * w2.wpDenomInverse()).normalize() + + val c = + sha256AsBigInt( + cW1.a.toString().toByteArray() + cW1.b.toString().toByteArray() + cW2.a.toString() + .toByteArray() + cW2.b.toString().toByteArray() + ) + + val d = w + c * x + val d1 = n1 + c * r1 + val d2 = n2 + c * r2 + + return EL(c, d, d1, d2) + } + + fun deserialize(serialized: ByteArray): Pair { + val (values, remainder) = unpack(serialized, NUM_PARAMS) + return Pair(EL(values[0], values[1], values[2], values[3]), remainder) + } + } + + override fun equals(other: Any?): Boolean { + if (other !is EL) + return false + return (this.c == other.c && this.d == other.d && this.d1 == other.d1 && this.d2 == other.d2) + } + + override fun hashCode(): Int { + return 6976 + } + + override fun toString(): String { + return "EL<$c,$d,$d1,$d2>" + } +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/boudot/primitives/SQR.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/boudot/primitives/SQR.kt new file mode 100644 index 00000000..d5c4a247 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/boudot/primitives/SQR.kt @@ -0,0 +1,58 @@ +package nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.boudot.primitives + +import nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.boudot.NUM_PARAMS +import nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.boudot.secureRandomNumber +import nl.tudelft.ipv8.attestation.wallet.cryptography.primitives.FP2Value +import nl.tudelft.ipv8.messaging.deserializeAmount +import nl.tudelft.ipv8.messaging.serializeVarLen +import java.math.BigInteger + +class SQR(val f: FP2Value, val el: EL) { + + fun check(g: FP2Value, h: FP2Value, y: FP2Value): Boolean { + return this.el.check(g, h, this.f, h, this.f, y) + } + + fun serialize(): ByteArray { + val minF = this.f.wpCompress() + return serializeVarLen(minF.mod.toByteArray()) + serializeVarLen(minF.a.toByteArray()) + serializeVarLen(minF.b.toByteArray()) + serializeVarLen( + this.el.serialize() + ) + } + + companion object { + + fun create(x: BigInteger, r1: BigInteger, g: FP2Value, h: FP2Value, b: Int, bitSpace: Int): SQR { + val r2 = secureRandomNumber( + -BigInteger("2") xor bitSpace.toBigInteger() * g.mod + BigInteger.ONE, + BigInteger("2") xor bitSpace.toBigInteger() * g.mod - BigInteger.ONE + ) + val f = g.bigIntPow(x) * h.bigIntPow(r2) + val r3 = r1 - r2 * x + return SQR(f, EL.create(x, r2, r3, g, h, f, h, b, bitSpace)) + } + + fun deserialize(serialized: ByteArray): Pair { + val (deserialized, rem) = deserializeAmount(serialized, NUM_PARAMS) + val mod = BigInteger(deserialized[0]) + val a = BigInteger(deserialized[1]) + val b = BigInteger(deserialized[2]) + val (el, _) = EL.deserialize(deserialized[3]) + return Pair(SQR(FP2Value(mod, a, b), el), rem) + } + } + + override fun equals(other: Any?): Boolean { + if (other !is SQR) + return false + return (this.f == other.f && this.el == other.el) + } + + override fun hashCode(): Int { + return 838182 + } + + override fun toString(): String { + return "SQR<$f,$el>" + } +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/commitments/PengBaoCommitment.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/commitments/PengBaoCommitment.kt new file mode 100644 index 00000000..41e3928a --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/commitments/PengBaoCommitment.kt @@ -0,0 +1,57 @@ +package nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.commitments + +import nl.tudelft.ipv8.attestation.wallet.cryptography.primitives.FP2Value +import nl.tudelft.ipv8.attestation.wallet.cryptography.util.PENG_BAO_COMMITMENT_NUM_PARAMS +import nl.tudelft.ipv8.attestation.wallet.cryptography.util.deserializeFP2Value +import nl.tudelft.ipv8.attestation.wallet.cryptography.util.serializeFP2Value +import nl.tudelft.ipv8.messaging.deserializeVarLen +import nl.tudelft.ipv8.messaging.serializeVarLen +import java.math.BigInteger + +class PengBaoCommitment( + val c: FP2Value, + val c1: FP2Value, + val c2: FP2Value, + val ca: FP2Value, + val ca1: FP2Value, + val ca2: FP2Value, + val ca3: FP2Value, + val caa: FP2Value, +) { + + fun serialize(): ByteArray { + return ( + serializeVarLen(this.c.mod.toByteArray()) + serializeFP2Value(this.c) + serializeFP2Value(this.c1) + + serializeFP2Value(this.c2) + serializeFP2Value(this.ca) + serializeFP2Value(this.ca1) + + serializeFP2Value(this.ca2) + serializeFP2Value(this.ca3) + serializeFP2Value(this.caa) + ) + } + + companion object { + fun deserialize(serialized: ByteArray): Pair { + val (deserializedMod, localOffset) = deserializeVarLen(serialized) + val mod = BigInteger(deserializedMod) + + var buffer = serialized.copyOfRange(localOffset, serialized.size) + val params = arrayListOf() + for (i in 0 until PENG_BAO_COMMITMENT_NUM_PARAMS) { + val (param, rem) = deserializeFP2Value(mod, buffer) + params.add(param) + buffer = rem + } + + return Pair( + PengBaoCommitment( + params[0], + params[1], + params[2], + params[3], + params[4], + params[5], + params[6], + params[7] + ), buffer + ) + } + } +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/commitments/PrivatePengBaoCommitment.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/commitments/PrivatePengBaoCommitment.kt new file mode 100644 index 00000000..81beda9c --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/commitments/PrivatePengBaoCommitment.kt @@ -0,0 +1,95 @@ +package nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.commitments + +import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPrivateKey +import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPublicKey +import nl.tudelft.ipv8.attestation.wallet.cryptography.util.PENG_BAO_PRIVATE_COMMITMENT_NUM_PARAMS +import nl.tudelft.ipv8.attestation.wallet.cryptography.util.deserializeFP2Value +import nl.tudelft.ipv8.attestation.wallet.cryptography.util.serializeFP2Value +import nl.tudelft.ipv8.messaging.deserializeAmount +import nl.tudelft.ipv8.messaging.deserializeUChar +import nl.tudelft.ipv8.messaging.serializeUChar +import nl.tudelft.ipv8.messaging.serializeVarLen +import nl.tudelft.ipv8.util.hexToBytes +import nl.tudelft.ipv8.util.toHex +import java.math.BigInteger + +class PengBaoPrivateData( + val m1: BigInteger, + val m2: BigInteger, + val m3: BigInteger, + val r1: BigInteger, + val r2: BigInteger, + val r3: BigInteger, +) { + + fun generateResponse(s: BigInteger, t: BigInteger): List { + return listOf( + s * this.m1 + this.m2 + this.m3, + this.m1 + t * this.m2 + this.m3, + s * this.r1 + this.r2 + this.r3, + this.r1 + t * this.r2 + this.r3 + ) + } + + fun serialize(): ByteArray { + return serializeVarLen(this.m1.toByteArray()) + serializeVarLen(this.m2.toByteArray()) + serializeVarLen(this.m3.toByteArray()) + serializeVarLen( + this.r1.toByteArray() + ) + serializeVarLen(this.r2.toByteArray()) + serializeVarLen(this.r3.toByteArray()) + } + + fun encode(publicKey: BonehPublicKey): ByteArray { + val serialized = this.serialize() + val hexSerialized = serialized.toHex() + var serializedEncodings = serializeUChar((hexSerialized.length / 2).toUByte()) + for (i in hexSerialized.indices step 2) { + val intValue = Integer.parseInt(hexSerialized.substring(i, i + 2), 16) + serializedEncodings += serializeFP2Value( + nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.encode( + publicKey, + intValue.toBigInteger() + ) + ) + } + return serializedEncodings + } + + companion object { + val MSG_SPACE = (0 until 256).toList().toTypedArray() + + fun deserialize(serialized: ByteArray): Pair { + val (values, rem) = deserializeAmount(serialized, PENG_BAO_PRIVATE_COMMITMENT_NUM_PARAMS) + val m1 = BigInteger(values[0]) + val m2 = BigInteger(values[1]) + val m3 = BigInteger(values[2]) + val r1 = BigInteger(values[3]) + val r2 = BigInteger(values[4]) + val r3 = BigInteger(values[5]) + + return Pair(PengBaoPrivateData(m1, m2, m3, r1, r2, r3), rem) + } + + fun decode(privateKey: BonehPrivateKey, serialized: ByteArray): PengBaoPrivateData { + var serialization = byteArrayOf() + val length = deserializeUChar(serialized.copyOfRange(0, 1)).toInt() + var rem = serialized.copyOfRange(1, serialized.size) + for (i in 0 until length) { + val (deserialized, localRem) = deserializeFP2Value(privateKey.g.mod, rem) + rem = localRem + var hexedRaw = nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.decode( + privateKey, + MSG_SPACE, + deserialized + )!! + var hexed = hexedRaw.toString(16) + if (hexed.endsWith("L", true)) { + hexed = hexed.substring(0, hexed.lastIndex) + } + if (hexed.length % 2 == 1) { + hexed = "0$hexed" + } + serialization += hexed.hexToBytes() + } + return deserialize(serialization).first + } + } +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/commitments/PublicPengBaoCommitment.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/commitments/PublicPengBaoCommitment.kt new file mode 100644 index 00000000..3af21b81 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/commitments/PublicPengBaoCommitment.kt @@ -0,0 +1,75 @@ +package nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.commitments + +import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPublicKey +import nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.boudot.primitives.EL +import nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.boudot.primitives.SQR +import nl.tudelft.ipv8.messaging.deserializeUChar +import nl.tudelft.ipv8.messaging.serializeUChar +import java.math.BigInteger + +class PengBaoPublicData( + val publicKey: BonehPublicKey, + val bitSpace: Int, + val commitment: PengBaoCommitment, + val el: EL, + val sqr1: SQR, + val sqr2: SQR, +) { + + fun check( + a: Int, + b: Int, + s: BigInteger, + t: BigInteger, + x: BigInteger, + y: BigInteger, + u: BigInteger, + v: BigInteger, + ): Boolean { + var out = this.el.check( + this.publicKey.g, + this.publicKey.h, + this.commitment.c1, + this.publicKey.h, + this.commitment.c2, + this.commitment.ca + ) + out = out && this.sqr1.check(this.commitment.ca, this.publicKey.h, this.commitment.caa) + out = out && this.sqr2.check(this.publicKey.g, this.publicKey.h, this.commitment.ca3) + out = + out && this.commitment.c1 == this.commitment.c / this.publicKey.g.bigIntPow(a.toBigInteger() - BigInteger.ONE) + out = + out && this.commitment.c2 == this.publicKey.g.bigIntPow(b.toBigInteger() + BigInteger.ONE) / this.commitment.c + out = out && this.commitment.caa == this.commitment.ca1 * this.commitment.ca2 * this.commitment.ca3 + out = out && (this.publicKey.g.bigIntPow(x) * this.publicKey.h.bigIntPow(u) + == (this.commitment.ca1.bigIntPow(s) * this.commitment.ca2 * this.commitment.ca3)) + out = out && ((this.publicKey.g.bigIntPow(y) * this.publicKey.h.bigIntPow(v)) + == (this.commitment.ca1 * this.commitment.ca2.bigIntPow(t) * this.commitment.ca3)) + + return out && x > BigInteger.ZERO && y > BigInteger.ZERO + } + + fun serialize(): ByteArray { + return (this.publicKey.serialize() + serializeUChar(this.bitSpace.toUByte()) + this.commitment.serialize() + + this.el.serialize() + this.sqr1.serialize() + this.sqr2.serialize()) + } + + companion object { + fun deserialize(serialized: ByteArray): Pair { + val publicKey = BonehPublicKey.deserialize(serialized)!! + var rem = serialized.copyOfRange(publicKey.serialize().size, serialized.size) + val bitSpace = deserializeUChar(rem.copyOfRange(0, 1)).toInt() + rem = rem.copyOfRange(1, rem.size) + val (commitment, localRem) = PengBaoCommitment.deserialize(rem) + rem = localRem + val (el, localRem2) = EL.deserialize(rem) + rem = localRem2 + val (sqr1, localRem3) = SQR.deserialize(rem) + rem = localRem3 + val (sqr2, localRem4) = SQR.deserialize(rem) + rem = localRem4 + + return Pair(PengBaoPublicData(publicKey, bitSpace, commitment, el, sqr1, sqr2), rem) + } + } +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/primitives/EC.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/primitives/EC.kt similarity index 98% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/primitives/EC.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/primitives/EC.kt index ea27a39e..cabb53cc 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/primitives/EC.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/primitives/EC.kt @@ -1,4 +1,4 @@ -package nl.tudelft.ipv8.attestation.wallet.primitives +package nl.tudelft.ipv8.attestation.wallet.cryptography.primitives import java.math.BigInteger diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/primitives/FP2Value.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/primitives/FP2Value.kt similarity index 99% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/primitives/FP2Value.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/primitives/FP2Value.kt index e7749dd2..a4abb701 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/primitives/FP2Value.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/primitives/FP2Value.kt @@ -1,4 +1,4 @@ -package nl.tudelft.ipv8.attestation.wallet.primitives +package nl.tudelft.ipv8.attestation.wallet.cryptography.primitives import java.math.BigInteger import kotlin.RuntimeException diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/AttestationHelperFunctions.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/util/AttestationHelperFunctions.kt similarity index 98% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/AttestationHelperFunctions.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/util/AttestationHelperFunctions.kt index f7982b5b..604c79c2 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/AttestationHelperFunctions.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/util/AttestationHelperFunctions.kt @@ -6,13 +6,11 @@ import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.attestations.B import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.attestations.BonehAttestation import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.decode import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.encode -import nl.tudelft.ipv8.attestation.wallet.primitives.FP2Value +import nl.tudelft.ipv8.attestation.wallet.cryptography.primitives.FP2Value import nl.tudelft.ipv8.util.sha256AsBigInt import nl.tudelft.ipv8.util.sha256_4_AsBigInt import nl.tudelft.ipv8.util.sha512AsBigInt -import java.math.BigDecimal import java.math.BigInteger -import java.math.RoundingMode import java.security.SecureRandom import java.util.* import kotlin.collections.ArrayList diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/util/Serialization.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/util/Serialization.kt new file mode 100644 index 00000000..8af1671f --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/util/Serialization.kt @@ -0,0 +1,21 @@ +package nl.tudelft.ipv8.attestation.wallet.cryptography.util + +import nl.tudelft.ipv8.attestation.wallet.cryptography.primitives.FP2Value +import nl.tudelft.ipv8.messaging.deserializeAmount +import nl.tudelft.ipv8.messaging.serializeVarLen +import java.math.BigInteger + +const val PENG_BAO_COMMITMENT_NUM_PARAMS = 8 +const val PENG_BAO_PRIVATE_COMMITMENT_NUM_PARAMS = 6 + +fun serializeFP2Value(value: FP2Value): ByteArray { + val compressed = value.wpCompress() + return serializeVarLen(compressed.a.toByteArray()) + serializeVarLen(compressed.b.toByteArray()) +} + +fun deserializeFP2Value(mod: BigInteger, serialized: ByteArray): Pair { + val (deserialized, rem) = deserializeAmount(serialized, 2) + val a = BigInteger(deserialized[0]) + val b = BigInteger(deserialized[1]) + return Pair(FP2Value(mod, a, b), rem) +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationSQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/store/AttestationSQLiteStore.kt similarity index 85% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationSQLiteStore.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/store/AttestationSQLiteStore.kt index 17670a7d..566bf18c 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationSQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/store/AttestationSQLiteStore.kt @@ -1,10 +1,7 @@ -package nl.tudelft.ipv8.attestation.wallet +package nl.tudelft.ipv8.attestation.wallet.store -import mu.KotlinLogging -import nl.tudelft.ipv8.attestation.WalletAttestation +import nl.tudelft.ipv8.attestation.wallet.cryptography.WalletAttestation import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPrivateKey -import nl.tudelft.ipv8.keyvault.PublicKey -import nl.tudelft.ipv8.keyvault.defaultCryptoProvider import nl.tudelft.ipv8.sqldelight.Database private val attestationMapper: ( @@ -23,8 +20,6 @@ private val attestationMapper: ( ) } -private val logger = KotlinLogging.logger {} - class AttestationSQLiteStore(database: Database) : AttestationStore { private val dao = database.dbAttestationQueries diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/store/AttestationStore.kt similarity index 84% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationStore.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/store/AttestationStore.kt index f530b2c9..9e62e487 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/store/AttestationStore.kt @@ -1,8 +1,7 @@ -package nl.tudelft.ipv8.attestation.wallet +package nl.tudelft.ipv8.attestation.wallet.store -import nl.tudelft.ipv8.attestation.WalletAttestation +import nl.tudelft.ipv8.attestation.wallet.cryptography.WalletAttestation import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPrivateKey -import nl.tudelft.ipv8.keyvault.PublicKey class AttestationBlob( val attestationHash: ByteArray, diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/identity/datastructures/tokenTree/TokenTest.kt similarity index 97% rename from ipv8/src/test/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTest.kt rename to ipv8/src/test/java/nl/tudelft/ipv8/attestation/identity/datastructures/tokenTree/TokenTest.kt index b35bf571..3fc3dd38 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/identity/datastructures/tokenTree/TokenTest.kt @@ -1,4 +1,4 @@ -package nl.tudelft.ipv8.attestation.tokenTree +package nl.tudelft.ipv8.attestation.identity.datastructures.tokenTree import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.PublicKey diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTreeTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/identity/datastructures/tokenTree/TokenTreeTest.kt similarity index 99% rename from ipv8/src/test/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTreeTest.kt rename to ipv8/src/test/java/nl/tudelft/ipv8/attestation/identity/datastructures/tokenTree/TokenTreeTest.kt index f838be15..864386c8 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTreeTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/identity/datastructures/tokenTree/TokenTreeTest.kt @@ -1,4 +1,4 @@ -package nl.tudelft.ipv8.attestation.tokenTree +package nl.tudelft.ipv8.attestation.identity.datastructures.tokenTree import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.PublicKey diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManagerTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManagerTest.kt index ae5da162..6803a819 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManagerTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManagerTest.kt @@ -2,8 +2,8 @@ package nl.tudelft.ipv8.attestation.identity.manager import com.squareup.sqldelight.db.SqlDriver import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver -import nl.tudelft.ipv8.attestation.identity.database.Credential -import nl.tudelft.ipv8.attestation.identity.database.IdentitySQLiteStore +import nl.tudelft.ipv8.attestation.identity.store.Credential +import nl.tudelft.ipv8.attestation.identity.store.IdentitySQLiteStore import nl.tudelft.ipv8.keyvault.defaultCryptoProvider import nl.tudelft.ipv8.sqldelight.Database import org.json.JSONObject diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/TestBoneh.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/TestBoneh.kt index 8cf6261b..d37047e5 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/TestBoneh.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/TestBoneh.kt @@ -1,6 +1,6 @@ package nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact -import nl.tudelft.ipv8.attestation.wallet.primitives.FP2Value +import nl.tudelft.ipv8.attestation.wallet.cryptography.primitives.FP2Value import nl.tudelft.ipv8.util.hexToBytes import org.junit.Assert.* import org.junit.Test diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/TestKeys.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/TestKeys.kt index 805887e7..0cb8881b 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/TestKeys.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/TestKeys.kt @@ -1,6 +1,6 @@ package nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact -import nl.tudelft.ipv8.attestation.schema.SchemaManager +import nl.tudelft.ipv8.attestation.common.SchemaManager import nl.tudelft.ipv8.util.toHex import org.junit.Assert.assertEquals import org.junit.Test diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/TestBoudot.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/TestBoudot.kt index 2d054329..6c3e2c11 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/TestBoudot.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/TestBoudot.kt @@ -1,7 +1,9 @@ package nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPublicKey -import nl.tudelft.ipv8.attestation.wallet.primitives.FP2Value +import nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.boudot.primitives.EL +import nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.boudot.primitives.SQR +import nl.tudelft.ipv8.attestation.wallet.cryptography.primitives.FP2Value import nl.tudelft.ipv8.util.hexToBytes import org.junit.Assert.* import org.junit.Test diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/primitives/TestEc.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/primitives/TestEc.kt index b3d8b93b..b4684f0e 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/primitives/TestEc.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/primitives/TestEc.kt @@ -1,8 +1,5 @@ package nl.tudelft.ipv8.attestation.wallet.cryptography.primitives -import nl.tudelft.ipv8.attestation.wallet.primitives.FP2Value -import nl.tudelft.ipv8.attestation.wallet.primitives.eSum -import nl.tudelft.ipv8.attestation.wallet.primitives.weilParing import org.junit.Assert.assertEquals import org.junit.Test import java.math.BigInteger From 1562a9dc78d0fa79ee9ca999735c733a8be6fee9 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 10 May 2021 17:47:16 +0200 Subject: [PATCH 114/144] Format tests + make test values private --- .../AttestationHelperFunctionsTest.kt | 10 +-- .../cryptography/bonehexact/TestBoneh.kt | 34 +++++--- .../cryptography/bonehexact/TestKeys.kt | 1 - .../cryptography/pengbaorange/TestBoudot.kt | 78 ++++++++++++------- .../wallet/cryptography/primitives/TestEc.kt | 13 ++-- 5 files changed, 82 insertions(+), 54 deletions(-) diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/AttestationHelperFunctionsTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/AttestationHelperFunctionsTest.kt index 7833b5ce..0da5c380 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/AttestationHelperFunctionsTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/AttestationHelperFunctionsTest.kt @@ -13,7 +13,6 @@ class AttestationHelperFunctionsTest { private val privateKey = BonehPrivateKey.deserialize("0000000907a016081ab53e90850000000900edf0f06d18de2c400000000906b15c56c9a13f1d250000000902fa4b47c93f63a2a3000000090412c4d01c5d61ce3b000000082426557bc0fc6af9000000044405f5d7".hexToBytes())!! - @Test fun generateInverseGroupTest() { /* @@ -27,7 +26,6 @@ class AttestationHelperFunctionsTest { assertEquals(20, group.size) assertEquals(BigInteger.ZERO, sum.mod(p + BigInteger.ONE)) - } @Test @@ -45,13 +43,13 @@ class AttestationHelperFunctionsTest { val decoded = arrayOf(0, 1, 1, 2) for (i in attestations.indices) { - assertEquals(decoded[i], - decode(privateKey, arrayOf(0, 1, 2, 3), attestations[i].bitPairs.get(0).compress())) + assertEquals( + decoded[i], + decode(privateKey, arrayOf(0, 1, 2, 3), attestations[i].bitPairs.get(0).compress()) + ) } - } - @Test fun emptyRelativityMapTest() { val relMap = createEmptyRelativityMap() diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/TestBoneh.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/TestBoneh.kt index d37047e5..ac482579 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/TestBoneh.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/TestBoneh.kt @@ -11,7 +11,6 @@ class TestBoneh { val privateKey = BonehPrivateKey.deserialize("000000193f66b1832ebda2377020c49d4efb1f02d06abd620a3bb1cef90000001930a3f4173587f326a01065403d695ef74cd43541aef197021900000019249746a549c80dc37771fc52591733507ed0eca7ef21a58eed0000001926b4c4866545b883aa6eec92de3ae08ddcca251c52d67fed6a0000001939e634b0c3815508b1281e680247bd10652b9d7573cd011a9f00000018491c79ac07c5eb7e32e2e756d79e1f25d6f7a0badb5e34d30000000c60bcec8cf857fc02e4885091".hexToBytes())!! - @Test fun generatePrimeTest() { /* @@ -25,14 +24,17 @@ class TestBoneh { /* * Check if a bilinear group can be created. */ - val x = bilinearGroup(BigInteger.valueOf(10), + val x = bilinearGroup( + BigInteger.valueOf(10), BigInteger.valueOf(29), BigInteger.valueOf(4), BigInteger.valueOf(5), BigInteger.valueOf(4), - BigInteger.valueOf(5)) + BigInteger.valueOf(5) + ) val y = FP2Value( - BigInteger.valueOf(29), BigInteger.valueOf(19), BigInteger.valueOf(5)) + BigInteger.valueOf(29), BigInteger.valueOf(19), BigInteger.valueOf(5) + ) assertEquals(x, y) } @@ -41,12 +43,16 @@ class TestBoneh { /* * Check if a bilinear group returns 0 if there is no possible pairing. */ - assertEquals(bilinearGroup(BigInteger.valueOf(10), - BigInteger.valueOf(29), - BigInteger.valueOf(2), - BigInteger.valueOf(3), - BigInteger.valueOf(2), - BigInteger.valueOf(3)), FP2Value(BigInteger.valueOf(29))) + assertEquals( + bilinearGroup( + BigInteger.valueOf(10), + BigInteger.valueOf(29), + BigInteger.valueOf(2), + BigInteger.valueOf(3), + BigInteger.valueOf(2), + BigInteger.valueOf(3) + ), FP2Value(BigInteger.valueOf(29)) + ) } @Test @@ -54,8 +60,12 @@ class TestBoneh { /* * Check if is_good_wp returns True for 26 + 17x with n = 10 */ - assertTrue(isGoodWp(BigInteger.valueOf(10), - FP2Value(BigInteger.valueOf(29), BigInteger.valueOf(26), BigInteger.valueOf(17)))) + assertTrue( + isGoodWp( + BigInteger.valueOf(10), + FP2Value(BigInteger.valueOf(29), BigInteger.valueOf(26), BigInteger.valueOf(17)) + ) + ) } @Test diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/TestKeys.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/TestKeys.kt index 0cb8881b..efb939bd 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/TestKeys.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/TestKeys.kt @@ -23,5 +23,4 @@ class TestKeys { assertEquals(keyRecovHex, keyHex) assertEquals(key, keyRecov) } - } diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/TestBoudot.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/TestBoudot.kt index 6c3e2c11..6e7461a6 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/TestBoudot.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/TestBoudot.kt @@ -12,28 +12,31 @@ import java.math.BigInteger class TestBoudot { // Test params to be equal to the PyIPV8 tests. - val pk = BonehPublicKey( + private val pk = BonehPublicKey( p = BigInteger("1855855294356961364177"), - g = FP2Value(mod = BigInteger("1855855294356961364177"), + g = FP2Value( + mod = BigInteger("1855855294356961364177"), a = BigInteger("1640955591379995824691"), - b = BigInteger("322057703443002024702")), - h = FP2Value(mod = BigInteger("1855855294356961364177"), + b = BigInteger("322057703443002024702") + ), + h = FP2Value( + mod = BigInteger("1855855294356961364177"), a = BigInteger("706495420229569786251"), - b = BigInteger("156305917664511526783")) + b = BigInteger("156305917664511526783") + ) ) - val bitspace = 32 - val a = 0.toBigInteger() - val b = 18.toBigInteger() - val r = 2.toBigInteger() - val ra = 3.toBigInteger() - + private val bitSpace = 32 + private val a = 0.toBigInteger() + private val b = 18.toBigInteger() + private val r = 2.toBigInteger() + private val ra = 3.toBigInteger() // Commitment generated with above parameters for message `7` - val el = + private val el = EL.deserialize("020000002101c42b8cb90f9de7b77897d0df644410cf8581a7381392562164b5e0da43d3e47f00000021012d725dd0b513efcfa5ba8b3f982d608a59011a25626138c43fb537a3faf168ff000000210710ae32e43e779edde25f437d9110433e16069ce04e488d0c6c242fba6c50be7c000000210096b92ee85a89f7e7d2dd459fcc16b0452c808d12b130b66bb3adaea4de5c0fb6".hexToBytes()).first - val sqr = + private val sqr = SQR.deserialize("00000009649b2a7d7992b008d1000000092ef4b2b3890136f39d00000009300f2cb5896dcadc49000000a7010000002a0a16027dee86ae81c4cfc7f529f46261608252ab4daa517d68e21720790e4199f78a1929dbd013a105b60000002a0285809f7ba1aba0714188435457007cbe08eaaf87506267fdb8c0ad262dfb6c15ca968e206a9777949e0000002102af10fec9115c85e85cd7d7aef94a65d3cc6c7357642706e8a37bb0ecd804845b0000002100abc43fb24457217a1735f5ebbe529974f31b1cd5d909c1ba28deec3b36011fa3".hexToBytes()).first @Test @@ -41,10 +44,12 @@ class TestBoudot { /* * Check if Boudot equality checks are correctly serialized. */ - val el = EL(BigInteger("68174117739048401651990398043836840253231911962332258219191049320869958258614"), + val el = EL( + BigInteger("68174117739048401651990398043836840253231911962332258219191049320869958258614"), BigInteger("818089412868580819823884776526042083038782943547987098630292591850439499103868"), BigInteger("-136348235478096803303980796087673680506463823924664516192465696382710419908863"), - BigInteger("204522353217145204955971194131510520759695735886996774897791958142625032430719")) + BigInteger("204522353217145204955971194131510520759695735886996774897791958142625032430719") + ) assertEquals(this.el, el) } @@ -132,10 +137,14 @@ class TestBoudot { /* * Check if the Boudot commitment-is-square holds. */ - val sqr = SQR.create(4.toBigInteger(), 81.toBigInteger(), this.pk.g, this.pk.h, this.b.toInt(), this.bitspace) - assertTrue(sqr.check(this.pk.g, - this.pk.h, - this.pk.g.bigIntPow(16.toBigInteger()) * this.pk.h.bigIntPow(81.toBigInteger()))) + val sqr = SQR.create(4.toBigInteger(), 81.toBigInteger(), this.pk.g, this.pk.h, this.b.toInt(), this.bitSpace) + assertTrue( + sqr.check( + this.pk.g, + this.pk.h, + this.pk.g.bigIntPow(16.toBigInteger()) * this.pk.h.bigIntPow(81.toBigInteger()) + ) + ) } @Test @@ -143,11 +152,14 @@ class TestBoudot { /* * Check if the Boudot commitment-is-square fails if the commitment message changes. */ - val sqr = SQR.create(9.toBigInteger(), 81.toBigInteger(), this.pk.g, this.pk.h, this.b.toInt(), this.bitspace) - assertFalse(sqr.check(this.pk.g, - this.pk.h, - this.pk.g.bigIntPow(16.toBigInteger()) * this.pk.h.bigIntPow(81.toBigInteger()))) - + val sqr = SQR.create(9.toBigInteger(), 81.toBigInteger(), this.pk.g, this.pk.h, this.b.toInt(), this.bitSpace) + assertFalse( + sqr.check( + this.pk.g, + this.pk.h, + this.pk.g.bigIntPow(16.toBigInteger()) * this.pk.h.bigIntPow(81.toBigInteger()) + ) + ) } @Test @@ -155,10 +167,14 @@ class TestBoudot { /* * Check if the Boudot commitment-is-square fails if the shadow commitment message changes. */ - val sqr = SQR.create(4.toBigInteger(), 81.toBigInteger(), this.pk.g, this.pk.h, this.b.toInt(), this.bitspace) - assertFalse(sqr.check(this.pk.g, - this.pk.h, - this.pk.g.bigIntPow(9.toBigInteger()) * this.pk.h.bigIntPow(81.toBigInteger()))) + val sqr = SQR.create(4.toBigInteger(), 81.toBigInteger(), this.pk.g, this.pk.h, this.b.toInt(), this.bitSpace) + assertFalse( + sqr.check( + this.pk.g, + this.pk.h, + this.pk.g.bigIntPow(9.toBigInteger()) * this.pk.h.bigIntPow(81.toBigInteger()) + ) + ) } @Test @@ -166,10 +182,12 @@ class TestBoudot { /* * Check if Boudot commitment-is-square checks are correctly serialized. */ - val el = EL(BigInteger("77692238748522549651683873494184958254240308467748145113388211342290056191907"), + val el = EL( + BigInteger("77692238748522549651683873494184958254240308467748145113388211342290056191907"), BigInteger("310768954994090198606735493976739833016961233870992580453552845369160224769115"), BigInteger("1378784829646587776157777333351527905785206201874845030390922605077647796646962410317344630260602014"), - BigInteger("-5515139318586351104624816262067481296619038413746351139945096955324703586833572052593411867046643126")) + BigInteger("-5515139318586351104624816262067481296619038413746351139945096955324703586833572052593411867046643126") + ) val sqr = SQR(FP2Value(this.pk.g.mod, BigInteger("866182580282760557469"), BigInteger("886537163949459823689")), el) diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/primitives/TestEc.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/primitives/TestEc.kt index b4684f0e..ccdef515 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/primitives/TestEc.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/wallet/cryptography/primitives/TestEc.kt @@ -4,7 +4,6 @@ import org.junit.Assert.assertEquals import org.junit.Test import java.math.BigInteger - class TestEC { @Test @@ -13,11 +12,13 @@ class TestEC { * Check if Weil pairing in E[4] mod 11 of (5, 4) and (5x, 4) with S=(7, 6) equals 9 + 7x */ val mod = BigInteger("11") - val wp = weilParing(mod, + val wp = weilParing( + mod, BigInteger("4"), Pair(FP2Value(mod, BigInteger("5")), FP2Value(mod, BigInteger("4"))), Pair(FP2Value(mod, b = BigInteger("5")), FP2Value(mod, BigInteger("4"))), - Pair(FP2Value(mod, BigInteger("7")), FP2Value(mod, BigInteger("6")))) + Pair(FP2Value(mod, BigInteger("7")), FP2Value(mod, BigInteger("6"))) + ) assertEquals(wp.a, BigInteger("9")) assertEquals(wp.b, BigInteger("7")) @@ -33,11 +34,13 @@ class TestEC { * Check if Weil pairing in E[408] mod 1223 of (764, 140) and (18x, 84) with S=(0, 1222) equals 438 + 50x */ val mod = BigInteger("1223") - val wp = weilParing(mod, + val wp = weilParing( + mod, BigInteger("408"), Pair(FP2Value(mod, BigInteger("764")), FP2Value(mod, BigInteger("140"))), Pair(FP2Value(mod, b = BigInteger("18")), FP2Value(mod, BigInteger("84"))), - Pair(FP2Value(mod, BigInteger.ZERO), FP2Value(mod, BigInteger("1222")))) + Pair(FP2Value(mod, BigInteger.ZERO), FP2Value(mod, BigInteger("1222"))) + ) assertEquals(wp.a, BigInteger("438")) assertEquals(wp.b, BigInteger("50")) From 57379daa843195a12a0d4bc187a369b0be49606d Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 10 May 2021 17:50:43 +0200 Subject: [PATCH 115/144] Refactor SimpleChurn constructor in Tracker --- tracker/src/main/java/nl/tudelft/ipv8/tracker/SimpleChurn.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracker/src/main/java/nl/tudelft/ipv8/tracker/SimpleChurn.kt b/tracker/src/main/java/nl/tudelft/ipv8/tracker/SimpleChurn.kt index af0bd37c..ebe5f34b 100644 --- a/tracker/src/main/java/nl/tudelft/ipv8/tracker/SimpleChurn.kt +++ b/tracker/src/main/java/nl/tudelft/ipv8/tracker/SimpleChurn.kt @@ -8,7 +8,7 @@ import java.util.* private val logger = KotlinLogging.logger {} class SimpleChurn( - private val overlay: Overlay + override val overlay: Overlay ) : DiscoveryStrategy { override fun takeStep() { synchronized(overlay.network.graphLock) { From 59f4f063df9973bb70519361a16b8379ab57211b Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Tue, 11 May 2021 16:02:23 +0200 Subject: [PATCH 116/144] Remove authorityManager dependency from AttestationCommunity --- .../ipv8/attestation/wallet/AttestationCommunity.kt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt index 90d1c3a2..74b27ffd 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/AttestationCommunity.kt @@ -10,7 +10,6 @@ import nl.tudelft.ipv8.Overlay import nl.tudelft.ipv8.Peer import nl.tudelft.ipv8.attestation.WalletAttestation import nl.tudelft.ipv8.attestation.IdentityAlgorithm -import nl.tudelft.ipv8.attestation.AuthorityManager import nl.tudelft.ipv8.attestation.RequestCache import nl.tudelft.ipv8.attestation.schema.* import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity.MessageId.ATTESTATION @@ -38,7 +37,7 @@ import kotlin.random.nextUBytes private val logger = KotlinLogging.logger {} private const val CHUNK_SIZE = 800 -class AttestationCommunity(val authorityManager: AuthorityManager, val database: AttestationStore) : +class AttestationCommunity(val database: AttestationStore) : Community() { override lateinit var myPeer: Peer @@ -49,10 +48,8 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: myPeer: Peer, endpoint: EndpointAggregator, network: Network, - authorityManager: AuthorityManager, database: AttestationStore, ) : this( - authorityManager, database ) { this.myPeer = myPeer @@ -79,7 +76,6 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: val requestCache = RequestCache() init { - authorityManager.loadTrustedAuthorities() schemaManager.registerDefaultSchemas() for (att in this.database.getAllAttestations()) { val hash = att.attestationHash @@ -700,11 +696,10 @@ class AttestationCommunity(val authorityManager: AuthorityManager, val database: } class Factory( - private val authorityManager: AuthorityManager, private val database: AttestationStore, ) : Overlay.Factory(AttestationCommunity::class.java) { override fun create(): AttestationCommunity { - return AttestationCommunity(authorityManager, database) + return AttestationCommunity(database) } } } From 868d14e073678197c40085d11ff0ccf5af577a3e Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Tue, 11 May 2021 16:03:12 +0200 Subject: [PATCH 117/144] Add revocation community to CommunicationManager --- .../communication/CommunicationChannel.kt | 24 ++++++------------- .../communication/CommunicationManager.kt | 14 +++++++++-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt index d5e3a6bf..e570790e 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt @@ -15,7 +15,7 @@ import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity import nl.tudelft.ipv8.attestation.communication.caches.DisclosureRequestCache import nl.tudelft.ipv8.attestation.identity.IdentityAttestation import nl.tudelft.ipv8.attestation.identity.database.Credential -import nl.tudelft.ipv8.attestation.schema.ID_METADATA +import nl.tudelft.ipv8.attestation.revocation.RevocationCommunity import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.keyvault.defaultCryptoProvider @@ -29,7 +29,6 @@ import nl.tudelft.ipv8.util.toByteArray import nl.tudelft.ipv8.util.toHex import nl.tudelft.ipv8.util.toKey import org.json.JSONObject -import java.util.Locale import java.util.UUID const val DEFAULT_TIME_OUT = 30_000L @@ -37,7 +36,8 @@ private val logger = KotlinLogging.logger {} class CommunicationChannel( val attestationOverlay: AttestationCommunity, - val identityOverlay: IdentityCommunity + val identityOverlay: IdentityCommunity, + val revocationOverlay: RevocationCommunity ) { val attestationRequests = hashMapOf, String, String?>>() @@ -65,7 +65,7 @@ class CommunicationChannel( get() = this.attestationOverlay.schemaManager.getSchemaNames() val authorityManager - get() = this.attestationOverlay.authorityManager + get() = this.revocationOverlay.authorityManager private fun onRequestAttestationAsync( peer: Peer, @@ -264,17 +264,7 @@ class CommunicationChannel( } fun revoke(signatures: List) { - val keyHash = myPeer.publicKey.keyToHash() - val latestVersion = authorityManager.getAuthority(keyHash)?.version?.plus(1) ?: 1L - var signableData = latestVersion.toByteArray() - signatures.forEach { signableData += it } - val versionSignature = (myPeer.key as PrivateKey).sign(sha3_256(signableData)) - authorityManager.insertRevocations( - myPeer.publicKey.keyToHash(), - latestVersion, - versionSignature, - signatures - ) + this.revocationOverlay.revokeAttestations(signatures) } fun verifyLocally( @@ -312,7 +302,7 @@ class CommunicationChannel( // Check if authority is recognized and the corresponding signature is correct. if (!attestors.any { attestor -> val authority = - this.attestationOverlay.authorityManager.getTrustedAuthority(attestor.first) + this.revocationOverlay.authorityManager.getTrustedAuthority(attestor.first) authority?.let { it.publicKey?.verify(attestor.second, metadata.hash) } == true @@ -322,7 +312,7 @@ class CommunicationChannel( } // Check if any authority has not revoked a signature - if (!this.attestationOverlay.authorityManager.verify(metadata.hash)) { + if (!this.authorityManager.verify(metadata.hash)) { logger.info("Not accepting ${attestationHash.toHex()}, signature was revoked.") return false } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt index a55357b9..2ffee3d2 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt @@ -8,6 +8,7 @@ import nl.tudelft.ipv8.attestation.identity.IdentityCommunity import nl.tudelft.ipv8.attestation.identity.createCommunity import nl.tudelft.ipv8.attestation.identity.database.IdentityStore import nl.tudelft.ipv8.attestation.identity.manager.IdentityManager +import nl.tudelft.ipv8.attestation.revocation.RevocationCommunity import nl.tudelft.ipv8.attestation.wallet.AttestationCommunity import nl.tudelft.ipv8.attestation.wallet.AttestationStore import nl.tudelft.ipv8.keyvault.PrivateKey @@ -76,13 +77,21 @@ class CommunicationManager( identityOverlay.myPeer, identityOverlay.endpoint, identityOverlay.network, - authorityManager, attestationStore ) attestationOverlay.load() + val revocationOverlay = RevocationCommunity( + identityOverlay.myPeer, + identityOverlay.endpoint, + identityOverlay.network, + authorityManager, + identityOverlay::getPeers + ) + revocationOverlay.load() + this.channels[publicKeyBytes.toKey()] = - CommunicationChannel(attestationOverlay, identityOverlay) + CommunicationChannel(attestationOverlay, identityOverlay, revocationOverlay) this.nameToChannel[name] = this.channels[publicKeyBytes.toKey()]!! } return this.nameToChannel[name]!! @@ -94,6 +103,7 @@ class CommunicationManager( this.channels.remove(communicationChannel.publicKeyBin.toKey()) this.iPv8Instance.unloadSecondaryOverlayStrategy(communicationChannel.identityOverlay.serviceId) communicationChannel.attestationOverlay.unload() + communicationChannel.revocationOverlay.unload() // TODO: Endpoint close? } } From 5ca64ae137285a3815ec619abf5a548c8f9a88e0 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Tue, 11 May 2021 16:04:32 +0200 Subject: [PATCH 118/144] Allow peers of other communities + use sha3 + allow nonsequential revocation versions --- .../revocation/RevocationCommunity.kt | 230 ++++++++++++------ 1 file changed, 160 insertions(+), 70 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt index 87701bcd..26102ebc 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt @@ -12,6 +12,7 @@ import nl.tudelft.ipv8.attestation.revocation.payloads.RevocationUpdateChunkPayl import nl.tudelft.ipv8.attestation.revocation.payloads.RevocationUpdatePreviewPayload import nl.tudelft.ipv8.attestation.revocation.payloads.RevocationUpdateRequestPayload import nl.tudelft.ipv8.attestation.RequestCache +import nl.tudelft.ipv8.attestation.revocation.caches.AllowedUpdateRequestCache import nl.tudelft.ipv8.attestation.wallet.caches.PeerCache import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.messaging.* @@ -30,24 +31,51 @@ const val REVOCATION_UPDATE_CHUNK_PAYLOAD = 3 class RevocationCommunity(val authorityManager: AuthorityManager) : Community() { override val serviceId = "fdbb9c5c18bf480a4baba08d352727e66ee89173" - override var network = Network() + + @Suppress("JoinDeclarationAndAssignment", "LateinitVarOverridesLateinitVar") + override lateinit var myPeer: Peer + + @Suppress("JoinDeclarationAndAssignment", "LateinitVarOverridesLateinitVar") + override lateinit var endpoint: EndpointAggregator + + @Suppress("JoinDeclarationAndAssignment", "LateinitVarOverridesLateinitVar") + override lateinit var network: Network + + // Possibility to override the getPeers method when using shared network between Communities. + private lateinit var fetchPeers: () -> List + + constructor( + myPeer: Peer, + endpoint: EndpointAggregator, + network: Network, + authorityManager: AuthorityManager, + getPeers: (() -> List)? + ) : this( + authorityManager + ) { + this.myPeer = myPeer + this.endpoint = endpoint + this.network = network + this.fetchPeers = getPeers ?: this::getPeers + } private lateinit var gossipRoutine: Job private val lock = Object() private val requestCache = RequestCache() - // private lateinit var onRevocationUpdatePreviewCallback: (List>) -> Unit // private lateinit var onRevocationUpdateRequestCallback: (Map>) -> Unit init { messageHandlers[REVOCATION_PRESENTATION_PAYLOAD] = ::onRevocationUpdatePreviewPayloadWrapper - messageHandlers[REVOCATION_UPDATE_REQUEST_PAYLOAD] = ::onRevocationUpdateRequestPayloadWrapper + messageHandlers[REVOCATION_UPDATE_REQUEST_PAYLOAD] = + ::onRevocationUpdateRequestPayloadWrapper messageHandlers[REVOCATION_UPDATE_CHUNK_PAYLOAD] = ::onRevocationUpdateChunkPayloadWrapper + start() } - suspend fun start() { + fun start() { this.gossipRoutine = GlobalScope.launch { while (isActive) { gossipRevocations(getRandomPeers(DEFAULT_GOSSIP_AMOUNT)) @@ -56,9 +84,12 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() } } - fun revokeAttestation(attestationHashes: List) { - logger.info("Revoking ${attestationHashes.size} hash(es)!") + override fun unload() { + super.unload() + this.gossipRoutine.cancel() + } + fun revokeAttestations(attestationHashes: List) { val myPublicKeyHash = this.myPeer.publicKey.keyToHash() var myAuthority = this.authorityManager.getAuthority(myPublicKeyHash) if (myAuthority == null) { @@ -68,10 +99,15 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() val version = myAuthority.version + 1 var signableData = serializeULong(version.toULong()) attestationHashes.forEach { signableData += it } - val signature = (this.myPeer.key as PrivateKey).sign(sha1(signableData)) - - logger.info("Revoking signatures with version $version") - this.authorityManager.insertRevocations(myPublicKeyHash, version, signature, attestationHashes) + val signature = (this.myPeer.key as PrivateKey).sign(sha3_256(signableData)) + + logger.info("Revoking ${attestationHashes.size} signature(s) with version $version") + this.authorityManager.insertRevocations( + myPublicKeyHash, + version, + signature, + attestationHashes + ) // this.gossipMyRevocations() } @@ -94,28 +130,50 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() this.onRevocationUpdateChunkPayload(peer, payload) } - private fun onRevocationUpdatePreviewPayload(peer: Peer, payload: RevocationUpdatePreviewPayload) { - val remoteRefs = payload.revocationRefs - val localRefs = this.authorityManager.getLatestRevocationPreviews() + private fun onRevocationUpdatePreviewPayload( + peer: Peer, + payload: RevocationUpdatePreviewPayload + ) { + val remoteRefs = payload.revocationRefs.filter { authorityManager.containsAuthority(it.key.bytes) } + val localRefs = this.authorityManager.getMissingRevocationPreviews() val requestedRefs = hashMapOf() for (key in remoteRefs.keys) { - val localVersion = localRefs.get(key) + val localVersion = localRefs[key] val remoteVersion = remoteRefs[key]!! // If we're already waiting on a version, wait until we receive it or the cache times out. // We want to receive versions concurrent for now. - val idPair = PendingRevocationUpdateCache.generateId(peer.publicKey.keyToHash(), key.bytes, (localVersion ?: 0L) + 1) + val idPair = + PendingRevocationUpdateCache.generateId( + peer.publicKey.keyToHash(), + key.bytes, + (localVersion ?: 0L) + 1 + ) if (!this.requestCache.has(idPair)) { if (localVersion == null) { requestedRefs[key] = 0L for (i in 1L..remoteVersion) { - this.requestCache.add(PendingRevocationUpdateCache(this.requestCache, peer.publicKey.keyToHash(), key.bytes, i)) + this.requestCache.add( + PendingRevocationUpdateCache( + this.requestCache, + peer.publicKey.keyToHash(), + key.bytes, + i + ) + ) } } else if (localVersion < remoteVersion) { requestedRefs[key] = localVersion for (i in (localVersion + 1L)..remoteVersion) { - this.requestCache.add(PendingRevocationUpdateCache(this.requestCache, peer.publicKey.keyToHash(), key.bytes, i)) + this.requestCache.add( + PendingRevocationUpdateCache( + this.requestCache, + peer.publicKey.keyToHash(), + key.bytes, + i + ) + ) } } } else { @@ -134,7 +192,6 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() } } - private fun onRevocationUpdateRequestPayload( peer: Peer, payload: RevocationUpdateRequestPayload, @@ -153,59 +210,71 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() var sequenceNumber = 0 for (i in blob.indices step CHUNK_SIZE) { val endIndex = if (i + CHUNK_SIZE > blob.size) blob.size else i + CHUNK_SIZE - val chunkPayload = RevocationUpdateChunkPayload(sequenceNumber, + val chunkPayload = RevocationUpdateChunkPayload( + sequenceNumber, hash, this.myPeer.publicKey.keyToHash(), 0L, - blob.copyOfRange(i, endIndex)) + blob.copyOfRange(i, endIndex) + ) val packet = serializePacket(REVOCATION_UPDATE_CHUNK_PAYLOAD, chunkPayload) logger.info("Sending update chunk $sequenceNumber") this.endpoint.send(peer, packet) sequenceNumber += 1 } } else { - val revocations = mutableListOf() + val solicited = this.requestCache.has(AllowedUpdateRequestCache.generateId(peer)) + if (solicited) { + val revocations = mutableListOf() - payload.revocationRefs.forEach { (hash, version) -> - revocations.addAll(this.authorityManager.getRevocations(hash.bytes, version)) - } - logger.info("CLIENT REQUESTED THE FOLLOWING VERSIONS: ") - revocations.forEach { print("${it.version}, ") } + payload.revocationRefs.forEach { (hash, version) -> + revocations.addAll(this.authorityManager.getRevocations(hash.bytes, version)) + } + logger.info("CLIENT REQUESTED THE FOLLOWING VERSIONS: ") + revocations.forEach { print("${it.version}, ") } - // TODO: ths could be performed in coroutines, however, would most likely lead to package lost. - for (rev in revocations) { + // TODO: ths could be performed in coroutines, however, would most likely lead to package lost. + for (rev in revocations) { // logger.info("Sending version ${rev.version}") - val blob = serializeRevocationBlob(rev) - val hash = sha1(blob) - var sequenceNumber = 0 - for (i in blob.indices step CHUNK_SIZE) { - val endIndex = if (i + CHUNK_SIZE > blob.size) blob.size else i + CHUNK_SIZE - val chunkPayload = - RevocationUpdateChunkPayload(sequenceNumber, hash, rev.publicKeyHash, rev.version, - blob.copyOfRange(i, endIndex)) - val packet = serializePacket(REVOCATION_UPDATE_CHUNK_PAYLOAD, chunkPayload) - logger.info("Sending update chunk $sequenceNumber") - this.endpoint.send(peer, packet) - sequenceNumber += 1 + val blob = serializeRevocationBlob(rev) + val hash = sha1(blob) + var sequenceNumber = 0 + for (i in blob.indices step CHUNK_SIZE) { + val endIndex = if (i + CHUNK_SIZE > blob.size) blob.size else i + CHUNK_SIZE + val chunkPayload = + RevocationUpdateChunkPayload( + sequenceNumber, hash, rev.publicKeyHash, rev.version, + blob.copyOfRange(i, endIndex) + ) + val packet = serializePacket(REVOCATION_UPDATE_CHUNK_PAYLOAD, chunkPayload) + logger.info("Sending update chunk $sequenceNumber") + this.endpoint.send(peer, packet) + sequenceNumber += 1 + } } + } else { + logger.warn("Ignoring unsolicited update request.") } } - } private fun onRevocationUpdateChunkPayload( peer: Peer, payload: RevocationUpdateChunkPayload, + unsafeInsertion: Boolean = false, bulkSending: Boolean = false, ) { if (bulkSending) { - val (prefix, id) = PeerCache.idFromAddress(PENDING_REVOCATION_UPDATE_CACHE_PREFIX, peer.mid) + val (prefix, id) = PeerCache.idFromAddress( + PENDING_REVOCATION_UPDATE_CACHE_PREFIX, + peer.mid + ) if (this.requestCache.has(prefix, id)) { val cache = this.requestCache.get(prefix, id) as PendingRevocationUpdateCache var localBlob = byteArrayOf() cache.revocationMap[payload.sequenceNumber] = payload.data cache.revocationMap.keys.sorted().forEach { localBlob += cache.revocationMap[it]!! } - if (sha1(localBlob).contentEquals(payload.hash)) { + if (sha1(localBlob).contentEquals(payload.payloadHash)) { this.requestCache.pop(prefix, id) as PendingRevocationUpdateCache val revocationMap = this.deserializeRevocationMap(localBlob) logger.info("Received update: ${revocationMap.keys.size}") @@ -216,10 +285,17 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() if (authority?.publicKey != null) { var signable = serializeULong(blob.version.toULong()) blob.revocations.forEach { signable += it } - if (!authority.publicKey.verify(blob.signature, signable)) { + if (!authority.publicKey.verify( + blob.signature, + sha3_256(signable) + ) + ) { logger.warn("Peer ${peer.mid} might have altered the revoked signatures, skipping!") continue } + } else if (!unsafeInsertion) { + logger.info("Dropping unsolicited revocations.") + continue } else { logger.info("Inserting revocations without verification as authority is not recognized.") } @@ -228,7 +304,8 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() hash.bytes, blob.version, blob.signature, - blob.revocations) + blob.revocations + ) } } } @@ -237,13 +314,18 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() } } else { val idPair = - PendingRevocationUpdateCache.generateId(peer.publicKey.keyToHash(), payload.publicKeyHash, payload.version) + PendingRevocationUpdateCache.generateId( + peer.publicKey.keyToHash(), + payload.authorityKeyHash, + payload.version + ) if (this.requestCache.has(idPair)) { val cache = this.requestCache.get(idPair) as PendingRevocationUpdateCache var localBlob = byteArrayOf() + cache.revocationMap[payload.sequenceNumber] = payload.data cache.revocationMap.keys.sorted().forEach { localBlob += cache.revocationMap[it]!! } - if (sha1(localBlob).contentEquals(payload.hash)) { + if (sha1(localBlob).contentEquals(payload.payloadHash)) { this.requestCache.pop(idPair) as PendingRevocationUpdateCache val revocationBlob = this.deserializeRevocationBlob(localBlob) logger.info("Received update: ${revocationBlob.revocations.size} revoked signatures") @@ -252,9 +334,17 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() if (authority?.publicKey != null) { var signable = revocationBlob.version.toByteArray() revocationBlob.revocations.forEach { signable += it } - if (!authority.publicKey.verify(revocationBlob.signature, sha3_256(signable))) { + if (!authority.publicKey.verify( + revocationBlob.signature, + sha3_256(signable) + ) + ) { logger.warn("Peer ${peer.mid} might have altered the revoked signatures, skipping!") + return } + } else if (!unsafeInsertion) { + logger.info("Dropping unsolicited revocations.") + return } else { logger.info("Inserting revocations without verification as authority is not recognized.") } @@ -263,18 +353,20 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() revocationBlob.publicKeyHash, revocationBlob.version, revocationBlob.signature, - revocationBlob.revocations) + revocationBlob.revocations + ) } } else { logger.warn { "Received update for version ${payload.version} we did not request, dropping." } } - } } private fun serializeRevocationBlob(blob: RevocationBlob): ByteArray { var out = - blob.publicKeyHash + blob.signature + serializeULong(blob.version.toULong()) + serializeUInt(blob.revocations.size.toUInt()) + blob.publicKeyHash + blob.signature + serializeULong(blob.version.toULong()) + serializeUInt( + blob.revocations.size.toUInt() + ) for (hash in blob.revocations) { out += hash } @@ -298,8 +390,8 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() val revocations = mutableListOf() for (i in 0 until revocationAmount) { - val revocation = serialized.copyOfRange(offset, offset + SERIALIZED_SHA1_HASH_SIZE) - offset += SERIALIZED_SHA1_HASH_SIZE + val revocation = serialized.copyOfRange(offset, offset + SERIALIZED_SHA3_256_SIZE) + offset += SERIALIZED_SHA3_256_SIZE revocations.add(revocation) } @@ -332,7 +424,8 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() val size = deserializeUInt(serialized, localOffset).toInt() localOffset += SERIALIZED_UINT_SIZE for (i in 0 until size) { - val keyHash = serialized.copyOfRange(localOffset, localOffset + SERIALIZED_SHA1_HASH_SIZE) + val keyHash = + serialized.copyOfRange(localOffset, localOffset + SERIALIZED_SHA1_HASH_SIZE) localOffset += SERIALIZED_SHA1_HASH_SIZE val versionAmount = deserializeUInt(serialized, localOffset).toInt() localOffset += SERIALIZED_UINT_SIZE @@ -348,9 +441,10 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() val revocations = mutableListOf() for (k in 0 until revocationAmount) { - val revocation = serialized.copyOfRange(localOffset, localOffset + SERIALIZED_SHA1_HASH_SIZE) + val revocation = + serialized.copyOfRange(localOffset, localOffset + SERIALIZED_SHA3_256_SIZE) revocations.add(revocation) - localOffset += SERIALIZED_SHA1_HASH_SIZE + localOffset += SERIALIZED_SHA3_256_SIZE } revocationBlobs.add(RevocationBlob(keyHash, version, signature, revocations)) } @@ -359,33 +453,31 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() return out } - // fun setOnRevocationPresentationCallback(f: (List, List) -> Unit) { // this.onRevocationUpdatePreviewCallback = f // } - fun shutdown() { - this.gossipRoutine.cancel() - } - private fun gossipMyRevocations() { - val peers = this.getPeers() + val peers = this.fetchPeers() this.gossipRevocations(peers) } private fun getRandomPeers(amount: Int): List { - return this.getPeers().random(amount).toList() + return this.fetchPeers().random(amount).toList() } private fun gossipRevocations(peers: List) { val revocations = this.authorityManager.getLatestRevocationPreviews() + if (revocations.isEmpty()) { + return + } val payload = RevocationUpdatePreviewPayload(revocations) val packet = serializePacket(REVOCATION_PRESENTATION_PAYLOAD, payload) - runBlocking { - peers.forEach { - launch { - endpoint.send(it, packet) - } + peers.forEach { + if (!requestCache.has(AllowedUpdateRequestCache.generateId(it))) { + logger.info("Sending revocation preview to ${it.mid}.") + endpoint.send(it, packet) + this.requestCache.add(AllowedUpdateRequestCache(this.requestCache, it)) } } } @@ -397,6 +489,4 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() return RevocationCommunity(authorityManager) } } - - } From 37f9dbab4bf7bd073563c52f066b2f902cebc6fe Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Tue, 11 May 2021 16:05:15 +0200 Subject: [PATCH 119/144] Format queries + add revocation queries --- .../nl/tudelft/ipv8/sqldelight/DbAuthority.sq | 43 +++++++++++++++---- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq index 32d4a4ad..f78f6ca2 100644 --- a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq +++ b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq @@ -23,25 +23,34 @@ CREATE TABLE authorities ( ); insertRevocation: -INSERT INTO revocations (authority_id, version_id, revoked_hash) VALUES (?, ?, ?); +INSERT INTO revocations (authority_id, version_id, revoked_hash) +VALUES (?, ?, ?); insertVersion: -INSERT INTO versions (authority_id, version_number, signature) VALUES (?, ?, ?); +INSERT INTO versions (authority_id, version_number, signature) +VALUES (?, ?, ?); insertAuthority: -INSERT INTO authorities (public_key, public_key_hash, latest_version_id, recognized) VALUES (?, ?, ?, ?); +INSERT INTO authorities (public_key, public_key_hash, latest_version_id, recognized) +VALUES (?, ?, ?, ?); getAllRecognizedAuthorities: -SELECT authorities.public_key, authorities.public_key_hash, versions.version_number, authorities.recognized FROM authorities LEFT JOIN versions ON authorities.latest_version_id = versions.version_id WHERE authorities.recognized = 1; +SELECT A.public_key, A.public_key_hash, V.version_number, A.recognized FROM authorities AS A +LEFT JOIN versions AS V ON A.latest_version_id = V.version_id +WHERE A.recognized = 1; getAllAuthorities: -SELECT authorities.public_key, authorities.public_key_hash, versions.version_number, authorities.recognized FROM authorities LEFT JOIN versions ON authorities.latest_version_id = versions.version_id; +SELECT A.public_key, A.public_key_hash, V.version_number, A.recognized FROM authorities AS A +LEFT JOIN versions AS V ON A.latest_version_id = V.version_id; getAuthorityIdByHash: -SELECT authority_id FROM authorities WHERE authorities.public_key_hash = ? LIMIT 1; +SELECT authority_id FROM authorities +WHERE authorities.public_key_hash = ? LIMIT 1; getAuthorityByHash: -SELECT authorities.public_key, authorities.public_key_hash, versions.version_number, authorities.recognized FROM authorities LEFT JOIN versions ON authorities.latest_version_id = versions.version_id WHERE public_key_hash = ?; +SELECT A.public_key, A.public_key_hash, V.version_number, A.recognized FROM authorities AS A +LEFT JOIN versions AS V ON A.latest_version_id = V.version_id +WHERE public_key_hash = ?; recognizeAuthority: UPDATE authorities SET recognized = 1 WHERE public_key_hash = ?; @@ -68,7 +77,23 @@ getVersionsSince: SELECT version_number FROM versions WHERE authority_id = ? AND version_number > ?; getAllRevocations: -SELECT authorities.public_key_hash, versions.version_number, versions.signature, revocations.revoked_hash FROM authorities LEFT JOIN versions ON authorities.latest_version_id = versions.version_id LEFT JOIN revocations ON authorities.authority_id = revocations.authority_id; +SELECT A.public_key_hash, V.version_number, V.signature, R.revoked_hash FROM authorities AS A +LEFT JOIN versions AS V ON A.latest_version_id = V.version_id +LEFT JOIN revocations AS R ON A.authority_id = R.authority_id; getRevocations: -SELECT revoked_hash FROM revocations; \ No newline at end of file +SELECT revoked_hash FROM revocations; + +getNumberOfRevocations: +SELECT COUNT(*) FROM revocations; + +getMissingVersionByAuthorityID: +SELECT MIN(A.version_number) FROM versions AS A +WHERE A.authority_id = ?1 AND +NOT EXISTS ( + SELECT B.version_number FROM versions AS B + WHERE B.authority_id = ?1 AND A.version_number + 1 = B.version_number) +GROUP BY A.version_number; + +isRevoked: +SELECT 1 FROM revocations WHERE revoked_hash = ?; \ No newline at end of file From 1a1d5895172878c77bd0f918a2d25efdbb1f8bc0 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Tue, 11 May 2021 16:05:41 +0200 Subject: [PATCH 120/144] Add BloomFilter --- .../revocation/datastructures/BloomFilter.kt | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/datastructures/BloomFilter.kt diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/datastructures/BloomFilter.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/datastructures/BloomFilter.kt new file mode 100644 index 00000000..4f26d3ba --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/datastructures/BloomFilter.kt @@ -0,0 +1,45 @@ +package nl.tudelft.ipv8.attestation.revocation.datastructures + +import java.math.BigInteger +import java.security.MessageDigest +import java.util.BitSet +import java.util.concurrent.locks.ReentrantReadWriteLock +import kotlin.concurrent.read +import kotlin.concurrent.write + +/** + * Adapted from https://github.com/ackintosh/bloom-filter-kotlin. + */ +class BloomFilter(initialCapacity: Int) { + private val bits = BitSet(initialCapacity) + private val hash = Hash(initialCapacity) + private val lock = ReentrantReadWriteLock() + + fun add(value: ByteArray) { + lock.write { + for (seed in 1..3) { + bits.set(hash.call(seed, value)) + } + } + } + + fun probablyContains(value: ByteArray): Boolean { + lock.read { + for (seed in 1..3) { + if (!bits.get(hash.call(seed, value))) { + return false + } + } + } + return true + } + + private class Hash(val filterSize: Int) { + private val md5 = MessageDigest.getInstance("MD5") + + fun call(seed: Int, value: ByteArray) = + BigInteger(1, md5.digest(value + seed.toByte())) + .remainder(BigInteger.valueOf(filterSize.toLong())) + .toInt() + } +} From a2f7f97a7bc29b68d6b316f0fdd0b9eb3abf84b1 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Tue, 11 May 2021 16:06:02 +0200 Subject: [PATCH 121/144] Update AuthorityStore for new queries --- .../revocation/AuthoritySQLiteStore.kt | 32 +++++++++++++------ .../attestation/revocation/AuthorityStore.kt | 8 ++--- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt index 04cd159e..189de546 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt @@ -5,7 +5,6 @@ import nl.tudelft.ipv8.attestation.Authority import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.keyvault.defaultCryptoProvider import nl.tudelft.ipv8.sqldelight.Database -import nl.tudelft.ipv8.sqldelight.GetAllRevocations private val authorityMapper: ( ByteArray?, @@ -70,15 +69,15 @@ class AuthoritySQLiteStore(database: Database) : AuthorityStore { authorityId = dao.getAuthorityIdByHash(publicKeyHash).executeAsOne() } - if (version >= 2L) { - val previousId = - dao.getVersionByAuthorityIDandVersionNumber(authorityId, version - 1L) - .executeAsOneOrNull()?.version_id - if (previousId == null) { - logger.warn("Received revocations out of order, skipping!") - return - } - } + // if (version >= 2L) { + // val previousId = + // dao.getVersionByAuthorityIDandVersionNumber(authorityId, version - 1L) + // .executeAsOneOrNull()?.version_id + // if (previousId == null) { + // logger.error("Received revocations out of order, skipping!") + // throw IllegalStateException("Encountered out-of-order revocation version.") + // } + // } var versionId = dao.getVersionByAuthorityIDandVersionNumber(authorityId, version) @@ -122,4 +121,17 @@ class AuthoritySQLiteStore(database: Database) : AuthorityStore { override fun getAllRevocations(): List { return dao.getRevocations().executeAsList() } + + override fun getNumberOfRevocations(): Long { + return dao.getNumberOfRevocations().executeAsOne() + } + + override fun getMissingVersion(authorityKeyHash: ByteArray): Long? { + val authorityId = dao.getAuthorityIdByHash(authorityKeyHash).executeAsOneOrNull() + return authorityId?.let { dao.getMissingVersionByAuthorityID(it).executeAsOneOrNull()?.MIN } + } + + override fun isRevoked(signature: ByteArray): Boolean { + return dao.isRevoked(signature).executeAsOneOrNull()?.toInt() == 1 + } } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt index 3db11245..83d47420 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt @@ -1,9 +1,7 @@ package nl.tudelft.ipv8.attestation.revocation import nl.tudelft.ipv8.attestation.Authority -import nl.tudelft.ipv8.attestation.Revocations import nl.tudelft.ipv8.keyvault.PublicKey -import nl.tudelft.ipv8.sqldelight.GetAllRevocations class RevocationBlob( val publicKeyHash: ByteArray, @@ -22,7 +20,6 @@ interface AuthorityStore { fun insertTrustedAuthority(publicKey: PublicKey) fun insertAuthority(publicKey: PublicKey) fun insertAuthority(hash: ByteArray) - fun insertRevocations( publicKeyHash: ByteArray, version: Long, @@ -30,9 +27,10 @@ interface AuthorityStore { revokedHashes: List, ) + fun isRevoked(signature: ByteArray): Boolean fun getRevocations(publicKeyHash: ByteArray, versions: List): List - fun getVersionsSince(publicKeyHash: ByteArray, sinceVersion: Long): List - fun getAllRevocations(): List + fun getNumberOfRevocations(): Long + fun getMissingVersion(authorityKeyHash: ByteArray): Long? } From 45502641f000d53719a7732ed6a3510a31235926 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Tue, 11 May 2021 16:06:22 +0200 Subject: [PATCH 122/144] Add sent update preview cache --- .../caches/AllowedUpdateRequestCache.kt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/AllowedUpdateRequestCache.kt diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/AllowedUpdateRequestCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/AllowedUpdateRequestCache.kt new file mode 100644 index 00000000..7b241908 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/AllowedUpdateRequestCache.kt @@ -0,0 +1,23 @@ +package nl.tudelft.ipv8.attestation.revocation.caches + +import nl.tudelft.ipv8.Peer +import nl.tudelft.ipv8.attestation.RequestCache +import nl.tudelft.ipv8.attestation.wallet.caches.HashCache +import nl.tudelft.ipv8.attestation.wallet.caches.NumberCache +import java.math.BigInteger + +const val ALLOWED_UPDATE_REQUEST_CACHE_PREFIX = "allowed-update-request" + +class AllowedUpdateRequestCache( + requestCache: RequestCache, + peer: Peer +) : + NumberCache(requestCache, ALLOWED_UPDATE_REQUEST_CACHE_PREFIX, this.generateId(peer).second) { + + + companion object { + fun generateId(peer: Peer): Pair { + return HashCache.idFromHash(ALLOWED_UPDATE_REQUEST_CACHE_PREFIX, peer.publicKey.keyToHash()) + } + } +} From a7f459744ed1b1c9c30fc91249c302baaca17ca8 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Tue, 11 May 2021 16:06:38 +0200 Subject: [PATCH 123/144] Format cache and payload --- .../revocation/caches/PendingRevocationUpdateCache.kt | 10 ++++++---- .../payloads/RevocationUpdateChunkPayload.kt | 6 +++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt index 571276b8..b41c16a0 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt @@ -13,11 +13,13 @@ class PendingRevocationUpdateCache( requestCache: RequestCache, senderHash: ByteArray, signeeHash: ByteArray, - version: Long, - override val timeout: Int = 10, + version: Long ) : - NumberCache(requestCache, PENDING_REVOCATION_UPDATE_CACHE_PREFIX, this.generateId( - senderHash, signeeHash, version).second) { + NumberCache( + requestCache, PENDING_REVOCATION_UPDATE_CACHE_PREFIX, this.generateId( + senderHash, signeeHash, version + ).second + ) { val revocationMap = hashMapOf() diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateChunkPayload.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateChunkPayload.kt index c95708a1..ba2604e9 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateChunkPayload.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/payloads/RevocationUpdateChunkPayload.kt @@ -4,13 +4,13 @@ import nl.tudelft.ipv8.messaging.* class RevocationUpdateChunkPayload( val sequenceNumber: Int, - val hash: ByteArray, - val publicKeyHash: ByteArray, + val payloadHash: ByteArray, + val authorityKeyHash: ByteArray, val version: Long, val data: ByteArray, ) : Serializable { override fun serialize(): ByteArray { - return serializeUInt(sequenceNumber.toUInt()) + hash + publicKeyHash + serializeULong(version.toULong()) + serializeVarLen( + return serializeUInt(sequenceNumber.toUInt()) + payloadHash + authorityKeyHash + serializeULong(version.toULong()) + serializeVarLen( data) } From 38b1ee19ab0007a9753057cb8edd3257e12fff27 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Tue, 11 May 2021 16:06:54 +0200 Subject: [PATCH 124/144] Use BloomFilter in AuthorityManager + fix member checking --- .../ipv8/attestation/AuthorityManager.kt | 52 ++++++++++++++++--- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt index 6f1b5753..f8242e37 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt @@ -1,7 +1,11 @@ package nl.tudelft.ipv8.attestation +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import mu.KotlinLogging import nl.tudelft.ipv8.attestation.revocation.AuthorityStore import nl.tudelft.ipv8.attestation.revocation.RevocationBlob +import nl.tudelft.ipv8.attestation.revocation.datastructures.BloomFilter import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.util.ByteArrayKey import nl.tudelft.ipv8.util.toKey @@ -20,11 +24,27 @@ class Revocations( val revocations: List, ) +const val DEFAULT_CAPACITY = 100 +private val logger = KotlinLogging.logger {} + class AuthorityManager(val authorityDatabase: AuthorityStore) { private val trustedAuthorities = hashMapOf() + private val revocations: BloomFilter private val lock = Object() + init { + loadTrustedAuthorities() + val revocationsAmount = authorityDatabase.getNumberOfRevocations() + if (revocationsAmount + 100 >= Integer.MAX_VALUE) { + logger.error("Number of revocations overflows bloom filter capacity.") + } + revocations = BloomFilter(revocationsAmount.toInt() + DEFAULT_CAPACITY) + GlobalScope.launch { + authorityDatabase.getAllRevocations().forEach { revocations.add(it) } + } + } + fun loadTrustedAuthorities() { val authorities = authorityDatabase.getRecognizedAuthorities() synchronized(lock) { @@ -35,7 +55,7 @@ class AuthorityManager(val authorityDatabase: AuthorityStore) { } fun verify(signature: ByteArray): Boolean { - return !getAllRevocations().any { it.contentEquals(signature) } + return !(this.revocations.probablyContains(signature) && authorityDatabase.isRevoked(signature)) } fun insertRevocations( @@ -48,13 +68,31 @@ class AuthorityManager(val authorityDatabase: AuthorityStore) { if (this.trustedAuthorities.containsKey(publicKeyHash.toKey())) { this.trustedAuthorities[publicKeyHash.toKey()]!!.version = versionNumber } + revokedHashes.forEach { revocations.add(it) } } + /** + * Method for fetching all latest known versions. + */ fun getLatestRevocationPreviews(): Map { val authorities = authorityDatabase.getKnownAuthorities() val localRefs = hashMapOf() authorities.forEach { - localRefs[it.hash.toKey()] = it.version + if (it.version > 0) + localRefs[it.hash.toKey()] = it.version + } + return localRefs + } + + /** + * Method for fetching the lowest missing versions. + */ + fun getMissingRevocationPreviews(): Map { + val authorities = authorityDatabase.getKnownAuthorities() + val localRefs = hashMapOf() + authorities.forEach { + localRefs[it.hash.toKey()] = + it.version.coerceAtMost(authorityDatabase.getMissingVersion(it.hash) ?: Long.MAX_VALUE) } return localRefs } @@ -82,7 +120,7 @@ class AuthorityManager(val authorityDatabase: AuthorityStore) { fun addTrustedAuthority(publicKey: PublicKey) { val hash = publicKey.keyToHash() - if (!this.contains(hash)) { + if (!this.containsAuthority(hash)) { val localAuthority = authorityDatabase.getAuthorityByHash(hash) if (localAuthority == null) { authorityDatabase.insertTrustedAuthority(publicKey) @@ -99,18 +137,18 @@ class AuthorityManager(val authorityDatabase: AuthorityStore) { } fun deleteTrustedAuthority(hash: ByteArray) { - if (this.contains(hash)) { + if (this.containsAuthority(hash)) { this.trustedAuthorities.remove(hash.toKey()) this.authorityDatabase.disregardAuthority(hash) } } fun getTrustedAuthority(hash: ByteArray): Authority? { - return this.trustedAuthorities.get(hash.toKey()) + return this.trustedAuthorities[hash.toKey()] } fun getAuthority(hash: ByteArray): Authority? { - return this.trustedAuthorities.get(hash.toKey()) ?: authorityDatabase.getAuthorityByHash( + return this.trustedAuthorities[hash.toKey()] ?: authorityDatabase.getAuthorityByHash( hash ) } @@ -119,7 +157,7 @@ class AuthorityManager(val authorityDatabase: AuthorityStore) { return this.deleteTrustedAuthority(publicKey.keyToHash()) } - fun contains(hash: ByteArray): Boolean { + fun containsAuthority(hash: ByteArray): Boolean { return this.trustedAuthorities.containsKey(hash.toKey()) } } From 8d479c27a83684fc024ea424fa01d6bcd81c7dc7 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Tue, 11 May 2021 17:41:36 +0200 Subject: [PATCH 125/144] Rename AllowedRevocationUpdateRequestCache --- .../ipv8/attestation/revocation/RevocationCommunity.kt | 8 ++++---- ...stCache.kt => AllowedRevocationUpdateRequestCache.kt} | 9 ++++----- 2 files changed, 8 insertions(+), 9 deletions(-) rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/{AllowedUpdateRequestCache.kt => AllowedRevocationUpdateRequestCache.kt} (55%) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt index 26102ebc..74d27e88 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt @@ -12,7 +12,7 @@ import nl.tudelft.ipv8.attestation.revocation.payloads.RevocationUpdateChunkPayl import nl.tudelft.ipv8.attestation.revocation.payloads.RevocationUpdatePreviewPayload import nl.tudelft.ipv8.attestation.revocation.payloads.RevocationUpdateRequestPayload import nl.tudelft.ipv8.attestation.RequestCache -import nl.tudelft.ipv8.attestation.revocation.caches.AllowedUpdateRequestCache +import nl.tudelft.ipv8.attestation.revocation.caches.AllowedRevocationUpdateRequestCache import nl.tudelft.ipv8.attestation.wallet.caches.PeerCache import nl.tudelft.ipv8.keyvault.PrivateKey import nl.tudelft.ipv8.messaging.* @@ -223,7 +223,7 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() sequenceNumber += 1 } } else { - val solicited = this.requestCache.has(AllowedUpdateRequestCache.generateId(peer)) + val solicited = this.requestCache.has(AllowedRevocationUpdateRequestCache.generateId(peer)) if (solicited) { val revocations = mutableListOf() @@ -474,10 +474,10 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() val payload = RevocationUpdatePreviewPayload(revocations) val packet = serializePacket(REVOCATION_PRESENTATION_PAYLOAD, payload) peers.forEach { - if (!requestCache.has(AllowedUpdateRequestCache.generateId(it))) { + if (!requestCache.has(AllowedRevocationUpdateRequestCache.generateId(it))) { logger.info("Sending revocation preview to ${it.mid}.") endpoint.send(it, packet) - this.requestCache.add(AllowedUpdateRequestCache(this.requestCache, it)) + this.requestCache.add(AllowedRevocationUpdateRequestCache(this.requestCache, it)) } } } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/AllowedUpdateRequestCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/AllowedRevocationUpdateRequestCache.kt similarity index 55% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/AllowedUpdateRequestCache.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/AllowedRevocationUpdateRequestCache.kt index 7b241908..94ba6f75 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/AllowedUpdateRequestCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/AllowedRevocationUpdateRequestCache.kt @@ -6,18 +6,17 @@ import nl.tudelft.ipv8.attestation.wallet.caches.HashCache import nl.tudelft.ipv8.attestation.wallet.caches.NumberCache import java.math.BigInteger -const val ALLOWED_UPDATE_REQUEST_CACHE_PREFIX = "allowed-update-request" +const val ALLOWED_REVOCATION_UPDATE_REQUEST_CACHE_PREFIX = "allowed-update-request" -class AllowedUpdateRequestCache( +class AllowedRevocationUpdateRequestCache( requestCache: RequestCache, peer: Peer ) : - NumberCache(requestCache, ALLOWED_UPDATE_REQUEST_CACHE_PREFIX, this.generateId(peer).second) { - + NumberCache(requestCache, ALLOWED_REVOCATION_UPDATE_REQUEST_CACHE_PREFIX, this.generateId(peer).second) { companion object { fun generateId(peer: Peer): Pair { - return HashCache.idFromHash(ALLOWED_UPDATE_REQUEST_CACHE_PREFIX, peer.publicKey.keyToHash()) + return HashCache.idFromHash(ALLOWED_REVOCATION_UPDATE_REQUEST_CACHE_PREFIX, peer.publicKey.keyToHash()) } } } From d0e60d27fe59464ad75dfef962a600848424609c Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Tue, 11 May 2021 17:42:02 +0200 Subject: [PATCH 126/144] Use defined authorityManager in CommunicationChannel --- .../ipv8/attestation/communication/CommunicationChannel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt index e570790e..873455e1 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt @@ -302,7 +302,7 @@ class CommunicationChannel( // Check if authority is recognized and the corresponding signature is correct. if (!attestors.any { attestor -> val authority = - this.revocationOverlay.authorityManager.getTrustedAuthority(attestor.first) + this.authorityManager.getTrustedAuthority(attestor.first) authority?.let { it.publicKey?.verify(attestor.second, metadata.hash) } == true From 2df123a78913fae2b2107915566ea749135d1429 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 12 May 2021 22:24:45 +0200 Subject: [PATCH 127/144] Add revocation update callback + initialize fetchPeers per default --- .../revocation/RevocationCommunity.kt | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt index 74d27e88..52f4467b 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt @@ -19,7 +19,7 @@ import nl.tudelft.ipv8.messaging.* import nl.tudelft.ipv8.peerdiscovery.Network import nl.tudelft.ipv8.util.* -const val DELAY = 30000L +const val DELAY = 10000L const val DEFAULT_GOSSIP_AMOUNT = 5 private const val CHUNK_SIZE = 800 @@ -42,31 +42,30 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() override lateinit var network: Network // Possibility to override the getPeers method when using shared network between Communities. - private lateinit var fetchPeers: () -> List + private var fetchPeers: () -> List = ::getPeers + + private lateinit var revocationUpdateCallback: (publicKeyHash: ByteArray, version: Long, amount: Int) -> Unit constructor( myPeer: Peer, endpoint: EndpointAggregator, network: Network, authorityManager: AuthorityManager, - getPeers: (() -> List)? + onGetPeers: (() -> List)? = null ) : this( authorityManager ) { this.myPeer = myPeer this.endpoint = endpoint this.network = network - this.fetchPeers = getPeers ?: this::getPeers + if (onGetPeers != null) { + this.fetchPeers = onGetPeers + } } private lateinit var gossipRoutine: Job - - private val lock = Object() private val requestCache = RequestCache() -// private lateinit var onRevocationUpdatePreviewCallback: (List>) -> Unit -// private lateinit var onRevocationUpdateRequestCallback: (Map>) -> Unit - init { messageHandlers[REVOCATION_PRESENTATION_PAYLOAD] = ::onRevocationUpdatePreviewPayloadWrapper messageHandlers[REVOCATION_UPDATE_REQUEST_PAYLOAD] = @@ -108,14 +107,12 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() signature, attestationHashes ) -// this.gossipMyRevocations() } private fun onRevocationUpdatePreviewPayloadWrapper(packet: Packet) { val (peer, payload) = packet.getAuthPayload(RevocationUpdatePreviewPayload.Deserializer) logger.info("Received RevocationPresentationPayload from ${peer.mid}.") this.onRevocationUpdatePreviewPayload(peer, payload) -// this.onRevocationUpdatePreviewCallback(payload.revocationRefs) } private fun onRevocationUpdateRequestPayloadWrapper(packet: Packet) { @@ -134,7 +131,8 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() peer: Peer, payload: RevocationUpdatePreviewPayload ) { - val remoteRefs = payload.revocationRefs.filter { authorityManager.containsAuthority(it.key.bytes) } + val remoteRefs = + payload.revocationRefs.filter { authorityManager.containsAuthority(it.key.bytes) } val localRefs = this.authorityManager.getMissingRevocationPreviews() val requestedRefs = hashMapOf() @@ -223,7 +221,8 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() sequenceNumber += 1 } } else { - val solicited = this.requestCache.has(AllowedRevocationUpdateRequestCache.generateId(peer)) + val solicited = + this.requestCache.has(AllowedRevocationUpdateRequestCache.generateId(peer)) if (solicited) { val revocations = mutableListOf() @@ -306,6 +305,9 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() blob.signature, blob.revocations ) + if (this::revocationUpdateCallback.isInitialized) { + this.revocationUpdateCallback(hash.bytes, blob.version, blob.revocations.size) + } } } } @@ -355,6 +357,9 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() revocationBlob.signature, revocationBlob.revocations ) + if (this::revocationUpdateCallback.isInitialized) { + this.revocationUpdateCallback(revocationBlob.publicKeyHash, revocationBlob.version, revocationBlob.revocations.size) + } } } else { logger.warn { "Received update for version ${payload.version} we did not request, dropping." } @@ -453,10 +458,6 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() return out } -// fun setOnRevocationPresentationCallback(f: (List, List) -> Unit) { -// this.onRevocationUpdatePreviewCallback = f -// } - private fun gossipMyRevocations() { val peers = this.fetchPeers() this.gossipRevocations(peers) @@ -482,6 +483,10 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() } } + fun setRevocationUpdateCallback(f: (publicKeyHash: ByteArray, version: Long, amount: Int) -> Unit) { + this.revocationUpdateCallback = f + } + class Factory( private val authorityManager: AuthorityManager, ) : Overlay.Factory(RevocationCommunity::class.java) { From 00d0d7d6dd56710535b942970b4dfb32daeba425 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 12 May 2021 22:26:17 +0200 Subject: [PATCH 128/144] Do not short circuit boolean operators --- .../ipv8/attestation/identity/manager/IdentityManager.kt | 2 +- .../java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt index fbeda0a9..97040883 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/IdentityManager.kt @@ -67,7 +67,7 @@ class IdentityManager(internal var database: IdentityStore) { ) ) authorityOffset += authoritySize - correct = correct && pseudonym.addAttestation( + correct = correct and pseudonym.addAttestation( authority, IdentityAttestation.deserialize(serializedAttestations, authority, attestationOffset) ) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt index da500937..feb98b34 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt @@ -25,7 +25,7 @@ class TokenTree(publicKey: PublicKey? = null, privateKey: PrivateKey? = null) { init { if (publicKey != null && privateKey == null) { - this.publicKey = publicKey.pub() + this.publicKey = publicKey this.privateKey = null } else if (publicKey == null && privateKey != null) { this.privateKey = privateKey @@ -148,7 +148,7 @@ class TokenTree(publicKey: PublicKey? = null, privateKey: PrivateKey? = null) { val chunkSize = DEFAULT_CHUNK_SIZE + signatureLength var isCorrect = true for (i in serialized.indices step chunkSize) { - isCorrect = isCorrect && this.gatherToken(Token.deserialize(serialized, this.publicKey, offset = i)) != null + isCorrect = isCorrect and (this.gatherToken(Token.deserialize(serialized, this.publicKey, offset = i)) != null) } return isCorrect } @@ -169,7 +169,7 @@ class TokenTree(publicKey: PublicKey? = null, privateKey: PrivateKey? = null) { } if (retryToken != null) { this.unchained.remove(retryToken) - if (this.gatherToken(retryToken) != null) { + if (this.gatherToken(retryToken) == null) { logger.warn { "Dropped illegal token $retryToken!" } } } From 8dec4986e14c48e2d9ab39df0527b55c18c867a5 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Wed, 12 May 2021 22:27:11 +0200 Subject: [PATCH 129/144] Fix token ordering + verify metadata correctly --- .../identity/manager/PseudonymManager.kt | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt index 7cca3f3f..220b1b8a 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/manager/PseudonymManager.kt @@ -48,19 +48,19 @@ class PseudonymManager( if (metadata.verify(this.publicKey) && metadata.tokenPointer.contentEquals(token.hash)) { this.database.insertMetadata(this.publicKey, metadata) - } - val validAttestations = mutableSetOf() + val validAttestations = mutableSetOf() - for ((authorityPublicKey, identityAttestation) in attestations) { - if (this.addAttestation(authorityPublicKey, identityAttestation)) { - validAttestations += identityAttestation + for ((authorityPublicKey, identityAttestation) in attestations) { + if (this.addAttestation(authorityPublicKey, identityAttestation)) { + validAttestations.add(identityAttestation) + } } - } - val out = Credential(metadata, validAttestations) - this.credentials.plusAssign(out) - return out + val out = Credential(metadata, validAttestations) + this.credentials.add(out) + return out + } } return null } @@ -90,9 +90,13 @@ class PseudonymManager( metadata: HashMap, after: Metadata? = null, ): Credential { - val preceding = if (after == null) null else this.tree.elements.get(after.tokenPointer.toKey()) + val preceding = if (after == null) null else this.tree.elements[after.tokenPointer.toKey()] val token = this.tree.addByHash(attestationHash, preceding) - val metadataObj = Metadata(token.hash, JSONObject(metadata).toString().toByteArray(), this.tree.privateKey) + val metadataObj = Metadata( + token.hash, + JSONObject(metadata).toString().toByteArray(), + this.tree.privateKey + ) return this.addCredential(token, metadataObj, setOf())!! } @@ -104,11 +108,14 @@ class PseudonymManager( return this.database.getCredentialsFor(this.publicKey) } - fun discloseCredentials(credentials: List, attestationSelector: Set): Disclosure { + fun discloseCredentials( + credentials: List, + attestationSelector: Set + ): Disclosure { return createDisclosure(credentials.map { it.metadata }.toSet(), attestationSelector) } - fun createDisclosure(metadata: Set, attestationSelector: Set): Disclosure { + private fun createDisclosure(metadata: Set, attestationSelector: Set): Disclosure { val attSelector = attestationSelector.map { ByteArrayKey(it) } var serializedMetadata = byteArrayOf() for (md in metadata) { @@ -130,7 +137,7 @@ class PseudonymManager( } } val requiredTokenHashes = metadata.map { it.tokenPointer } - val tokens = mutableSetOf() + val tokens = mutableListOf() for (requiredTokenHash in requiredTokenHashes) { val rootToken = this.tree.elements[requiredTokenHash.toKey()]!! @@ -139,14 +146,17 @@ class PseudonymManager( throw RuntimeException("Attempted to create disclosure for undisclosable Token!") } - tokens += rootToken + tokens.add(rootToken) var currentToken = rootToken while (!currentToken.previousTokenHash.contentEquals(this.tree.genesisHash)) { currentToken = this.tree.elements[currentToken.previousTokenHash.toKey()]!! - tokens += currentToken + tokens.add(currentToken) } } + + // This is the order that they are present in the tree, as we stepped backwards. + tokens.reverse() var serializedTokens = byteArrayOf() tokens.forEach { serializedTokens += it.getPlaintextSigned() } return Disclosure(serializedMetadata, serializedTokens, attestations, authorities) From b9f663b4e104646f8d40939eaf53e83b8a2f757a Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 13 May 2021 11:02:34 +0200 Subject: [PATCH 130/144] Decrease cache timeouts + check for network initialization --- .../ipv8/attestation/revocation/RevocationCommunity.kt | 6 ++++-- .../caches/AllowedRevocationUpdateRequestCache.kt | 2 +- .../revocation/caches/PendingRevocationUpdateCache.kt | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt index 52f4467b..48efc5a0 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt @@ -77,8 +77,10 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() fun start() { this.gossipRoutine = GlobalScope.launch { while (isActive) { - gossipRevocations(getRandomPeers(DEFAULT_GOSSIP_AMOUNT)) - delay(DELAY) + if (::network.isInitialized) { + gossipRevocations(getRandomPeers(DEFAULT_GOSSIP_AMOUNT)) + delay(DELAY) + } } } } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/AllowedRevocationUpdateRequestCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/AllowedRevocationUpdateRequestCache.kt index 94ba6f75..8625a81f 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/AllowedRevocationUpdateRequestCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/AllowedRevocationUpdateRequestCache.kt @@ -12,7 +12,7 @@ class AllowedRevocationUpdateRequestCache( requestCache: RequestCache, peer: Peer ) : - NumberCache(requestCache, ALLOWED_REVOCATION_UPDATE_REQUEST_CACHE_PREFIX, this.generateId(peer).second) { + NumberCache(requestCache, ALLOWED_REVOCATION_UPDATE_REQUEST_CACHE_PREFIX, this.generateId(peer).second, timeout = 30) { companion object { fun generateId(peer: Peer): Pair { diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt index b41c16a0..574a15e8 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt @@ -18,7 +18,7 @@ class PendingRevocationUpdateCache( NumberCache( requestCache, PENDING_REVOCATION_UPDATE_CACHE_PREFIX, this.generateId( senderHash, signeeHash, version - ).second + ).second, timeout = 30 ) { val revocationMap = hashMapOf() From 5a3ce5a1d6cce713738e77ab26865ba468cf7cf6 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 13 May 2021 11:05:19 +0200 Subject: [PATCH 131/144] Add method for checking revocations per authority --- .../attestation/revocation/AuthoritySQLiteStore.kt | 11 ++++++++++- .../ipv8/attestation/revocation/AuthorityStore.kt | 1 + .../nl/tudelft/ipv8/sqldelight/DbAuthority.sq | 5 ++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt index 189de546..0a3be5f3 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt @@ -132,6 +132,15 @@ class AuthoritySQLiteStore(database: Database) : AuthorityStore { } override fun isRevoked(signature: ByteArray): Boolean { - return dao.isRevoked(signature).executeAsOneOrNull()?.toInt() == 1 + return dao.isRevoked(signature).executeAsList().isNotEmpty() + } + + override fun isRevokedBy(signature: ByteArray, authorityKeyHash: ByteArray): Boolean { + val authorityId = dao.getAuthorityIdByHash(authorityKeyHash).executeAsOneOrNull() + return if (authorityId == null) { + false + } else { + dao.isRevokedBy(signature, authorityId).executeAsList().isNotEmpty() + } } } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt index 83d47420..22187733 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthorityStore.kt @@ -28,6 +28,7 @@ interface AuthorityStore { ) fun isRevoked(signature: ByteArray): Boolean + fun isRevokedBy(signature: ByteArray, authorityKeyHash: ByteArray): Boolean fun getRevocations(publicKeyHash: ByteArray, versions: List): List fun getVersionsSince(publicKeyHash: ByteArray, sinceVersion: Long): List fun getAllRevocations(): List diff --git a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq index f78f6ca2..241ce6a5 100644 --- a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq +++ b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq @@ -96,4 +96,7 @@ NOT EXISTS ( GROUP BY A.version_number; isRevoked: -SELECT 1 FROM revocations WHERE revoked_hash = ?; \ No newline at end of file +SELECT 1 FROM revocations WHERE revoked_hash = ?; + +isRevokedBy: +SELECT 1 FROM revocations WHERE revoked_hash = ? AND authority_id = ?; From ec0992849ec1fc99dff6274a7e23c647de9d4891 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 13 May 2021 11:06:16 +0200 Subject: [PATCH 132/144] Add verification per authority --- .../ipv8/attestation/AuthorityManager.kt | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt index f8242e37..6dd55583 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/AuthorityManager.kt @@ -17,13 +17,6 @@ class Authority( val recognized: Boolean = false, ) -class Revocations( - val publicKeyHash: String, - val encryptedVersion: ByteArray, - val signature: String, - val revocations: List, -) - const val DEFAULT_CAPACITY = 100 private val logger = KotlinLogging.logger {} @@ -55,7 +48,16 @@ class AuthorityManager(val authorityDatabase: AuthorityStore) { } fun verify(signature: ByteArray): Boolean { - return !(this.revocations.probablyContains(signature) && authorityDatabase.isRevoked(signature)) + return !(this.revocations.probablyContains(signature) && authorityDatabase.isRevoked( + signature + )) + } + + fun verify(signature: ByteArray, authorityKeyHash: ByteArray): Boolean { + return !(this.revocations.probablyContains(signature) && authorityDatabase.isRevokedBy( + signature, + authorityKeyHash + )) } fun insertRevocations( @@ -92,7 +94,9 @@ class AuthorityManager(val authorityDatabase: AuthorityStore) { val localRefs = hashMapOf() authorities.forEach { localRefs[it.hash.toKey()] = - it.version.coerceAtMost(authorityDatabase.getMissingVersion(it.hash) ?: Long.MAX_VALUE) + it.version.coerceAtMost( + authorityDatabase.getMissingVersion(it.hash) ?: Long.MAX_VALUE + ) } return localRefs } From 0fd3aeb763f0181939d38fe954779737aeb7a2bb Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 13 May 2021 11:07:04 +0200 Subject: [PATCH 133/144] Add revocation check + empty attestations check --- .../attestation/communication/CommunicationChannel.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt index 873455e1..cf0f433d 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt @@ -357,6 +357,9 @@ class CommunicationChannel( for (credential in pseudonym.getCredentials()) { val attestations = credential.attestations.toList() + if (attestations.isEmpty()) { + continue + } val attestors = mutableListOf>() @@ -396,6 +399,7 @@ class CommunicationChannel( fun getAttributesSignedBy(peer: Peer): List { val db = this.identityOverlay.identityManager.database + val myKeyHash = myPeer.publicKey.keyToHash() // Exclude own public key val subjects = db.getKnownSubjects() - peer.publicKey val out = mutableListOf() @@ -409,12 +413,13 @@ class CommunicationChannel( metadata.hash, metadata, md.getString("name"), - md.getDouble("date").toFloat() + md.getDouble("date").toFloat(), + !this.revocationOverlay.authorityManager.verify(metadata.hash, myKeyHash) ) ) } } - return out.sortedBy { it.publicKey.keyToHash().toHex() } + return out.sortedBy { -it.signDate } } @Deprecated("This should not be used.") @@ -450,6 +455,7 @@ class SubjectAttestationPresentation( val metadata: Metadata, val attributeName: String, val signDate: Float, + val isRevoked: Boolean ) { override fun equals(other: Any?): Boolean { return other is SubjectAttestationPresentation && this.publicKey == other.publicKey && this.metadata == other.metadata From 304c580d91fb549ed9e534936e6099f263151159 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 13 May 2021 11:09:12 +0200 Subject: [PATCH 134/144] Format IdentityCommunity + use mutablemaps --- .../attestation/identity/IdentityCommunity.kt | 77 ++++++++++++------- 1 file changed, 50 insertions(+), 27 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index 5a40fc5e..464bd67f 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -67,9 +67,9 @@ class IdentityCommunity( private val knownAttestationHashes = hashMapOf() private val pseudonymManager = this.identityManager.getPseudonym(this.myPeer.key) - private var tokenChain: List = mutableListOf() - private var metadataChain: List = mutableListOf() - private var attestationChain: List = mutableListOf() + private var tokenChain: MutableList = mutableListOf() + private var metadataChain: MutableList = mutableListOf() + private var attestationChain: MutableList = mutableListOf() private val permissions: HashMap = hashMapOf() init { @@ -77,16 +77,16 @@ class IdentityCommunity( super.network = network for (token in this.pseudonymManager.tree.elements.values) { - val chain = this.pseudonymManager.tree.getRootPath(token) + val chain = this.pseudonymManager.tree.getRootPath(token).reversed() if (chain.size > this.tokenChain.size) { - this.tokenChain = chain + this.tokenChain = chain.toMutableList() } } for (credential in this.pseudonymManager.getCredentials()) { for (token in this.tokenChain) { if (credential.metadata.tokenPointer.contentEquals(token.hash)) { - this.metadataChain += credential.metadata - this.attestationChain += credential.attestations + this.metadataChain.add(credential.metadata) + this.attestationChain.addAll(credential.attestations) break } } @@ -142,7 +142,7 @@ class IdentityCommunity( val hash = if (attributeHash.size == 20) padSHA1Hash(attributeHash) else attributeHash for (credential in this.pseudonymManager.getCredentials()) { val token = - this.pseudonymManager.tree.elements.get(ByteArrayKey(credential.metadata.tokenPointer)) + this.pseudonymManager.tree.elements[ByteArrayKey(credential.metadata.tokenPointer)] if (token?.contentHash.contentEquals(hash)) { return credential.metadata } @@ -150,7 +150,11 @@ class IdentityCommunity( return null } - private fun shouldSign(pseudonym: PseudonymManager, metadata: Metadata, isVerification: Boolean = false): Boolean { + private fun shouldSign( + pseudonym: PseudonymManager, + metadata: Metadata, + isVerification: Boolean = false + ): Boolean { val transaction = JSONObject(String(metadata.serializedMetadata)) val requestedKeys = transaction.keySet() if (!pseudonym.tree.elements.containsKey(metadata.tokenPointer.toKey())) { @@ -186,8 +190,7 @@ class IdentityCommunity( } if (this.knownAttestationHashes[attributeHash.toKey()]!!.metadata != null && transaction.asMap().filterKeys { it !in DEFAULT_METADATA } - // TODO: Remove filter here. - != this.knownAttestationHashes[attributeHash.toKey()]!!.metadata!!.filterKeys { it !in DEFAULT_METADATA } + != this.knownAttestationHashes[attributeHash.toKey()]!!.metadata!! ) { logger.debug("Not signing $metadata, metadata does not match!") return false @@ -217,7 +220,7 @@ class IdentityCommunity( } packetSpace = max(0, packetSpace) val trimLength = packetSpace / tokenSize - tokensOut = tokens.copyOfRange(tokens.size - (trimLength * tokenSize), tokens.size) + tokensOut = tokens.copyOfRange(0, (trimLength * tokenSize)) } return Disclosure(metadata, tokensOut, attestations, authorities) } @@ -276,7 +279,8 @@ class IdentityCommunity( ) val disclosureJSON = JSONObject(disclosureInformation) - val requiredAttributes = listOf(disclosureJSON.getString("attestationHash").hexToBytes().toKey()) + val requiredAttributes = + listOf(disclosureJSON.getString("attestationHash").hexToBytes().toKey()) val knownAttributes: List = pseudonym.tree.elements.values.map { ByteArrayKey(it.contentHash) } @@ -313,7 +317,14 @@ class IdentityCommunity( if (!knownAttributes.contains(attributeHash)) { logger.info("Missing information for attestation ${attributeHash.bytes.toHex()}, requesting more.") // TODO: add second parameter for uniqueness. - requestCache.add(TokenRequestCache(requestCache, peer.mid, attributeName, disclosureInformation)) + requestCache.add( + TokenRequestCache( + requestCache, + peer.mid, + attributeName, + disclosureInformation + ) + ) val payload = RequestMissingPayload(pseudonym.tree.elements.size) this.endpoint.send(peer, serializePacket(REQUEST_MISSING_PAYLOAD, payload)) } @@ -325,11 +336,11 @@ class IdentityCommunity( credential: Credential, presentationMetadata: String, ) { - // val credential = this.selfAdvertise(attributeHash, attributeName, blockType, metadata) this.permissions[peer] = this.tokenChain.size val disclosure = this.pseudonymManager.discloseCredentials(listOf(credential), setOf()) val (metadataObj, tokens, attestations, authorities) = this.fitDisclosure(disclosure) - val payload = DisclosePayload(metadataObj, tokens, attestations, authorities, presentationMetadata) + val payload = + DisclosePayload(metadataObj, tokens, attestations, authorities, presentationMetadata) this.endpoint.send(peer, serializePacket(DISCLOSURE_PAYLOAD, payload)) } @@ -372,15 +383,16 @@ class IdentityCommunity( if (this.metadataChain.isNotEmpty()) this.metadataChain.last() else null ) - this.attestationChain += credential.attestations - this.metadataChain += credential.metadata - this.tokenChain += this.pseudonymManager.tree.elements[credential.metadata.tokenPointer.toKey()]!! + this.attestationChain.addAll(credential.attestations) + this.metadataChain.add(credential.metadata) + this.tokenChain.add(pseudonymManager.tree.elements[credential.metadata.tokenPointer.toKey()]!!) return credential } private fun onDisclosure(peer: Peer, payload: DisclosePayload) { - val isAttestationRequest = this.knownAttestationHashes.values.any { it.publicKey == peer.publicKey } + val isAttestationRequest = + this.knownAttestationHashes.values.any { it.publicKey == peer.publicKey } val disclosureMD = JSONObject(payload.advertisementInformation ?: "{}") val id = disclosureMD.optString("id") val idPair = DisclosureRequestCache.idFromUUID(id) @@ -392,7 +404,12 @@ class IdentityCommunity( val cache = this.requestCache.pop(idPair)!! as DisclosureRequestCache this.receivedDisclosureForPresentation( peer, - Disclosure(payload.metadata, payload.tokens, payload.attestations, payload.authorities), + Disclosure( + payload.metadata, + payload.tokens, + payload.attestations, + payload.authorities + ), cache.disclosureRequest.attributeName, payload.advertisementInformation!! ) @@ -400,7 +417,12 @@ class IdentityCommunity( isAttestationRequest -> { this.receivedDisclosureForAttest( peer, - Disclosure(payload.metadata, payload.tokens, payload.attestations, payload.authorities) + Disclosure( + payload.metadata, + payload.tokens, + payload.attestations, + payload.authorities + ) ) } else -> { @@ -421,23 +443,24 @@ class IdentityCommunity( private fun onRequestMissing(peer: Peer, payload: RequestMissingPayload) { logger.info("Received missing request from ${peer.mid} for ${payload.known} tokens") var out = byteArrayOf() - val permitted = this.tokenChain.subList(0, this.permissions.get(peer) ?: 0) - permitted.forEachIndexed { index, token -> + val permitted = this.tokenChain.subList(0, this.permissions[peer] ?: 0) + + for ((index, token) in permitted.withIndex()) { if (index >= payload.known) { val serialized = token.getPlaintextSigned() if (out.size + serialized.size > SAFE_UDP_PACKET_LENGTH) { - return@forEachIndexed + break } out += serialized } } - val responsePayload = MissingResponsePayload(out) this.endpoint.send(peer, serializePacket(MISSING_RESPONSE_PAYLOAD, responsePayload)) } private fun onMissingResponse(peer: Peer, payload: MissingResponsePayload) { - val solicitedAttestationRequest = this.knownAttestationHashes.values.any { it.publicKey == peer.publicKey } + val solicitedAttestationRequest = + this.knownAttestationHashes.values.any { it.publicKey == peer.publicKey } val idPair = TokenRequestCache.generateId(peer.mid) val solicitedAttestationPresentation = this.requestCache.has(idPair) From 0a2a199de74e165e9bfb13e88c691c6e559910c3 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 13 May 2021 11:10:20 +0200 Subject: [PATCH 135/144] Format + use mutable map + change hash method in SignedObject --- .../main/java/nl/tudelft/ipv8/attestation/SignedObject.kt | 2 +- .../ipv8/attestation/revocation/RevocationCommunity.kt | 6 +++++- .../java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/SignedObject.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/SignedObject.kt index d886b32a..bd4ff2b9 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/SignedObject.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/SignedObject.kt @@ -48,6 +48,6 @@ abstract class SignedObject(val privateKey: PrivateKey? = null, private val know override fun hashCode(): Int { // TODO: verify that this is correct. - return deserializeULong(this.hash).toInt() + return deserializeULong(this.hash.copyOfRange(0, 8)).toInt() } } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt index 48efc5a0..590f0ff8 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt @@ -360,7 +360,11 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() revocationBlob.revocations ) if (this::revocationUpdateCallback.isInitialized) { - this.revocationUpdateCallback(revocationBlob.publicKeyHash, revocationBlob.version, revocationBlob.revocations.size) + this.revocationUpdateCallback( + revocationBlob.publicKeyHash, + revocationBlob.version, + revocationBlob.revocations.size + ) } } } else { diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt index feb98b34..3be47f3a 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/tokenTree/TokenTree.kt @@ -103,7 +103,7 @@ class TokenTree(publicKey: PublicKey? = null, privateKey: PrivateKey? = null) { fun getRootPath(token: Token, maxDepth: Int = 1000): List { var current = token var steps = 0 - val path = arrayListOf(token) + val path = mutableListOf(token) while (maxDepth == -1 || maxDepth > steps) { if (!current.verify(this.publicKey)) { return arrayListOf() From 2ccf724577d072be56bbef178f47761a47024c09 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 13 May 2021 13:58:00 +0200 Subject: [PATCH 136/144] Clean up unnecessary comments --- .../ipv8/attestation/revocation/RevocationCommunity.kt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt index 590f0ff8..29ed32dc 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt @@ -185,9 +185,6 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() val updateRequestPayload = RevocationUpdateRequestPayload(requestedRefs) val packet = serializePacket(REVOCATION_UPDATE_REQUEST_PAYLOAD, updateRequestPayload) logger.info("Requesting revocation update: ${requestedRefs}.") -// logger.info("Remoterefs: $remoteRefs") -// logger.info("Localrefs: $localRefs") -// this.requestCache.add(PendingRevocationUpdateCache(this.requestCache, peer.mid)) this.endpoint.send(peer, packet) } } @@ -197,8 +194,6 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() payload: RevocationUpdateRequestPayload, bulkSending: Boolean = false, ) { - // TODO make sure we want to send to this clients. - if (bulkSending) { val revocations = hashMapOf>() payload.revocationRefs.forEach { (hash, version) -> @@ -236,7 +231,6 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() // TODO: ths could be performed in coroutines, however, would most likely lead to package lost. for (rev in revocations) { -// logger.info("Sending version ${rev.version}") val blob = serializeRevocationBlob(rev) val hash = sha1(blob) var sequenceNumber = 0 From 6e6082ee0f142551a0ecd9d8c686342b2f0baca1 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Thu, 13 May 2021 14:03:27 +0200 Subject: [PATCH 137/144] Remove unused logic --- .../attestation/revocation/AuthoritySQLiteStore.kt | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt index 0a3be5f3..e724eab8 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt @@ -69,16 +69,6 @@ class AuthoritySQLiteStore(database: Database) : AuthorityStore { authorityId = dao.getAuthorityIdByHash(publicKeyHash).executeAsOne() } - // if (version >= 2L) { - // val previousId = - // dao.getVersionByAuthorityIDandVersionNumber(authorityId, version - 1L) - // .executeAsOneOrNull()?.version_id - // if (previousId == null) { - // logger.error("Received revocations out of order, skipping!") - // throw IllegalStateException("Encountered out-of-order revocation version.") - // } - // } - var versionId = dao.getVersionByAuthorityIDandVersionNumber(authorityId, version) .executeAsOneOrNull()?.version_id From 691fd794f299c4fbb3f97033b781d0bb9c0207cf Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 14 May 2021 11:34:37 +0200 Subject: [PATCH 138/144] Implement identity removal --- .../communication/CommunicationChannel.kt | 17 +++++++++++------ .../identity/store/IdentitySQLiteStore.kt | 9 +++++++++ .../attestation/identity/store/IdentityStore.kt | 1 + .../wallet/store/AttestationSQLiteStore.kt | 4 ++++ .../wallet/store/AttestationStore.kt | 2 ++ .../nl/tudelft/ipv8/sqldelight/DbAttestation.sq | 3 +++ .../nl/tudelft/ipv8/sqldelight/DbIdentity.sq | 11 ++++++++++- 7 files changed, 40 insertions(+), 7 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt index 36811152..4cf1472b 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt @@ -159,16 +159,21 @@ class CommunicationChannel( this.verify(peer, stripSHA1Padding(attributeHash), listOf(value), idFormat) } - private fun dropIdentityTableData() { - TODO("") + private fun dropIdentityTableData(): List { + val database = this.identityOverlay.identityManager.database + return database.dropIdentityTable(this.myPeer.publicKey) } - private fun dropAttestationTableData() { - TODO("") + private fun dropAttestationTableData(attestationHashes: List) { + val database = this.attestationOverlay.database + return database.deleteAttestations(attestationHashes) } - fun remove() { - TODO("") + fun deleteIdentity() { + val hashes = this.dropIdentityTableData().map { stripSHA1Padding(it) } + this.dropAttestationTableData(hashes) + this.attestationRequests.clear() + this.verifyRequests.clear() } fun requestAttestation( diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/store/IdentitySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/store/IdentitySQLiteStore.kt index 447e4f6f..deaa5a49 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/store/IdentitySQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/store/IdentitySQLiteStore.kt @@ -102,4 +102,13 @@ class IdentitySQLiteStore(database: Database) : IdentityStore { return dao.getKnownSubjects().executeAsList() .map { defaultCryptoProvider.keyFromPublicBin(it) } } + + override fun dropIdentityTable(publicKey: PublicKey): List { + val attestationHashes = this.getTokensFor(publicKey).map { it.contentHash } + val keyBin = publicKey.keyToBin() + dao.deleteTokensFor(keyBin) + dao.deleteMetadataFor(keyBin) + dao.deleteIdentityAttestationsFor(keyBin) + return attestationHashes + } } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/store/IdentityStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/store/IdentityStore.kt index f09742f7..a593b308 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/store/IdentityStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/store/IdentityStore.kt @@ -27,4 +27,5 @@ interface IdentityStore { fun getCredentialsFor(publicKey: PublicKey): List fun getKnownIdentities(): List fun getKnownSubjects(): List + fun dropIdentityTable(publicKey: PublicKey): List } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/store/AttestationSQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/store/AttestationSQLiteStore.kt index 566bf18c..8b370fcb 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/store/AttestationSQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/store/AttestationSQLiteStore.kt @@ -55,4 +55,8 @@ class AttestationSQLiteStore(database: Database) : AttestationStore { override fun deleteAttestationByHash(attestationHash: ByteArray) { return dao.deleteAttestationByHash(attestationHash) } + + override fun deleteAttestations(attestationHashes: List) { + return dao.deleteAttestations(attestationHashes) + } } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/store/AttestationStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/store/AttestationStore.kt index 9e62e487..b70a0e86 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/store/AttestationStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/store/AttestationStore.kt @@ -27,4 +27,6 @@ interface AttestationStore { fun getValueByHash(attestationHash: ByteArray): ByteArray? fun deleteAttestationByHash(attestationHash: ByteArray) + + fun deleteAttestations(attestationHashes: List) } diff --git a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAttestation.sq b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAttestation.sq index d8165542..b52cb34b 100644 --- a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAttestation.sq +++ b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAttestation.sq @@ -21,3 +21,6 @@ SELECT value FROM attestations WHERE hash = ?; deleteAttestationByHash: DELETE FROM attestations WHERE hash = ?; + +deleteAttestations: +DELETE FROM attestations WHERE hash IN ?; diff --git a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq index 15141b77..bc3e9a9e 100644 --- a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq +++ b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbIdentity.sq @@ -54,4 +54,13 @@ getKnownIdentities: SELECT public_key FROM tokens; getKnownSubjects: -SELECT DISTINCT public_key FROM metadata; \ No newline at end of file +SELECT DISTINCT public_key FROM metadata; + +deleteTokensFor: +DELETE FROM tokens WHERE public_key = ?; + +deleteMetadataFor: +DELETE FROM metadata WHERE public_key = ?; + +deleteIdentityAttestationsFor: +DELETE FROM identity_attestations WHERE public_key = ?; From 4dbcb3466b1fc81922ed5c332470fbb8a676433d Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 14 May 2021 11:50:01 +0200 Subject: [PATCH 139/144] Format + use consts in cryptography --- .../ipv8/attestation/common/SchemaManager.kt | 24 ++++++---- .../wallet/consts/CryptographyConsts.kt | 13 +++++ .../{BonehExactAlgorithm.kt => BonehExact.kt} | 48 ++++++++++++++----- .../attestations/BitPairAttestation.kt | 12 ++--- .../cryptography/pengbaorange/PengBao.kt | 37 ++++++++++---- 5 files changed, 96 insertions(+), 38 deletions(-) create mode 100644 ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/consts/CryptographyConsts.kt rename ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/{BonehExactAlgorithm.kt => BonehExact.kt} (71%) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/SchemaManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/SchemaManager.kt index 649dba5a..57a899e0 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/SchemaManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/SchemaManager.kt @@ -8,9 +8,15 @@ import nl.tudelft.ipv8.attestation.common.consts.SchemaConstants.ID_METADATA_BIG import nl.tudelft.ipv8.attestation.common.consts.SchemaConstants.ID_METADATA_HUGE import nl.tudelft.ipv8.attestation.common.consts.SchemaConstants.ID_METADATA_RANGE_18PLUS import nl.tudelft.ipv8.attestation.common.consts.SchemaConstants.ID_METADATA_RANGE_UNDERAGE +import nl.tudelft.ipv8.attestation.wallet.consts.Cryptography.ALGORITHM +import nl.tudelft.ipv8.attestation.wallet.consts.Cryptography.HASH +import nl.tudelft.ipv8.attestation.wallet.consts.Cryptography.KEY_SIZE +import nl.tudelft.ipv8.attestation.wallet.consts.Cryptography.SHA256 +import nl.tudelft.ipv8.attestation.wallet.consts.Cryptography.SHA256_4 +import nl.tudelft.ipv8.attestation.wallet.consts.Cryptography.SHA512 import nl.tudelft.ipv8.attestation.wallet.cryptography.IdentityAlgorithm import nl.tudelft.ipv8.attestation.wallet.cryptography.WalletAttestation -import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehExactAlgorithm +import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehExact import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPrivateKey import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.attestations.BonehAttestation import nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange.PengBaoRange @@ -80,16 +86,16 @@ class SchemaManager { // TODO: Read in default schemas. fun registerDefaultSchemas() { val defaultSchemas = arrayListOf() - defaultSchemas.add(AlgorithmScheme(ID_METADATA, BONEH_EXACT, 32, "sha256_4")) - defaultSchemas.add(AlgorithmScheme(ID_METADATA_BIG, BONEH_EXACT, 64, "sha256")) - defaultSchemas.add(AlgorithmScheme(ID_METADATA_HUGE, BONEH_EXACT, 96, "sha512")) + defaultSchemas.add(AlgorithmScheme(ID_METADATA, BONEH_EXACT, 32, SHA256_4)) + defaultSchemas.add(AlgorithmScheme(ID_METADATA_BIG, BONEH_EXACT, 64, SHA256)) + defaultSchemas.add(AlgorithmScheme(ID_METADATA_HUGE, BONEH_EXACT, 96, SHA512)) defaultSchemas.add(AlgorithmScheme(ID_METADATA_RANGE_18PLUS, PENG_BAO_RANGE, 32, min = 18, max = 200)) defaultSchemas.add(AlgorithmScheme(ID_METADATA_RANGE_UNDERAGE, PENG_BAO_RANGE, 32, min = 0, max = 17)) defaultSchemas.forEach { - val params = hashMapOf("key_size" to it.keySize) + val params = hashMapOf(KEY_SIZE to it.keySize) if (it.hashAlgorithm != null) { - params["hash"] = it.hashAlgorithm + params[HASH] = it.hashAlgorithm } if (it.min != null && it.max != null) { params["min"] = it.min @@ -107,13 +113,13 @@ class SchemaManager { fun getAlgorithmInstance(idFormat: String): IdentityAlgorithm { return when (val algorithmName = getAlgorithmName(idFormat)) { BONEH_EXACT -> { - BonehExactAlgorithm(idFormat, this.formats) + BonehExact(idFormat, this.formats) } PENG_BAO_RANGE -> { PengBaoRange(idFormat, this.formats) } IRMA_EXACT -> { - TODO("Not yet implemented.") + TODO("IRMA is not implemented.") } else -> { throw RuntimeException("Attempted to load unknown proof algorithm: ${algorithmName}.") @@ -122,7 +128,7 @@ class SchemaManager { } fun getAlgorithmName(idFormat: String): String { - return this.formats[idFormat]?.get("algorithm").toString() + return this.formats[idFormat]?.get(ALGORITHM).toString() } fun getSchemaNames(): List { diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/consts/CryptographyConsts.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/consts/CryptographyConsts.kt new file mode 100644 index 00000000..73f1f440 --- /dev/null +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/consts/CryptographyConsts.kt @@ -0,0 +1,13 @@ +package nl.tudelft.ipv8.attestation.wallet.consts + +object Cryptography { + const val KEY_SIZE = "key_size" + const val ALGORITHM = "algorithm" + const val ATTESTATION = "attestation" + const val MIN = "min" + const val MAX = "max" + const val HASH = "hash" + const val SHA256 = "sha256" + const val SHA256_4 = "sha256_4" + const val SHA512 = "sha512" +} diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/BonehExactAlgorithm.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/BonehExact.kt similarity index 71% rename from ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/BonehExactAlgorithm.kt rename to ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/BonehExact.kt index 727726b8..2a7d7ec3 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/BonehExactAlgorithm.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/BonehExact.kt @@ -1,17 +1,29 @@ package nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact +import nl.tudelft.ipv8.attestation.common.consts.AlgorithmNames.BONEH_EXACT +import nl.tudelft.ipv8.attestation.wallet.consts.Cryptography.ALGORITHM +import nl.tudelft.ipv8.attestation.wallet.consts.Cryptography.HASH +import nl.tudelft.ipv8.attestation.wallet.consts.Cryptography.KEY_SIZE +import nl.tudelft.ipv8.attestation.wallet.consts.Cryptography.SHA256 +import nl.tudelft.ipv8.attestation.wallet.consts.Cryptography.SHA256_4 +import nl.tudelft.ipv8.attestation.wallet.consts.Cryptography.SHA512 import nl.tudelft.ipv8.attestation.wallet.cryptography.IdentityAlgorithm import nl.tudelft.ipv8.attestation.wallet.cryptography.* import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.attestations.BonehAttestation import nl.tudelft.ipv8.messaging.* import java.math.BigInteger -const val ALGORITHM_NAME = "bonehexact" +const val ALGORITHM_NAME = BONEH_EXACT +const val MIN_KEY_SIZE = 32 +const val MAX_KEY_SIZE = 512 -class BonehExactAlgorithm(val idFormat: String, val formats: HashMap>) : +class BonehExact( + val idFormat: String, + val formats: HashMap> +) : IdentityAlgorithm(idFormat, formats) { - private val keySize = formats[idFormat]?.get("key_size") as Int + private val keySize = formats[idFormat]?.get(KEY_SIZE) as Int private var attestationFunction: (BonehPublicKey, ByteArray) -> BonehAttestation private var aggregateReference: (ByteArray) -> HashMap @@ -24,24 +36,24 @@ class BonehExactAlgorithm(val idFormat: String, val formats: HashMap 512) { + if (this.keySize < MIN_KEY_SIZE || this.keySize > MAX_KEY_SIZE) { throw RuntimeException("Illegal key size specified!") } - when (val hashMode = format["hash"]) { - "sha256" -> { + when (val hashMode = format[HASH]) { + SHA256 -> { this.attestationFunction = ::attestSHA256 this.aggregateReference = ::binaryRelativitySHA256 } - "sha256_4" -> { + SHA256_4 -> { this.attestationFunction = ::attestSHA256_4 this.aggregateReference = ::binaryRelativitySHA256_4 } - "sha512" -> { + SHA512 -> { this.attestationFunction = ::attestSHA512 this.aggregateReference = ::binaryRelativitySHA512 } @@ -71,15 +83,22 @@ class BonehExactAlgorithm(val idFormat: String, val formats: HashMap): Double { @Suppress("UNCHECKED_CAST") - return binaryRelativityCertainty(this.aggregateReference(value), aggregate as HashMap) + return binaryRelativityCertainty( + this.aggregateReference(value), + aggregate as HashMap + ) } - override fun createChallenges(publicKey: BonehPublicKey, attestation: WalletAttestation): ArrayList { + override fun createChallenges( + publicKey: BonehPublicKey, + attestation: WalletAttestation + ): ArrayList { attestation as BonehAttestation val challenges = arrayListOf() for (bitPair in attestation.bitPairs) { val challenge = createChallenge(attestation.publicKey, bitPair) - val serialized = serializeVarLen(challenge.a.toByteArray()) + serializeVarLen(challenge.b.toByteArray()) + val serialized = + serializeVarLen(challenge.a.toByteArray()) + serializeVarLen(challenge.b.toByteArray()) challenges.add(serialized) } @@ -104,7 +123,10 @@ class BonehExactAlgorithm(val idFormat: String, val formats: HashMap, deserialized.toInt()) + return internalProcessChallengeResponse( + aggregate as HashMap, + deserialized.toInt() + ) } override fun createCertaintyAggregate(attestation: WalletAttestation?): HashMap { diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/attestations/BitPairAttestation.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/attestations/BitPairAttestation.kt index e40717e5..a5d843cf 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/attestations/BitPairAttestation.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/bonehexact/attestations/BitPairAttestation.kt @@ -22,15 +22,15 @@ class BitPairAttestation(private val a: FP2Value, private val b: FP2Value, priva companion object { fun deserialize(serialized: ByteArray, prime: BigInteger): BitPairAttestation { var localOffset = 0 - val nums = arrayListOf() - while (serialized.isNotEmpty() && nums.size < 6) { + val numbers = arrayListOf() + while (serialized.isNotEmpty() && numbers.size < 6) { val unpacked = deserializeVarLen(serialized, localOffset) - nums.add(BigInteger(unpacked.first)) + numbers.add(BigInteger(unpacked.first)) localOffset += unpacked.second } - return BitPairAttestation(FP2Value(prime, nums[0], nums[1]), - FP2Value(prime, nums[2], nums[3]), - FP2Value(prime, nums[4], nums[5])) + return BitPairAttestation(FP2Value(prime, numbers[0], numbers[1]), + FP2Value(prime, numbers[2], numbers[3]), + FP2Value(prime, numbers[4], numbers[5])) } } } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/PengBao.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/PengBao.kt index fe48718a..de601b98 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/PengBao.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/PengBao.kt @@ -1,6 +1,11 @@ package nl.tudelft.ipv8.attestation.wallet.cryptography.pengbaorange import nl.tudelft.ipv8.attestation.common.consts.AlgorithmNames.PENG_BAO_RANGE +import nl.tudelft.ipv8.attestation.wallet.consts.Cryptography.ALGORITHM +import nl.tudelft.ipv8.attestation.wallet.consts.Cryptography.ATTESTATION +import nl.tudelft.ipv8.attestation.wallet.consts.Cryptography.KEY_SIZE +import nl.tudelft.ipv8.attestation.wallet.consts.Cryptography.MAX +import nl.tudelft.ipv8.attestation.wallet.consts.Cryptography.MIN import nl.tudelft.ipv8.attestation.wallet.cryptography.IdentityAlgorithm import nl.tudelft.ipv8.attestation.wallet.cryptography.WalletAttestation import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.BonehPrivateKey @@ -16,6 +21,8 @@ import java.math.BigInteger import java.security.SecureRandom const val LARGE_INTEGER = 32765 +const val MIN_KEY_SIZE = 32 +const val MAX_KEY_SIZE = 512 class PengBaoRange(idFormat: String, formats: HashMap>) : IdentityAlgorithm(idFormat, formats) { @@ -29,18 +36,18 @@ class PengBaoRange(idFormat: String, formats: HashMap 512) { + if (this.keySize < MIN_KEY_SIZE || this.keySize > MAX_KEY_SIZE) { throw RuntimeException("Illegal key size specified.") } - a = format["min"] as Int - b = format["max"] as Int + a = format[MIN] as Int + b = format[MAX] as Int } override fun generateSecretKey(): BonehPrivateKey { @@ -57,7 +64,13 @@ class PengBaoRange(idFormat: String, formats: HashMap): Double { @@ -71,7 +84,10 @@ class PengBaoRange(idFormat: String, formats: HashMap { + override fun createChallenges( + publicKey: BonehPublicKey, + attestation: WalletAttestation + ): ArrayList { val mod = publicKey.g.mod - BigInteger.ONE return arrayListOf( serializeVarLen(safeRandomNumber(this.keySize, mod).toByteArray()) + serializeVarLen( @@ -105,7 +121,7 @@ class PengBaoRange(idFormat: String, formats: HashMap { @Suppress("UNCHECKED_CAST") - return hashMapOf("attestation" to (attestation as PengBaoAttestation)) as HashMap + return hashMapOf(ATTESTATION to (attestation as PengBaoAttestation)) as HashMap } override fun processChallengeResponse( @@ -116,8 +132,9 @@ class PengBaoRange(idFormat: String, formats: HashMap Date: Fri, 14 May 2021 11:54:21 +0200 Subject: [PATCH 140/144] Remove refactor artifect --- .../ipv8/attestation/wallet/cryptography/WalletAttestation.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/WalletAttestation.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/WalletAttestation.kt index f975c164..0226935f 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/WalletAttestation.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/WalletAttestation.kt @@ -30,7 +30,7 @@ abstract class WalletAttestation { } override fun toString(): String { - return "nl.tudelft.ipv8.attestation.wallet.cryptography.WalletAttestation(publicKey=$publicKey, idFormat=$idFormat)" + return "WalletAttestation(publicKey=$publicKey, idFormat=$idFormat)" } } From 1c2ae08a447d77b1c33ff24bc788874a41d9faaa Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Fri, 14 May 2021 12:04:53 +0200 Subject: [PATCH 141/144] Add import alias for decode function --- .../commitments/PrivatePengBaoCommitment.kt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/commitments/PrivatePengBaoCommitment.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/commitments/PrivatePengBaoCommitment.kt index 81beda9c..5212da37 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/commitments/PrivatePengBaoCommitment.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/cryptography/pengbaorange/commitments/PrivatePengBaoCommitment.kt @@ -12,6 +12,7 @@ import nl.tudelft.ipv8.messaging.serializeVarLen import nl.tudelft.ipv8.util.hexToBytes import nl.tudelft.ipv8.util.toHex import java.math.BigInteger +import nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.decode as bonehExactDecode class PengBaoPrivateData( val m1: BigInteger, @@ -32,9 +33,9 @@ class PengBaoPrivateData( } fun serialize(): ByteArray { - return serializeVarLen(this.m1.toByteArray()) + serializeVarLen(this.m2.toByteArray()) + serializeVarLen(this.m3.toByteArray()) + serializeVarLen( - this.r1.toByteArray() - ) + serializeVarLen(this.r2.toByteArray()) + serializeVarLen(this.r3.toByteArray()) + return serializeVarLen(this.m1.toByteArray()) + serializeVarLen(this.m2.toByteArray()) + + serializeVarLen(this.m3.toByteArray()) + serializeVarLen(this.r1.toByteArray()) + + serializeVarLen(this.r2.toByteArray()) + serializeVarLen(this.r3.toByteArray()) } fun encode(publicKey: BonehPublicKey): ByteArray { @@ -57,7 +58,10 @@ class PengBaoPrivateData( val MSG_SPACE = (0 until 256).toList().toTypedArray() fun deserialize(serialized: ByteArray): Pair { - val (values, rem) = deserializeAmount(serialized, PENG_BAO_PRIVATE_COMMITMENT_NUM_PARAMS) + val (values, rem) = deserializeAmount( + serialized, + PENG_BAO_PRIVATE_COMMITMENT_NUM_PARAMS + ) val m1 = BigInteger(values[0]) val m2 = BigInteger(values[1]) val m3 = BigInteger(values[2]) @@ -75,7 +79,7 @@ class PengBaoPrivateData( for (i in 0 until length) { val (deserialized, localRem) = deserializeFP2Value(privateKey.g.mod, rem) rem = localRem - var hexedRaw = nl.tudelft.ipv8.attestation.wallet.cryptography.bonehexact.decode( + val hexedRaw = bonehExactDecode( privateKey, MSG_SPACE, deserialized From 38703c1ab7a1894a13ee4b46d32cfa7a8d78e19c Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Mon, 17 May 2021 11:26:59 +0200 Subject: [PATCH 142/144] Add identity attestation callback --- .../attestation/communication/CommunicationChannel.kt | 4 ++-- .../attestation/communication/CommunicationManager.kt | 11 +++++++++++ .../ipv8/attestation/identity/IdentityCommunity.kt | 8 ++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt index 4cf1472b..2829620b 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationChannel.kt @@ -269,7 +269,7 @@ class CommunicationChannel( } fun revoke(signatures: List) { - this.revocationOverlay.revokeAttestations(signatures) + this.revocationOverlay.revokeAttestations(signatures) } fun verifyLocally( @@ -463,7 +463,7 @@ class SubjectAttestationPresentation( val isRevoked: Boolean ) { override fun equals(other: Any?): Boolean { - return other is SubjectAttestationPresentation && this.publicKey == other.publicKey && this.metadata == other.metadata + return other is SubjectAttestationPresentation && this.publicKey == other.publicKey && this.metadata == other.metadata && this.isRevoked == other.isRevoked } override fun hashCode(): Int { diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt index b8fc37e8..d042d4c0 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/communication/CommunicationManager.kt @@ -6,6 +6,7 @@ import nl.tudelft.ipv8.Peer import nl.tudelft.ipv8.attestation.common.AuthorityManager import nl.tudelft.ipv8.attestation.identity.IdentityCommunity import nl.tudelft.ipv8.attestation.identity.createCommunity +import nl.tudelft.ipv8.attestation.identity.datastructures.IdentityAttestation import nl.tudelft.ipv8.attestation.identity.store.IdentityStore import nl.tudelft.ipv8.attestation.identity.manager.IdentityManager import nl.tudelft.ipv8.attestation.revocation.RevocationCommunity @@ -38,6 +39,13 @@ class CommunicationManager( private val loadPseudonym = loadPseudonym ?: Companion::loadPseudonym private val storePseudonym = storePseudonym ?: Companion::storePseudonym + private lateinit var attestationCallback: (peer: Peer, attestation: IdentityAttestation) -> Unit + + fun setAttestationCallback(f: (peer: Peer, attestation: IdentityAttestation) -> Unit) { + this.attestationCallback = f + channels.values.forEach { it.identityOverlay.setAttestationCallback(f) } + } + private fun lazyIdentityManager(): IdentityManager { if (this.identityManager == null) { this.identityManager = IdentityManager(identityStore) @@ -72,6 +80,9 @@ class CommunicationManager( identityStore, decodedRendezvousToken ) + if (this::attestationCallback.isInitialized) { + identityOverlay.setAttestationCallback(this.attestationCallback) + } val attestationOverlay = AttestationCommunity( identityOverlay.myPeer, diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt index 1cc97108..32039569 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/identity/IdentityCommunity.kt @@ -72,6 +72,7 @@ class IdentityCommunity( val requestCache = RequestCache() private lateinit var attestationPresentationCallback: (peer: Peer, attributeHash: ByteArray, value: ByteArray, metadata: Metadata, attestations: List, disclosureInformation: String) -> Unit + private lateinit var attestationCallback: (peer: Peer, attestation: IdentityAttestation) -> Unit private val knownAttestationHashes = hashMapOf() private val pseudonymManager = this.identityManager.getPseudonym(this.myPeer.key) @@ -416,6 +417,9 @@ class IdentityCommunity( val attestation = IdentityAttestation.deserialize(payload.attestation, peer.publicKey) if (this.pseudonymManager.addAttestation(peer.publicKey, attestation)) { logger.info("Received attestation from ${peer.mid}.") + if (this::attestationCallback.isInitialized) { + this.attestationCallback(peer, attestation) + } } else { logger.warn("Received invalid attestation from ${peer.mid}.") } @@ -472,6 +476,10 @@ class IdentityCommunity( this.attestationPresentationCallback = f } + fun setAttestationCallback(f: (peer: Peer, attestation: IdentityAttestation) -> Unit) { + this.attestationCallback = f + } + private fun onDisclosureWrapper(packet: Packet) { val (peer, payload) = packet.getAuthPayload(DisclosePayload.Deserializer) logger.info(" Disclose payload from ${peer.mid}.") From 59fd5aa94c45f40cd66d24191b6c8ec2abcb445c Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Tue, 14 Jun 2022 10:51:16 +0200 Subject: [PATCH 143/144] optimize revocation performance --- .../ipv8/attestation/common/RequestCache.kt | 13 +- .../revocation/AuthoritySQLiteStore.kt | 16 ++- .../revocation/RevocationCommunity.kt | 128 +++++++++++++----- .../caches/PendingRevocationUpdateCache.kt | 5 +- .../attestation/wallet/caches/NumberCache.kt | 7 +- .../tudelft/ipv8/util/CollectionExtensions.kt | 11 +- .../nl/tudelft/ipv8/sqldelight/DbAuthority.sq | 20 ++- 7 files changed, 150 insertions(+), 50 deletions(-) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/RequestCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/RequestCache.kt index e8a76a20..e37f9c99 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/RequestCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/common/RequestCache.kt @@ -13,13 +13,16 @@ class RequestCache { private val lock = Object() private val identifiers = hashMapOf() + val size: Int + get() = this.identifiers.size + fun add(cache: NumberCache): NumberCache? { synchronized(lock) { val identifier = this.createIdentifier(cache.prefix, cache.number) return if (identifiers.containsKey(identifier)) { - this.logger.error("Attempted to add cache with duplicate identifier $identifier.") + this.logger.warn("Attempted to add cache with duplicate identifier $identifier.") null } else { this.logger.debug("Add cache $cache") @@ -57,8 +60,14 @@ class RequestCache { return this.get(identifierPair.first, identifierPair.second) } + fun clear() { + synchronized(lock) { + this.identifiers.values.forEach { it.stop() } + this.identifiers.clear() + } + } + private fun createIdentifier(prefix: String, number: BigInteger): String { return "$prefix:$number" } - } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt index fab5e90e..25802e7b 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/AuthoritySQLiteStore.kt @@ -1,6 +1,5 @@ package nl.tudelft.ipv8.attestation.revocation -import mu.KotlinLogging import nl.tudelft.ipv8.attestation.common.Authority import nl.tudelft.ipv8.keyvault.PublicKey import nl.tudelft.ipv8.keyvault.defaultCryptoProvider @@ -20,8 +19,6 @@ private val authorityMapper: ( ) } -private val logger = KotlinLogging.logger {} - class AuthoritySQLiteStore(database: Database) : AuthorityStore { private val dao = database.dbAuthorityQueries @@ -78,8 +75,13 @@ class AuthoritySQLiteStore(database: Database) : AuthorityStore { .executeAsOne().version_id } + val authority = dao.getAuthorityByHash(publicKeyHash).executeAsOne() + revokedHashes.forEach { dao.insertRevocation(authorityId, versionId, it) } - dao.updateVersionFor(versionId, publicKeyHash) + + if ((authority.version_number ?: 0) < version) { + dao.updateVersionFor(versionId, publicKeyHash) + } } override fun getVersionsSince(publicKeyHash: ByteArray, sinceVersion: Long): List { @@ -133,4 +135,10 @@ class AuthoritySQLiteStore(database: Database) : AuthorityStore { dao.isRevokedBy(signature, authorityId).executeAsList().isNotEmpty() } } + + fun clearRevocations() { + dao.clearRevocations() + dao.clearVersions() + dao.clearAuthorityVersions() + } } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt index dc872a6c..52e139d3 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/RevocationCommunity.kt @@ -19,7 +19,7 @@ import nl.tudelft.ipv8.messaging.* import nl.tudelft.ipv8.peerdiscovery.Network import nl.tudelft.ipv8.util.* -const val DELAY = 10000L +const val DELAY = 2500L const val DEFAULT_GOSSIP_AMOUNT = 5 private const val CHUNK_SIZE = 800 @@ -30,6 +30,7 @@ const val REVOCATION_UPDATE_REQUEST_PAYLOAD = 2 const val REVOCATION_UPDATE_CHUNK_PAYLOAD = 3 class RevocationCommunity(val authorityManager: AuthorityManager) : Community() { + private var udpDelay: Long = 0L override val serviceId = "fdbb9c5c18bf480a4baba08d352727e66ee89173" @Suppress("JoinDeclarationAndAssignment", "LateinitVarOverridesLateinitVar") @@ -44,6 +45,8 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() // Possibility to override the getPeers method when using shared network between Communities. private var fetchPeers: () -> List = ::getPeers + var paused: Boolean = false + private lateinit var revocationUpdateCallback: (publicKeyHash: ByteArray, version: Long, amount: Int) -> Unit constructor( @@ -64,32 +67,58 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() } private lateinit var gossipRoutine: Job - private val requestCache = RequestCache() + val requestCache = RequestCache() init { messageHandlers[REVOCATION_PRESENTATION_PAYLOAD] = ::onRevocationUpdatePreviewPayloadWrapper messageHandlers[REVOCATION_UPDATE_REQUEST_PAYLOAD] = ::onRevocationUpdateRequestPayloadWrapper messageHandlers[REVOCATION_UPDATE_CHUNK_PAYLOAD] = ::onRevocationUpdateChunkPayloadWrapper + } + + override fun load() { + super.load() + if (!this::network.isInitialized) { + this.network = super.network + } + + if (!this::myPeer.isInitialized) { + this.myPeer = super.myPeer + } + + if (!this::endpoint.isInitialized) { + this.endpoint = super.endpoint + } start() } + override fun unload() { + super.unload() + this.gossipRoutine.cancel() + } + + fun setUDPDelay(delay: Long) { + this.udpDelay = delay + } + fun start() { this.gossipRoutine = GlobalScope.launch { while (isActive) { - if (::network.isInitialized) { - gossipRevocations(getRandomPeers(DEFAULT_GOSSIP_AMOUNT)) + if (!paused) { + try { + gossipRevocations(getRandomPeers(DEFAULT_GOSSIP_AMOUNT)) + } catch (e: UninitializedPropertyAccessException) { + logger.info("Community not fully initialised.") + } finally { + delay(DELAY) + } + } else { delay(DELAY) } } } } - override fun unload() { - super.unload() - this.gossipRoutine.cancel() - } - fun revokeAttestations(attestationHashes: List) { val myPublicKeyHash = this.myPeer.publicKey.keyToHash() var myAuthority = this.authorityManager.getAuthority(myPublicKeyHash) @@ -98,7 +127,7 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() myAuthority = this.authorityManager.getAuthority(myPublicKeyHash)!! } val version = myAuthority.version + 1 - var signableData = serializeULong(version.toULong()) + var signableData = version.toByteArray() attestationHashes.forEach { signableData += it } val signature = (this.myPeer.key as PrivateKey).sign(sha3_256(signableData)) @@ -120,7 +149,7 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() private fun onRevocationUpdateRequestPayloadWrapper(packet: Packet) { val (peer, payload) = packet.getAuthPayload(RevocationUpdateRequestPayload.Deserializer) logger.info("Received RevocationUpdateRequestPayload from ${peer.mid}.") - this.onRevocationUpdateRequestPayload(peer, payload) + GlobalScope.launch { onRevocationUpdateRequestPayload(peer, payload) } } private fun onRevocationUpdateChunkPayloadWrapper(packet: Packet) { @@ -159,21 +188,33 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() this.requestCache, peer.publicKey.keyToHash(), key.bytes, - i + i, + timeout = (30 + i * 10).toInt() ) ) } } else if (localVersion < remoteVersion) { requestedRefs[key] = localVersion for (i in (localVersion + 1L)..remoteVersion) { - this.requestCache.add( - PendingRevocationUpdateCache( - this.requestCache, - peer.publicKey.keyToHash(), - key.bytes, - i + val peerHash = peer.publicKey.keyToHash() + if (!this.requestCache.has( + PendingRevocationUpdateCache.generateId( + peerHash, + key.bytes, + i + ) ) - ) + ) { + this.requestCache.add( + PendingRevocationUpdateCache( + this.requestCache, + peerHash, + key.bytes, + i, + timeout = (30 + i * 10).toInt() + ) + ) + } } } } else { @@ -189,7 +230,8 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() } } - private fun onRevocationUpdateRequestPayload( + @OptIn(ExperimentalUnsignedTypes::class) + private suspend fun onRevocationUpdateRequestPayload( peer: Peer, payload: RevocationUpdateRequestPayload, bulkSending: Boolean = false, @@ -203,6 +245,7 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() val blob = serializeRevocationMap(revocations) val hash = sha1(blob) var sequenceNumber = 0 + logger.info("Sending update chunks.") for (i in blob.indices step CHUNK_SIZE) { val endIndex = if (i + CHUNK_SIZE > blob.size) blob.size else i + CHUNK_SIZE val chunkPayload = RevocationUpdateChunkPayload( @@ -219,15 +262,15 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() } } else { val solicited = - this.requestCache.has(AllowedRevocationUpdateRequestCache.generateId(peer)) + this.requestCache.pop(AllowedRevocationUpdateRequestCache.generateId(peer)) != null if (solicited) { val revocations = mutableListOf() payload.revocationRefs.forEach { (hash, version) -> revocations.addAll(this.authorityManager.getRevocations(hash.bytes, version)) } - logger.info("CLIENT REQUESTED THE FOLLOWING VERSIONS: ") - revocations.forEach { print("${it.version}, ") } + + logger.info("Client request the following versions: ${revocations.forEachIndexed { index, it -> if (index != revocations.lastIndex) it.version.toString() + ", " else it.version }}") // TODO: ths could be performed in coroutines, however, would most likely lead to package lost. for (rev in revocations) { @@ -244,6 +287,7 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() val packet = serializePacket(REVOCATION_UPDATE_CHUNK_PAYLOAD, chunkPayload) logger.info("Sending update chunk $sequenceNumber") this.endpoint.send(peer, packet) + delay(udpDelay) sequenceNumber += 1 } } @@ -253,6 +297,7 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() } } + @OptIn(ExperimentalUnsignedTypes::class) private fun onRevocationUpdateChunkPayload( peer: Peer, payload: RevocationUpdateChunkPayload, @@ -302,13 +347,17 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() blob.revocations ) if (this::revocationUpdateCallback.isInitialized) { - this.revocationUpdateCallback(hash.bytes, blob.version, blob.revocations.size) + this.revocationUpdateCallback( + hash.bytes, + blob.version, + blob.revocations.size + ) } } } } } else { - logger.warn { "Received update we did not request, dropping." } + logger.warn("Received update we did not request, dropping.") } } else { val idPair = @@ -347,6 +396,7 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() logger.info("Inserting revocations without verification as authority is not recognized.") } + logger.info("IG-SSI: Inserting version ${revocationBlob.version} at ${System.currentTimeMillis()}, tot: ${this.authorityManager.authorityDatabase.getNumberOfRevocations()}") this.authorityManager.insertRevocations( revocationBlob.publicKeyHash, revocationBlob.version, @@ -362,11 +412,12 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() } } } else { - logger.warn { "Received update for version ${payload.version} we did not request, dropping." } + logger.warn("Received update for version ${payload.version} we did not request, dropping.") } } } + @OptIn(ExperimentalUnsignedTypes::class) private fun serializeRevocationBlob(blob: RevocationBlob): ByteArray { var out = blob.publicKeyHash + blob.signature + serializeULong(blob.version.toULong()) + serializeUInt( @@ -403,6 +454,7 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() return RevocationBlob(keyHash, version, signature, revocations) } + @OptIn(ExperimentalUnsignedTypes::class) private fun serializeRevocationMap(map: Map>): ByteArray { val size = map.size var out = serializeUInt(size.toUInt()) @@ -423,6 +475,7 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() return out } + @OptIn(ExperimentalUnsignedTypes::class) private fun deserializeRevocationMap(serialized: ByteArray): Map> { var localOffset = 0 val out = hashMapOf>() @@ -458,15 +511,15 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() return out } - private fun gossipMyRevocations() { - val peers = this.fetchPeers() - this.gossipRevocations(peers) + fun gossipRevocations() { + gossipRevocations(getRandomPeers(DEFAULT_GOSSIP_AMOUNT)) } private fun getRandomPeers(amount: Int): List { return this.fetchPeers().random(amount).toList() } + @OptIn(ExperimentalUnsignedTypes::class) private fun gossipRevocations(peers: List) { val revocations = this.authorityManager.getLatestRevocationPreviews() if (revocations.isEmpty()) { @@ -475,10 +528,19 @@ class RevocationCommunity(val authorityManager: AuthorityManager) : Community() val payload = RevocationUpdatePreviewPayload(revocations) val packet = serializePacket(REVOCATION_PRESENTATION_PAYLOAD, payload) peers.forEach { - if (!requestCache.has(AllowedRevocationUpdateRequestCache.generateId(it))) { - logger.info("Sending revocation preview to ${it.mid}.") - endpoint.send(it, packet) - this.requestCache.add(AllowedRevocationUpdateRequestCache(this.requestCache, it)) + if (!this.requestCache.has(AllowedRevocationUpdateRequestCache.generateId(it))) { + try { + this.requestCache.add( + AllowedRevocationUpdateRequestCache( + this.requestCache, + it + ) + ) + logger.info("Sending revocation preview to ${it.mid}.") + endpoint.send(it, packet) + } catch (e: RuntimeException) { + // Other co-routine was faster. + } } } } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt index 70b04877..b061f31b 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/revocation/caches/PendingRevocationUpdateCache.kt @@ -13,12 +13,13 @@ class PendingRevocationUpdateCache( requestCache: RequestCache, senderHash: ByteArray, signeeHash: ByteArray, - version: Long + version: Long, + timeout: Int = 30 ) : NumberCache( requestCache, PENDING_REVOCATION_UPDATE_CACHE_PREFIX, this.generateId( senderHash, signeeHash, version - ).second, timeout = 30 + ).second, timeout = timeout ) { val revocationMap = hashMapOf() diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt index 47195c89..704c2341 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/attestation/wallet/caches/NumberCache.kt @@ -30,12 +30,15 @@ abstract class NumberCache( val timeoutValue = (overWrittenTimeout ?: timeout) * SECOND_IN_MILLISECONDS withTimeout(timeoutValue) { timeOutJob = launch { - // Add some delta to ensure the timeout is triggered. - delay(timeoutValue + SECOND_IN_MILLISECONDS) + while (isActive) { + // Add some delta to ensure the timeout is triggered. + delay(timeoutValue + SECOND_IN_MILLISECONDS) + } } } } catch (e: TimeoutCancellationException) { logger.warn("Cache $prefix$number timed out") + requestCache.pop(prefix, number) calleeCallback?.invoke() onTimeout() } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/util/CollectionExtensions.kt b/ipv8/src/main/java/nl/tudelft/ipv8/util/CollectionExtensions.kt index d647e71f..c6d3b2c9 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/util/CollectionExtensions.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/util/CollectionExtensions.kt @@ -1,6 +1,13 @@ package nl.tudelft.ipv8.util -fun Collection.random(maxSampleSize: Int): Collection { +import kotlin.random.Random + +fun Collection.random(maxSampleSize: Int, random: Random? = null): Collection { val sampleSize = kotlin.math.min(size, maxSampleSize) - return shuffled().subList(0, sampleSize) + return if (random == null) { + shuffled().subList(0, sampleSize) + } else { + shuffled(random).subList(0, sampleSize) + } + } diff --git a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq index 241ce6a5..f6a0b09f 100644 --- a/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq +++ b/ipv8/src/main/sqldelight/nl/tudelft/ipv8/sqldelight/DbAuthority.sq @@ -3,7 +3,8 @@ CREATE TABLE revocations ( version_id INTEGER NOT NULL, revoked_hash BLOB NOT NULL, FOREIGN KEY(authority_id) REFERENCES authorities(authority_id), - FOREIGN KEY(version_id) REFERENCES versions(version_id) + FOREIGN KEY(version_id) REFERENCES versions(version_id), + PRIMARY KEY(authority_id, version_id, revoked_hash) ); CREATE TABLE versions ( @@ -23,7 +24,7 @@ CREATE TABLE authorities ( ); insertRevocation: -INSERT INTO revocations (authority_id, version_id, revoked_hash) +INSERT OR IGNORE INTO revocations (authority_id, version_id, revoked_hash) VALUES (?, ?, ?); insertVersion: @@ -62,7 +63,7 @@ getRevocationsByAuthorityId: SELECT revoked_hash FROM revocations WHERE authority_id = ?; getRevocationsByAuthorityIdAndVersionId: -SELECT revoked_hash FROM revocations WHERE authority_id = ? AND version_id = ?; +SELECT revoked_hash FROM revocations WHERE authority_id = ? AND version_id = ? ORDER BY rowid; updateVersionFor: UPDATE authorities SET latest_version_id = ? WHERE public_key_hash = ?; @@ -92,11 +93,20 @@ SELECT MIN(A.version_number) FROM versions AS A WHERE A.authority_id = ?1 AND NOT EXISTS ( SELECT B.version_number FROM versions AS B - WHERE B.authority_id = ?1 AND A.version_number + 1 = B.version_number) -GROUP BY A.version_number; + WHERE B.authority_id = ?1 AND A.version_number + 1 = B.version_number); isRevoked: SELECT 1 FROM revocations WHERE revoked_hash = ?; isRevokedBy: SELECT 1 FROM revocations WHERE revoked_hash = ? AND authority_id = ?; + +clearRevocations: +DELETE FROM revocations; + +clearVersions: +DELETE FROM versions; + +clearAuthorityVersions: +UPDATE authorities +SET latest_version_id = NULL; \ No newline at end of file From 7d652be9b4738780ac527cfde09ab0fe9dd0d6c5 Mon Sep 17 00:00:00 2001 From: Rowdy Chotkan Date: Tue, 14 Jun 2022 10:59:40 +0200 Subject: [PATCH 144/144] Update libsodium and recyclerview dependencies --- build.gradle | 9 ++++----- demo-android/build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 ++-- ipv8-android/build.gradle | 4 ++-- .../ipv8/android/keyvault/AndroidCryptoProvider.kt | 4 ++-- ipv8/build.gradle | 12 +++++++++++- ipv8/src/main/java/nl/tudelft/ipv8/Community.kt | 3 +-- .../nl/tudelft/ipv8/keyvault/JavaCryptoProvider.kt | 4 ++-- .../main/java/nl/tudelft/ipv8/keyvault/LibNaClPK.kt | 4 ++-- .../main/java/nl/tudelft/ipv8/keyvault/LibNaClSK.kt | 4 ++-- .../test/java/nl/tudelft/ipv8/BaseCommunityTest.kt | 4 ++-- ipv8/src/test/java/nl/tudelft/ipv8/CommunityTest.kt | 10 +++------- ipv8/src/test/java/nl/tudelft/ipv8/TestCommunity.kt | 4 ++-- .../attestation/trustchain/TrustChainBlockTest.kt | 4 ++-- .../trustchain/payload/CrawlRequestPayloadTest.kt | 4 ++-- .../trustchain/payload/CrawlResponsePayloadTest.kt | 4 ++-- .../payload/HalfBlockBroadcastPayloadTest.kt | 4 ++-- .../payload/HalfBlockPairBroadcastPayloadTest.kt | 4 ++-- .../trustchain/payload/HalfBlockPairPayloadTest.kt | 4 ++-- .../trustchain/payload/HalfBlockPayloadTest.kt | 4 ++-- .../trustchain/store/TrustChainStoreTest.kt | 4 ++-- .../java/nl/tudelft/ipv8/keyvault/LibNaClPKTest.kt | 4 ++-- .../java/nl/tudelft/ipv8/keyvault/LibNaClSKTest.kt | 4 ++-- 23 files changed, 56 insertions(+), 52 deletions(-) diff --git a/build.gradle b/build.gradle index 3c4d9e45..01de4f01 100644 --- a/build.gradle +++ b/build.gradle @@ -13,11 +13,11 @@ buildscript { ext.dokka_version = "0.10.1" repositories { google() - jcenter() + mavenCentral() maven { url "https://plugins.gradle.org/m2/" } } dependencies { - classpath 'com.android.tools.build:gradle:4.0.0' + classpath 'com.android.tools.build:gradle:4.1.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jlleitschuh.gradle:ktlint-gradle:$ktlint_gradle_version" classpath "com.squareup.sqldelight:gradle-plugin:$sqldelight_version" @@ -31,9 +31,8 @@ buildscript { allprojects { repositories { google() - jcenter() - maven { url "https://dl.bintray.com/mattskala/maven" } - maven { url "https://dl.bintray.com/terl/lazysodium-maven" } + mavenCentral() + maven { url 'https://jitpack.io' } } // Temp fix for issue https://github.com/mockk/mockk/issues/281 diff --git a/demo-android/build.gradle b/demo-android/build.gradle index 5800edc2..0b954358 100644 --- a/demo-android/build.gradle +++ b/demo-android/build.gradle @@ -79,7 +79,7 @@ dependencies { implementation 'io.github.microutils:kotlin-logging:1.7.7' implementation 'com.github.tony19:logback-android:2.0.0' - implementation 'com.mattskala:itemadapter:0.3' + implementation 'com.github.MattSkala:recyclerview-itemadapter:0.4' // Testing testImplementation 'junit:junit:4.12' diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 38750810..cefe5d5a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Jan 12 11:23:56 CET 2021 +#Tue May 11 09:51:47 CEST 2021 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/ipv8-android/build.gradle b/ipv8-android/build.gradle index 9e3e6d38..aa3db5a2 100644 --- a/ipv8-android/build.gradle +++ b/ipv8-android/build.gradle @@ -49,7 +49,7 @@ android { dependencies { api (project(':ipv8')) { - exclude group: 'com.goterl.lazycode' + exclude module: 'lazysodium-java' } // Kotlin @@ -64,7 +64,7 @@ dependencies { implementation "androidx.lifecycle:lifecycle-common-java8:2.2.0" // Crypto - implementation "com.goterl.lazycode:lazysodium-android:4.1.0@aar" + implementation "com.goterl:lazysodium-android:5.0.1@aar" implementation 'net.java.dev.jna:jna:5.5.0@aar' // BLE diff --git a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/keyvault/AndroidCryptoProvider.kt b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/keyvault/AndroidCryptoProvider.kt index 3fa8e0be..bb61ec3b 100644 --- a/ipv8-android/src/main/java/nl/tudelft/ipv8/android/keyvault/AndroidCryptoProvider.kt +++ b/ipv8-android/src/main/java/nl/tudelft/ipv8/android/keyvault/AndroidCryptoProvider.kt @@ -1,7 +1,7 @@ package nl.tudelft.ipv8.android.keyvault -import com.goterl.lazycode.lazysodium.LazySodiumAndroid -import com.goterl.lazycode.lazysodium.SodiumAndroid +import com.goterl.lazysodium.LazySodiumAndroid +import com.goterl.lazysodium.SodiumAndroid import nl.tudelft.ipv8.keyvault.* private val lazySodium = LazySodiumAndroid(SodiumAndroid()) diff --git a/ipv8/build.gradle b/ipv8/build.gradle index 1aa87254..6f6ecb93 100644 --- a/ipv8/build.gradle +++ b/ipv8/build.gradle @@ -10,6 +10,8 @@ apply plugin: 'org.jlleitschuh.gradle.ktlint' apply plugin: 'com.squareup.sqldelight' +apply plugin: 'kotlin-kapt' + dokka { outputFormat = 'html' outputDirectory = "$buildDir/dokka" @@ -64,7 +66,7 @@ dependencies { implementation 'commons-net:commons-net:3.6' // Crypto - implementation "com.goterl.lazycode:lazysodium-java:4.2.4" + implementation "com.goterl:lazysodium-java:5.0.1" // Logging implementation 'io.github.microutils:kotlin-logging:1.7.7' @@ -78,6 +80,13 @@ dependencies { testImplementation "com.squareup.sqldelight:sqlite-driver:$sqldelight_version" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version" + implementation "org.openjdk.jmh:jmh-core:1.21" + kapt "org.openjdk.jmh:jmh-generator-annprocess:1.21" + + // Guava + implementation "com.google.guava:guava:30.1.1-jre" + implementation "com.squareup.sqldelight:sqlite-driver:$sqldelight_version" + // https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on implementation group: 'org.bouncycastle', name: 'bcprov-jdk15to18', version: '1.63' @@ -88,6 +97,7 @@ dependencies { tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { kotlinOptions.freeCompilerArgs += [ "-Xuse-experimental=kotlin.Experimental,kotlin.ExperimentalUnsignedTypes", + "-Xopt-in=kotlin.RequiresOptIn", "-Werror" // Set Kotlin compiler warnings as errors ] } diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/Community.kt b/ipv8/src/main/java/nl/tudelft/ipv8/Community.kt index f282053f..9c5636ac 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/Community.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/Community.kt @@ -68,9 +68,8 @@ abstract class Community : Overlay { } override fun unload() { - super.unload() - job.cancel() + super.unload() } override fun bootstrap() { diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/keyvault/JavaCryptoProvider.kt b/ipv8/src/main/java/nl/tudelft/ipv8/keyvault/JavaCryptoProvider.kt index ffb3c4a6..157093d3 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/keyvault/JavaCryptoProvider.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/keyvault/JavaCryptoProvider.kt @@ -1,7 +1,7 @@ package nl.tudelft.ipv8.keyvault -import com.goterl.lazycode.lazysodium.LazySodiumJava -import com.goterl.lazycode.lazysodium.SodiumJava +import com.goterl.lazysodium.LazySodiumJava +import com.goterl.lazysodium.SodiumJava private val lazySodium = LazySodiumJava(SodiumJava()) diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/keyvault/LibNaClPK.kt b/ipv8/src/main/java/nl/tudelft/ipv8/keyvault/LibNaClPK.kt index 71d4bb7c..39556b00 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/keyvault/LibNaClPK.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/keyvault/LibNaClPK.kt @@ -1,7 +1,7 @@ package nl.tudelft.ipv8.keyvault -import com.goterl.lazycode.lazysodium.LazySodium -import com.goterl.lazycode.lazysodium.interfaces.Box +import com.goterl.lazysodium.LazySodium +import com.goterl.lazysodium.interfaces.Box import nl.tudelft.ipv8.util.toHex class LibNaClPK( diff --git a/ipv8/src/main/java/nl/tudelft/ipv8/keyvault/LibNaClSK.kt b/ipv8/src/main/java/nl/tudelft/ipv8/keyvault/LibNaClSK.kt index 6d71516e..c57e9f79 100644 --- a/ipv8/src/main/java/nl/tudelft/ipv8/keyvault/LibNaClSK.kt +++ b/ipv8/src/main/java/nl/tudelft/ipv8/keyvault/LibNaClSK.kt @@ -1,7 +1,7 @@ package nl.tudelft.ipv8.keyvault -import com.goterl.lazycode.lazysodium.LazySodium -import com.goterl.lazycode.lazysodium.interfaces.Box +import com.goterl.lazysodium.LazySodium +import com.goterl.lazysodium.interfaces.Box import nl.tudelft.ipv8.util.toHex import kotlin.random.Random diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/BaseCommunityTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/BaseCommunityTest.kt index 2b638c88..7a186a20 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/BaseCommunityTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/BaseCommunityTest.kt @@ -1,7 +1,7 @@ package nl.tudelft.ipv8 -import com.goterl.lazycode.lazysodium.LazySodiumJava -import com.goterl.lazycode.lazysodium.SodiumJava +import com.goterl.lazysodium.LazySodiumJava +import com.goterl.lazysodium.SodiumJava import io.mockk.mockk import io.mockk.spyk import kotlinx.coroutines.Dispatchers diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/CommunityTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/CommunityTest.kt index 073a3113..94e13dbf 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/CommunityTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/CommunityTest.kt @@ -1,16 +1,14 @@ package nl.tudelft.ipv8 -import com.goterl.lazycode.lazysodium.LazySodiumJava -import com.goterl.lazycode.lazysodium.SodiumJava import io.mockk.every import io.mockk.mockk import io.mockk.spyk import io.mockk.verify -import nl.tudelft.ipv8.keyvault.* +import nl.tudelft.ipv8.keyvault.JavaCryptoProvider +import nl.tudelft.ipv8.keyvault.PrivateKey +import nl.tudelft.ipv8.keyvault.defaultCryptoProvider import nl.tudelft.ipv8.messaging.Address import nl.tudelft.ipv8.messaging.Packet -import nl.tudelft.ipv8.messaging.payload.BinMemberAuthenticationPayload -import nl.tudelft.ipv8.messaging.payload.GlobalTimeDistributionPayload import nl.tudelft.ipv8.messaging.payload.PunctureRequestPayload import nl.tudelft.ipv8.peerdiscovery.Network import nl.tudelft.ipv8.util.hexToBytes @@ -18,8 +16,6 @@ import nl.tudelft.ipv8.util.toHex import org.junit.Assert import org.junit.Test -private val lazySodium = LazySodiumJava(SodiumJava()) - class CommunityTest : BaseCommunityTest() { private fun getCommunity(): TestCommunity { val myPrivateKey = getPrivateKey() diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/TestCommunity.kt b/ipv8/src/test/java/nl/tudelft/ipv8/TestCommunity.kt index 206c0a14..bd9b46fb 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/TestCommunity.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/TestCommunity.kt @@ -1,7 +1,7 @@ package nl.tudelft.ipv8 -import com.goterl.lazycode.lazysodium.LazySodiumJava -import com.goterl.lazycode.lazysodium.SodiumJava +import com.goterl.lazysodium.LazySodiumJava +import com.goterl.lazysodium.SodiumJava import nl.tudelft.ipv8.keyvault.LibNaClPK import nl.tudelft.ipv8.util.hexToBytes diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/TrustChainBlockTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/TrustChainBlockTest.kt index 46e67e01..d30edfa9 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/TrustChainBlockTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/TrustChainBlockTest.kt @@ -1,7 +1,7 @@ package nl.tudelft.ipv8.attestation.trustchain -import com.goterl.lazycode.lazysodium.LazySodiumJava -import com.goterl.lazycode.lazysodium.SodiumJava +import com.goterl.lazysodium.LazySodiumJava +import com.goterl.lazysodium.SodiumJava import io.mockk.every import io.mockk.mockk import nl.tudelft.ipv8.attestation.trustchain.payload.HalfBlockPayload diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/CrawlRequestPayloadTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/CrawlRequestPayloadTest.kt index ceb924a6..c4163315 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/CrawlRequestPayloadTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/CrawlRequestPayloadTest.kt @@ -1,7 +1,7 @@ package nl.tudelft.ipv8.attestation.trustchain.payload -import com.goterl.lazycode.lazysodium.LazySodiumJava -import com.goterl.lazycode.lazysodium.SodiumJava +import com.goterl.lazysodium.LazySodiumJava +import com.goterl.lazysodium.SodiumJava import nl.tudelft.ipv8.keyvault.LibNaClSK import nl.tudelft.ipv8.util.hexToBytes import org.junit.Assert diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/CrawlResponsePayloadTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/CrawlResponsePayloadTest.kt index 840c819f..697f8d68 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/CrawlResponsePayloadTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/CrawlResponsePayloadTest.kt @@ -1,7 +1,7 @@ package nl.tudelft.ipv8.attestation.trustchain.payload -import com.goterl.lazycode.lazysodium.LazySodiumJava -import com.goterl.lazycode.lazysodium.SodiumJava +import com.goterl.lazysodium.LazySodiumJava +import com.goterl.lazysodium.SodiumJava import nl.tudelft.ipv8.attestation.trustchain.EMPTY_SIG import nl.tudelft.ipv8.keyvault.LibNaClSK import nl.tudelft.ipv8.util.hexToBytes diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/HalfBlockBroadcastPayloadTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/HalfBlockBroadcastPayloadTest.kt index 949b6bd5..4789024b 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/HalfBlockBroadcastPayloadTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/HalfBlockBroadcastPayloadTest.kt @@ -1,7 +1,7 @@ package nl.tudelft.ipv8.attestation.trustchain.payload -import com.goterl.lazycode.lazysodium.LazySodiumJava -import com.goterl.lazycode.lazysodium.SodiumJava +import com.goterl.lazysodium.LazySodiumJava +import com.goterl.lazysodium.SodiumJava import nl.tudelft.ipv8.attestation.trustchain.EMPTY_SIG import nl.tudelft.ipv8.keyvault.LibNaClSK import nl.tudelft.ipv8.util.hexToBytes diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/HalfBlockPairBroadcastPayloadTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/HalfBlockPairBroadcastPayloadTest.kt index beab33c5..a5781eb5 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/HalfBlockPairBroadcastPayloadTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/HalfBlockPairBroadcastPayloadTest.kt @@ -1,7 +1,7 @@ package nl.tudelft.ipv8.attestation.trustchain.payload -import com.goterl.lazycode.lazysodium.LazySodiumJava -import com.goterl.lazycode.lazysodium.SodiumJava +import com.goterl.lazysodium.LazySodiumJava +import com.goterl.lazysodium.SodiumJava import nl.tudelft.ipv8.attestation.trustchain.EMPTY_SIG import nl.tudelft.ipv8.keyvault.LibNaClSK import nl.tudelft.ipv8.util.hexToBytes diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/HalfBlockPairPayloadTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/HalfBlockPairPayloadTest.kt index 59684892..72c4f40b 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/HalfBlockPairPayloadTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/HalfBlockPairPayloadTest.kt @@ -1,7 +1,7 @@ package nl.tudelft.ipv8.attestation.trustchain.payload -import com.goterl.lazycode.lazysodium.LazySodiumJava -import com.goterl.lazycode.lazysodium.SodiumJava +import com.goterl.lazysodium.LazySodiumJava +import com.goterl.lazysodium.SodiumJava import nl.tudelft.ipv8.attestation.trustchain.EMPTY_SIG import nl.tudelft.ipv8.keyvault.LibNaClSK import nl.tudelft.ipv8.util.hexToBytes diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/HalfBlockPayloadTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/HalfBlockPayloadTest.kt index d5bc42b5..df1b3ff4 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/HalfBlockPayloadTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/payload/HalfBlockPayloadTest.kt @@ -1,7 +1,7 @@ package nl.tudelft.ipv8.attestation.trustchain.payload -import com.goterl.lazycode.lazysodium.LazySodiumJava -import com.goterl.lazycode.lazysodium.SodiumJava +import com.goterl.lazysodium.LazySodiumJava +import com.goterl.lazysodium.SodiumJava import nl.tudelft.ipv8.attestation.trustchain.ANY_COUNTERPARTY_PK import nl.tudelft.ipv8.attestation.trustchain.EMPTY_SIG import nl.tudelft.ipv8.attestation.trustchain.GENESIS_HASH diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/store/TrustChainStoreTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/store/TrustChainStoreTest.kt index 5c80ffee..1f1cc71e 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/store/TrustChainStoreTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/attestation/trustchain/store/TrustChainStoreTest.kt @@ -1,7 +1,7 @@ package nl.tudelft.ipv8.attestation.trustchain.store -import com.goterl.lazycode.lazysodium.LazySodiumJava -import com.goterl.lazycode.lazysodium.SodiumJava +import com.goterl.lazysodium.LazySodiumJava +import com.goterl.lazysodium.SodiumJava import com.squareup.sqldelight.db.SqlDriver import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver.Companion.IN_MEMORY diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/keyvault/LibNaClPKTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/keyvault/LibNaClPKTest.kt index 051ae70f..8d187965 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/keyvault/LibNaClPKTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/keyvault/LibNaClPKTest.kt @@ -1,7 +1,7 @@ package nl.tudelft.ipv8.keyvault -import com.goterl.lazycode.lazysodium.LazySodiumJava -import com.goterl.lazycode.lazysodium.SodiumJava +import com.goterl.lazysodium.LazySodiumJava +import com.goterl.lazysodium.SodiumJava import nl.tudelft.ipv8.util.hexToBytes import nl.tudelft.ipv8.util.toHex import org.junit.Assert diff --git a/ipv8/src/test/java/nl/tudelft/ipv8/keyvault/LibNaClSKTest.kt b/ipv8/src/test/java/nl/tudelft/ipv8/keyvault/LibNaClSKTest.kt index cc7d6980..1b53ed8c 100644 --- a/ipv8/src/test/java/nl/tudelft/ipv8/keyvault/LibNaClSKTest.kt +++ b/ipv8/src/test/java/nl/tudelft/ipv8/keyvault/LibNaClSKTest.kt @@ -1,7 +1,7 @@ package nl.tudelft.ipv8.keyvault -import com.goterl.lazycode.lazysodium.LazySodiumJava -import com.goterl.lazycode.lazysodium.SodiumJava +import com.goterl.lazysodium.LazySodiumJava +import com.goterl.lazysodium.SodiumJava import nl.tudelft.ipv8.util.toHex import org.junit.Assert import org.junit.Test