Skip to content

Commit f3bb7ef

Browse files
committed
Prepared to handle unencryptable messages. We really need this feature.
1 parent f6253be commit f3bb7ef

File tree

7 files changed

+159
-53
lines changed

7 files changed

+159
-53
lines changed

src/net/sharksystem/asap/protocol/ASAP_Modem_Impl.java

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -75,17 +75,17 @@ public void interest(CharSequence sender, CharSequence recipient, CharSequence f
7575
throws IOException, ASAPException, ASAPSecurityException {
7676

7777
// prepare encryption and signing if required
78-
CryptoSession cryptoSession = new CryptoSession(ASAP_1_0.INTEREST_CMD,
78+
CryptoMessage cryptoMessage = new CryptoMessage(ASAP_1_0.INTEREST_CMD,
7979
os, signed, encrypted, recipient,
8080
this.signAndEncryptionKeyStorage);
8181

82-
cryptoSession.sendCmd();
82+
cryptoMessage.sendCmd();
8383

8484
InterestPDU_Impl.sendPDUWithoutCmd(sender, recipient, format, channel, eraFrom, eraTo,
85-
cryptoSession.getOutputStream(), signed);
85+
cryptoMessage.getOutputStream(), signed);
8686

8787
// finish crypto session - if any
88-
cryptoSession.finish();
88+
cryptoMessage.finish();
8989
}
9090

9191
@Override
@@ -114,44 +114,48 @@ public ASAP_PDU_1_0 readPDU(InputStream is) throws IOException, ASAPException {
114114

115115
// encrypted?
116116
boolean encrypted = (cmd & ENCRYPTED_MASK) != 0;
117-
// remove encrypted flag
118-
cmd = (byte)(cmd & CMD_MASK);
119117

120118
if(encrypted) {
121-
try {
122-
CryptoSession cryptoSession = new CryptoSession(this.signAndEncryptionKeyStorage);
123-
InputStream decryptedIS = cryptoSession.decrypt(is);
119+
CryptoMessage cryptoMessage = new CryptoMessage(this.signAndEncryptionKeyStorage);
120+
boolean ownerIsRecipient = cryptoMessage.initDecryption(cmd, is);
121+
if(ownerIsRecipient) {
122+
// peer is recipient - decrypt and go ahead
123+
InputStream decryptedIS = cryptoMessage.doDecryption(is);
124124
is = decryptedIS;
125-
}
126-
catch(ASAPSecurityException e) {
127-
System.out.println(this.getLogStart() + "cannot decrypt message. TODO: Store (according to some rules) and forward it?!");
125+
} else {
126+
// we cannot decrypt this message - we are not recipient - but we keep and redistribute
127+
byte[] encryptedASAPMessage = cryptoMessage.getEncryptedMessage();
128+
System.out.println(this.getLogStart() + "TODO: handle unencryptable message - redistribute?!");
129+
throw new ASAPSecurityException("recived encrypted message which is not for me - TODO: keep it and redistribute. That's not an error but a missing feature.");
128130
}
129131
}
130132

131133
int flagsInt = PDU_Impl.readByte(is);
132134

133135
InputStream realIS = is;
134-
CryptoSession verifyCryptoSession = null;
136+
CryptoMessage verifyCryptoMessage = null;
135137
if(PDU_Impl.flagSet(PDU_Impl.SIGNED_TO_BIT_POSITION, flagsInt)) {
136-
verifyCryptoSession = new CryptoSession(this.signAndEncryptionKeyStorage);
137-
is = verifyCryptoSession.setupInputStreamListener(is, flagsInt);
138+
verifyCryptoMessage = new CryptoMessage(this.signAndEncryptionKeyStorage);
139+
is = verifyCryptoMessage.setupInputStreamCopier(flagsInt, is);
138140
}
139141

140142
PDU_Impl pdu = null;
141143

144+
// remove encrypted flag
145+
cmd = (byte)(cmd & CMD_MASK);
142146
switch(cmd) {
143147
case ASAP_1_0.OFFER_CMD: pdu = new OfferPDU_Impl(flagsInt, encrypted, is); break;
144148
case ASAP_1_0.INTEREST_CMD: pdu = new InterestPDU_Impl(flagsInt, encrypted, is); break;
145149
case ASAP_1_0.ASSIMILATE_CMD: pdu = new AssimilationPDU_Impl(flagsInt, encrypted, is); break;
146150
default: throw new ASAPException("unknown command: " + cmd);
147151
}
148152

149-
if(verifyCryptoSession != null) {
153+
if(verifyCryptoMessage != null) {
150154
String sender = pdu.getSender();
151155
if(sender != null) {
152156
// read signature and try to verify
153157
try {
154-
pdu.setVerified(verifyCryptoSession.verify(sender, realIS));
158+
pdu.setVerified(verifyCryptoMessage.verify(sender, realIS));
155159
}
156160
catch(ASAPException e) {
157161
System.out.println(this.getLogStart() + " cannot verify message");

src/net/sharksystem/asap/protocol/CryptoSession.java renamed to src/net/sharksystem/asap/protocol/CryptoMessage.java

Lines changed: 75 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,14 @@
22

33
import net.sharksystem.asap.ASAPException;
44
import net.sharksystem.asap.ASAPSecurityException;
5-
import net.sharksystem.asap.protocol.ASAP_1_0;
6-
import net.sharksystem.asap.protocol.PDU_Impl;
75
import net.sharksystem.crypto.ASAPBasicKeyStorage;
86

97
import javax.crypto.*;
108
import javax.crypto.spec.SecretKeySpec;
119
import java.io.*;
1210
import java.security.*;
1311

14-
class CryptoSession {
15-
private static final int MAX_ENCRYPTION_BLOCK_SIZE = 128;
12+
class CryptoMessage {
1613
private Signature signature;
1714
private CharSequence recipient;
1815
private ASAPBasicKeyStorage keyStorage;
@@ -23,13 +20,15 @@ class CryptoSession {
2320
private OutputStream effectivOS;
2421
private OutputStream realOS;
2522
private ByteArrayOutputStream asapMessageOS;
26-
private InputStreamCopy verifyStream;
23+
private InputStreamCopy inputStreamCopy;
24+
private byte[] encryptedSymmetricKey;
25+
private byte[] encryptedContent;
2726

28-
CryptoSession(ASAPBasicKeyStorage keyStorage) {
27+
CryptoMessage(ASAPBasicKeyStorage keyStorage) {
2928
this.keyStorage = keyStorage;
3029
}
3130

32-
CryptoSession(byte cmd, OutputStream os, boolean sign, boolean encrypted,
31+
CryptoMessage(byte cmd, OutputStream os, boolean sign, boolean encrypted,
3332
CharSequence recipient,
3433
ASAPBasicKeyStorage keyStorage)
3534
throws ASAPSecurityException {
@@ -50,6 +49,10 @@ class CryptoSession {
5049
"but there is not key store at all - fatal, give up");
5150
}
5251

52+
if(this.recipient == null) {
53+
throw new ASAPSecurityException("cannot encrypt message with no specified receiver - fatal, give up");
54+
}
55+
5356
this.publicKey = keyStorage.getPublicKey(recipient);
5457
// there should be an exception - but better safe than sorry
5558
if(this.publicKey == null) {
@@ -158,6 +161,9 @@ public void finish() throws ASAPSecurityException {
158161
// must be after signing
159162
if(this.cipher != null) {
160163
try {
164+
// send receiver - unencrypted - need this for ad-hoc routing
165+
PDU_Impl.sendCharSequenceParameter(this.recipient, this.realOS);
166+
161167
// get symmetric key
162168
SecretKey encryptionKey = this.keyStorage.generateSymmetricKey();
163169
byte[] encodedSymmetricKey = encryptionKey.getEncoded();
@@ -186,6 +192,7 @@ public void finish() throws ASAPSecurityException {
186192
187193
int lastStepLen = asapMessageAsBytes.length - i;
188194
symmetricCipher.update(asapMessageAsBytes, i, lastStepLen);
195+
// did not work - ignored previous updates. anyway, there is a solution, see below
189196
byte[] encryptedContent = symmetricCipher.doFinal();
190197
*/
191198

@@ -226,13 +233,18 @@ byte[] getCopy() {
226233
}
227234
}
228235

229-
public InputStream setupInputStreamListener(InputStream is, int flagsInt) throws IOException {
236+
public InputStream setupInputStreamCopier(int priorInt, InputStream is)
237+
throws IOException {
238+
230239
ByteArrayOutputStream baos = new ByteArrayOutputStream();
231-
PDU_Impl.sendFlags(flagsInt, baos);
240+
// if(writeInt) {
241+
// PDU_Impl.sendFlags(priorInt, baos);
242+
// }
232243

233-
this.verifyStream = new InputStreamCopy(baos.toByteArray(), is);
244+
baos.write(priorInt);
234245

235-
return this.verifyStream;
246+
this.inputStreamCopy = new InputStreamCopy(baos.toByteArray(), is);
247+
return this.inputStreamCopy;
236248
}
237249

238250
public boolean verify(String sender, InputStream is) throws IOException, ASAPException {
@@ -244,7 +256,7 @@ public boolean verify(String sender, InputStream is) throws IOException, ASAPExc
244256
this.signature = Signature.getInstance(this.keyStorage.getRSASigningAlgorithm());
245257
this.signature.initVerify(publicKey);
246258
// get data which are to be verified
247-
byte[] signedData = this.verifyStream.getCopy();
259+
byte[] signedData = this.inputStreamCopy.getCopy();
248260
this.signature.update(signedData);
249261
byte[] signatureBytes = this.readByteArray(is);
250262
boolean wasVerified = this.signature.verify(signatureBytes);
@@ -256,35 +268,74 @@ public boolean verify(String sender, InputStream is) throws IOException, ASAPExc
256268

257269
////////////////////////////////// decrypt
258270

259-
public InputStream decrypt(InputStream is) throws ASAPSecurityException {
260-
return this.decrypt(is, this.keyStorage.getPrivateKey());
271+
/**
272+
* Simple idea: We read anything from stream and keep a copy. Later, we figure out
273+
* if we can encrypt that message or not. Either way, we can keep and redistribute a copy.
274+
*
275+
*
276+
* @param cmd
277+
* @param is
278+
* @return
279+
* @throws IOException
280+
* @throws ASAPException
281+
*/
282+
public boolean initDecryption(byte cmd, InputStream is) throws IOException, ASAPException {
283+
// make a copy of read data
284+
InputStream copyStream = this.setupInputStreamCopier(cmd, is);
285+
286+
// read recipient
287+
this.recipient = PDU_Impl.readCharSequenceParameter(copyStream);
288+
289+
// read encrypted symmetric key
290+
this.encryptedSymmetricKey = this.readByteArray(copyStream);
291+
292+
// read content
293+
this.encryptedContent = this.readByteArray(copyStream);
294+
295+
// read anything - are we recipient?
296+
if(this.keyStorage.isOwner(this.recipient)) {
297+
return true;
298+
}
299+
300+
return false;
301+
}
302+
303+
byte[] getEncryptedMessage() throws ASAPSecurityException {
304+
if(this.inputStreamCopy == null) {
305+
throw new ASAPSecurityException(
306+
this.getLogStart() + "no copy made, maybe forgot to initialize decryption?");
307+
}
308+
309+
return this.inputStreamCopy.getCopy();
310+
}
311+
312+
public InputStream doDecryption(InputStream is) throws ASAPSecurityException {
313+
return this.doDecryption(is, this.keyStorage.getPrivateKey());
261314
}
262315

263316
// parameter private key is usually not an option. Good entry for testing / debugging, though
264-
private InputStream decrypt(InputStream is, PrivateKey privateKey) throws ASAPSecurityException {
317+
public InputStream doDecryption(InputStream is, PrivateKey privateKey) throws ASAPSecurityException {
265318
try {
266-
// read encrypted symmetric key
267-
byte[] encryptedSymmetricKey = this.readByteArray(is);
268-
269319
// decrypt encoded symmetric key
270320
this.cipher = Cipher.getInstance(keyStorage.getRSAEncryptionAlgorithm());
271321
this.cipher.init(Cipher.DECRYPT_MODE, privateKey);
272-
byte[] encodedSymmetricKey = this.cipher.doFinal(encryptedSymmetricKey);
322+
323+
// read encryptedKey in initDecryption
324+
byte[] encodedSymmetricKey = this.cipher.doFinal(this.encryptedSymmetricKey);
273325

274326
// create symmetric key object
275327
SecretKey symmetricKey =
276328
new SecretKeySpec(encodedSymmetricKey, this.keyStorage.getSymmetricKeyType());
277329

278-
// read content
279-
byte[] encryptedContent = this.readByteArray(is);
280-
281330
// decrypt content
282331
Cipher symmetricCipher = Cipher.getInstance(keyStorage.getSymmetricEncryptionAlgorithm());
283332
symmetricCipher.init(Cipher.DECRYPT_MODE, symmetricKey);
284-
byte[] decryptedBytes = symmetricCipher.doFinal(encryptedContent);
333+
334+
// read encryptedContent in initDecryption
335+
byte[] decryptedBytes = symmetricCipher.doFinal(this.encryptedContent);
285336
return new ByteArrayInputStream(decryptedBytes);
286337
} catch (BadPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException |
287-
NoSuchPaddingException | InvalidKeyException | IOException | ASAPException e) {
338+
NoSuchPaddingException | InvalidKeyException e) {
288339
throw new ASAPSecurityException(this.getLogStart(), e);
289340
}
290341
}

src/net/sharksystem/asap/protocol/PDU_Impl.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -217,16 +217,16 @@ static int readIntegerParameter(InputStream is) throws IOException, ASAPExceptio
217217
return value;
218218
}
219219

220-
protected long readLongParameter(InputStream is) throws IOException, ASAPException {
221-
long value = this.readIntegerParameter(is);
220+
static long readLongParameter(InputStream is) throws IOException, ASAPException {
221+
long value = readIntegerParameter(is);
222222
value = value << 32;
223-
long right = this.readIntegerParameter(is);
223+
long right = readIntegerParameter(is);
224224
value += right;
225225
return value;
226226
}
227227

228-
protected String readCharSequenceParameter(InputStream is) throws IOException, ASAPException {
229-
int length = this.readIntegerParameter(is);
228+
static String readCharSequenceParameter(InputStream is) throws IOException, ASAPException {
229+
int length = readIntegerParameter(is);
230230
byte[] parameterBytes = new byte[length];
231231

232232
is.read(parameterBytes);

src/net/sharksystem/crypto/ASAPBasicKeyStorage.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,11 @@ public interface ASAPBasicKeyStorage {
4040
String getSymmetricEncryptionAlgorithm();
4141

4242
String getSymmetricKeyType();
43+
44+
/**
45+
*
46+
* @param peerID
47+
* @return true if peerID is owners' id.
48+
*/
49+
boolean isOwner(CharSequence peerID);
4350
}

src/net/sharksystem/crypto/TestASAPKeyStorage.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,27 @@
1010

1111
public class TestASAPKeyStorage implements ASAPBasicKeyStorage {
1212
private final KeyPair keyPair;
13-
private final String name;
13+
private final CharSequence ownerID;
1414
private long timeInMillis = 0;
1515

1616
public static final String DEFAULT_RSA_ENCRYPTION_ALGORITHM = "RSA/ECB/PKCS1Padding";
1717
public static final String DEFAULT_SYMMETRIC_KEY_TYPE = "AES";
1818
public static final String DEFAULT_SYMMETRIC_ENCRYPTION_ALGORITHM = "AES/ECB/PKCS5Padding";
19-
// public static int DEFAULT_AES_KEY_SIZE = 256; TODO we need a better one
20-
public static int DEFAULT_AES_KEY_SIZE = 128;
19+
// public static int DEFAULT_AES_KEY_SIZE = 256;
20+
public static int DEFAULT_AES_KEY_SIZE = 128; // TODO we can do better
2121
public static final String DEFAULT_SIGNATURE_ALGORITHM = "SHA256withRSA";
2222

2323
private HashMap<String, KeyPair> peerKeyPairs = new HashMap<>();
2424

25-
public TestASAPKeyStorage(String name) throws ASAPSecurityException {
25+
public TestASAPKeyStorage(String ownerID) throws ASAPSecurityException {
2626
// generate owners key pair;
27-
this.name = name;
27+
this.ownerID = ownerID;
2828
this.keyPair = this.generateKeyPair();
2929
this.timeInMillis = System.currentTimeMillis();
3030
}
3131

32-
public TestASAPKeyStorage(String name, KeyPair ownerKeyPair) {
33-
this.name = name;
32+
public TestASAPKeyStorage(CharSequence ownerID, KeyPair ownerKeyPair) {
33+
this.ownerID = ownerID;
3434
this.keyPair = ownerKeyPair;
3535
}
3636

@@ -128,12 +128,18 @@ public String getSymmetricKeyType() {
128128
return DEFAULT_SYMMETRIC_KEY_TYPE;
129129
}
130130

131+
@Override
132+
public boolean isOwner(CharSequence peerID) {
133+
return peerID.equals(this.ownerID);
134+
}
135+
131136
@Override
132137
public String getRSASigningAlgorithm() {
133138
return DEFAULT_SIGNATURE_ALGORITHM;
134139
}
135140

136141
public void addKeyPair(String peerID, KeyPair keyPair) {
142+
137143
this.peerKeyPairs.put(peerID, keyPair);
138144
}
139145
}

0 commit comments

Comments
 (0)