serialization of personas. Load persona on startup
This commit is contained in:
8
core/src/main/groovy/com/muwire/core/Constants.groovy
Normal file
8
core/src/main/groovy/com/muwire/core/Constants.groovy
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package com.muwire.core
|
||||||
|
|
||||||
|
import net.i2p.crypto.SigType
|
||||||
|
|
||||||
|
class Constants {
|
||||||
|
public static final byte PERSONA_VERSION = (byte)1
|
||||||
|
public static final SigType SIG_TYPE = SigType.ECDSA_SHA512_P521 // TODO: decide which
|
||||||
|
}
|
@@ -1,5 +1,7 @@
|
|||||||
package com.muwire.core
|
package com.muwire.core
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
|
||||||
import com.muwire.core.connection.ConnectionAcceptor
|
import com.muwire.core.connection.ConnectionAcceptor
|
||||||
import com.muwire.core.connection.ConnectionEstablisher
|
import com.muwire.core.connection.ConnectionEstablisher
|
||||||
import com.muwire.core.connection.ConnectionEvent
|
import com.muwire.core.connection.ConnectionEvent
|
||||||
@@ -21,6 +23,12 @@ import net.i2p.client.I2PSession
|
|||||||
import net.i2p.client.streaming.I2PSocketManager
|
import net.i2p.client.streaming.I2PSocketManager
|
||||||
import net.i2p.client.streaming.I2PSocketManagerFactory
|
import net.i2p.client.streaming.I2PSocketManagerFactory
|
||||||
import net.i2p.client.streaming.I2PSocketOptions
|
import net.i2p.client.streaming.I2PSocketOptions
|
||||||
|
import net.i2p.crypto.DSAEngine
|
||||||
|
import net.i2p.crypto.SigType
|
||||||
|
import net.i2p.data.Destination
|
||||||
|
import net.i2p.data.PrivateKey
|
||||||
|
import net.i2p.data.Signature
|
||||||
|
import net.i2p.data.SigningPrivateKey
|
||||||
|
|
||||||
@Log
|
@Log
|
||||||
class Core {
|
class Core {
|
||||||
@@ -46,14 +54,13 @@ class Core {
|
|||||||
props = new MuWireSettings(props)
|
props = new MuWireSettings(props)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
log.info("initializing I2P socket manager")
|
log.info("initializing I2P socket manager")
|
||||||
def i2pClient = new I2PClientFactory().createClient()
|
def i2pClient = new I2PClientFactory().createClient()
|
||||||
File keyDat = new File(home, "key.dat")
|
File keyDat = new File(home, "key.dat")
|
||||||
if (!keyDat.exists()) {
|
if (!keyDat.exists()) {
|
||||||
log.info("Creating new key.dat")
|
log.info("Creating new key.dat")
|
||||||
keyDat.withOutputStream {
|
keyDat.withOutputStream {
|
||||||
i2pClient.createDestination(it)
|
i2pClient.createDestination(it, Constants.SIG_TYPE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +75,32 @@ class Core {
|
|||||||
socketManager.getDefaultOptions().setConnectTimeout(30000)
|
socketManager.getDefaultOptions().setConnectTimeout(30000)
|
||||||
i2pSession = socketManager.getSession()
|
i2pSession = socketManager.getSession()
|
||||||
|
|
||||||
|
Persona me
|
||||||
|
def destination = new Destination()
|
||||||
|
def spk = new SigningPrivateKey(Constants.SIG_TYPE)
|
||||||
|
keyDat.withInputStream {
|
||||||
|
destination.readBytes(it)
|
||||||
|
def privateKey = new PrivateKey()
|
||||||
|
privateKey.readBytes(it)
|
||||||
|
spk.readBytes(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
def baos = new ByteArrayOutputStream()
|
||||||
|
def daos = new DataOutputStream(baos)
|
||||||
|
daos.write(Constants.PERSONA_VERSION)
|
||||||
|
daos.writeShort((short)props.getNickname().length())
|
||||||
|
daos.write(props.getNickname().getBytes(StandardCharsets.UTF_8))
|
||||||
|
destination.writeBytes(daos)
|
||||||
|
daos.flush()
|
||||||
|
byte [] payload = baos.toByteArray()
|
||||||
|
Signature sig = DSAEngine.getInstance().sign(payload, spk)
|
||||||
|
|
||||||
|
baos = new ByteArrayOutputStream()
|
||||||
|
baos.write(payload)
|
||||||
|
sig.writeBytes(baos)
|
||||||
|
me = new Persona(new ByteArrayInputStream(baos.toByteArray()))
|
||||||
|
log.info("Loaded myself as "+me.getHumanReadableName())
|
||||||
|
|
||||||
EventBus eventBus = new EventBus()
|
EventBus eventBus = new EventBus()
|
||||||
|
|
||||||
log.info("initializing trust service")
|
log.info("initializing trust service")
|
||||||
|
@@ -0,0 +1,17 @@
|
|||||||
|
package com.muwire.core
|
||||||
|
|
||||||
|
class InvalidSignatureException extends Exception {
|
||||||
|
|
||||||
|
public InvalidSignatureException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidSignatureException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidSignatureException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -10,7 +10,7 @@ class MuWireSettings {
|
|||||||
isLeaf = Boolean.valueOf(props.get("leaf","false"))
|
isLeaf = Boolean.valueOf(props.get("leaf","false"))
|
||||||
allowUntrusted = Boolean.valueOf(props.get("allowUntrusted","true"))
|
allowUntrusted = Boolean.valueOf(props.get("allowUntrusted","true"))
|
||||||
crawlerResponse = CrawlerResponse.valueOf(props.get("crawlerResponse","REGISTERED"))
|
crawlerResponse = CrawlerResponse.valueOf(props.get("crawlerResponse","REGISTERED"))
|
||||||
nickname = props.getProperty("nickname")
|
nickname = props.getProperty("nickname","MuWireUser")
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean isLeaf
|
final boolean isLeaf
|
||||||
@@ -37,4 +37,8 @@ class MuWireSettings {
|
|||||||
void setCrawlerResponse(CrawlerResponse crawlerResponse) {
|
void setCrawlerResponse(CrawlerResponse crawlerResponse) {
|
||||||
this.crawlerResponse = crawlerResponse
|
this.crawlerResponse = crawlerResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getNickname() {
|
||||||
|
nickname
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,7 @@ public class Name {
|
|||||||
public void write(OutputStream out) throws IOException {
|
public void write(OutputStream out) throws IOException {
|
||||||
DataOutputStream dos = new DataOutputStream(out)
|
DataOutputStream dos = new DataOutputStream(out)
|
||||||
dos.writeShort(name.length())
|
dos.writeShort(name.length())
|
||||||
dos.writeBuffer(name.getBytes(StandardCharsets.UTF_8))
|
dos.write(name.getBytes(StandardCharsets.UTF_8))
|
||||||
}
|
}
|
||||||
|
|
||||||
public getName() {
|
public getName() {
|
||||||
|
74
core/src/main/groovy/com/muwire/core/Persona.groovy
Normal file
74
core/src/main/groovy/com/muwire/core/Persona.groovy
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
package com.muwire.core
|
||||||
|
|
||||||
|
import net.i2p.crypto.DSAEngine
|
||||||
|
import net.i2p.crypto.SigType
|
||||||
|
import net.i2p.data.Destination
|
||||||
|
import net.i2p.data.Signature
|
||||||
|
import net.i2p.data.SigningPublicKey
|
||||||
|
|
||||||
|
public class Persona {
|
||||||
|
private static final int SIG_LEN = Constants.SIG_TYPE.getSigLen()
|
||||||
|
|
||||||
|
private final byte version
|
||||||
|
private final Name name
|
||||||
|
private final Destination destination
|
||||||
|
private final byte[] sig
|
||||||
|
private volatile String humanReadableName
|
||||||
|
private volatile byte[] payload
|
||||||
|
|
||||||
|
public Persona(InputStream personaStream) throws IOException, InvalidSignatureException {
|
||||||
|
version = (byte) (personaStream.read() & 0xFF)
|
||||||
|
if (version != Constants.PERSONA_VERSION)
|
||||||
|
throw new IOException("Unknown version "+version)
|
||||||
|
|
||||||
|
name = new Name(personaStream)
|
||||||
|
destination = Destination.create(personaStream)
|
||||||
|
sig = new byte[SIG_LEN]
|
||||||
|
DataInputStream dis = new DataInputStream(personaStream)
|
||||||
|
dis.readFully(sig)
|
||||||
|
if (!verify(version, name, destination, sig))
|
||||||
|
throw new InvalidSignatureException(getHumanReadableName() + " didn't verify")
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean verify(byte version, Name name, Destination destination, byte [] sig) {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream()
|
||||||
|
baos.write(version)
|
||||||
|
name.write(baos)
|
||||||
|
destination.writeBytes(baos)
|
||||||
|
byte[] payload = baos.toByteArray()
|
||||||
|
SigningPublicKey spk = destination.getSigningPublicKey()
|
||||||
|
Signature signature = new Signature(Constants.SIG_TYPE, sig)
|
||||||
|
DSAEngine.getInstance().verifySignature(signature, payload, spk)
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(OutputStream out) throws IOException {
|
||||||
|
if (payload == null) {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream()
|
||||||
|
baos.write(version)
|
||||||
|
name.write(baos)
|
||||||
|
destination.writeBytes(baos)
|
||||||
|
baos.write(sig)
|
||||||
|
payload = baos.toByteArray()
|
||||||
|
}
|
||||||
|
out.write(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHumanReadableName() {
|
||||||
|
if (humanReadableName == null)
|
||||||
|
humanReadableName = name.getName() + "@" + destination.toBase32().substring(0,32)
|
||||||
|
humanReadableName
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
name.hashCode() ^ destination.hashCode()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (!(o instanceof Persona))
|
||||||
|
return false
|
||||||
|
Persona other = (Persona)o
|
||||||
|
name.equals(other.name) && destination.equals(other.destination)
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user