Add signature and checksum to message encryption

This commit is contained in:
Manfred Karrer 2015-04-09 02:41:43 +02:00
parent 47f7f3b0bb
commit 32c56dad1a
26 changed files with 732 additions and 164 deletions

View File

@ -94,6 +94,30 @@
</build>
<dependencies>
<dependency>
<groupId>org.bitcoinj</groupId>
<artifactId>bitcoinj-core</artifactId>
<version>0.13.d13665c-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>net.tomp2p</groupId>
<artifactId>tomp2p-all</artifactId>
<version>5.0-Beta6</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.52</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>16.0.1</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
@ -104,21 +128,6 @@
<artifactId>logback-classic</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.bitcoinj</groupId>
<artifactId>bitcoinj-core</artifactId>
<version>0.13.d13665c-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>net.tomp2p</groupId>
<artifactId>tomp2p-all</artifactId>
<version>5.0-Beta6</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>16.0.1</version>
</dependency>
<dependency>
<groupId>io.reactivex</groupId>
@ -173,6 +182,11 @@
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>com.codahale.metrics</groupId>
<artifactId>metrics-graphite</artifactId>
<version>3.0.2</version>
</dependency>
</dependencies>
</project>

View File

@ -27,6 +27,9 @@ public class Version {
public static final int MINOR_VERSION = 1;
public static final int PATCH_VERSION = 3; // Will be used by UpdatedFX
public static final byte[] NETWORK_PROTOCOL_VERSION = new byte[]{0x01};
public static final int LOCLA_DB_VERSION = 1;
public static final String VERSION = MAJOR_VERSION + "." + MINOR_VERSION + "." + PATCH_VERSION;
}

View File

