wip on signing queries

This commit is contained in:
Zlatin Balevsky
2019-11-02 18:34:13 +00:00
parent 27aad9d75d
commit 1ce410e943
5 changed files with 53 additions and 4 deletions

View File

@@ -8,7 +8,11 @@ import com.muwire.core.search.SearchEvent
import com.muwire.core.search.UIResultBatchEvent import com.muwire.core.search.UIResultBatchEvent
import com.muwire.core.search.UIResultEvent import com.muwire.core.search.UIResultEvent
import net.i2p.crypto.DSAEngine
import net.i2p.data.Base64 import net.i2p.data.Base64
import net.i2p.data.Signature
import java.nio.charset.StandardCharsets
import com.googlecode.lanterna.gui2.TextGUIThread import com.googlecode.lanterna.gui2.TextGUIThread
import com.googlecode.lanterna.gui2.table.TableModel import com.googlecode.lanterna.gui2.table.TableModel
@@ -40,20 +44,27 @@ class SearchModel {
} }
def searchEvent def searchEvent
byte [] payload
if (hashSearch) { if (hashSearch) {
searchEvent = new SearchEvent(searchHash : root, uuid : UUID.randomUUID(), oobInfohash : true, compressedResults : true) searchEvent = new SearchEvent(searchHash : root, uuid : UUID.randomUUID(), oobInfohash : true, compressedResults : true)
payload = root
} else { } else {
def replaced = query.toLowerCase().trim().replaceAll(SplitPattern.SPLIT_PATTERN, " ") def replaced = query.toLowerCase().trim().replaceAll(SplitPattern.SPLIT_PATTERN, " ")
def terms = replaced.split(" ") def terms = replaced.split(" ")
def nonEmpty = [] def nonEmpty = []
terms.each { if (it.length() > 0) nonEmpty << it } terms.each { if (it.length() > 0) nonEmpty << it }
payload = String.join(" ", nonEmpty).getBytes(StandardCharsets.UTF_8)
searchEvent = new SearchEvent(searchTerms : nonEmpty, uuid : UUID.randomUUID(), oobInfohash: true, searchEvent = new SearchEvent(searchTerms : nonEmpty, uuid : UUID.randomUUID(), oobInfohash: true,
searchComments : core.muOptions.searchComments, compressedResults : true) searchComments : core.muOptions.searchComments, compressedResults : true)
} }
boolean firstHop = core.muOptions.allowUntrusted || core.muOptions.searchExtraHop boolean firstHop = core.muOptions.allowUntrusted || core.muOptions.searchExtraHop
Signature sig = DSAEngine.getInstance().sign(payload, core.spk)
core.eventBus.publish(new QueryEvent(searchEvent : searchEvent, firstHop : firstHop, core.eventBus.publish(new QueryEvent(searchEvent : searchEvent, firstHop : firstHop,
replyTo: core.me.destination, receivedOn: core.me.destination, replyTo: core.me.destination, receivedOn: core.me.destination,
originator : core.me)) originator : core.me, sig: sig.data))
} }
void unregister() { void unregister() {

View File

@@ -104,6 +104,8 @@ public class Core {
final AtomicBoolean shutdown = new AtomicBoolean() final AtomicBoolean shutdown = new AtomicBoolean()
final SigningPrivateKey spk
public Core(MuWireSettings props, File home, String myVersion) { public Core(MuWireSettings props, File home, String myVersion) {
this.home = home this.home = home
this.muOptions = props this.muOptions = props
@@ -180,7 +182,7 @@ public class Core {
i2pSession = socketManager.getSession() i2pSession = socketManager.getSession()
def destination = new Destination() def destination = new Destination()
def spk = new SigningPrivateKey(Constants.SIG_TYPE) spk = new SigningPrivateKey(Constants.SIG_TYPE)
keyDat.withInputStream { keyDat.withInputStream {
destination.readBytes(it) destination.readBytes(it)
def privateKey = new PrivateKey() def privateKey = new PrivateKey()

View File

@@ -1,5 +1,6 @@
package com.muwire.core.connection package com.muwire.core.connection
import java.nio.charset.StandardCharsets
import java.util.concurrent.BlockingQueue import java.util.concurrent.BlockingQueue
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
import java.util.concurrent.ExecutorService import java.util.concurrent.ExecutorService
@@ -10,6 +11,7 @@ import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import java.util.logging.Level import java.util.logging.Level
import com.muwire.core.Constants
import com.muwire.core.EventBus import com.muwire.core.EventBus
import com.muwire.core.MuWireSettings import com.muwire.core.MuWireSettings
import com.muwire.core.Persona import com.muwire.core.Persona
@@ -21,8 +23,10 @@ import com.muwire.core.trust.TrustLevel
import com.muwire.core.trust.TrustService import com.muwire.core.trust.TrustService
import groovy.util.logging.Log import groovy.util.logging.Log
import net.i2p.crypto.DSAEngine
import net.i2p.data.Base64 import net.i2p.data.Base64
import net.i2p.data.Destination import net.i2p.data.Destination
import net.i2p.data.Signature
@Log @Log
abstract class Connection implements Closeable { abstract class Connection implements Closeable {
@@ -147,6 +151,8 @@ abstract class Connection implements Closeable {
query.replyTo = e.replyTo.toBase64() query.replyTo = e.replyTo.toBase64()
if (e.originator != null) if (e.originator != null)
query.originator = e.originator.toBase64() query.originator = e.originator.toBase64()
if (e.sig != null)
query.sig = Base64.encode(e.sig)
messages.put(query) messages.put(query)
} }
@@ -225,6 +231,24 @@ abstract class Connection implements Closeable {
boolean compressedResults = false boolean compressedResults = false
if (search.compressedResults != null) if (search.compressedResults != null)
compressedResults = search.compressedResults compressedResults = search.compressedResults
byte[] sig = null
// TODO: make this mandatory at some point
if (search.sig != null) {
sig = Base64.decode(search.sig)
byte [] payload
if (infohash != null)
payload = infohash
else
payload = String.join(" ",search.keywords).getBytes(StandardCharsets.UTF_8)
def spk = originator.destination.getSigningPublicKey()
def signature = new Signature(Constants.SIG_TYPE, sig)
if (!DSAEngine.getInstance().verifySig(signature, payload, spk)) {
log.info("signature didn't match keywords")
return
} else
log.info("query signature verified")
} else
log.info("no signature in query")
SearchEvent searchEvent = new SearchEvent(searchTerms : search.keywords, SearchEvent searchEvent = new SearchEvent(searchTerms : search.keywords,
searchHash : infohash, searchHash : infohash,
@@ -236,7 +260,8 @@ abstract class Connection implements Closeable {
replyTo : replyTo, replyTo : replyTo,
originator : originator, originator : originator,
receivedOn : endpoint.destination, receivedOn : endpoint.destination,
firstHop : search.firstHop ) firstHop : search.firstHop,
sig : sig )
eventBus.publish(event) eventBus.publish(event)
} }

View File

@@ -12,6 +12,7 @@ class QueryEvent extends Event {
Destination replyTo Destination replyTo
Persona originator Persona originator
Destination receivedOn Destination receivedOn
byte[] sig
String toString() { String toString() {
"searchEvent: $searchEvent firstHop:$firstHop, replyTo:${replyTo.toBase32()}" + "searchEvent: $searchEvent firstHop:$firstHop, replyTo:${replyTo.toBase32()}" +

View File

@@ -7,7 +7,11 @@ import griffon.core.mvc.MVCGroup
import griffon.core.mvc.MVCGroupConfiguration import griffon.core.mvc.MVCGroupConfiguration
import griffon.inject.MVCMember import griffon.inject.MVCMember
import griffon.metadata.ArtifactProviderFor import griffon.metadata.ArtifactProviderFor
import net.i2p.crypto.DSAEngine
import net.i2p.data.Base64 import net.i2p.data.Base64
import net.i2p.data.Signature
import java.nio.charset.StandardCharsets
import javax.annotation.Nonnull import javax.annotation.Nonnull
import javax.inject.Inject import javax.inject.Inject
@@ -77,21 +81,27 @@ class MainFrameController {
} }
def searchEvent def searchEvent
byte [] payload
if (hashSearch) { if (hashSearch) {
searchEvent = new SearchEvent(searchHash : root, uuid : uuid, oobInfohash: true, compressedResults : true) searchEvent = new SearchEvent(searchHash : root, uuid : uuid, oobInfohash: true, compressedResults : true)
payload = root
} else { } else {
// this can be improved a lot // this can be improved a lot
def replaced = search.toLowerCase().trim().replaceAll(SplitPattern.SPLIT_PATTERN, " ") def replaced = search.toLowerCase().trim().replaceAll(SplitPattern.SPLIT_PATTERN, " ")
def terms = replaced.split(" ") def terms = replaced.split(" ")
def nonEmpty = [] def nonEmpty = []
terms.each { if (it.length() > 0) nonEmpty << it } terms.each { if (it.length() > 0) nonEmpty << it }
payload = String.join(" ",nonEmpty).getBytes(StandardCharsets.UTF_8)
searchEvent = new SearchEvent(searchTerms : nonEmpty, uuid : uuid, oobInfohash: true, searchEvent = new SearchEvent(searchTerms : nonEmpty, uuid : uuid, oobInfohash: true,
searchComments : core.muOptions.searchComments, compressedResults : true) searchComments : core.muOptions.searchComments, compressedResults : true)
} }
boolean firstHop = core.muOptions.allowUntrusted || core.muOptions.searchExtraHop boolean firstHop = core.muOptions.allowUntrusted || core.muOptions.searchExtraHop
Signature sig = DSAEngine.getInstance().sign(payload, core.spk)
core.eventBus.publish(new QueryEvent(searchEvent : searchEvent, firstHop : firstHop, core.eventBus.publish(new QueryEvent(searchEvent : searchEvent, firstHop : firstHop,
replyTo: core.me.destination, receivedOn: core.me.destination, replyTo: core.me.destination, receivedOn: core.me.destination,
originator : core.me)) originator : core.me, sig : sig.data))
} }
void search(String infoHash, String tabTitle) { void search(String infoHash, String tabTitle) {