Skip to content

Commit 62f9ebc

Browse files
committed
Prepared SharkNetMessage to be used in SN2 Android App
1 parent ceeab0c commit 62f9ebc

File tree

6 files changed

+263
-26
lines changed

6 files changed

+263
-26
lines changed

src/net/sharksystem/asap/sharknet/SharkNetMessage.java

Lines changed: 125 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,61 +9,158 @@
99
import java.io.ByteArrayInputStream;
1010
import java.io.ByteArrayOutputStream;
1111
import java.io.IOException;
12-
12+
import java.util.HashSet;
13+
import java.util.Set;
14+
15+
/**
16+
* A SharkNet message is issued by a peer (sender), has content and can be tagged with an URI. It can have
17+
* null (to anybody), one or more recipients. A message can be signed. A message that is for a single recipient
18+
* can be encrypted.
19+
*/
1320
class SharkNetMessage {
1421
private static final int SIGNED_MASK = 0x1;
1522
private static final int ENCRYPTED_MASK = 0x2;
16-
private final byte[] snMessage;
23+
public static final CharSequence ANY_RECIPIENT = "SN_ANY";
24+
public static final CharSequence ANONYMOUS = "SN_ANON";
25+
private byte[] snContent;
1726
private final CharSequence snSender;
18-
private final boolean verified;
19-
private final boolean encrypted;
27+
private byte[] serializedMessage;
28+
private boolean verified;
29+
private boolean encrypted;
2030
private final CharSequence topic;
31+
private Set<CharSequence> snRecipients;
2132

22-
public SharkNetMessage(byte[] snMessage, String snSender, boolean verified, boolean encrypted) {
23-
this(snMessage, null, snSender, verified, encrypted);
33+
SharkNetMessage(byte[] snContent, String snSender, boolean verified, boolean encrypted) {
34+
this(snContent, null, snSender, new HashSet<>(), verified, encrypted);
2435
}
2536

26-
public SharkNetMessage(byte[] message, CharSequence topic, CharSequence sender, boolean verified, boolean encrypted) {
27-
this.snMessage = message;
37+
/**
38+
* Received
39+
* @param message
40+
* @param topic
41+
* @param sender
42+
* @param verified
43+
* @param encrypted
44+
*/
45+
SharkNetMessage(byte[] message, CharSequence topic, CharSequence sender,
46+
Set<CharSequence> snRecipients,
47+
boolean verified, boolean encrypted) {
48+
this.snContent = message;
2849
this.snSender = sender;
2950
this.verified = verified;
3051
this.encrypted = encrypted;
3152
this.topic = topic;
53+
this.snRecipients = snRecipients;
54+
}
55+
56+
/**
57+
* Use this constructor to set a message that is to be sent
58+
* @param content content
59+
* @param topic uri
60+
* @param sender sender - me - or a synonym
61+
* @param recipient message recipient
62+
* @param sign sing message
63+
* @param encrypt encrypt message
64+
*/
65+
public SharkNetMessage(byte[] content, CharSequence topic, CharSequence sender, CharSequence recipient,
66+
boolean sign, boolean encrypt, BasicCryptoParameters basicCryptoParameters)
67+
throws IOException, ASAPException {
68+
69+
this.snContent = content;
70+
this.snSender = sender;
71+
this.topic = topic;
72+
73+
this.serializedMessage =
74+
SharkNetMessage.serializeMessage(content, topic, recipient,
75+
sign, encrypt, sender, basicCryptoParameters);
76+
}
77+
78+
/**
79+
* Use this constructor to set a message that is to be sent
80+
* @param content
81+
* @param topic
82+
* @param sender
83+
* @param recipients more than one recipient - such a message cannot (yet) be signed. See group key project.
84+
* @param sign
85+
*/
86+
public SharkNetMessage(byte[] content, CharSequence topic, CharSequence sender,
87+
Set<CharSequence> recipients, boolean sign,
88+
BasicCryptoParameters basicCryptoParameters) throws IOException, ASAPException {
89+
90+
this.snSender = sender;
91+
this.topic = topic;
92+
93+
this.serializedMessage =
94+
SharkNetMessage.serializeMessage(content, topic, recipients,
95+
sign, false, sender, basicCryptoParameters);
96+
3297
}
3398

3499
static byte[] serializeMessage(byte[] message, CharSequence topic, CharSequence recipient,
35-
boolean sign, boolean encrypt, CharSequence ownerID, BasicCryptoParameters basicCryptoParameters)
100+
boolean sign, boolean encrypt, CharSequence ownerID,
101+
BasicCryptoParameters basicCryptoParameters)
36102
throws IOException, ASAPException {
37103

104+
Set<CharSequence> recipients = null;
105+
if(recipient != null) {
106+
recipients = new HashSet<>();
107+
recipients.add(recipient);
108+
}
109+
110+
return SharkNetMessage.serializeMessage(message, topic, recipients,
111+
sign, encrypt, ownerID, basicCryptoParameters);
112+
113+
}
114+
115+
static byte[] serializeMessage(byte[] content, CharSequence topic, Set<CharSequence> recipients,
116+
boolean sign, boolean encrypt, CharSequence sender, BasicCryptoParameters basicCryptoParameters)
117+
throws IOException, ASAPException {
118+
119+
if( (recipients != null && recipients.size() > 1) && encrypt) {
120+
throw new ASAPSecurityException("cannot (yet) encrypt one message for more than one recipient - split it into more messages");
121+
}
122+
123+
if(recipients == null) {
124+
recipients = new HashSet<>();
125+
recipients.add(SharkNetMessage.ANY_RECIPIENT);
126+
}
127+
128+
if(sender == null) {
129+
sender = SharkNetMessage.ANONYMOUS;
130+
}
131+
38132
// merge content, sender and recipient
39133
ByteArrayOutputStream baos = new ByteArrayOutputStream();
40-
ASAPSerialization.writeByteArray(message, baos);
41-
ASAPSerialization.writeCharSequenceParameter(ownerID, baos);
42-
ASAPSerialization.writeCharSequenceParameter(recipient, baos);
43-
message = baos.toByteArray();
134+
ASAPSerialization.writeByteArray(content, baos);
135+
ASAPSerialization.writeCharSequenceParameter(sender, baos);
136+
// ASAPSerialization.writeCharSequenceParameter(recipient, baos);
137+
ASAPSerialization.writeCharSequenceSetParameter(recipients, baos);
138+
content = baos.toByteArray();
44139

45140
byte flags = 0;
46141
if(sign) {
47-
byte[] signature = ASAPCryptoAlgorithms.sign(message, basicCryptoParameters);
142+
byte[] signature = ASAPCryptoAlgorithms.sign(content, basicCryptoParameters);
48143
baos = new ByteArrayOutputStream();
49-
ASAPSerialization.writeByteArray(message, baos); // message has three parts: content, sender, receiver
144+
ASAPSerialization.writeByteArray(content, baos); // message has three parts: content, sender, receiver
50145
// append signature
51146
ASAPSerialization.writeByteArray(signature, baos);
52147
// attach signature to message
53-
message = baos.toByteArray();
148+
content = baos.toByteArray();
54149
flags += SIGNED_MASK;
55150
}
56151

57152
if(encrypt) {
58-
message = ASAPCryptoAlgorithms.produceEncryptedMessagePackage(
59-
message, recipient, basicCryptoParameters);
153+
content = ASAPCryptoAlgorithms.produceEncryptedMessagePackage(
154+
content,
155+
recipients.iterator().next(), // already checked if one and only one is recipient
156+
basicCryptoParameters);
60157
flags += ENCRYPTED_MASK;
61158
}
62159

63160
// serialize SN message
64161
baos = new ByteArrayOutputStream();
65162
ASAPSerialization.writeByteParameter(flags, baos);
66-
ASAPSerialization.writeByteArray(message, baos);
163+
ASAPSerialization.writeByteArray(content, baos);
67164

68165
return baos.toByteArray();
69166
}
@@ -106,7 +203,8 @@ static SharkNetMessage parseMessage(byte[] message, String sender, String uri,
106203
bais = new ByteArrayInputStream(tmpMessage);
107204
byte[] snMessage = ASAPSerialization.readByteArray(bais);
108205
String snSender = ASAPSerialization.readCharSequenceParameter(bais);
109-
String snReceiver = ASAPSerialization.readCharSequenceParameter(bais);
206+
Set<CharSequence> snReceivers = ASAPSerialization.readCharSequenceSetParameter(bais);
207+
//String snReceiver = ASAPSerialization.readCharSequenceParameter(bais);
110208

111209
boolean verified = false; // initialize
112210
if(signature != null) {
@@ -120,12 +218,16 @@ static SharkNetMessage parseMessage(byte[] message, String sender, String uri,
120218
}
121219
}
122220

123-
return new SharkNetMessage(snMessage, snSender, verified, encrypted);
221+
return new SharkNetMessage(snMessage, uri, snSender, snReceivers, verified, encrypted);
124222
}
125223

126-
public byte[] getContent() { return this.snMessage;}
127-
224+
public byte[] getContent() { return this.snContent;}
128225
public CharSequence getSender() { return this.snSender; }
226+
public Set<CharSequence> getRecipients() { return this.snRecipients; }
129227
public boolean verified() { return this.verified; }
130228
public boolean encrypted() { return this.encrypted; }
229+
230+
public byte[] getSerializedMessage() {
231+
return this.serializedMessage;
232+
}
131233
}

src/net/sharksystem/utils/ASAPSerialization.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import java.io.IOException;
66
import java.io.InputStream;
77
import java.io.OutputStream;
8+
import java.util.HashSet;
9+
import java.util.Set;
810

911
public class ASAPSerialization {
1012
public static void writeByteArray(byte[] bytes2Write, OutputStream os) throws IOException {
@@ -104,4 +106,32 @@ public static String readCharSequenceParameter(InputStream is) throws IOExceptio
104106

105107
return new String(parameterBytes);
106108
}
109+
110+
public static void writeCharSequenceSetParameter(Set<CharSequence> charSet, OutputStream os) throws IOException {
111+
if(charSet == null || charSet.size() == 0) {
112+
ASAPSerialization.writeNonNegativeIntegerParameter(0, os);
113+
return;
114+
}
115+
116+
// more recipients
117+
118+
// write len
119+
ASAPSerialization.writeNonNegativeIntegerParameter(charSet.size(), os);
120+
121+
// write entries
122+
for(CharSequence entry : charSet) {
123+
ASAPSerialization.writeCharSequenceParameter(entry, os);
124+
}
125+
}
126+
127+
public static Set<CharSequence> readCharSequenceSetParameter(InputStream is) throws IOException, ASAPException {
128+
Set<CharSequence> charSet = new HashSet<>();
129+
int len = ASAPSerialization.readIntegerParameter(is);
130+
131+
while(len-- > 0) {
132+
charSet.add(ASAPSerialization.readCharSequenceParameter(is));
133+
}
134+
135+
return charSet;
136+
}
107137
}

test/net/sharksystem/asap/Workbench.java

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import net.sharksystem.crypto.BasicCryptoKeyStorage;
77
import org.junit.Test;
88

9-
import java.io.IOException;
9+
import java.io.*;
1010
import java.security.KeyPair;
1111

1212
public class Workbench {
@@ -20,6 +20,69 @@ public class Workbench {
2020
public static final int EXAMPLE_PORT = 7070;
2121
public static final String EXAMPLE_MESSAGE_STRING = "Hi";
2222

23+
@Test
24+
public void scratch() throws IOException {
25+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
26+
DataOutputStream dos = new DataOutputStream(baos);
27+
28+
// sender. Ich sende long long, int long und teile das vorher mit
29+
long[] lValues = new long[3];
30+
int iValue = -1;
31+
lValues[0] = 1;
32+
lValues[1] = 2;
33+
lValues[2] = 3;
34+
35+
int types = 0;
36+
37+
// long comes first
38+
types += 0x01;
39+
types = types << 8;
40+
41+
// another long
42+
types += 0x01;
43+
types = types << 8;
44+
45+
// an int
46+
types += 0x00;
47+
types = types << 8;
48+
49+
// another long
50+
types += 0x01;
51+
52+
// sage was passiert
53+
dos.writeLong(types);
54+
55+
dos.writeLong(lValues[0]);
56+
dos.writeLong(lValues[1]);
57+
dos.writeInt(iValue);
58+
dos.writeLong(lValues[2]);
59+
System.out.println("l1 == " + lValues[0] + " | l2 == " + lValues[1] + " | i1 == " + iValue + " | l3 == " + lValues[2]);
60+
61+
// read
62+
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
63+
DataInputStream dis = new DataInputStream(bais);
64+
65+
// init l index
66+
int lIndex = 0;
67+
68+
// read Reihenfolge
69+
types = dis.readInt();
70+
int mask = 0xFF;
71+
mask = mask << 24;
72+
73+
while (mask > 0) {
74+
if ((types & mask) != 0) {
75+
// long value
76+
lValues[lIndex++] = dis.readLong();
77+
} else {
78+
// int
79+
iValue = dis.readInt();
80+
}
81+
mask = mask >> 8;
82+
}
83+
System.out.println("l1 == " + lValues[0] + " | l2 == " + lValues[1] + " | i1 == " + iValue + " | l3 == " + lValues[2]);
84+
}
85+
2386
@Test
2487
public void routeEncryptedMessage() throws IOException, ASAPException, InterruptedException {
2588
/*

test/net/sharksystem/asap/sharknet/SharkNetMessageASAPSerializationTests.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@
77

88
import java.io.IOException;
99
import java.security.KeyPair;
10+
import java.util.HashSet;
11+
import java.util.Set;
1012

1113
public class SharkNetMessageASAPSerializationTests {
1214
public static final String WORKING_SUB_DIRECTORY = "sharkNetTests/";
1315
public static final String ALICE_ID = "Alice";
1416
public static final String BOB_ID = "Bob";
17+
public static final String CLARA_ID = "Clara";
1518
public static final String MESSAGE = "Hi";
1619
public static final String URI = "sn2://all";
20+
public static final String ALICE_FOLDER = WORKING_SUB_DIRECTORY + "/" + ALICE_ID;
1721

1822
@Test
1923
public void serializationTestPlain() throws ASAPException, IOException {
@@ -108,5 +112,35 @@ public void serializationTestEncryptedAndSigned() throws ASAPException, IOExcept
108112
Assert.assertTrue(sharkNetMessage.encrypted());
109113
}
110114

115+
@Test
116+
public void snTestSignedMultipleRecipients() throws ASAPException, IOException, InterruptedException {
117+
// Alice
118+
BasicCryptoKeyStorage keyStorageAlice = new BasicCryptoKeyStorage(ALICE_ID);
119+
120+
BasicCryptoKeyStorage keyStorageBob = new BasicCryptoKeyStorage(BOB_ID);
121+
keyStorageBob.addKeyPair(ALICE_ID, keyStorageAlice.getKeyPair()); // Bob knows Alice
122+
123+
SharkNetPeer snPeerAlice = new SharkNetPeerFS(ALICE_ID, ALICE_FOLDER, keyStorageAlice);
124+
SharkNetMessageReceivedListener snListenerAlice = new SharkNetMessageReceivedListener();
125+
snPeerAlice.addSharkNetMessageListener(snListenerAlice);
111126

127+
Set<CharSequence> recipients = new HashSet<>();
128+
recipients.add(BOB_ID);
129+
recipients.add(CLARA_ID);
130+
// create Message
131+
SharkNetMessage alice2bobAndClara = new SharkNetMessage(
132+
MESSAGE.getBytes(), URI, ALICE_ID, recipients, true, keyStorageAlice);
133+
134+
byte[] asapMessage = alice2bobAndClara.getSerializedMessage();
135+
136+
// parse
137+
SharkNetMessage receivedMessage =
138+
SharkNetMessage.parseMessage(asapMessage, ALICE_ID, URI, ALICE_ID, keyStorageBob);
139+
140+
Assert.assertEquals(MESSAGE, new String(receivedMessage.getContent()));
141+
Assert.assertEquals(2, receivedMessage.getRecipients().size());
142+
Assert.assertEquals(ALICE_ID, receivedMessage.getSender());
143+
Assert.assertTrue(receivedMessage.verified());
144+
Assert.assertFalse(receivedMessage.encrypted());
145+
}
112146
}

test/net/sharksystem/asap/sharknet/SharkNetMessageReceivedListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ public class SharkNetMessageReceivedListener implements SharkNetMessageListener
88

99
@Override
1010
public void messageReceived(byte[] message, CharSequence topic, CharSequence senderID, boolean verified, boolean encrypted) {
11-
this.receivedMessages.add(new SharkNetMessage(message, topic, senderID, verified, encrypted));
11+
this.receivedMessages.add(new SharkNetMessage(message, topic, senderID, null, verified, encrypted));
1212
}
1313
}

0 commit comments

Comments
 (0)