From cad53018271814288596978bf7f24d5886db7af1 Mon Sep 17 00:00:00 2001 From: Zlatin Balevsky Date: Thu, 7 Nov 2019 17:41:32 +0000 Subject: [PATCH] rewrite Persona and Name in java --- .../main/groovy/com/muwire/core/Name.groovy | 46 -------- .../groovy/com/muwire/core/Persona.groovy | 94 ---------------- .../core/InvalidSignatureException.java} | 2 +- core/src/main/java/com/muwire/core/Name.java | 51 +++++++++ .../main/java/com/muwire/core/Persona.java | 102 ++++++++++++++++++ 5 files changed, 154 insertions(+), 141 deletions(-) delete mode 100644 core/src/main/groovy/com/muwire/core/Name.groovy delete mode 100644 core/src/main/groovy/com/muwire/core/Persona.groovy rename core/src/main/{groovy/com/muwire/core/InvalidSignatureException.groovy => java/com/muwire/core/InvalidSignatureException.java} (93%) create mode 100644 core/src/main/java/com/muwire/core/Name.java create mode 100644 core/src/main/java/com/muwire/core/Persona.java diff --git a/core/src/main/groovy/com/muwire/core/Name.groovy b/core/src/main/groovy/com/muwire/core/Name.groovy deleted file mode 100644 index 61d5c6a1..00000000 --- a/core/src/main/groovy/com/muwire/core/Name.groovy +++ /dev/null @@ -1,46 +0,0 @@ -package com.muwire.core - -import java.nio.charset.StandardCharsets - -/** - * A name of persona, file or search term - */ -public class Name { - final String name - - Name(String name) { - this.name = name - } - - Name(InputStream nameStream) throws IOException { - DataInputStream dis = new DataInputStream(nameStream) - int length = dis.readUnsignedShort() - byte [] nameBytes = new byte[length] - dis.readFully(nameBytes) - this.name = new String(nameBytes, StandardCharsets.UTF_8) - } - - public void write(OutputStream out) throws IOException { - DataOutputStream dos = new DataOutputStream(out) - byte [] bytes = name.getBytes(StandardCharsets.UTF_8) - dos.writeShort(bytes.length) - dos.write(bytes) - } - - public getName() { - name - } - - @Override - public int hashCode() { - name.hashCode() - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof Name)) - return false - Name other = (Name)o - name.equals(other.name) - } -} diff --git a/core/src/main/groovy/com/muwire/core/Persona.groovy b/core/src/main/groovy/com/muwire/core/Persona.groovy deleted file mode 100644 index b703ab9d..00000000 --- a/core/src/main/groovy/com/muwire/core/Persona.groovy +++ /dev/null @@ -1,94 +0,0 @@ -package com.muwire.core - -import net.i2p.crypto.DSAEngine -import net.i2p.crypto.SigType -import net.i2p.data.Base64 -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 String base64 - 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 - } - - public String toBase64() { - if (base64 == null) { - def baos = new ByteArrayOutputStream() - write(baos) - base64 = Base64.encode(baos.toByteArray()) - } - base64 - } - - @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) - } - - public static void main(String []args) { - if (args.length != 1) { - println "This utility decodes a bas64-encoded persona" - System.exit(1) - } - Persona p = new Persona(new ByteArrayInputStream(Base64.decode(args[0]))) - println p.getHumanReadableName() - } -} diff --git a/core/src/main/groovy/com/muwire/core/InvalidSignatureException.groovy b/core/src/main/java/com/muwire/core/InvalidSignatureException.java similarity index 93% rename from core/src/main/groovy/com/muwire/core/InvalidSignatureException.groovy rename to core/src/main/java/com/muwire/core/InvalidSignatureException.java index e0c235c9..d18971ae 100644 --- a/core/src/main/groovy/com/muwire/core/InvalidSignatureException.groovy +++ b/core/src/main/java/com/muwire/core/InvalidSignatureException.java @@ -1,4 +1,4 @@ -package com.muwire.core +package com.muwire.core; class InvalidSignatureException extends Exception { diff --git a/core/src/main/java/com/muwire/core/Name.java b/core/src/main/java/com/muwire/core/Name.java new file mode 100644 index 00000000..beae7e29 --- /dev/null +++ b/core/src/main/java/com/muwire/core/Name.java @@ -0,0 +1,51 @@ +package com.muwire.core; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; + +/** + * A name of persona, file or search term + */ +public class Name { + final String name; + + Name(String name) { + this.name = name; + } + + Name(InputStream nameStream) throws IOException { + DataInputStream dis = new DataInputStream(nameStream); + int length = dis.readUnsignedShort(); + byte [] nameBytes = new byte[length]; + dis.readFully(nameBytes); + this.name = new String(nameBytes, StandardCharsets.UTF_8); + } + + public void write(OutputStream out) throws IOException { + DataOutputStream dos = new DataOutputStream(out); + byte [] bytes = name.getBytes(StandardCharsets.UTF_8); + dos.writeShort(bytes.length); + dos.write(bytes); + } + + public String getName() { + return name; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Name)) + return false; + Name other = (Name)o; + return name.equals(other.name); + } +} diff --git a/core/src/main/java/com/muwire/core/Persona.java b/core/src/main/java/com/muwire/core/Persona.java new file mode 100644 index 00000000..b280dd62 --- /dev/null +++ b/core/src/main/java/com/muwire/core/Persona.java @@ -0,0 +1,102 @@ +package com.muwire.core; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import net.i2p.crypto.DSAEngine; +import net.i2p.data.Base64; +import net.i2p.data.DataFormatException; +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 String base64; + private volatile byte[] payload; + + public Persona(InputStream personaStream) throws IOException, DataFormatException, 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) + throws IOException, DataFormatException { + 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); + return DSAEngine.getInstance().verifySignature(signature, payload, spk); + } + + public void write(OutputStream out) throws IOException, DataFormatException { + 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); + return humanReadableName; + } + + public String toBase64() throws DataFormatException, IOException { + if (base64 == null) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + write(baos); + base64 = Base64.encode(baos.toByteArray()); + } + return base64; + } + + @Override + public int hashCode() { + return name.hashCode() ^ destination.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Persona)) + return false; + Persona other = (Persona)o; + return name.equals(other.name) && destination.equals(other.destination); + } + + public static void main(String []args) throws Exception { + if (args.length != 1) { + System.out.println("This utility decodes a bas64-encoded persona"); + System.exit(1); + } + Persona p = new Persona(new ByteArrayInputStream(Base64.decode(args[0]))); + System.out.println(p.getHumanReadableName()); + } +}