@ -17,9 +17,9 @@
package io.bitsquare.arbitration;
import io.bitsquare.crypto.Util;
import io.bitsquare.locale.LanguageUtil;
import io.bitsquare.storage.Storage;
import io.bitsquare.util.DSAKeyUtil;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Utils;
@ -68,7 +68,7 @@ public class ArbitrationRepository implements Serializable {
byte[] walletPubKey = Utils.HEX.decode("03a418bf0cb60a35ce217c7f80a2db08a4f5efbe56a0e7602fbc392dea6b63f840");
PublicKey p2pSigPubKey = null;
p2pSigPubKey = DSAKeyUtil.decodePubKeyHex
p2pSigPubKey = Util.decodeDSAPubKeyHex
("308201b83082012c06072a8648ce3804013082011f02818100fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c70215009760508f15230bccb292b982a2eb840bf0581cf502818100f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d0782675159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243bcca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a0381850002818100db47d4cf76e9bfcc0ba1e98c21c19ba45d1440fa2fec732f664dc8fd63e98877e648aac6db8d1035cd640fe5ff2e0030c2f8694ed124e81bd42c5446a1ce5288d5c8b4073d1cd890fe61ee4527f4e3184279f394cb9c2a4e7924cb2e82320a846cc140304eac6d41d4eaebc4d69b92725715497a82890be9f49d348fda20b095");
this.defaultArbitrator = new Arbitrator(arbitratorStorage,
"default-524f-46c0-b96e-de5a11d3475d",

View File

@ -0,0 +1,44 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.crypto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CryptoException extends Exception {
private static final Logger log = LoggerFactory.getLogger(CryptoException.class);
public CryptoException() {
}
public CryptoException(String message) {
super(message);
}
public CryptoException(String message, Throwable cause) {
super(message, cause);
}
public CryptoException(Throwable cause) {
super(cause);
}
public CryptoException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@ -17,8 +17,16 @@
package io.bitsquare.crypto;
import io.bitsquare.app.Version;
import io.bitsquare.p2p.Message;
import io.bitsquare.util.Utilities;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Utils;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyPair;
@ -26,6 +34,9 @@ import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.util.Arrays;
import javax.inject.Inject;
@ -39,18 +50,26 @@ import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class EncryptionService<T> {
private static final Logger log = LoggerFactory.getLogger(EncryptionService.class);
private static final String ALGO_SYM = "AES";
private static final String CIPHER_SYM = "AES";
private static final String CIPHER_SYM = "AES";// AES/CBC/PKCS5Padding
private static final String ALGO_ASYM = "RSA";
private static final String CIPHER_ASYM = "RSA/ECB/PKCS1Padding";
private static final int KEY_SIZE_SYM = 128;
private static final int KEY_SIZE_ASYM = 1024;
private static final int MAX_SIZE = 10000; // in bytes
static {
Security.addProvider(new BouncyCastleProvider());
}
private SignatureService signatureService;
@Inject
public EncryptionService() {
public EncryptionService(SignatureService signatureService) {
this.signatureService = signatureService;
}
public KeyPair getGeneratedDSAKeyPair() throws NoSuchAlgorithmException {
@ -65,65 +84,157 @@ public class EncryptionService<T> {
public KeyPair getGeneratedRSAKeyPair() throws NoSuchAlgorithmException {
long ts = System.currentTimeMillis();
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGO_ASYM);
keyPairGenerator.initialize(KEY_SIZE_ASYM);
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.genKeyPair();
log.debug("getGeneratedRSAKeyPair needed {} ms", System.currentTimeMillis() - ts);
return keyPair;
}
public Bucket encryptObject(PublicKey publicKey, Object object) throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException,
NoSuchAlgorithmException, NoSuchPaddingException {
return encrypt(publicKey, Utilities.objectToBytArray(object));
public byte[] encryptObject(PublicKey publicKey, ECKey signatureKeyPair, Object object) throws CryptoException {
return encryptBytes(publicKey, signatureKeyPair, Utilities.objectToBytArray(object));
}
public T decryptToObject(PrivateKey privateKey, Bucket bucket) throws IllegalBlockSizeException, InvalidKeyException,
BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
return Utilities.<T>byteArrayToObject(decrypt(privateKey, bucket));
public byte[] encryptMessage(PublicKey publicKey, ECKey signatureKeyPair, Message object) throws CryptoException {
return encryptBytes(publicKey, signatureKeyPair, Utilities.objectToBytArray(object));
}
public Bucket encrypt(PublicKey publicKey, byte[] payload) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
BadPaddingException, IllegalBlockSizeException {
public byte[] encryptBytes(PublicKey publicKey, ECKey signatureKeyPair, byte[] plainText) throws CryptoException {
long ts = System.currentTimeMillis();
// Create symmetric key and
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGO_SYM);
keyGenerator.init(KEY_SIZE_SYM);
SecretKey secretKey = keyGenerator.generateKey();
// Encrypt secretKey with asymmetric key
Cipher cipherAsym = Cipher.getInstance(CIPHER_ASYM);
cipherAsym.init(Cipher.ENCRYPT_MODE, publicKey);
log.debug("encrypt secret key length: " + secretKey.getEncoded().length);
byte[] encryptedKey = cipherAsym.doFinal(secretKey.getEncoded());
if (plainText.length == 0)
throw new CryptoException("Input data is null.");
// Encrypt payload with symmetric key
SecretKeySpec keySpec = new SecretKeySpec(secretKey.getEncoded(), ALGO_SYM);
Cipher cipherSym = Cipher.getInstance(CIPHER_SYM);
cipherSym.init(Cipher.ENCRYPT_MODE, keySpec);
log.debug("encrypt payload length: " + payload.length);
byte[] encryptedPayload = cipherSym.doFinal(payload);
log.debug("Encryption needed {} ms", System.currentTimeMillis() - ts);
return new Bucket(encryptedKey, encryptedPayload);
try {
// Create symmetric key
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGO_SYM);
keyGenerator.init(128);
SecretKey oneTimeKey = keyGenerator.generateKey();
// Encrypt secretKey with asymmetric key (16 bytes)
Cipher cipherAsym = Cipher.getInstance(CIPHER_ASYM);
cipherAsym.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedOneTimeKey = cipherAsym.doFinal(oneTimeKey.getEncoded());
// Create signature of plainText (65 bytes)
ECKey.ECDSASignature signature = signatureService.signBytes(signatureKeyPair, plainText).toCanonicalised();
byte[] sig = signature.encodeToDER(); // has 70-72 bytes ;-(
byte[] sigLength = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(sig.length).array();
// Encrypt plainText with symmetric key
Cipher cipherSym = Cipher.getInstance(CIPHER_SYM);
cipherSym.init(Cipher.ENCRYPT_MODE, oneTimeKey);
byte[] cipherText = cipherSym.doFinal(plainText);
// payload
byte[] payload = Utilities.concatByteArrays(sigLength, sig, signatureKeyPair.getPubKey(), encryptedOneTimeKey, cipherText);
byte[] payloadLength = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(payload.length).array();
// Checksum
byte[] checksum = Utils.sha256hash160(Utilities.concatByteArrays(payloadLength, payload));
// 1 byte version | 20 byte checksum | 4 byte payload length | n bytes payload
// payload consist of: 4 byte sigLength | sigLength(70-72) bytes for sig | 33 bytes for signaturePubKey | 128 bytes for encryptedOneTimeKey |
// remaining
// bytes for cipherText
byte[] result = Utilities.concatByteArrays(Version.NETWORK_PROTOCOL_VERSION, checksum, payloadLength, payload);
log.debug("result.length " + result.length);
log.debug("Encryption needed {} ms", System.currentTimeMillis() - ts);
return result;
} catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) {
throw new CryptoException(e);
}
}
public byte[] decrypt(PrivateKey privateKey, Bucket bucket) throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
public T decryptToMessage(PrivateKey privateKey, byte[] data) throws IllegalBlockSizeException, InvalidKeyException,
BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, CryptoException {
return Utilities.<T>byteArrayToObject(decryptBytes(privateKey, data));
}
public byte[] decryptBytes(PrivateKey privateKey, byte[] data) throws CryptoException {
long ts = System.currentTimeMillis();
byte[] encryptedPayload = bucket.encryptedPayload;
byte[] encryptedKey = bucket.encryptedKey;
// Decrypt secretKey key with asymmetric key
Cipher cipherAsym = Cipher.getInstance(CIPHER_ASYM);
cipherAsym.init(Cipher.DECRYPT_MODE, privateKey);
byte[] secretKey = cipherAsym.doFinal(encryptedKey);
log.debug("decrypt secret key length: " + secretKey.length);
// Decrypt payload with symmetric key
Key key = new SecretKeySpec(secretKey, ALGO_SYM);
Cipher cipherSym = Cipher.getInstance(CIPHER_SYM);
cipherSym.init(Cipher.DECRYPT_MODE, key);
byte[] payload = cipherSym.doFinal(encryptedPayload);
log.debug("decrypt payload length: " + payload.length);
log.debug("Decryption needed {} ms", System.currentTimeMillis() - ts);
return payload;
if (data.length < 25)
throw new CryptoException("The data is shorter as the min. overhead length.");
else if (data.length > MAX_SIZE)
throw new CryptoException("The data exceeds the max. size.");
// 1 byte version | 20 byte checksum | 4 byte payload length | n bytes payload consisting of sig, encryptedOneTimeKey, cipherText
byte[] version = new byte[1];
int cursor = 0;
System.arraycopy(data, cursor, version, 0, version.length);
if (!Arrays.equals(version, Version.NETWORK_PROTOCOL_VERSION))
throw new CryptoException("Incorrect version.");
byte[] checksum = new byte[20];
cursor += version.length;
System.arraycopy(data, cursor, checksum, 0, checksum.length);
byte[] payloadLength = new byte[4];
cursor += checksum.length;
System.arraycopy(data, cursor, payloadLength, 0, payloadLength.length);
int payloadLengthInt = ByteBuffer.wrap(payloadLength).order(ByteOrder.LITTLE_ENDIAN).getInt();
log.debug("encode payloadLengthInt " + payloadLengthInt);
if (payloadLengthInt < 0)
throw new CryptoException("Payload length cannot be negative.");
else if (payloadLengthInt > data.length - 25)
throw new CryptoException("Payload length cannot be larger then data excluding overhead.");
byte[] payload = new byte[payloadLengthInt];
cursor += payloadLength.length;
System.arraycopy(data, cursor, payload, 0, payload.length);
byte[] sigLength = new byte[4];
// cursor stays the same
System.arraycopy(data, cursor, sigLength, 0, sigLength.length);
int sigLengthInt = ByteBuffer.wrap(sigLength).order(ByteOrder.LITTLE_ENDIAN).getInt();
byte[] sig = new byte[sigLengthInt];
cursor += sigLength.length;
System.arraycopy(data, cursor, sig, 0, sig.length);
byte[] signaturePubKey = new byte[33];
cursor += sig.length;
System.arraycopy(data, cursor, signaturePubKey, 0, signaturePubKey.length);
byte[] encryptedOneTimeKey = new byte[128];
cursor += signaturePubKey.length;
System.arraycopy(data, cursor, encryptedOneTimeKey, 0, encryptedOneTimeKey.length);
byte[] cipherText = new byte[payloadLengthInt - (sigLength.length + sig.length + signaturePubKey.length + encryptedOneTimeKey.length)];
cursor += encryptedOneTimeKey.length;
System.arraycopy(data, cursor, cipherText, 0, cipherText.length);
// Checksum
byte[] controlChecksum = Utils.sha256hash160(Utilities.concatByteArrays(payloadLength, payload));
if (!Arrays.equals(checksum, controlChecksum))
throw new CryptoException("The checksum is invalid.");
try {
// Decrypt oneTimeKey key with asymmetric key
Cipher cipherAsym = Cipher.getInstance(CIPHER_ASYM);
cipherAsym.init(Cipher.DECRYPT_MODE, privateKey);
byte[] oneTimeKey = cipherAsym.doFinal(encryptedOneTimeKey);
// Decrypt payload with symmetric key
Key key = new SecretKeySpec(oneTimeKey, ALGO_SYM);
Cipher cipherSym = Cipher.getInstance(CIPHER_SYM);
cipherSym.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = cipherSym.doFinal(cipherText);
// Verify signature
boolean verified = signatureService.verify(ECKey.fromPublicOnly(signaturePubKey).getPubKey(), plainText, ECKey.ECDSASignature.decodeFromDER(sig));
if (!verified)
throw new CryptoException("Signature is not valid");
log.debug("Encryption needed {} ms", System.currentTimeMillis() - ts);
return plainText;
} catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) {
throw new CryptoException(e);
}
}
}

View File

@ -33,6 +33,15 @@ public class SignatureService {
return signMessage(key, hash);
}
public ECKey.ECDSASignature signBytes(ECKey key, byte[] data) {
return key.sign(Sha256Hash.hashTwice(data), null);
}
public String signMessage(ECKey key, byte[] data) {
Sha256Hash hash = Sha256Hash.hashTwice(data);
return signMessage(key, hash);
}
public String signMessage(ECKey key, Sha256Hash hash) {
ECKey.ECDSASignature sig = key.sign(hash, null);
// Now we have to work backwards to figure out the recId needed to recover the signature.
@ -54,12 +63,13 @@ public class SignatureService {
return new String(Base64.encode(sigData), Charsets.UTF_8);
}
public byte[] digestMessageWithSignature(ECKey key, String message) {
String signedMessage = signMessage(key, message);
return Utils.sha256hash160(message.concat(signedMessage).getBytes(Charsets.UTF_8));
}
public boolean verify(ECKey key, Sha256Hash hash, ECKey.ECDSASignature signature) {
return key.verify(hash, signature);
public boolean verify(byte[] signaturePubKey, byte[] data, ECKey.ECDSASignature sig) {
return ECKey.fromPublicOnly(signaturePubKey).verify(Sha256Hash.hashTwice(data), sig);
}
}

View File

@ -15,7 +15,7 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.util;
package io.bitsquare.crypto;
import org.bitcoinj.core.Utils;
@ -28,10 +28,15 @@ import java.security.spec.X509EncodedKeySpec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DSAKeyUtil {
private static final Logger log = LoggerFactory.getLogger(DSAKeyUtil.class);
public class Util {
private static final Logger log = LoggerFactory.getLogger(Util.class);
public static PublicKey decodePubKeyHex(String pubKeyHex) throws NoSuchAlgorithmException, InvalidKeySpecException {
public static String getHexFromPubKey(PublicKey publicKey) {
final X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey.getEncoded());
return Utils.HEX.encode(x509EncodedKeySpec.getEncoded());
}
public static PublicKey decodeDSAPubKeyHex(String pubKeyHex) throws NoSuchAlgorithmException, InvalidKeySpecException {
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(Utils.HEX.decode(pubKeyHex));
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
return keyFactory.generatePublic(pubKeySpec);
@ -40,5 +45,4 @@ public class DSAKeyUtil {
public static String encodePubKeyToHex(PublicKey pubKey) {
return Utils.HEX.encode(pubKey.getEncoded());
}
}

View File

@ -17,8 +17,6 @@
package io.bitsquare.p2p;
import io.bitsquare.crypto.Bucket;
import java.io.Serializable;
import org.slf4j.Logger;
@ -31,13 +29,13 @@ public class EncryptedMailboxMessage implements MailboxMessage, Serializable {
private static final long serialVersionUID = -3111178895546299769L;
private static final Logger log = LoggerFactory.getLogger(EncryptedMailboxMessage.class);
private final Bucket bucket;
private final byte[] bytes;
public EncryptedMailboxMessage(Bucket bucket) {
this.bucket = bucket;
public EncryptedMailboxMessage(byte[] bytes) {
this.bytes = bytes;
}
public Bucket getBucket() {
return bucket;
public byte[] getBytes() {
return bytes;
}
}

View File

@ -20,13 +20,16 @@ package io.bitsquare.p2p;
import io.bitsquare.p2p.listener.SendMessageListener;
import org.bitcoinj.core.ECKey;
import java.security.PublicKey;
public interface MessageService extends P2PService {
void sendMessage(Peer peer, Message message, SendMessageListener listener);
void sendMessage(Peer peer, Message message, PublicKey recipientP2pSigPubKey, PublicKey recipientP2pEncryptPubKey, SendMessageListener listener);
void sendMessage(Peer peer, Message message, PublicKey recipientP2pSigPubKey, PublicKey recipientP2pEncryptPubKey, ECKey registrationKeyPair,
SendMessageListener listener);
void addMessageHandler(MessageHandler listener);

View File

@ -34,7 +34,6 @@ import javax.inject.Inject;
import net.tomp2p.dht.FutureGet;
import net.tomp2p.dht.FuturePut;
import net.tomp2p.dht.FutureRemove;
import net.tomp2p.futures.BaseFuture;
import net.tomp2p.futures.BaseFutureAdapter;
import net.tomp2p.futures.BaseFutureListener;
@ -84,7 +83,6 @@ public class TomP2PAddressService extends TomP2PDHTService implements AddressSer
timerForIPCheck.cancel();
if (timerForStoreAddress != null)
timerForStoreAddress.cancel();
removeAddress();
super.shutDown();
}
@ -172,18 +170,4 @@ public class TomP2PAddressService extends TomP2PDHTService implements AddressSer
log.error("Exception at storePeerAddress " + e.toString());
}
}
private void removeAddress() {
try {
FutureRemove futureRemove = removeDataFromMyProtectedDomain(locationKey);
if (futureRemove != null) {
boolean success = futureRemove.awaitUninterruptibly(1000);
log.debug("removeDataFromMyProtectedDomain success=" + success);
}
} catch (Throwable t) {
t.printStackTrace();
log.error(t.getMessage());
}
}
}

View File

@ -17,7 +17,6 @@
package io.bitsquare.p2p.tomp2p;
import io.bitsquare.crypto.Bucket;
import io.bitsquare.crypto.EncryptionService;
import io.bitsquare.p2p.EncryptedMailboxMessage;
import io.bitsquare.p2p.MailboxMessage;
@ -28,6 +27,8 @@ import io.bitsquare.p2p.MessageService;
import io.bitsquare.p2p.Peer;
import io.bitsquare.p2p.listener.SendMessageListener;
import org.bitcoinj.core.ECKey;
import java.security.PublicKey;
import java.util.concurrent.CopyOnWriteArrayList;
@ -74,11 +75,11 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
@Override
public void sendMessage(Peer peer, Message message, SendMessageListener listener) {
sendMessage(peer, message, null, null, listener);
sendMessage(peer, message, null, null, null, listener);
}
@Override
public void sendMessage(Peer peer, Message message, PublicKey recipientP2pSigPubKey, PublicKey recipientP2pEncryptPubKey,
public void sendMessage(Peer peer, Message message, PublicKey recipientP2pSigPubKey, PublicKey recipientP2pEncryptPubKey, ECKey registrationKeyPair,
SendMessageListener listener) {
if (peer == null)
@ -97,7 +98,7 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
else {
if (recipientP2pSigPubKey != null && recipientP2pEncryptPubKey != null) {
log.info("sendMessage failed. We will try to send the message to the mailbox. Fault reason: " + futureDirect.failedReason());
sendMailboxMessage(recipientP2pSigPubKey, recipientP2pEncryptPubKey, (MailboxMessage) message, listener);
sendMailboxMessage(recipientP2pSigPubKey, recipientP2pEncryptPubKey, registrationKeyPair, (MailboxMessage) message, listener);
}
else {
log.error("sendMessage failed with reason " + futureDirect.failedReason());
@ -110,7 +111,7 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
public void exceptionCaught(Throwable t) throws Exception {
if (recipientP2pSigPubKey != null && recipientP2pEncryptPubKey != null) {
log.info("sendMessage failed with exception. We will try to send the message to the mailbox. Exception: " + t.getMessage());
sendMailboxMessage(recipientP2pSigPubKey, recipientP2pEncryptPubKey, (MailboxMessage) message, listener);
sendMailboxMessage(recipientP2pSigPubKey, recipientP2pEncryptPubKey, registrationKeyPair, (MailboxMessage) message, listener);
}
else {
log.error("sendMessage failed with exception " + t.getMessage());
@ -120,18 +121,19 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
});
}
private void sendMailboxMessage(PublicKey recipientP2pSigPubKey, PublicKey recipientP2pEncryptPubKey, MailboxMessage message, SendMessageListener
listener) {
Bucket bucket = null;
private void sendMailboxMessage(PublicKey recipientP2pSigPubKey, PublicKey recipientP2pEncryptPubKey, ECKey registrationKeyPair, MailboxMessage message,
SendMessageListener
listener) {
byte[] result = null;
log.info("sendMailboxMessage called");
try {
bucket = encryptionService.encryptObject(recipientP2pEncryptPubKey, message);
result = encryptionService.encryptMessage(recipientP2pEncryptPubKey, registrationKeyPair, message);
} catch (Throwable t) {
t.printStackTrace();
log.error(t.getMessage());
executor.execute(listener::handleFault);
}
EncryptedMailboxMessage encrypted = new EncryptedMailboxMessage(bucket);
EncryptedMailboxMessage encrypted = new EncryptedMailboxMessage(result);
mailboxService.addMessage(recipientP2pSigPubKey,
encrypted,
() -> {

View File

@ -17,9 +17,9 @@
package io.bitsquare.trade;
import io.bitsquare.crypto.Util;
import io.bitsquare.fiat.FiatAccount;
import io.bitsquare.offer.Offer;
import io.bitsquare.util.Utilities;
import org.bitcoinj.core.Coin;
@ -61,8 +61,8 @@ public class Contract implements Serializable {
this.sellerAccountID = sellerAccountID;
this.buyerFiatAccount = buyerFiatAccount;
this.sellerFiatAccount = sellerFiatAccount;
this.buyerP2pSigPubKeyAsString = Utilities.getHexFromPubKey(buyerP2pSigPubKey);
this.sellerP2pSigPubKeyAsString = Utilities.getHexFromPubKey(sellerP2pSigPubKey);
this.buyerP2pSigPubKeyAsString = Util.getHexFromPubKey(buyerP2pSigPubKey);
this.sellerP2pSigPubKeyAsString = Util.getHexFromPubKey(sellerP2pSigPubKey);
}
@Override

View File

@ -180,7 +180,7 @@ public class TradeManager {
log.trace("applyMailboxMessage encryptedMailboxMessage.size=" + encryptedMailboxMessages.size());
for (EncryptedMailboxMessage encrypted : encryptedMailboxMessages) {
try {
MailboxMessage mailboxMessage = encryptionService.decryptToObject(user.getP2pEncryptPrivateKey(), encrypted.getBucket());
MailboxMessage mailboxMessage = encryptionService.decryptToMessage(user.getP2pEncryptPrivateKey(), encrypted.getBytes());
if (mailboxMessage instanceof TradeMessage) {
String tradeId = ((TradeMessage) mailboxMessage).tradeId;
Optional<Trade> tradeOptional = pendingTrades.stream().filter(e -> e.getId().equals(tradeId)).findAny();

View File

@ -81,18 +81,23 @@ public class SellerAsOffererProtocol extends TradeProtocol implements SellerProt
log.debug("setMailboxMessage " + mailboxMessage);
// Find first the actual peer address, as it might have changed in the meantime
findPeerAddress(processModel.tradingPeer.getP2pSigPubKey(),
() -> {
if (mailboxMessage instanceof FiatTransferStartedMessage) {
handle((FiatTransferStartedMessage) mailboxMessage);
}
else if (mailboxMessage instanceof DepositTxPublishedMessage) {
handle((DepositTxPublishedMessage) mailboxMessage);
}
},
(errorMessage -> {
log.error(errorMessage);
}));
if (mailboxMessage instanceof PayoutTxFinalizedMessage) {
handle((PayoutTxFinalizedMessage) mailboxMessage);
}
else {
findPeerAddress(processModel.tradingPeer.getP2pSigPubKey(),
() -> {
if (mailboxMessage instanceof FiatTransferStartedMessage) {
handle((FiatTransferStartedMessage) mailboxMessage);
}
else if (mailboxMessage instanceof DepositTxPublishedMessage) {
handle((DepositTxPublishedMessage) mailboxMessage);
}
},
(errorMessage -> {
log.error(errorMessage);
}));
}
}

View File

@ -81,21 +81,23 @@ public class SellerAsTakerProtocol extends TradeProtocol implements SellerProtoc
log.debug("setMailboxMessage " + mailboxMessage);
// Find first the actual peer address, as it might have changed in the meantime
findPeerAddress(trade.getOffer().getP2pSigPubKey(),
() -> {
if (mailboxMessage instanceof FiatTransferStartedMessage) {
handle((FiatTransferStartedMessage) mailboxMessage);
}
else if (mailboxMessage instanceof DepositTxPublishedMessage) {
handle((DepositTxPublishedMessage) mailboxMessage);
}
else if (mailboxMessage instanceof PayoutTxFinalizedMessage) {
handle((PayoutTxFinalizedMessage) mailboxMessage);
}
},
(errorMessage -> {
log.error(errorMessage);
}));
if (mailboxMessage instanceof PayoutTxFinalizedMessage) {
handle((PayoutTxFinalizedMessage) mailboxMessage);
}
else {
findPeerAddress(trade.getOffer().getP2pSigPubKey(),
() -> {
if (mailboxMessage instanceof FiatTransferStartedMessage) {
handle((FiatTransferStartedMessage) mailboxMessage);
}
else if (mailboxMessage instanceof DepositTxPublishedMessage) {
handle((DepositTxPublishedMessage) mailboxMessage);
}
},
(errorMessage -> {
log.error(errorMessage);
}));
}
}
@Override
@ -195,6 +197,7 @@ public class SellerAsTakerProtocol extends TradeProtocol implements SellerProtoc
}
private void handle(PayoutTxFinalizedMessage tradeMessage) {
log.debug("handle PayoutTxFinalizedMessage");
processModel.setTradeMessage(tradeMessage);
TradeTaskRunner taskRunner = new TradeTaskRunner(sellerAsTakerTrade,

View File

@ -48,6 +48,7 @@ public class SendFiatTransferStartedMessage extends TradeTask {
processModel.getMessageService().sendMessage(trade.getTradingPeer(), tradeMessage,
processModel.tradingPeer.getP2pSigPubKey(),
processModel.tradingPeer.getP2pEncryptPubKey(),
processModel.getRegistrationKeyPair(),
new SendMessageListener() {
@Override
public void handleResult() {

View File

@ -42,6 +42,7 @@ public class SendPayoutTxFinalizedMessage extends TradeTask {
tradeMessage,
processModel.tradingPeer.getP2pSigPubKey(),
processModel.tradingPeer.getP2pEncryptPubKey(),
processModel.getRegistrationKeyPair(),
new SendMessageListener() {
@Override
public void handleResult() {

View File

@ -52,6 +52,7 @@ public class SendRequestFinalizePayoutTxMessage extends TradeTask {
message,
processModel.tradingPeer.getP2pSigPubKey(),
processModel.tradingPeer.getP2pEncryptPubKey(),
processModel.getRegistrationKeyPair(),
new SendMessageListener() {
@Override
public void handleResult() {

View File

@ -17,8 +17,6 @@
package io.bitsquare.util;
import org.bitcoinj.core.Utils;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@ -37,9 +35,6 @@ import java.io.Serializable;
import java.net.URI;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -91,6 +86,20 @@ public class Utilities {
openURI(new URI(target));
}
public static byte[] concatByteArrays(byte[]... arrays) {
int totalLength = 0;
for (int i = 0; i < arrays.length; i++) {
totalLength += arrays[i].length;
}
byte[] result = new byte[totalLength];
int currentIndex = 0;
for (int i = 0; i < arrays.length; i++) {
System.arraycopy(arrays[i], 0, result, currentIndex, arrays[i].length);
currentIndex += arrays[i].length;
}
return result;
}
public static <T> T jsonToObject(String jsonString, Class<T> classOfT) {
Gson gson =
@ -248,8 +257,4 @@ public class Utilities {
}
}
public static String getHexFromPubKey(PublicKey publicKey) {
final X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey.getEncoded());
return Utils.HEX.encode(x509EncodedKeySpec.getEncoded());
}
}

View File

@ -0,0 +1,31 @@
/**
* Copyright (C) 2014 Open WhisperSystems
* <p/>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* <p/>
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* <p/>
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whispersystems.textsecuregcm.metrics;
import com.codahale.metrics.Gauge;
import com.sun.management.OperatingSystemMXBean;
import java.lang.management.ManagementFactory;
public class CpuUsageGauge implements Gauge<Integer> {
@Override
public Integer getValue() {
OperatingSystemMXBean mbean = (OperatingSystemMXBean)
ManagementFactory.getOperatingSystemMXBean();
return (int) Math.ceil(mbean.getSystemCpuLoad() * 100);
}
}

View File

@ -0,0 +1,33 @@
/**
* Copyright (C) 2014 Open WhisperSystems
* <p/>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* <p/>
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* <p/>
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whispersystems.textsecuregcm.metrics;
import com.codahale.metrics.Gauge;
import com.sun.management.OperatingSystemMXBean;
import java.lang.management.ManagementFactory;
public class FreeMemoryGauge implements Gauge<Long> {
@Override
public Long getValue() {
OperatingSystemMXBean mbean = (OperatingSystemMXBean)
ManagementFactory.getOperatingSystemMXBean();
return mbean.getFreePhysicalMemorySize();
}
}

View File

@ -0,0 +1,53 @@
/**
* Copyright (C) 2014 Open WhisperSystems
* <p/>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* <p/>
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* <p/>
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whispersystems.textsecuregcm.metrics;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import com.codahale.metrics.Gauge;
import org.whispersystems.textsecuregcm.util.Pair;
public abstract class NetworkGauge implements Gauge<Long> {
protected Pair<Long, Long> getSentReceived() throws IOException {
File proc = new File("/proc/net/dev");
BufferedReader reader = new BufferedReader(new FileReader(proc));
String header = reader.readLine();
String header2 = reader.readLine();
long bytesSent = 0;
long bytesReceived = 0;
String interfaceStats;
while ((interfaceStats = reader.readLine()) != null) {
String[] stats = interfaceStats.split("\\s+");
if (!stats[1].equals("lo:")) {
bytesReceived += Long.parseLong(stats[2]);
bytesSent += Long.parseLong(stats[10]);
}
}
return new Pair<>(bytesSent, bytesReceived);
}
}

View File

@ -0,0 +1,55 @@
/**
* Copyright (C) 2014 Open WhisperSystems
* <p/>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* <p/>
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* <p/>
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whispersystems.textsecuregcm.metrics;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.util.Pair;
public class NetworkReceivedGauge extends NetworkGauge {
private final Logger logger = LoggerFactory.getLogger(NetworkSentGauge.class);
private long lastTimestamp;
private long lastReceived;
@Override
public Long getValue() {
try {
long timestamp = System.currentTimeMillis();
Pair<Long, Long> sentAndReceived = getSentReceived();
long result = 0;
if (lastTimestamp != 0) {
result = sentAndReceived.second() - lastReceived;
lastReceived = sentAndReceived.second();
}
lastTimestamp = timestamp;
return result;
} catch (IOException e) {
logger.warn("NetworkReceivedGauge", e);
return -1L;
}
}
}

View File

@ -0,0 +1,54 @@
/**
* Copyright (C) 2014 Open WhisperSystems
* <p/>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* <p/>
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* <p/>
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whispersystems.textsecuregcm.metrics;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.util.Pair;
public class NetworkSentGauge extends NetworkGauge {
private final Logger logger = LoggerFactory.getLogger(NetworkSentGauge.class);
private long lastTimestamp;
private long lastSent;
@Override
public Long getValue() {
try {
long timestamp = System.currentTimeMillis();
Pair<Long, Long> sentAndReceived = getSentReceived();
long result = 0;
if (lastTimestamp != 0) {
result = sentAndReceived.first() - lastSent;
lastSent = sentAndReceived.first();
}
lastTimestamp = timestamp;
return result;
} catch (IOException e) {
logger.warn("NetworkSentGauge", e);
return -1L;
}
}
}

View File

@ -0,0 +1,47 @@
/**
* Copyright (C) 2014 Open WhisperSystems
* <p/>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* <p/>
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* <p/>
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whispersystems.textsecuregcm.util;
import static com.google.common.base.Objects.equal;
public class Pair<T1, T2> {
private final T1 v1;
private final T2 v2;
public Pair(T1 v1, T2 v2) {
this.v1 = v1;
this.v2 = v2;
}
public T1 first() {
return v1;
}
public T2 second() {
return v2;
}
public boolean equals(Object o) {
return o instanceof Pair &&
equal(((Pair) o).first(), first()) &&
equal(((Pair) o).second(), second());
}
public int hashCode() {
return first().hashCode() ^ second().hashCode();
}
}

View File

@ -19,63 +19,169 @@ package io.bitsquare.crypto;
import io.bitsquare.p2p.MailboxMessage;
import org.bitcoinj.core.ECKey;
import java.security.KeyPair;
import java.util.Arrays;
import java.util.Random;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.springframework.test.util.AssertionErrors.assertEquals;
import static org.junit.Assert.*;
public class EncryptionServiceTests {
private static final Logger log = LoggerFactory.getLogger(EncryptionServiceTests.class);
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void testEncryptionWithMailboxMessage() throws Exception {
EncryptionService<MailboxMessage> encryptionService = new EncryptionService<>();
SignatureService signatureService = new SignatureService();
EncryptionService<MailboxMessage> encryptionService = new EncryptionService<>(signatureService);
KeyPair p2pEncryptKeyPair = encryptionService.getGeneratedRSAKeyPair();
ECKey signatureKeyPair = new ECKey();
TestMessage message = new TestMessage("test");
Bucket bucket = encryptionService.encryptObject(p2pEncryptKeyPair.getPublic(), message);
MailboxMessage result = encryptionService.decryptToObject(p2pEncryptKeyPair.getPrivate(), bucket);
assertEquals("", message.data, ((TestMessage) result).data);
TestMessage data = new TestMessage("test");
byte[] encrypted = encryptionService.encryptMessage(p2pEncryptKeyPair.getPublic(), signatureKeyPair, data);
MailboxMessage decrypted = encryptionService.decryptToMessage(p2pEncryptKeyPair.getPrivate(), encrypted);
assertEquals("", data.data, ((TestMessage) decrypted).data);
}
@Test
public void testEncryptionWithInteger() throws Exception {
EncryptionService<Integer> encryptionService = new EncryptionService<>();
SignatureService signatureService = new SignatureService();
EncryptionService<Integer> encryptionService = new EncryptionService<>(signatureService);
KeyPair p2pEncryptKeyPair = encryptionService.getGeneratedRSAKeyPair();
int data = 1234;
Bucket bucket = encryptionService.encryptObject(p2pEncryptKeyPair.getPublic(), data);
Integer result = encryptionService.decryptToObject(p2pEncryptKeyPair.getPrivate(), bucket);
assertEquals("", data, result);
ECKey signatureKeyPair = new ECKey();
Integer data = 1234;
byte[] encrypted = encryptionService.encryptObject(p2pEncryptKeyPair.getPublic(), signatureKeyPair, data);
Integer decrypted = encryptionService.decryptToMessage(p2pEncryptKeyPair.getPrivate(), encrypted);
assertEquals("", data, decrypted);
}
@Test
public void testEncryptionWithBytes() throws Exception {
EncryptionService encryptionService = new EncryptionService();
SignatureService signatureService = new SignatureService();
EncryptionService<MailboxMessage> encryptionService = new EncryptionService<>(signatureService);
KeyPair p2pEncryptKeyPair = encryptionService.getGeneratedRSAKeyPair();
ECKey signatureKeyPair = new ECKey();
byte[] data = new byte[]{0x00, 0x01, 0x02, 0x03, 0x04};
Bucket bucket = encryptionService.encrypt(p2pEncryptKeyPair.getPublic(), data);
byte[] result = encryptionService.decrypt(p2pEncryptKeyPair.getPrivate(), bucket);
assertEquals("", result, data);
byte[] encrypted = encryptionService.encryptBytes(p2pEncryptKeyPair.getPublic(), signatureKeyPair, data);
byte[] decrypted = encryptionService.decryptBytes(p2pEncryptKeyPair.getPrivate(), encrypted);
assertTrue(Arrays.equals(data, decrypted));
}
@Test
public void testEncryptionWithLargeData() throws Exception {
EncryptionService encryptionService = new EncryptionService();
SignatureService signatureService = new SignatureService();
EncryptionService<MailboxMessage> encryptionService = new EncryptionService<>(signatureService);
KeyPair p2pEncryptKeyPair = encryptionService.getGeneratedRSAKeyPair();
ECKey signatureKeyPair = new ECKey();
byte[] data = new byte[2000];
new Random().nextBytes(data);
Bucket bucket = encryptionService.encrypt(p2pEncryptKeyPair.getPublic(), data);
byte[] result = encryptionService.decrypt(p2pEncryptKeyPair.getPrivate(), bucket);
assertEquals("", result, data);
byte[] encrypted = encryptionService.encryptBytes(p2pEncryptKeyPair.getPublic(), signatureKeyPair, data);
byte[] decrypted = encryptionService.decryptBytes(p2pEncryptKeyPair.getPrivate(), encrypted);
assertTrue(Arrays.equals(data, decrypted));
}
@Test
public void testEncryptionWithTooMuchData() throws Exception {
SignatureService signatureService = new SignatureService();
EncryptionService<MailboxMessage> encryptionService = new EncryptionService<>(signatureService);
KeyPair p2pEncryptKeyPair = encryptionService.getGeneratedRSAKeyPair();
ECKey signatureKeyPair = new ECKey();
byte[] data = new byte[11000];
new Random().nextBytes(data);
thrown.expect(CryptoException.class);
thrown.expectMessage("The data exceeds the max. size.");
byte[] encrypted = encryptionService.encryptBytes(p2pEncryptKeyPair.getPublic(), signatureKeyPair, data);
byte[] decrypted = encryptionService.decryptBytes(p2pEncryptKeyPair.getPrivate(), encrypted);
}
@Test
public void testEncryptionWithTooLessData() throws Exception {
SignatureService signatureService = new SignatureService();
EncryptionService<MailboxMessage> encryptionService = new EncryptionService<>(signatureService);
KeyPair p2pEncryptKeyPair = encryptionService.getGeneratedRSAKeyPair();
ECKey signatureKeyPair = new ECKey();
byte[] data = new byte[11000];
new Random().nextBytes(data);
thrown.expect(CryptoException.class);
thrown.expectMessage("The data is shorter as the min. overhead length.");
byte[] encrypted = encryptionService.encryptBytes(p2pEncryptKeyPair.getPublic(), signatureKeyPair, data);
byte[] decrypted = encryptionService.decryptBytes(p2pEncryptKeyPair.getPrivate(), new byte[24]);
}
@Test
public void testEncryptionWithManipulatedPayload() throws Exception {
SignatureService signatureService = new SignatureService();
EncryptionService<MailboxMessage> encryptionService = new EncryptionService<>(signatureService);
KeyPair p2pEncryptKeyPair = encryptionService.getGeneratedRSAKeyPair();
ECKey signatureKeyPair = new ECKey();
byte[] data = new byte[110];
new Random().nextBytes(data);
thrown.expect(CryptoException.class);
thrown.expectMessage("The checksum is invalid.");
byte[] encrypted = encryptionService.encryptBytes(p2pEncryptKeyPair.getPublic(), signatureKeyPair, data);
byte[] manipulated = new byte[encrypted.length];
System.arraycopy(encrypted, 0, manipulated, 0, manipulated.length);
manipulated[manipulated.length - 1] = 0x31;
byte[] decrypted = encryptionService.decryptBytes(p2pEncryptKeyPair.getPrivate(), manipulated);
}
@Test
public void testEncryptionWithWrongVersion() throws Exception {
SignatureService signatureService = new SignatureService();
EncryptionService<MailboxMessage> encryptionService = new EncryptionService<>(signatureService);
KeyPair p2pEncryptKeyPair = encryptionService.getGeneratedRSAKeyPair();
ECKey signatureKeyPair = new ECKey();
byte[] data = new byte[1100];
new Random().nextBytes(data);
thrown.expect(CryptoException.class);
thrown.expectMessage("Incorrect version.");
byte[] encrypted = encryptionService.encryptBytes(p2pEncryptKeyPair.getPublic(), signatureKeyPair, data);
byte[] manipulated = new byte[encrypted.length];
System.arraycopy(encrypted, 0, manipulated, 0, manipulated.length);
manipulated[0] = 0x02;
byte[] decrypted = encryptionService.decryptBytes(p2pEncryptKeyPair.getPrivate(), manipulated);
}
@Test
public void testEncryptionWithNoData() throws Exception {
SignatureService signatureService = new SignatureService();
EncryptionService<MailboxMessage> encryptionService = new EncryptionService<>(signatureService);
KeyPair p2pEncryptKeyPair = encryptionService.getGeneratedRSAKeyPair();
ECKey signatureKeyPair = new ECKey();
byte[] data = new byte[0];
thrown.expect(CryptoException.class);
thrown.expectMessage("Input data is null.");
byte[] encrypted = encryptionService.encryptBytes(p2pEncryptKeyPair.getPublic(), signatureKeyPair, data);
byte[] decrypted = encryptionService.decryptBytes(p2pEncryptKeyPair.getPrivate(), encrypted);
}
}