207 lines
9.4 KiB
Java
207 lines
9.4 KiB
Java
/*
|
|
* 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.factory;
|
|
|
|
import ch.dissem.bitmessage.entity.BitmessageAddress;
|
|
import ch.dissem.bitmessage.entity.NetworkMessage;
|
|
import ch.dissem.bitmessage.entity.ObjectMessage;
|
|
import ch.dissem.bitmessage.entity.Plaintext;
|
|
import ch.dissem.bitmessage.entity.payload.*;
|
|
import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
|
|
import ch.dissem.bitmessage.exception.NodeException;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.net.SocketException;
|
|
import java.net.SocketTimeoutException;
|
|
|
|
import static ch.dissem.bitmessage.utils.Singleton.security;
|
|
|
|
/**
|
|
* Creates {@link NetworkMessage} objects from {@link InputStream InputStreams}
|
|
*/
|
|
public class Factory {
|
|
public static final Logger LOG = LoggerFactory.getLogger(Factory.class);
|
|
|
|
public static NetworkMessage getNetworkMessage(int version, InputStream stream) throws SocketTimeoutException {
|
|
try {
|
|
return V3MessageFactory.read(stream);
|
|
} catch (SocketTimeoutException | NodeException e) {
|
|
throw e;
|
|
} catch (SocketException e) {
|
|
throw new NodeException(e.getMessage(), e);
|
|
} catch (Exception e) {
|
|
LOG.error(e.getMessage(), e);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public static ObjectMessage getObjectMessage(int version, InputStream stream, int length) {
|
|
try {
|
|
return V3MessageFactory.readObject(stream, length);
|
|
} catch (IOException e) {
|
|
LOG.error(e.getMessage(), e);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public static Pubkey createPubkey(long version, long stream, byte[] publicSigningKey, byte[] publicEncryptionKey,
|
|
long nonceTrialsPerByte, long extraBytes, Pubkey.Feature... features) {
|
|
return createPubkey(version, stream, publicSigningKey, publicEncryptionKey, nonceTrialsPerByte, extraBytes,
|
|
Pubkey.Feature.bitfield(features));
|
|
}
|
|
|
|
public static Pubkey createPubkey(long version, long stream, byte[] publicSigningKey, byte[] publicEncryptionKey,
|
|
long nonceTrialsPerByte, long extraBytes, int behaviourBitfield) {
|
|
if (publicSigningKey.length != 64 && publicSigningKey.length != 65)
|
|
throw new IllegalArgumentException("64 bytes signing key expected, but it was "
|
|
+ publicSigningKey.length + " bytes long.");
|
|
if (publicEncryptionKey.length != 64 && publicEncryptionKey.length != 65)
|
|
throw new IllegalArgumentException("64 bytes encryption key expected, but it was "
|
|
+ publicEncryptionKey.length + " bytes long.");
|
|
|
|
switch ((int) version) {
|
|
case 2:
|
|
return new V2Pubkey.Builder()
|
|
.stream(stream)
|
|
.publicSigningKey(publicSigningKey)
|
|
.publicEncryptionKey(publicEncryptionKey)
|
|
.behaviorBitfield(behaviourBitfield)
|
|
.build();
|
|
case 3:
|
|
return new V3Pubkey.Builder()
|
|
.stream(stream)
|
|
.publicSigningKey(publicSigningKey)
|
|
.publicEncryptionKey(publicEncryptionKey)
|
|
.behaviorBitfield(behaviourBitfield)
|
|
.nonceTrialsPerByte(nonceTrialsPerByte)
|
|
.extraBytes(extraBytes)
|
|
.build();
|
|
case 4:
|
|
return new V4Pubkey(
|
|
new V3Pubkey.Builder()
|
|
.stream(stream)
|
|
.publicSigningKey(publicSigningKey)
|
|
.publicEncryptionKey(publicEncryptionKey)
|
|
.behaviorBitfield(behaviourBitfield)
|
|
.nonceTrialsPerByte(nonceTrialsPerByte)
|
|
.extraBytes(extraBytes)
|
|
.build()
|
|
);
|
|
default:
|
|
throw new IllegalArgumentException("Unexpected pubkey version " + version);
|
|
}
|
|
}
|
|
|
|
public static BitmessageAddress createIdentityFromPrivateKey(String address,
|
|
byte[] privateSigningKey, byte[] privateEncryptionKey,
|
|
long nonceTrialsPerByte, long extraBytes,
|
|
int behaviourBitfield) {
|
|
BitmessageAddress temp = new BitmessageAddress(address);
|
|
PrivateKey privateKey = new PrivateKey(privateSigningKey, privateEncryptionKey,
|
|
createPubkey(temp.getVersion(), temp.getStream(),
|
|
security().createPublicKey(privateSigningKey),
|
|
security().createPublicKey(privateEncryptionKey),
|
|
nonceTrialsPerByte, extraBytes, behaviourBitfield));
|
|
BitmessageAddress result = new BitmessageAddress(privateKey);
|
|
if (!result.getAddress().equals(address)) {
|
|
throw new IllegalArgumentException("Address not matching private key. Address: " + address
|
|
+ "; Address derived from private key: " + result.getAddress());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static BitmessageAddress generatePrivateAddress(boolean shorter,
|
|
long stream,
|
|
Pubkey.Feature... features) {
|
|
return new BitmessageAddress(new PrivateKey(shorter, stream, 1000, 1000, features));
|
|
}
|
|
|
|
static ObjectPayload getObjectPayload(long objectType,
|
|
long version,
|
|
long streamNumber,
|
|
InputStream stream,
|
|
int length) throws IOException {
|
|
ObjectType type = ObjectType.fromNumber(objectType);
|
|
if (type != null) {
|
|
switch (type) {
|
|
case GET_PUBKEY:
|
|
return parseGetPubkey(version, streamNumber, stream, length);
|
|
case PUBKEY:
|
|
return parsePubkey(version, streamNumber, stream, length);
|
|
case MSG:
|
|
return parseMsg(version, streamNumber, stream, length);
|
|
case BROADCAST:
|
|
return parseBroadcast(version, streamNumber, stream, length);
|
|
default:
|
|
LOG.error("This should not happen, someone broke something in the code!");
|
|
}
|
|
}
|
|
// fallback: just store the message - we don't really care what it is
|
|
LOG.trace("Unexpected object type: " + objectType);
|
|
return GenericPayload.read(version, stream, streamNumber, length);
|
|
}
|
|
|
|
private static ObjectPayload parseGetPubkey(long version, long streamNumber, InputStream stream, int length) throws IOException {
|
|
return GetPubkey.read(stream, streamNumber, length, version);
|
|
}
|
|
|
|
public static Pubkey readPubkey(long version, long stream, InputStream is, int length, boolean encrypted) throws IOException {
|
|
switch ((int) version) {
|
|
case 2:
|
|
return V2Pubkey.read(is, stream);
|
|
case 3:
|
|
return V3Pubkey.read(is, stream);
|
|
case 4:
|
|
return V4Pubkey.read(is, stream, length, encrypted);
|
|
}
|
|
LOG.debug("Unexpected pubkey version " + version + ", handling as generic payload object");
|
|
return null;
|
|
}
|
|
|
|
private static ObjectPayload parsePubkey(long version, long streamNumber, InputStream stream, int length) throws IOException {
|
|
Pubkey pubkey = readPubkey(version, streamNumber, stream, length, true);
|
|
return pubkey != null ? pubkey : GenericPayload.read(version, stream, streamNumber, length);
|
|
}
|
|
|
|
private static ObjectPayload parseMsg(long version, long streamNumber, InputStream stream, int length) throws IOException {
|
|
return Msg.read(stream, streamNumber, length);
|
|
}
|
|
|
|
private static ObjectPayload parseBroadcast(long version, long streamNumber, InputStream stream, int length) throws IOException {
|
|
switch ((int) version) {
|
|
case 4:
|
|
return V4Broadcast.read(stream, streamNumber, length);
|
|
case 5:
|
|
return V5Broadcast.read(stream, streamNumber, length);
|
|
default:
|
|
LOG.debug("Encountered unknown broadcast version " + version);
|
|
return GenericPayload.read(version, stream, streamNumber, length);
|
|
}
|
|
}
|
|
|
|
public static ObjectPayload getBroadcast(BitmessageAddress sendingAddress, Plaintext plaintext) {
|
|
if (sendingAddress.getVersion() < 4) {
|
|
return new V4Broadcast(sendingAddress, plaintext);
|
|
} else {
|
|
return new V5Broadcast(sendingAddress, plaintext);
|
|
}
|
|
}
|
|
}
|