mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-04-19 07:15:54 -04:00
Add signature and checksum to message encryption
This commit is contained in:
parent
47f7f3b0bb
commit
32c56dad1a
44
core/pom.xml
44
core/pom.xml
@ -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>
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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",
|
||||
|
44
core/src/main/java/io/bitsquare/crypto/CryptoException.java
Normal file
44
core/src/main/java/io/bitsquare/crypto/CryptoException.java
Normal 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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
14
core/src/main/java/io/bitsquare/util/DSAKeyUtil.java → core/src/main/java/io/bitsquare/crypto/Util.java
Executable file → Normal file
14
core/src/main/java/io/bitsquare/util/DSAKeyUtil.java → core/src/main/java/io/bitsquare/crypto/Util.java
Executable file → Normal 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());
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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,
|
||||
() -> {
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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() {
|
||||
|
@ -42,6 +42,7 @@ public class SendPayoutTxFinalizedMessage extends TradeTask {
|
||||
tradeMessage,
|
||||
processModel.tradingPeer.getP2pSigPubKey(),
|
||||
processModel.tradingPeer.getP2pEncryptPubKey(),
|
||||
processModel.getRegistrationKeyPair(),
|
||||
new SendMessageListener() {
|
||||
@Override
|
||||
public void handleResult() {
|
||||
|
@ -52,6 +52,7 @@ public class SendRequestFinalizePayoutTxMessage extends TradeTask {
|
||||
message,
|
||||
processModel.tradingPeer.getP2pSigPubKey(),
|
||||
processModel.tradingPeer.getP2pEncryptPubKey(),
|
||||
processModel.getRegistrationKeyPair(),
|
||||
new SendMessageListener() {
|
||||
@Override
|
||||
public void handleResult() {
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user