Added some address generation and handling
This commit is contained in:
parent
096f5db1bb
commit
d3499c9627
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage;
|
package ch.dissem.bitmessage;
|
||||||
|
|
||||||
import ch.dissem.bitmessage.ports.AddressRepository;
|
import ch.dissem.bitmessage.ports.NodeRegistry;
|
||||||
import ch.dissem.bitmessage.ports.Inventory;
|
import ch.dissem.bitmessage.ports.Inventory;
|
||||||
import ch.dissem.bitmessage.ports.NetworkHandler;
|
import ch.dissem.bitmessage.ports.NetworkHandler;
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ public class Context {
|
|||||||
private static Context instance;
|
private static Context instance;
|
||||||
|
|
||||||
private Inventory inventory;
|
private Inventory inventory;
|
||||||
private AddressRepository addressRepo;
|
private NodeRegistry addressRepo;
|
||||||
private NetworkHandler networkHandler;
|
private NetworkHandler networkHandler;
|
||||||
|
|
||||||
private Collection<Long> streams = new TreeSet<>();
|
private Collection<Long> streams = new TreeSet<>();
|
||||||
@ -42,7 +42,7 @@ public class Context {
|
|||||||
private long networkNonceTrialsPerByte = 1000;
|
private long networkNonceTrialsPerByte = 1000;
|
||||||
private long networkExtraBytes = 1000;
|
private long networkExtraBytes = 1000;
|
||||||
|
|
||||||
private Context(Inventory inventory, AddressRepository addressRepo,
|
private Context(Inventory inventory, NodeRegistry addressRepo,
|
||||||
NetworkHandler networkHandler, int port) {
|
NetworkHandler networkHandler, int port) {
|
||||||
this.inventory = inventory;
|
this.inventory = inventory;
|
||||||
this.addressRepo = addressRepo;
|
this.addressRepo = addressRepo;
|
||||||
@ -50,8 +50,8 @@ public class Context {
|
|||||||
this.port = port;
|
this.port = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void init(Inventory inventory, AddressRepository addressRepository, NetworkHandler networkHandler, int port) {
|
public static void init(Inventory inventory, NodeRegistry nodeRegistry, NetworkHandler networkHandler, int port) {
|
||||||
instance = new Context(inventory, addressRepository, networkHandler, port);
|
instance = new Context(inventory, nodeRegistry, networkHandler, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Context getInstance() {
|
public static Context getInstance() {
|
||||||
@ -62,7 +62,7 @@ public class Context {
|
|||||||
return inventory;
|
return inventory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AddressRepository getAddressRepository() {
|
public NodeRegistry getAddressRepository() {
|
||||||
return addressRepo;
|
return addressRepo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,55 +17,115 @@
|
|||||||
package ch.dissem.bitmessage.entity;
|
package ch.dissem.bitmessage.entity;
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
||||||
import ch.dissem.bitmessage.utils.Base58;
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
||||||
import ch.dissem.bitmessage.utils.Encode;
|
import ch.dissem.bitmessage.utils.*;
|
||||||
import ch.dissem.bitmessage.utils.Security;
|
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
import static ch.dissem.bitmessage.utils.Security.ripemd160;
|
|
||||||
import static ch.dissem.bitmessage.utils.Security.sha512;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Bitmessage address. Can be a user's private address, an address string without public keys or a recipient's address
|
* A Bitmessage address. Can be a user's private address, an address string without public keys or a recipient's address
|
||||||
* holding private keys.
|
* holding private keys.
|
||||||
*/
|
*/
|
||||||
public abstract class BitmessageAddress {
|
public class BitmessageAddress {
|
||||||
private long version;
|
private long version;
|
||||||
private long streamNumber;
|
private long stream;
|
||||||
|
private byte[] ripe;
|
||||||
|
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
private PrivateKey privateKey;
|
||||||
private Pubkey pubkey;
|
private Pubkey pubkey;
|
||||||
|
|
||||||
public BitmessageAddress(Pubkey pubkey) {
|
private String alias;
|
||||||
this.pubkey = pubkey;
|
|
||||||
|
public BitmessageAddress(PrivateKey privateKey) {
|
||||||
|
this.privateKey = privateKey;
|
||||||
|
this.pubkey = privateKey.getPubkey();
|
||||||
|
this.ripe = pubkey.getRipe();
|
||||||
|
this.address = generateAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BitmessageAddress(String address) {
|
public BitmessageAddress(String address) {
|
||||||
Base58.decode(address.substring(3));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
try {
|
try {
|
||||||
byte[] combinedKeys = new byte[pubkey.getSigningKey().length + pubkey.getEncryptionKey().length];
|
byte[] bytes = Base58.decode(address.substring(3));
|
||||||
System.arraycopy(pubkey.getSigningKey(), 0, combinedKeys, 0, pubkey.getSigningKey().length);
|
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
|
||||||
System.arraycopy(pubkey.getEncryptionKey(), 0, combinedKeys, pubkey.getSigningKey().length, pubkey.getEncryptionKey().length);
|
AccessCounter counter = new AccessCounter();
|
||||||
|
this.version = Decode.varInt(in, counter);
|
||||||
byte[] hash = ripemd160(sha512(combinedKeys));
|
this.stream = Decode.varInt(in, counter);
|
||||||
|
this.ripe = Decode.bytes(in, bytes.length - counter.length() - 4);
|
||||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
testChecksum(Decode.bytes(in, 4), bytes);
|
||||||
Encode.varInt(version, stream);
|
this.address = generateAddress();
|
||||||
Encode.varInt(streamNumber, stream);
|
|
||||||
stream.write(hash);
|
|
||||||
|
|
||||||
byte[] checksum = Security.doubleSha512(stream.toByteArray());
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
stream.write(checksum[i]);
|
|
||||||
}
|
|
||||||
return "BM-" + Base58.encode(stream.toByteArray());
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void testChecksum(byte[] expected, byte[] address) {
|
||||||
|
byte[] checksum = Security.doubleSha512(address, address.length - 4);
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (expected[i] != checksum[i]) throw new IllegalArgumentException("Checksum of address failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateAddress() {
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
|
Encode.varInt(version, os);
|
||||||
|
Encode.varInt(stream, os);
|
||||||
|
os.write(ripe);
|
||||||
|
|
||||||
|
byte[] checksum = Security.doubleSha512(os.toByteArray());
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
os.write(checksum[i]);
|
||||||
|
}
|
||||||
|
return "BM-" + Base58.encode(os.toByteArray());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getStream() {
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pubkey getPubkey() {
|
||||||
|
return pubkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPubkey(Pubkey pubkey) {
|
||||||
|
if (!Arrays.equals(ripe, pubkey.getRipe())) throw new IllegalArgumentException("Pubkey has incompatible RIPE");
|
||||||
|
this.pubkey = pubkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrivateKey getPrivateKey() {
|
||||||
|
return privateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlias(String alias) {
|
||||||
|
this.alias = alias;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlias() {
|
||||||
|
return alias;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return alias != null ? alias : address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getRipe() {
|
||||||
|
return ripe;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,24 +16,63 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.entity.payload;
|
package ch.dissem.bitmessage.entity.payload;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import static ch.dissem.bitmessage.utils.Security.ripemd160;
|
||||||
|
import static ch.dissem.bitmessage.utils.Security.sha512;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public keys for signing and encryption, the answer to a 'getpubkey' request.
|
* Public keys for signing and encryption, the answer to a 'getpubkey' request.
|
||||||
*/
|
*/
|
||||||
public interface Pubkey extends ObjectPayload {
|
public abstract class Pubkey implements ObjectPayload {
|
||||||
// bits 0 through 29 are yet undefined
|
public final static long LATEST_VERSION = 4;
|
||||||
|
|
||||||
|
public abstract long getVersion();
|
||||||
|
|
||||||
|
public abstract byte[] getSigningKey();
|
||||||
|
|
||||||
|
public abstract byte[] getEncryptionKey();
|
||||||
|
|
||||||
|
public byte[] getRipe() {
|
||||||
|
return ripemd160(sha512(getSigningKey(), getEncryptionKey()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bits 0 through 29 are yet undefined
|
||||||
|
*/
|
||||||
|
public enum Feature {
|
||||||
/**
|
/**
|
||||||
* Receiving node expects that the RIPE hash encoded in their address preceedes the encrypted message data of msg
|
* Receiving node expects that the RIPE hash encoded in their address preceedes the encrypted message data of msg
|
||||||
* messages bound for them.
|
* messages bound for them.
|
||||||
*/
|
*/
|
||||||
int FEATURE_INCLUDE_DESTINATION = 30;
|
INCLUDE_DESTINATION(1 << 30),
|
||||||
/**
|
/**
|
||||||
* If true, the receiving node does send acknowledgements (rather than dropping them).
|
* If true, the receiving node does send acknowledgements (rather than dropping them).
|
||||||
*/
|
*/
|
||||||
int FEATURE_DOES_ACK = 31;
|
DOES_ACK(1 << 31);
|
||||||
|
|
||||||
long getVersion();
|
private int bit;
|
||||||
|
|
||||||
byte[] getSigningKey();
|
Feature(int bit) {
|
||||||
|
this.bit = bit;
|
||||||
|
}
|
||||||
|
|
||||||
byte[] getEncryptionKey();
|
public static int bitfield(Feature... features) {
|
||||||
|
int bits = 0;
|
||||||
|
for (Feature feature : features) {
|
||||||
|
bits |= feature.bit;
|
||||||
|
}
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Feature[] features(int bitfield){
|
||||||
|
ArrayList<Feature> features = new ArrayList<>(Feature.values().length);
|
||||||
|
for (Feature feature:Feature.values()){
|
||||||
|
if ((bitfield & feature.bit) != 0){
|
||||||
|
features.add(feature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return features.toArray(new Feature[features.size()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ import java.io.OutputStream;
|
|||||||
/**
|
/**
|
||||||
* A version 2 public key.
|
* A version 2 public key.
|
||||||
*/
|
*/
|
||||||
public class V2Pubkey implements Pubkey {
|
public class V2Pubkey extends Pubkey {
|
||||||
protected long stream;
|
protected long stream;
|
||||||
protected int behaviorBitfield;
|
protected int behaviorBitfield;
|
||||||
protected byte[] publicSigningKey; // 64 Bytes
|
protected byte[] publicSigningKey; // 64 Bytes
|
||||||
@ -44,7 +44,7 @@ public class V2Pubkey implements Pubkey {
|
|||||||
|
|
||||||
public static V2Pubkey read(InputStream is, long stream) throws IOException {
|
public static V2Pubkey read(InputStream is, long stream) throws IOException {
|
||||||
return new V2Pubkey.Builder()
|
return new V2Pubkey.Builder()
|
||||||
.streamNumber(stream)
|
.stream(stream)
|
||||||
.behaviorBitfield((int) Decode.uint32(is))
|
.behaviorBitfield((int) Decode.uint32(is))
|
||||||
.publicSigningKey(Decode.bytes(is, 64))
|
.publicSigningKey(Decode.bytes(is, 64))
|
||||||
.publicEncryptionKey(Decode.bytes(is, 64))
|
.publicEncryptionKey(Decode.bytes(is, 64))
|
||||||
@ -87,7 +87,7 @@ public class V2Pubkey implements Pubkey {
|
|||||||
public Builder() {
|
public Builder() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder streamNumber(long streamNumber) {
|
public Builder stream(long streamNumber) {
|
||||||
this.streamNumber = streamNumber;
|
this.streamNumber = streamNumber;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ public class V3Pubkey extends V2Pubkey {
|
|||||||
|
|
||||||
public static V3Pubkey read(InputStream is, long stream) throws IOException {
|
public static V3Pubkey read(InputStream is, long stream) throws IOException {
|
||||||
V3Pubkey.Builder v3 = new V3Pubkey.Builder()
|
V3Pubkey.Builder v3 = new V3Pubkey.Builder()
|
||||||
.streamNumber(stream)
|
.stream(stream)
|
||||||
.behaviorBitfield((int) Decode.uint32(is))
|
.behaviorBitfield((int) Decode.uint32(is))
|
||||||
.publicSigningKey(Decode.bytes(is, 64))
|
.publicSigningKey(Decode.bytes(is, 64))
|
||||||
.publicEncryptionKey(Decode.bytes(is, 64))
|
.publicEncryptionKey(Decode.bytes(is, 64))
|
||||||
@ -82,7 +82,7 @@ public class V3Pubkey extends V2Pubkey {
|
|||||||
public Builder() {
|
public Builder() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder streamNumber(long streamNumber) {
|
public Builder stream(long streamNumber) {
|
||||||
this.streamNumber = streamNumber;
|
this.streamNumber = streamNumber;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ import java.io.OutputStream;
|
|||||||
* use that pubkey. This prevents people from gathering pubkeys sent around the network and using the data from them
|
* use that pubkey. This prevents people from gathering pubkeys sent around the network and using the data from them
|
||||||
* to create messages to be used in spam or in flooding attacks.
|
* to create messages to be used in spam or in flooding attacks.
|
||||||
*/
|
*/
|
||||||
public class V4Pubkey implements Pubkey {
|
public class V4Pubkey extends Pubkey {
|
||||||
private long stream;
|
private long stream;
|
||||||
private byte[] tag;
|
private byte[] tag;
|
||||||
private byte[] encrypted;
|
private byte[] encrypted;
|
||||||
@ -47,7 +47,7 @@ public class V4Pubkey implements Pubkey {
|
|||||||
// TODO: this.encrypted
|
// TODO: this.encrypted
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ObjectPayload read(InputStream stream, long streamNumber, int length) throws IOException {
|
public static V4Pubkey read(InputStream stream, long streamNumber, int length) throws IOException {
|
||||||
return new V4Pubkey(streamNumber, Decode.bytes(stream, 32), Decode.bytes(stream, length - 32));
|
return new V4Pubkey(streamNumber, Decode.bytes(stream, 32), Decode.bytes(stream, length - 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Christian Basler
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ch.dissem.bitmessage.entity.valueobject;
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.Streamable;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
||||||
|
import ch.dissem.bitmessage.factory.Factory;
|
||||||
|
import ch.dissem.bitmessage.utils.Bytes;
|
||||||
|
import ch.dissem.bitmessage.utils.Decode;
|
||||||
|
import ch.dissem.bitmessage.utils.Encode;
|
||||||
|
import ch.dissem.bitmessage.utils.Security;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by chris on 18.04.15.
|
||||||
|
*/
|
||||||
|
public class PrivateKey implements Streamable {
|
||||||
|
private final byte[] privateSigningKey; // 32 bytes
|
||||||
|
private final byte[] privateEncryptionKey; // 32 bytes
|
||||||
|
|
||||||
|
private final Pubkey pubkey;
|
||||||
|
|
||||||
|
public PrivateKey(long nonceTrialsPerByte, long extraBytes, Pubkey.Feature... features) {
|
||||||
|
this.privateSigningKey = Security.randomBytes(64);
|
||||||
|
this.privateEncryptionKey = Security.randomBytes(64);
|
||||||
|
this.pubkey = Security.createPubkey(Pubkey.LATEST_VERSION, privateSigningKey, privateEncryptionKey,
|
||||||
|
nonceTrialsPerByte, extraBytes, features);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PrivateKey(byte[] privateSigningKey, byte[] privateEncryptionKey, Pubkey pubkey) {
|
||||||
|
this.privateSigningKey = privateSigningKey;
|
||||||
|
this.privateEncryptionKey = privateEncryptionKey;
|
||||||
|
this.pubkey = pubkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrivateKey(long version, String passphrase, long nonceTrialsPerByte, long extraBytes, Pubkey.Feature... features) {
|
||||||
|
try {
|
||||||
|
// FIXME: this is most definitely wrong
|
||||||
|
this.privateSigningKey = Bytes.truncate(Security.sha512(passphrase.getBytes("UTF-8"), new byte[]{0}), 32);
|
||||||
|
this.privateEncryptionKey = Bytes.truncate(Security.sha512(passphrase.getBytes("UTF-8"), new byte[]{1}), 32);
|
||||||
|
this.pubkey = Security.createPubkey(version, privateSigningKey, privateEncryptionKey,
|
||||||
|
nonceTrialsPerByte, extraBytes, features);
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PrivateKey read(InputStream is) throws IOException {
|
||||||
|
int version = (int) Decode.varInt(is);
|
||||||
|
long stream = Decode.varInt(is);
|
||||||
|
int len = (int) Decode.varInt(is);
|
||||||
|
Pubkey pubkey = Factory.readPubkey(version, stream, is, len);
|
||||||
|
len = (int) Decode.varInt(is);
|
||||||
|
byte[] signingKey = Decode.bytes(is, len);
|
||||||
|
len = (int) Decode.varInt(is);
|
||||||
|
byte[] encryptionKey = Decode.bytes(is, len);
|
||||||
|
return new PrivateKey(signingKey, encryptionKey, pubkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pubkey getPubkey() {
|
||||||
|
return pubkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(OutputStream os) throws IOException {
|
||||||
|
Encode.varInt(pubkey.getVersion(), os);
|
||||||
|
Encode.varInt(pubkey.getStream(), os);
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
pubkey.write(baos);
|
||||||
|
Encode.varInt(baos.size(), os);
|
||||||
|
os.write(baos.toByteArray());
|
||||||
|
Encode.varInt(privateSigningKey.length, os);
|
||||||
|
os.write(privateSigningKey);
|
||||||
|
Encode.varInt(privateEncryptionKey.length, os);
|
||||||
|
os.write(privateEncryptionKey);
|
||||||
|
}
|
||||||
|
}
|
@ -16,10 +16,11 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.factory;
|
package ch.dissem.bitmessage.factory;
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
import ch.dissem.bitmessage.entity.NetworkMessage;
|
import ch.dissem.bitmessage.entity.NetworkMessage;
|
||||||
import ch.dissem.bitmessage.entity.ObjectMessage;
|
import ch.dissem.bitmessage.entity.ObjectMessage;
|
||||||
import ch.dissem.bitmessage.entity.payload.*;
|
import ch.dissem.bitmessage.entity.payload.*;
|
||||||
import ch.dissem.bitmessage.utils.Decode;
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -53,17 +54,60 @@ public class Factory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Pubkey createPubkey(long version, byte[] publicSigningKey, byte[] publicEncryptionKey,
|
||||||
|
long nonceTrialsPerByte, long extraBytes, Pubkey.Feature... features) {
|
||||||
|
if (publicSigningKey.length != 64)
|
||||||
|
throw new IllegalArgumentException("64 bytes signing key expected, but it was "
|
||||||
|
+ publicSigningKey.length + " bytes long.");
|
||||||
|
if (publicEncryptionKey.length != 64)
|
||||||
|
throw new IllegalArgumentException("64 bytes encryption key expected, but it was "
|
||||||
|
+ publicEncryptionKey.length + " bytes long.");
|
||||||
|
|
||||||
|
switch ((int) version) {
|
||||||
|
case 2:
|
||||||
|
return new V2Pubkey.Builder()
|
||||||
|
.publicSigningKey(publicSigningKey)
|
||||||
|
.publicEncryptionKey(publicEncryptionKey)
|
||||||
|
.behaviorBitfield(Pubkey.Feature.bitfield(features))
|
||||||
|
.build();
|
||||||
|
case 3:
|
||||||
|
return new V3Pubkey.Builder()
|
||||||
|
.publicSigningKey(publicSigningKey)
|
||||||
|
.publicEncryptionKey(publicEncryptionKey)
|
||||||
|
.behaviorBitfield(Pubkey.Feature.bitfield(features))
|
||||||
|
.nonceTrialsPerByte(nonceTrialsPerByte)
|
||||||
|
.extraBytes(extraBytes)
|
||||||
|
.build();
|
||||||
|
case 4:
|
||||||
|
return new V4Pubkey(
|
||||||
|
new V3Pubkey.Builder()
|
||||||
|
.publicSigningKey(publicSigningKey)
|
||||||
|
.publicEncryptionKey(publicEncryptionKey)
|
||||||
|
.behaviorBitfield(Pubkey.Feature.bitfield(features))
|
||||||
|
.nonceTrialsPerByte(nonceTrialsPerByte)
|
||||||
|
.extraBytes(extraBytes)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unexpected pubkey version " + version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BitmessageAddress generatePrivateAddress(Pubkey.Feature... features) {
|
||||||
|
return new BitmessageAddress(new PrivateKey(1000, 1000, features));
|
||||||
|
}
|
||||||
|
|
||||||
static ObjectPayload getObjectPayload(long objectType, long version, long streamNumber, InputStream stream, int length) throws IOException {
|
static ObjectPayload getObjectPayload(long objectType, long version, long streamNumber, InputStream stream, int length) throws IOException {
|
||||||
if (objectType < 4) {
|
if (objectType < 4) {
|
||||||
switch ((int) objectType) {
|
switch ((int) objectType) {
|
||||||
case 0:
|
case 0:
|
||||||
return parseGetPubkey((int) version, streamNumber, stream, length);
|
return parseGetPubkey(version, streamNumber, stream, length);
|
||||||
case 1:
|
case 1:
|
||||||
return parsePubkey((int) version, streamNumber, stream, length);
|
return parsePubkey(version, streamNumber, stream, length);
|
||||||
case 2:
|
case 2:
|
||||||
return parseMsg((int) version, streamNumber, stream, length);
|
return parseMsg(version, streamNumber, stream, length);
|
||||||
case 3:
|
case 3:
|
||||||
return parseBroadcast((int) version, streamNumber, stream, length);
|
return parseBroadcast(version, streamNumber, stream, length);
|
||||||
default:
|
default:
|
||||||
LOG.error("This should not happen, someone broke something in the code!");
|
LOG.error("This should not happen, someone broke something in the code!");
|
||||||
}
|
}
|
||||||
@ -73,29 +117,34 @@ public class Factory {
|
|||||||
return GenericPayload.read(stream, streamNumber, length);
|
return GenericPayload.read(stream, streamNumber, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ObjectPayload parseGetPubkey(int version, long streamNumber, InputStream stream, int length) throws IOException {
|
private static ObjectPayload parseGetPubkey(long version, long streamNumber, InputStream stream, int length) throws IOException {
|
||||||
return GetPubkey.read(stream, streamNumber, length);
|
return GetPubkey.read(stream, streamNumber, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ObjectPayload parsePubkey(int version, long streamNumber, InputStream stream, int length) throws IOException {
|
public static Pubkey readPubkey(long version, long stream, InputStream is, int length) throws IOException {
|
||||||
switch (version) {
|
switch ((int) version) {
|
||||||
case 2:
|
case 2:
|
||||||
return V2Pubkey.read(stream, streamNumber);
|
return V2Pubkey.read(is, stream);
|
||||||
case 3:
|
case 3:
|
||||||
return V3Pubkey.read(stream, streamNumber);
|
return V3Pubkey.read(is, stream);
|
||||||
case 4:
|
case 4:
|
||||||
return V4Pubkey.read(stream, streamNumber, length);
|
return V4Pubkey.read(is, stream, length);
|
||||||
}
|
}
|
||||||
LOG.debug("Unexpected pubkey version " + version + ", handling as generic payload object");
|
LOG.debug("Unexpected pubkey version " + version + ", handling as generic payload object");
|
||||||
return GenericPayload.read(stream, streamNumber, length);
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ObjectPayload parseMsg(int version, long streamNumber, InputStream stream, int length) throws IOException {
|
private static ObjectPayload parsePubkey(long version, long streamNumber, InputStream stream, int length) throws IOException {
|
||||||
|
Pubkey pubkey = readPubkey(version, streamNumber, stream, length);
|
||||||
|
return pubkey != null ? pubkey : GenericPayload.read(stream, streamNumber, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ObjectPayload parseMsg(long version, long streamNumber, InputStream stream, int length) throws IOException {
|
||||||
return Msg.read(stream, streamNumber, length);
|
return Msg.read(stream, streamNumber, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ObjectPayload parseBroadcast(int version, long streamNumber, InputStream stream, int length) throws IOException {
|
private static ObjectPayload parseBroadcast(long version, long streamNumber, InputStream stream, int length) throws IOException {
|
||||||
switch (version) {
|
switch ((int) version) {
|
||||||
case 4:
|
case 4:
|
||||||
return V4Broadcast.read(stream, streamNumber, length);
|
return V4Broadcast.read(stream, streamNumber, length);
|
||||||
case 5:
|
case 5:
|
||||||
|
@ -16,15 +16,25 @@
|
|||||||
|
|
||||||
package ch.dissem.bitmessage.ports;
|
package ch.dissem.bitmessage.ports;
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores and provides known peers.
|
* Created by chris on 23.04.15.
|
||||||
*/
|
*/
|
||||||
public interface AddressRepository {
|
public interface AddressRepository {
|
||||||
List<NetworkAddress> getKnownAddresses(int limit, long... streams);
|
/**
|
||||||
|
* Returns all Bitmessage addresses that belong to this user, i.e. have a private key.
|
||||||
|
*/
|
||||||
|
List<BitmessageAddress> findIdentities();
|
||||||
|
|
||||||
void offerAddresses(List<NetworkAddress> addresses);
|
/**
|
||||||
|
* Returns all Bitmessage addresses that have no private key.
|
||||||
|
*/
|
||||||
|
List<BitmessageAddress> findContacts();
|
||||||
|
|
||||||
|
void save(BitmessageAddress address);
|
||||||
|
|
||||||
|
void remove(BitmessageAddress address);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Christian Basler
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ch.dissem.bitmessage.ports;
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores and provides known peers.
|
||||||
|
*/
|
||||||
|
public interface NodeRegistry {
|
||||||
|
List<NetworkAddress> getKnownAddresses(int limit, long... streams);
|
||||||
|
|
||||||
|
void offerAddresses(List<NetworkAddress> addresses);
|
||||||
|
}
|
@ -78,9 +78,25 @@ public class Bytes {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new byte array containing the first <em>size</em> bytes of the given array.
|
||||||
|
*/
|
||||||
public static byte[] truncate(byte[] source, int size) {
|
public static byte[] truncate(byte[] source, int size) {
|
||||||
byte[] result = new byte[size];
|
byte[] result = new byte[size];
|
||||||
System.arraycopy(source, 0, result, 0, size);
|
System.arraycopy(source, 0, result, 0, size);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] subArray(byte[] source, int offset, int length) {
|
||||||
|
byte[] result = new byte[length];
|
||||||
|
System.arraycopy(source, offset, result, 0, length);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] concatenate(byte first, byte[] bytes) {
|
||||||
|
byte[] result = new byte[bytes.length + 1];
|
||||||
|
result[0] = first;
|
||||||
|
System.arraycopy(bytes, 0, result, 1, bytes.length);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,12 @@
|
|||||||
package ch.dissem.bitmessage.utils;
|
package ch.dissem.bitmessage.utils;
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.ObjectMessage;
|
import ch.dissem.bitmessage.entity.ObjectMessage;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
||||||
|
import ch.dissem.bitmessage.factory.Factory;
|
||||||
import ch.dissem.bitmessage.ports.ProofOfWorkEngine;
|
import ch.dissem.bitmessage.ports.ProofOfWorkEngine;
|
||||||
|
import org.bouncycastle.asn1.sec.SECNamedCurves;
|
||||||
|
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||||
|
import org.bouncycastle.crypto.params.ECDomainParameters;
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -35,6 +40,8 @@ public class Security {
|
|||||||
public static final Logger LOG = LoggerFactory.getLogger(Security.class);
|
public static final Logger LOG = LoggerFactory.getLogger(Security.class);
|
||||||
private static final SecureRandom RANDOM = new SecureRandom();
|
private static final SecureRandom RANDOM = new SecureRandom();
|
||||||
private static final BigInteger TWO = BigInteger.valueOf(2);
|
private static final BigInteger TWO = BigInteger.valueOf(2);
|
||||||
|
private static final X9ECParameters EC_CURVE = SECNamedCurves.getByName("secp256k1");
|
||||||
|
private static final ECDomainParameters EC_PARAMETERS = new ECDomainParameters(EC_CURVE.getCurve(), EC_CURVE.getG(), EC_CURVE.getN(), EC_CURVE.getH());
|
||||||
|
|
||||||
static {
|
static {
|
||||||
java.security.Security.addProvider(new BouncyCastleProvider());
|
java.security.Security.addProvider(new BouncyCastleProvider());
|
||||||
@ -52,6 +59,12 @@ public class Security {
|
|||||||
return mda.digest(mda.digest());
|
return mda.digest(mda.digest());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] doubleSha512(byte[] data, int length) {
|
||||||
|
MessageDigest mda = md("SHA-512");
|
||||||
|
mda.update(data, 0, length);
|
||||||
|
return mda.digest(mda.digest());
|
||||||
|
}
|
||||||
|
|
||||||
public static byte[] ripemd160(byte[]... data) {
|
public static byte[] ripemd160(byte[]... data) {
|
||||||
return hash("RIPEMD160", data);
|
return hash("RIPEMD160", data);
|
||||||
}
|
}
|
||||||
@ -115,4 +128,16 @@ public class Security {
|
|||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Pubkey createPubkey(long version, byte[] privateSigningKey, byte[] privateEncryptionKey,
|
||||||
|
long nonceTrialsPerByte, long extraBytes, Pubkey.Feature... features) {
|
||||||
|
byte[] publicSigningKey = EC_PARAMETERS.getG().multiply(keyToBigInt(privateSigningKey)).getEncoded(false);
|
||||||
|
byte[] publicEncryptionKey = EC_PARAMETERS.getG().multiply(keyToBigInt(privateEncryptionKey)).getEncoded(false);
|
||||||
|
return Factory.createPubkey(Bytes.subArray(publicSigningKey, 1, 64), Bytes.subArray(publicEncryptionKey, 1, 64),
|
||||||
|
nonceTrialsPerByte, extraBytes, features);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BigInteger keyToBigInt(byte[] key) {
|
||||||
|
return new BigInteger(Bytes.concatenate((byte) 0x00, key));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Christian Basler
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ch.dissem.bitmessage.entity;
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
public class BitmessageAddressTest {
|
||||||
|
@Test
|
||||||
|
public void ensureAddressStaysSame() {
|
||||||
|
String address = "BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ";
|
||||||
|
assertEquals(address, new BitmessageAddress(address).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ensureStreamAndVersionAreParsed() {
|
||||||
|
BitmessageAddress address = new BitmessageAddress("BM-2D9Vc5rFxxR5vTi53T9gkLfemViHRMVLQZ");
|
||||||
|
assertEquals(1, address.getStream());
|
||||||
|
assertEquals(3, address.getVersion());
|
||||||
|
|
||||||
|
address = new BitmessageAddress("BM-87hJ99tPAXxtetvnje7Z491YSvbEtBJVc5e");
|
||||||
|
assertEquals(1, address.getStream());
|
||||||
|
assertEquals(4, address.getVersion());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateAddress() {
|
||||||
|
BitmessageAddress address = new BitmessageAddress(new PrivateKey(0, 0));
|
||||||
|
assertNotNull(address.getPubkey());
|
||||||
|
}
|
||||||
|
}
|
@ -17,17 +17,19 @@
|
|||||||
package ch.dissem.bitmessage.inventory;
|
package ch.dissem.bitmessage.inventory;
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.ObjectMessage;
|
import ch.dissem.bitmessage.entity.ObjectMessage;
|
||||||
|
import ch.dissem.bitmessage.entity.Streamable;
|
||||||
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
|
import ch.dissem.bitmessage.entity.valueobject.InventoryVector;
|
||||||
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
|
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
|
||||||
import ch.dissem.bitmessage.factory.Factory;
|
import ch.dissem.bitmessage.factory.Factory;
|
||||||
import ch.dissem.bitmessage.ports.AddressRepository;
|
|
||||||
import ch.dissem.bitmessage.ports.Inventory;
|
import ch.dissem.bitmessage.ports.Inventory;
|
||||||
|
import ch.dissem.bitmessage.ports.NodeRegistry;
|
||||||
import org.flywaydb.core.Flyway;
|
import org.flywaydb.core.Flyway;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -38,7 +40,7 @@ import static ch.dissem.bitmessage.utils.UnixTime.now;
|
|||||||
/**
|
/**
|
||||||
* Stores everything in a database
|
* Stores everything in a database
|
||||||
*/
|
*/
|
||||||
public class DatabaseRepository implements Inventory, AddressRepository {
|
public class DatabaseRepository implements Inventory, NodeRegistry {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(DatabaseRepository.class);
|
private static final Logger LOG = LoggerFactory.getLogger(DatabaseRepository.class);
|
||||||
|
|
||||||
private static final String DB_URL = "jdbc:h2:~/jabit";
|
private static final String DB_URL = "jdbc:h2:~/jabit";
|
||||||
@ -170,6 +172,13 @@ public class DatabaseRepository implements Inventory, AddressRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void writeBlob(PreparedStatement ps, int parameterIndex, Streamable data) throws SQLException, IOException {
|
||||||
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
|
data.write(os);
|
||||||
|
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
|
||||||
|
ps.setBlob(parameterIndex, is);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cleanup() {
|
public void cleanup() {
|
||||||
try {
|
try {
|
||||||
@ -180,7 +189,7 @@ public class DatabaseRepository implements Inventory, AddressRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Connection getConnection() {
|
protected Connection getConnection() {
|
||||||
try {
|
try {
|
||||||
return DriverManager.getConnection(DB_URL, DB_USER, DB_PWD);
|
return DriverManager.getConnection(DB_URL, DB_USER, DB_PWD);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Christian Basler
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ch.dissem.bitmessage.inventory;
|
||||||
|
|
||||||
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
||||||
|
import ch.dissem.bitmessage.entity.payload.Pubkey;
|
||||||
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
||||||
|
import ch.dissem.bitmessage.factory.Factory;
|
||||||
|
import ch.dissem.bitmessage.ports.AddressRepository;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.*;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by chris on 23.04.15.
|
||||||
|
*/
|
||||||
|
public class JdbcAddressRepository extends DatabaseRepository implements AddressRepository {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(DatabaseRepository.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BitmessageAddress> findIdentities() {
|
||||||
|
return find("private_signing_key IS NOT NULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BitmessageAddress> findContacts() {
|
||||||
|
return find("private_signing_key IS NULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<BitmessageAddress> find(String where) {
|
||||||
|
List<BitmessageAddress> result = new LinkedList<>();
|
||||||
|
try {
|
||||||
|
Statement stmt = getConnection().createStatement();
|
||||||
|
ResultSet rs = stmt.executeQuery("SELECT address, alias, public_key, private_key FROM Address WHERE " + where);
|
||||||
|
while (rs.next()) {
|
||||||
|
BitmessageAddress address;
|
||||||
|
Blob privateKeyBlob = rs.getBlob("private_key");
|
||||||
|
if (privateKeyBlob != null) {
|
||||||
|
PrivateKey privateKey = PrivateKey.read(privateKeyBlob.getBinaryStream());
|
||||||
|
address = new BitmessageAddress(privateKey);
|
||||||
|
} else {
|
||||||
|
address = new BitmessageAddress(rs.getString("address"));
|
||||||
|
Blob publicKeyBlob = rs.getBlob("public_key");
|
||||||
|
if (publicKeyBlob != null) {
|
||||||
|
Pubkey pubkey = Factory.readPubkey(address.getVersion(), address.getStream(),
|
||||||
|
publicKeyBlob.getBinaryStream(), (int)publicKeyBlob.length());
|
||||||
|
address.setPubkey(pubkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
address.setAlias(rs.getString("alias"));
|
||||||
|
|
||||||
|
result.add(address);
|
||||||
|
}
|
||||||
|
} catch (IOException | SQLException e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(BitmessageAddress address) {
|
||||||
|
try {
|
||||||
|
PreparedStatement ps = getConnection().prepareStatement(
|
||||||
|
"INSERT INTO Address (address, alias, public_key, private_key) VALUES (?, ?, ?, ?, ?)");
|
||||||
|
ps.setString(1, address.getAddress());
|
||||||
|
ps.setString(2, address.getAlias());
|
||||||
|
writeBlob(ps, 3, address.getPubkey());
|
||||||
|
writeBlob(ps, 4, address.getPrivateKey());
|
||||||
|
} catch (IOException | SQLException e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(BitmessageAddress address) {
|
||||||
|
try {
|
||||||
|
Statement stmt = getConnection().createStatement();
|
||||||
|
stmt.executeUpdate("DELETE FROM Address WHERE address = '" + address.getAddress() + "'");
|
||||||
|
} catch (SQLException e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,7 @@
|
|||||||
package ch.dissem.bitmessage.inventory;
|
package ch.dissem.bitmessage.inventory;
|
||||||
|
|
||||||
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
|
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress;
|
||||||
import ch.dissem.bitmessage.ports.AddressRepository;
|
import ch.dissem.bitmessage.ports.NodeRegistry;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -25,7 +25,7 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* Created by chris on 06.04.15.
|
* Created by chris on 06.04.15.
|
||||||
*/
|
*/
|
||||||
public class SimpleAddressRepository implements AddressRepository {
|
public class SimpleNodeRegistry implements NodeRegistry {
|
||||||
@Override
|
@Override
|
||||||
public List<NetworkAddress> getKnownAddresses(int limit, long... streams) {
|
public List<NetworkAddress> getKnownAddresses(int limit, long... streams) {
|
||||||
return Collections.singletonList(new NetworkAddress.Builder().ipv4(127, 0, 0, 1).port(8444).build());
|
return Collections.singletonList(new NetworkAddress.Builder().ipv4(127, 0, 0, 1).port(8444).build());
|
@ -0,0 +1,6 @@
|
|||||||
|
CREATE TABLE Address (
|
||||||
|
address VARCHAR(40) NOT NULL PRIMARY KEY,
|
||||||
|
alias VARCHAR(255),
|
||||||
|
public_key BLOB,
|
||||||
|
private_key BLOB
|
||||||
|
);
|
Loading…
Reference in New Issue
Block a user