serialization of personas. Load persona on startup

This commit is contained in:
Zlatin Balevsky
2019-05-23 18:55:47 +01:00
parent 681feed70c
commit ee8c39f032
6 changed files with 140 additions and 5 deletions

View 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
}

View File

@@ -1,5 +1,7 @@
package com.muwire.core
import java.nio.charset.StandardCharsets
import com.muwire.core.connection.ConnectionAcceptor
import com.muwire.core.connection.ConnectionEstablisher
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.I2PSocketManagerFactory
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
class Core {
@@ -46,14 +54,13 @@ class Core {
props = new MuWireSettings(props)
log.info("initializing I2P socket manager")
def i2pClient = new I2PClientFactory().createClient()
File keyDat = new File(home, "key.dat")
if (!keyDat.exists()) {
log.info("Creating new key.dat")
keyDat.withOutputStream {
i2pClient.createDestination(it)
i2pClient.createDestination(it, Constants.SIG_TYPE)
}
}
@@ -68,7 +75,32 @@ class Core {
socketManager.getDefaultOptions().setConnectTimeout(30000)
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()
log.info("initializing trust service")

View File

@@ -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);
}
}

View File

@@ -10,7 +10,7 @@ class MuWireSettings {
isLeaf = Boolean.valueOf(props.get("leaf","false"))
allowUntrusted = Boolean.valueOf(props.get("allowUntrusted","true"))
crawlerResponse = CrawlerResponse.valueOf(props.get("crawlerResponse","REGISTERED"))
nickname = props.getProperty("nickname")
nickname = props.getProperty("nickname","MuWireUser")
}
final boolean isLeaf
@@ -37,4 +37,8 @@ class MuWireSettings {
void setCrawlerResponse(CrawlerResponse crawlerResponse) {
this.crawlerResponse = crawlerResponse
}
String getNickname() {
nickname
}
}

View File

@@ -23,7 +23,7 @@ public class Name {
public void write(OutputStream out) throws IOException {
DataOutputStream dos = new DataOutputStream(out)
dos.writeShort(name.length())
dos.writeBuffer(name.getBytes(StandardCharsets.UTF_8))
dos.write(name.getBytes(StandardCharsets.UTF_8))
}
public getName() {

View 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)
}
}