Some code for supporting chans

This commit is contained in:
Christian Basler 2016-03-31 20:04:23 +02:00
parent 3e5e431d6f
commit ead5341b2e
6 changed files with 115 additions and 17 deletions

View File

@ -17,10 +17,7 @@
package ch.dissem.bitmessage; package ch.dissem.bitmessage;
import ch.dissem.bitmessage.entity.*; import ch.dissem.bitmessage.entity.*;
import ch.dissem.bitmessage.entity.payload.Broadcast; import ch.dissem.bitmessage.entity.payload.*;
import ch.dissem.bitmessage.entity.payload.Msg;
import ch.dissem.bitmessage.entity.payload.ObjectPayload;
import ch.dissem.bitmessage.entity.payload.ObjectType;
import ch.dissem.bitmessage.entity.payload.Pubkey.Feature; import ch.dissem.bitmessage.entity.payload.Pubkey.Feature;
import ch.dissem.bitmessage.entity.valueobject.Label; import ch.dissem.bitmessage.entity.valueobject.Label;
import ch.dissem.bitmessage.entity.valueobject.PrivateKey; import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
@ -117,9 +114,17 @@ public class BitmessageContext {
return identity; return identity;
} }
public void addDistributedMailingList(String address, String alias) { public BitmessageAddress joinChan(String passphrase, String address) {
// TODO BitmessageAddress chan = BitmessageAddress.chan(address, passphrase);
throw new ApplicationException("not implemented"); ctx.getAddressRepository().save(chan);
return chan;
}
public BitmessageAddress createChan(String passphrase) {
// FIXME: hardcoded stream number
BitmessageAddress chan = BitmessageAddress.chan(1, passphrase);
ctx.getAddressRepository().save(chan);
return chan;
} }
public void broadcast(final BitmessageAddress from, final String subject, final String message) { public void broadcast(final BitmessageAddress from, final String subject, final String message) {

View File

@ -57,6 +57,7 @@ public class BitmessageAddress implements Serializable {
private String alias; private String alias;
private boolean subscribed; private boolean subscribed;
private boolean chan;
BitmessageAddress(long version, long stream, byte[] ripe) { BitmessageAddress(long version, long stream, byte[] ripe) {
try { try {
@ -93,6 +94,27 @@ public class BitmessageAddress implements Serializable {
this.pubkey = publicKey; this.pubkey = publicKey;
} }
public BitmessageAddress(String address, String passphrase) {
this(address);
this.privateKey = new PrivateKey(this, passphrase);
if (!Arrays.equals(ripe, privateKey.getPubkey().getRipe())) {
throw new IllegalArgumentException("Wrong address or passphrase");
}
}
public static BitmessageAddress chan(String address, String passphrase) {
BitmessageAddress result = new BitmessageAddress(address, passphrase);
result.chan = true;
return result;
}
public static BitmessageAddress chan(long stream, String passphrase) {
PrivateKey privateKey = new PrivateKey(Pubkey.LATEST_VERSION, stream, passphrase);
BitmessageAddress result = new BitmessageAddress(privateKey);
result.chan = true;
return result;
}
public BitmessageAddress(PrivateKey privateKey) { public BitmessageAddress(PrivateKey privateKey) {
this(privateKey.getPubkey()); this(privateKey.getPubkey());
this.privateKey = privateKey; this.privateKey = privateKey;
@ -221,4 +243,8 @@ public class BitmessageAddress implements Serializable {
public void setSubscribed(boolean subscribed) { public void setSubscribed(boolean subscribed) {
this.subscribed = subscribed; this.subscribed = subscribed;
} }
public boolean isChan() {
return chan;
}
} }

View File

@ -16,6 +16,7 @@
package ch.dissem.bitmessage.entity.valueobject; package ch.dissem.bitmessage.entity.valueobject;
import ch.dissem.bitmessage.entity.BitmessageAddress;
import ch.dissem.bitmessage.entity.Streamable; import ch.dissem.bitmessage.entity.Streamable;
import ch.dissem.bitmessage.entity.payload.Pubkey; import ch.dissem.bitmessage.entity.payload.Pubkey;
import ch.dissem.bitmessage.exception.ApplicationException; import ch.dissem.bitmessage.exception.ApplicationException;
@ -64,14 +65,32 @@ public class PrivateKey implements Streamable {
this.pubkey = pubkey; this.pubkey = pubkey;
} }
public PrivateKey(long version, long stream, String passphrase, long nonceTrialsPerByte, long extraBytes, Pubkey.Feature... features) { public PrivateKey(BitmessageAddress address, String passphrase) {
this(address.getVersion(), address.getStream(), passphrase);
}
public PrivateKey(long version, long stream, String passphrase) {
try { try {
// FIXME: this is most definitely wrong byte[] signingKey;
this.privateSigningKey = Bytes.truncate(security().sha512(passphrase.getBytes("UTF-8"), new byte[]{0}), 32); int signingKeyNonce = 0;
this.privateEncryptionKey = Bytes.truncate(security().sha512(passphrase.getBytes("UTF-8"), new byte[]{1}), 32); byte[] encryptionKey;
this.pubkey = security().createPubkey(version, stream, privateSigningKey, privateEncryptionKey, int encryptionKeyNonce = 1;
nonceTrialsPerByte, extraBytes, features); byte[] passPhraseBytes = passphrase.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) { byte[] ripe;
do {
signingKey = Bytes.truncate(security().sha512(passPhraseBytes, Encode.varInt(signingKeyNonce)), 32);
encryptionKey = Bytes.truncate(security().sha512(passPhraseBytes, Encode.varInt(encryptionKeyNonce)), 32);
byte[] publicSigningKey = security().createPublicKey(signingKey);
byte[] publicEncryptionKey = security().createPublicKey(encryptionKey);
ripe = security().ripemd160(security().sha512(publicSigningKey, publicEncryptionKey));
signingKeyNonce += 2;
encryptionKeyNonce += 2;
} while (ripe[0] != 0);
this.privateSigningKey = signingKey;
this.privateEncryptionKey = encryptionKey;
this.pubkey = security().createPubkey(version, stream, privateSigningKey, privateEncryptionKey, 0, 0);
} catch (IOException e) {
throw new ApplicationException(e); throw new ApplicationException(e);
} }
} }

View File

@ -41,6 +41,34 @@ public class Encode {
varInt(value, stream, null); varInt(value, stream, null);
} }
public static byte[] varInt(long value) throws IOException {
final byte[] result;
if (value < 0) {
// This is due to the fact that Java doesn't really support unsigned values.
// Please be aware that this might be an error due to a smaller negative value being cast to long.
// Normally, negative values shouldn't occur within the protocol, and I large enough longs
// to being recognized as negatives aren't realistic.
ByteBuffer buffer = ByteBuffer.allocate(9);
buffer.put((byte) 0xff);
result = buffer.putLong(value).array();
} else if (value < 0xfd) {
result = new byte[]{(byte) value};
} else if (value <= 0xffffL) {
ByteBuffer buffer = ByteBuffer.allocate(3);
buffer.put((byte) 0xfd);
result = buffer.putShort((short) value).array();
} else if (value <= 0xffffffffL) {
ByteBuffer buffer = ByteBuffer.allocate(5);
buffer.put((byte) 0xfe);
result = buffer.putInt((int) value).array();
} else {
ByteBuffer buffer = ByteBuffer.allocate(9);
buffer.put((byte) 0xff);
result = buffer.putLong(value).array();
}
return result;
}
public static void varInt(long value, OutputStream stream, AccessCounter counter) throws IOException { public static void varInt(long value, OutputStream stream, AccessCounter counter) throws IOException {
if (value < 0) { if (value < 0) {
// This is due to the fact that Java doesn't really support unsigned values. // This is due to the fact that Java doesn't really support unsigned values.
@ -81,7 +109,7 @@ public class Encode {
} }
public static void int16(long value, OutputStream stream, AccessCounter counter) throws IOException { public static void int16(long value, OutputStream stream, AccessCounter counter) throws IOException {
stream.write(ByteBuffer.allocate(4).putInt((int) value).array(), 2, 2); stream.write(ByteBuffer.allocate(2).putShort((short) value).array());
inc(counter, 2); inc(counter, 2);
} }

View File

@ -39,7 +39,7 @@ import static ch.dissem.bitmessage.entity.payload.ObjectType.*;
import static ch.dissem.bitmessage.utils.MessageMatchers.object; import static ch.dissem.bitmessage.utils.MessageMatchers.object;
import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat; import static org.junit.Assert.*;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@ -206,4 +206,21 @@ public class BitmessageContextTest {
.build(); .build();
ctx.send(msg); ctx.send(msg);
} }
@Test
public void ensureChanIsJoined() {
String chanAddress = "BM-2cW67GEKkHGonXKZLCzouLLxnLym3azS8r";
BitmessageAddress chan = ctx.joinChan("general", chanAddress);
assertNotNull(chan);
assertEquals(chan.getAddress(), chanAddress);
assertTrue(chan.isChan());
}
@Test
public void ensureChanIsCreated() {
BitmessageAddress chan = ctx.createChan("test");
assertNotNull(chan);
assertEquals(chan.getVersion(), Pubkey.LATEST_VERSION);
assertTrue(chan.isChan());
}
} }

View File

@ -20,7 +20,10 @@ import ch.dissem.bitmessage.entity.payload.Pubkey;
import ch.dissem.bitmessage.entity.payload.V4Pubkey; import ch.dissem.bitmessage.entity.payload.V4Pubkey;
import ch.dissem.bitmessage.entity.valueobject.PrivateKey; import ch.dissem.bitmessage.entity.valueobject.PrivateKey;
import ch.dissem.bitmessage.exception.DecryptionFailedException; import ch.dissem.bitmessage.exception.DecryptionFailedException;
import ch.dissem.bitmessage.utils.*; import ch.dissem.bitmessage.utils.Base58;
import ch.dissem.bitmessage.utils.Bytes;
import ch.dissem.bitmessage.utils.Strings;
import ch.dissem.bitmessage.utils.TestUtils;
import org.junit.Test; import org.junit.Test;
import java.io.IOException; import java.io.IOException;