diff --git a/common/src/main/java/io/bitsquare/common/crypto/DecryptedPayloadWithPubKey.java b/common/src/main/java/io/bitsquare/common/crypto/DecryptedPayloadWithPubKey.java index 15b4e3df1d..dd3f4314db 100644 --- a/common/src/main/java/io/bitsquare/common/crypto/DecryptedPayloadWithPubKey.java +++ b/common/src/main/java/io/bitsquare/common/crypto/DecryptedPayloadWithPubKey.java @@ -22,11 +22,6 @@ import io.bitsquare.app.Version; import java.io.Serializable; import java.security.PublicKey; -/** - * Packs the encrypted symmetric secretKey and the encrypted and signed message into one object. - * SecretKey is encrypted with asymmetric pubKey of peer. Signed message is encrypted with secretKey. - * Using that hybrid encryption model we are not restricted by data size and performance as symmetric encryption is very fast. - */ public final class DecryptedPayloadWithPubKey implements Serializable { // That object is sent over the wire, so we need to take care of version compatibility. private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION; @@ -39,4 +34,30 @@ public final class DecryptedPayloadWithPubKey implements Serializable { this.sigPublicKey = sigPublicKey; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof DecryptedPayloadWithPubKey)) return false; + + DecryptedPayloadWithPubKey that = (DecryptedPayloadWithPubKey) o; + + if (payload != null ? !payload.equals(that.payload) : that.payload != null) return false; + return !(sigPublicKey != null ? !sigPublicKey.equals(that.sigPublicKey) : that.sigPublicKey != null); + + } + + @Override + public int hashCode() { + int result = payload != null ? payload.hashCode() : 0; + result = 31 * result + (sigPublicKey != null ? sigPublicKey.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "DecryptedPayloadWithPubKey{" + + "payload=" + payload + + ", sigPublicKey.hashCode()=" + sigPublicKey.hashCode() + + '}'; + } } diff --git a/common/src/main/java/io/bitsquare/common/crypto/Encryption.java b/common/src/main/java/io/bitsquare/common/crypto/Encryption.java index 14cc8a673c..b945430389 100644 --- a/common/src/main/java/io/bitsquare/common/crypto/Encryption.java +++ b/common/src/main/java/io/bitsquare/common/crypto/Encryption.java @@ -30,24 +30,28 @@ import java.io.Serializable; import java.security.*; import java.util.Arrays; +// TODO: which counter modes and paddings should we use? +// https://security.stackexchange.com/questions/52665/which-is-the-best-cipher-mode-and-padding-mode-for-aes-encryption public class Encryption { private static final Logger log = LoggerFactory.getLogger(Encryption.class); - public static final String ENCR_KEY_ALGO = "RSA"; - public static final String SYM_KEY_ALGO = "AES"; - public static final String SYM_CIPHER = "AES"; // java.security.NoSuchAlgorithmException: AES/ECB/PKCS5Padding KeyGenerator not available - public static final String ASYM_CIPHER = "RSA"; // TODO test with RSA/ECB/PKCS1Padding + public static final String ASYM_KEY_ALGO = "RSA"; // RSA/NONE/OAEPWithSHA256AndMGF1Padding + public static final String ASYM_CIPHER = "RSA"; + + public static final String SYM_KEY_ALGO = "AES"; // AES/CTR/NoPadding + public static final String SYM_CIPHER = "AES"; + public static final String HMAC = "HmacSHA256"; public static KeyPair generateKeyPair() { long ts = System.currentTimeMillis(); try { - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ENCR_KEY_ALGO); + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ASYM_KEY_ALGO, "BC"); keyPairGenerator.initialize(2048); KeyPair keyPair = keyPairGenerator.genKeyPair(); log.trace("Generate msgEncryptionKeyPair needed {} ms", System.currentTimeMillis() - ts); return keyPair; - } catch (NoSuchAlgorithmException e) { + } catch (NoSuchAlgorithmException | NoSuchProviderException e) { e.printStackTrace(); throw new RuntimeException("Could not create key."); } @@ -60,11 +64,11 @@ public class Encryption { public static byte[] encrypt(byte[] payload, SecretKey secretKey) throws CryptoException { try { - Cipher cipher = Cipher.getInstance(SYM_CIPHER); + Cipher cipher = Cipher.getInstance(SYM_CIPHER, "BC"); cipher.init(Cipher.ENCRYPT_MODE, secretKey); return cipher.doFinal(payload); } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException - | BadPaddingException | IllegalBlockSizeException e) { + | BadPaddingException | IllegalBlockSizeException | NoSuchProviderException e) { e.printStackTrace(); throw new CryptoException(e); } @@ -72,11 +76,11 @@ public class Encryption { public static byte[] decrypt(byte[] encryptedPayload, SecretKey secretKey) throws CryptoException { try { - Cipher cipher = Cipher.getInstance(SYM_CIPHER); + Cipher cipher = Cipher.getInstance(SYM_CIPHER, "BC"); cipher.init(Cipher.DECRYPT_MODE, secretKey); return cipher.doFinal(encryptedPayload); } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException - | BadPaddingException | IllegalBlockSizeException e) { + | BadPaddingException | IllegalBlockSizeException | NoSuchProviderException e) { e.printStackTrace(); throw new CryptoException(e); } @@ -99,7 +103,7 @@ public class Encryption { outputStream.write(hmac); outputStream.flush(); payloadWithHmac = outputStream.toByteArray().clone(); - } catch (IOException e) { + } catch (IOException | NoSuchProviderException e) { e.printStackTrace(); throw new RuntimeException("Could not create hmac"); } finally { @@ -122,14 +126,14 @@ public class Encryption { try { byte[] hmacTest = getHmac(message, secretKey); return Arrays.equals(hmacTest, hmac); - } catch (NoSuchAlgorithmException | InvalidKeyException e) { + } catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchProviderException e) { e.printStackTrace(); throw new RuntimeException("Could not create cipher"); } } - private static byte[] getHmac(byte[] payload, SecretKey secretKey) throws NoSuchAlgorithmException, InvalidKeyException { - Mac mac = Mac.getInstance(HMAC); + private static byte[] getHmac(byte[] payload, SecretKey secretKey) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException { + Mac mac = Mac.getInstance(HMAC, "BC"); mac.init(secretKey); return mac.doFinal(payload); } @@ -170,11 +174,11 @@ public class Encryption { public static byte[] encrypt(byte[] payload, PublicKey publicKey) throws CryptoException { try { - Cipher cipher = Cipher.getInstance(ASYM_CIPHER); + Cipher cipher = Cipher.getInstance(ASYM_CIPHER, "BC"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return cipher.doFinal(payload); } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException - | BadPaddingException | IllegalBlockSizeException e) { + | BadPaddingException | IllegalBlockSizeException | NoSuchProviderException e) { e.printStackTrace(); throw new CryptoException("Couldn't encrypt payload"); } @@ -182,11 +186,11 @@ public class Encryption { public static byte[] decrypt(byte[] encryptedPayload, PrivateKey privateKey) throws CryptoException { try { - Cipher cipher = Cipher.getInstance(ASYM_CIPHER); + Cipher cipher = Cipher.getInstance(ASYM_CIPHER, "BC"); cipher.init(Cipher.DECRYPT_MODE, privateKey); return cipher.doFinal(encryptedPayload); } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException - | BadPaddingException | IllegalBlockSizeException e) { + | BadPaddingException | IllegalBlockSizeException | NoSuchProviderException e) { // errors when trying to decrypt foreign messages are normal throw new CryptoException(e); } @@ -199,14 +203,13 @@ public class Encryption { /** * @param payload The data to encrypt. - * @param sigPrivateKey The private key for signing. - * @param sigPublicKey The public key used for signing. + * @param signatureKeyPair The key pair for signing. * @param encryptionPublicKey The public key used for encryption. * @return A SealedAndSigned object. * @throws CryptoException */ - public static SealedAndSigned encryptHybridWithSignature(Serializable payload, PrivateKey sigPrivateKey, - PublicKey sigPublicKey, PublicKey encryptionPublicKey) + public static SealedAndSigned encryptHybridWithSignature(Serializable payload, KeyPair signatureKeyPair, + PublicKey encryptionPublicKey) throws CryptoException { // Create a symmetric key SecretKey secretKey = generateSecretKey(); @@ -214,22 +217,15 @@ public class Encryption { // Encrypt secretKey with receivers publicKey byte[] encryptedSecretKey = encrypt(secretKey.getEncoded(), encryptionPublicKey); - // Encrypt with sym key and add hmac + // Encrypt with sym key payload with appended hmac byte[] encryptedPayloadWithHmac = encryptPayloadWithHmac(payload, secretKey); // sign hash of encryptedPayloadWithHmac byte[] hash = Hash.getHash(encryptedPayloadWithHmac); - try { - byte[] signature = Sig.sign(sigPrivateKey, hash); - - // Pack all together - return new SealedAndSigned(encryptedSecretKey, encryptedPayloadWithHmac, signature, sigPublicKey); - } catch (SignatureException | NoSuchAlgorithmException | InvalidKeyException e) { - e.printStackTrace(); - throw new CryptoException(e); - } - + byte[] signature = Sig.sign(signatureKeyPair.getPrivate(), hash); + // Pack all together + return new SealedAndSigned(encryptedSecretKey, encryptedPayloadWithHmac, signature, signatureKeyPair.getPublic()); } /** @@ -240,18 +236,14 @@ public class Encryption { */ public static DecryptedPayloadWithPubKey decryptHybridWithSignature(SealedAndSigned sealedAndSigned, PrivateKey privateKey) throws CryptoException { SecretKey secretKey = getSecretKeyFromBytes(decrypt(sealedAndSigned.encryptedSecretKey, privateKey)); - try { - boolean isValid = Sig.verify(sealedAndSigned.sigPublicKey, - Hash.getHash(sealedAndSigned.encryptedPayloadWithHmac), - sealedAndSigned.signature); - if (!isValid) - throw new CryptoException("Signature verification failed."); - - Serializable decryptedPayload = Utilities.deserialize(decryptPayloadWithHmac(sealedAndSigned.encryptedPayloadWithHmac, secretKey)); - return new DecryptedPayloadWithPubKey(decryptedPayload, sealedAndSigned.sigPublicKey); - } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException e) { + boolean isValid = Sig.verify(sealedAndSigned.sigPublicKey, + Hash.getHash(sealedAndSigned.encryptedPayloadWithHmac), + sealedAndSigned.signature); + if (!isValid) throw new CryptoException("Signature verification failed."); - } + + Serializable decryptedPayload = Utilities.deserialize(decryptPayloadWithHmac(sealedAndSigned.encryptedPayloadWithHmac, secretKey)); + return new DecryptedPayloadWithPubKey(decryptedPayload, sealedAndSigned.sigPublicKey); } @@ -265,10 +257,11 @@ public class Encryption { private static SecretKey generateSecretKey() { try { - KeyGenerator keyPairGenerator = KeyGenerator.getInstance(SYM_CIPHER); + KeyGenerator keyPairGenerator = KeyGenerator.getInstance(SYM_CIPHER, "BC"); keyPairGenerator.init(256); return keyPairGenerator.generateKey(); - } catch (NoSuchAlgorithmException e) { + } catch (NoSuchAlgorithmException | NoSuchProviderException e) { + e.printStackTrace(); throw new RuntimeException("Couldn't generate key"); } } diff --git a/common/src/main/java/io/bitsquare/common/crypto/Hash.java b/common/src/main/java/io/bitsquare/common/crypto/Hash.java index bbeffb0700..8a780d153e 100644 --- a/common/src/main/java/io/bitsquare/common/crypto/Hash.java +++ b/common/src/main/java/io/bitsquare/common/crypto/Hash.java @@ -27,6 +27,7 @@ import java.io.Serializable; import java.nio.ByteBuffer; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; public class Hash { private static final Logger log = LoggerFactory.getLogger(Hash.class); @@ -38,8 +39,8 @@ public class Hash { public static byte[] getHash(byte[] data) { MessageDigest digest; try { - digest = MessageDigest.getInstance("SHA-256"); - } catch (NoSuchAlgorithmException e) { + digest = MessageDigest.getInstance("SHA-256", "BC"); + } catch (NoSuchAlgorithmException | NoSuchProviderException e) { log.error("Could not create MessageDigest for hash. " + e.getMessage()); throw new RuntimeException(e); } diff --git a/common/src/main/java/io/bitsquare/common/crypto/KeyRing.java b/common/src/main/java/io/bitsquare/common/crypto/KeyRing.java index 3c8d6959c0..ad865f7490 100644 --- a/common/src/main/java/io/bitsquare/common/crypto/KeyRing.java +++ b/common/src/main/java/io/bitsquare/common/crypto/KeyRing.java @@ -21,7 +21,6 @@ import javax.inject.Inject; import java.security.KeyPair; public class KeyRing { - private final KeyPair signatureKeyPair; private final KeyPair encryptionKeyPair; private final PubKeyRing pubKeyRing; @@ -52,4 +51,36 @@ public class KeyRing { public PubKeyRing getPubKeyRing() { return pubKeyRing; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof KeyRing)) return false; + + KeyRing keyRing = (KeyRing) o; + + if (signatureKeyPair != null ? !signatureKeyPair.equals(keyRing.signatureKeyPair) : keyRing.signatureKeyPair != null) + return false; + if (encryptionKeyPair != null ? !encryptionKeyPair.equals(keyRing.encryptionKeyPair) : keyRing.encryptionKeyPair != null) + return false; + return !(pubKeyRing != null ? !pubKeyRing.equals(keyRing.pubKeyRing) : keyRing.pubKeyRing != null); + + } + + @Override + public int hashCode() { + int result = signatureKeyPair != null ? signatureKeyPair.hashCode() : 0; + result = 31 * result + (encryptionKeyPair != null ? encryptionKeyPair.hashCode() : 0); + result = 31 * result + (pubKeyRing != null ? pubKeyRing.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "KeyRing{" + + "signatureKeyPair.hashCode()=" + signatureKeyPair.hashCode() + + ", encryptionKeyPair.hashCode()=" + encryptionKeyPair.hashCode() + + ", pubKeyRing.hashCode()=" + pubKeyRing.hashCode() + + '}'; + } } diff --git a/common/src/main/java/io/bitsquare/common/crypto/KeyStorage.java b/common/src/main/java/io/bitsquare/common/crypto/KeyStorage.java index 13b1937aaf..af9db573e7 100644 --- a/common/src/main/java/io/bitsquare/common/crypto/KeyStorage.java +++ b/common/src/main/java/io/bitsquare/common/crypto/KeyStorage.java @@ -34,6 +34,7 @@ import java.security.interfaces.DSAPrivateKey; import java.security.interfaces.RSAPrivateCrtKey; import java.security.spec.*; +// TODO: use a password protection for storage? public class KeyStorage { private static final Logger log = LoggerFactory.getLogger(KeyStorage.class); @@ -41,7 +42,7 @@ public class KeyStorage { public enum KeyEntry { MSG_SIGNATURE("sig", Sig.KEY_ALGO), - MSG_ENCRYPTION("enc", Encryption.ENCR_KEY_ALGO); + MSG_ENCRYPTION("enc", Encryption.ASYM_KEY_ALGO); private final String fileName; private final String algorithm; @@ -87,7 +88,7 @@ public class KeyStorage { public KeyPair loadKeyPair(KeyEntry keyEntry) { // long now = System.currentTimeMillis(); try { - KeyFactory keyFactory = KeyFactory.getInstance(keyEntry.getAlgorithm()); + KeyFactory keyFactory = KeyFactory.getInstance(keyEntry.getAlgorithm(), "BC"); PublicKey publicKey; PrivateKey privateKey; @@ -123,7 +124,7 @@ public class KeyStorage { //log.info("load completed in {} msec", System.currentTimeMillis() - now); return new KeyPair(publicKey, privateKey); - } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { + } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException e) { e.printStackTrace(); log.error(e.getMessage()); throw new RuntimeException("Could not load key " + keyEntry.toString(), e); diff --git a/common/src/main/java/io/bitsquare/common/crypto/PubKeyRing.java b/common/src/main/java/io/bitsquare/common/crypto/PubKeyRing.java index 309f674957..61740ca5c2 100644 --- a/common/src/main/java/io/bitsquare/common/crypto/PubKeyRing.java +++ b/common/src/main/java/io/bitsquare/common/crypto/PubKeyRing.java @@ -26,13 +26,14 @@ import java.io.ObjectInputStream; import java.io.Serializable; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; /** * Same as KeyRing but with public keys only. - * Used to sent over the wire to other peer. + * Used to send public keys over the wire to other peer. */ public class PubKeyRing implements Serializable { // That object is sent over the wire, so we need to take care of version compatibility. @@ -57,9 +58,9 @@ public class PubKeyRing implements Serializable { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { try { in.defaultReadObject(); - signaturePubKey = KeyFactory.getInstance(Sig.KEY_ALGO).generatePublic(new X509EncodedKeySpec(signaturePubKeyBytes)); - encryptionPubKey = KeyFactory.getInstance(Encryption.ENCR_KEY_ALGO).generatePublic(new X509EncodedKeySpec(encryptionPubKeyBytes)); - } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { + signaturePubKey = KeyFactory.getInstance(Sig.KEY_ALGO, "BC").generatePublic(new X509EncodedKeySpec(signaturePubKeyBytes)); + encryptionPubKey = KeyFactory.getInstance(Encryption.ASYM_KEY_ALGO, "BC").generatePublic(new X509EncodedKeySpec(encryptionPubKeyBytes)); + } catch (InvalidKeySpecException | NoSuchAlgorithmException | NoSuchProviderException e) { e.printStackTrace(); log.error(e.getMessage()); } catch (Throwable t) { @@ -98,8 +99,8 @@ public class PubKeyRing implements Serializable { @Override public String toString() { return "PubKeyRing{" + - "\n\nmsgSignaturePubKey=\n" + Util.pubKeyToString(getSignaturePubKey()) + - "\n\nmsgEncryptionPubKey=\n" + Util.pubKeyToString(getEncryptionPubKey()) + + "\n\nsignaturePubKey=\n" + Util.pubKeyToString(getSignaturePubKey()) + + "\n\nencryptionPubKey=\n" + Util.pubKeyToString(getEncryptionPubKey()) + '}'; } diff --git a/common/src/main/java/io/bitsquare/common/crypto/SealedAndSigned.java b/common/src/main/java/io/bitsquare/common/crypto/SealedAndSigned.java index 458b23a52c..5da7220c8b 100644 --- a/common/src/main/java/io/bitsquare/common/crypto/SealedAndSigned.java +++ b/common/src/main/java/io/bitsquare/common/crypto/SealedAndSigned.java @@ -23,11 +23,6 @@ import java.io.Serializable; import java.security.PublicKey; import java.util.Arrays; -/** - * Packs the encrypted symmetric secretKey and the encrypted and signed message into one object. - * SecretKey is encrypted with asymmetric pubKey of peer. Signed message is encrypted with secretKey. - * Using that hybrid encryption model we are not restricted by data size and performance as symmetric encryption is very fast. - */ public final class SealedAndSigned implements Serializable { // That object is sent over the wire, so we need to take care of version compatibility. private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION; diff --git a/common/src/main/java/io/bitsquare/common/crypto/Sig.java b/common/src/main/java/io/bitsquare/common/crypto/Sig.java index 3de75442fb..0021545f90 100644 --- a/common/src/main/java/io/bitsquare/common/crypto/Sig.java +++ b/common/src/main/java/io/bitsquare/common/crypto/Sig.java @@ -36,7 +36,7 @@ public class Sig { private static final Logger log = LoggerFactory.getLogger(Sig.class); public static final String KEY_ALGO = "DSA"; - public static final String ALGO = "SHA1withDSA"; //TODO better SHA512withECDSA + public static final String ALGO = "SHA256withDSA"; /** @@ -45,12 +45,12 @@ public class Sig { public static KeyPair generateKeyPair() { long ts = System.currentTimeMillis(); try { - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGO); + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGO, "BC"); keyPairGenerator.initialize(1024); KeyPair keyPair = keyPairGenerator.genKeyPair(); log.trace("Generate msgSignatureKeyPair needed {} ms", System.currentTimeMillis() - ts); return keyPair; - } catch (NoSuchAlgorithmException e) { + } catch (NoSuchAlgorithmException | NoSuchProviderException e) { e.printStackTrace(); throw new RuntimeException("Could not create key."); } @@ -65,12 +65,15 @@ public class Sig { * @throws NoSuchAlgorithmException * @throws InvalidKeyException */ - public static byte[] sign(PrivateKey privateKey, byte[] data) - throws SignatureException, NoSuchAlgorithmException, InvalidKeyException { - Signature sig = Signature.getInstance(ALGO); - sig.initSign(privateKey); - sig.update(data); - return sig.sign(); + public static byte[] sign(PrivateKey privateKey, byte[] data) throws CryptoException { + try { + Signature sig = Signature.getInstance(ALGO, "BC"); + sig.initSign(privateKey); + sig.update(data); + return sig.sign(); + } catch (SignatureException | NoSuchProviderException | InvalidKeyException | NoSuchAlgorithmException e) { + throw new CryptoException("Signing failed. " + e.getMessage()); + } } /** @@ -81,8 +84,7 @@ public class Sig { * @throws NoSuchAlgorithmException * @throws InvalidKeyException */ - public static String sign(PrivateKey privateKey, String message) - throws SignatureException, NoSuchAlgorithmException, InvalidKeyException { + public static String sign(PrivateKey privateKey, String message) throws CryptoException { byte[] sigAsBytes = sign(privateKey, message.getBytes(Charsets.UTF_8)); return Base64.toBase64String(sigAsBytes); } @@ -96,12 +98,16 @@ public class Sig { * @throws InvalidKeyException * @throws SignatureException */ - public static boolean verify(PublicKey publicKey, byte[] data, byte[] signature) - throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { - Signature sig = Signature.getInstance(ALGO); - sig.initVerify(publicKey); - sig.update(data); - return sig.verify(signature); + public static boolean verify(PublicKey publicKey, byte[] data, byte[] signature) throws CryptoException { + byte[] sigAsBytes = new byte[0]; + try { + Signature sig = Signature.getInstance(ALGO, "BC"); + sig.initVerify(publicKey); + sig.update(data); + return sig.verify(signature); + } catch (SignatureException | NoSuchProviderException | InvalidKeyException | NoSuchAlgorithmException e) { + throw new CryptoException("Signature verification failed. " + e.getMessage()); + } } /** @@ -113,8 +119,7 @@ public class Sig { * @throws InvalidKeyException * @throws SignatureException */ - public static boolean verify(PublicKey publicKey, String message, String signature) - throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { + public static boolean verify(PublicKey publicKey, String message, String signature) throws CryptoException { return verify(publicKey, message.getBytes(Charsets.UTF_8), Base64.decode(signature)); } } diff --git a/common/src/main/java/io/bitsquare/common/crypto/Util.java b/common/src/main/java/io/bitsquare/common/crypto/Util.java index 1c5f514241..5c56eed8ae 100644 --- a/common/src/main/java/io/bitsquare/common/crypto/Util.java +++ b/common/src/main/java/io/bitsquare/common/crypto/Util.java @@ -17,18 +17,14 @@ package io.bitsquare.common.crypto; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.security.PublicKey; import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; public class Util { - private static final Logger log = LoggerFactory.getLogger(Util.class); - public static String pubKeyToString(PublicKey publicKey) { final X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey.getEncoded()); - return java.util.Base64.getEncoder().encodeToString(x509EncodedKeySpec.getEncoded()); + return Base64.getEncoder().encodeToString(x509EncodedKeySpec.getEncoded()); } } diff --git a/core/src/main/java/io/bitsquare/arbitration/DisputeManager.java b/core/src/main/java/io/bitsquare/arbitration/DisputeManager.java index 6ff800ca0e..a0d6aa5353 100644 --- a/core/src/main/java/io/bitsquare/arbitration/DisputeManager.java +++ b/core/src/main/java/io/bitsquare/arbitration/DisputeManager.java @@ -30,7 +30,7 @@ import io.bitsquare.p2p.Address; import io.bitsquare.p2p.Message; import io.bitsquare.p2p.P2PService; import io.bitsquare.p2p.P2PServiceListener; -import io.bitsquare.p2p.messaging.DecryptedMessageWithPubKey; +import io.bitsquare.p2p.messaging.DecryptedMsgWithPubKey; import io.bitsquare.p2p.messaging.SendMailboxMessageListener; import io.bitsquare.storage.Storage; import io.bitsquare.trade.Contract; @@ -68,8 +68,8 @@ public class DisputeManager { transient private final ObservableList disputesObservableList; private final String disputeInfo; private final P2PServiceListener p2PServiceListener; - private final List decryptedMailboxMessageWithPubKeys = new CopyOnWriteArrayList<>(); - private final List decryptedMailMessageWithPubKeys = new CopyOnWriteArrayList<>(); + private final List decryptedMailboxMessageWithPubKeys = new CopyOnWriteArrayList<>(); + private final List decryptedMailMessageWithPubKeys = new CopyOnWriteArrayList<>(); /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/core/src/main/java/io/bitsquare/crypto/ScryptUtil.java b/core/src/main/java/io/bitsquare/crypto/ScryptUtil.java index 8d45506739..21adecae61 100644 --- a/core/src/main/java/io/bitsquare/crypto/ScryptUtil.java +++ b/core/src/main/java/io/bitsquare/crypto/ScryptUtil.java @@ -8,25 +8,25 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongycastle.crypto.params.KeyParameter; -//TODO +//TODO: Borrowed form BitcoinJ/Lighthouse. Remove Protos dependency, check complete code logic. public class ScryptUtil { private static final Logger log = LoggerFactory.getLogger(ScryptUtil.class); - public ScryptUtil() { - } - - public static final Protos.ScryptParameters SCRYPT_PARAMETERS = Protos.ScryptParameters.newBuilder() - .setP(6) - .setR(8) - .setN(32768) - .setSalt(ByteString.copyFrom(KeyCrypterScrypt.randomSalt())) - .build(); - - public interface ScryptKeyDerivationResultHandler { + public interface DeriveKeyResultHandler { void handleResult(KeyParameter aesKey); } - public static void deriveKeyWithScrypt(KeyCrypterScrypt keyCrypterScrypt, String password, ScryptKeyDerivationResultHandler resultHandler) { + public static KeyCrypterScrypt getKeyCrypterScrypt() { + Protos.ScryptParameters scryptParameters = Protos.ScryptParameters.newBuilder() + .setP(6) + .setR(8) + .setN(32768) + .setSalt(ByteString.copyFrom(KeyCrypterScrypt.randomSalt())) + .build(); + return new KeyCrypterScrypt(scryptParameters); + } + + public static void deriveKeyWithScrypt(KeyCrypterScrypt keyCrypterScrypt, String password, DeriveKeyResultHandler resultHandler) { new Thread(() -> { log.info("Doing key derivation"); diff --git a/core/src/main/java/io/bitsquare/trade/Trade.java b/core/src/main/java/io/bitsquare/trade/Trade.java index 501a7fd27a..16a427c0c2 100644 --- a/core/src/main/java/io/bitsquare/trade/Trade.java +++ b/core/src/main/java/io/bitsquare/trade/Trade.java @@ -30,7 +30,7 @@ import io.bitsquare.common.crypto.KeyRing; import io.bitsquare.common.taskrunner.Model; import io.bitsquare.p2p.Address; import io.bitsquare.p2p.P2PService; -import io.bitsquare.p2p.messaging.DecryptedMessageWithPubKey; +import io.bitsquare.p2p.messaging.DecryptedMsgWithPubKey; import io.bitsquare.storage.Storage; import io.bitsquare.trade.offer.Offer; import io.bitsquare.trade.offer.OpenOfferManager; @@ -149,7 +149,7 @@ abstract public class Trade implements Tradable, Model, Serializable { private final ProcessModel processModel; // Mutable - private DecryptedMessageWithPubKey decryptedMessageWithPubKey; + private DecryptedMsgWithPubKey decryptedMsgWithPubKey; private Date takeOfferDate = new Date(0); // in some error cases the date is not set and cause null pointers, so we set a default protected State state; @@ -236,8 +236,8 @@ abstract public class Trade implements Tradable, Model, Serializable { tradeProtocol.checkPayoutTxTimeLock(this); - if (decryptedMessageWithPubKey != null) { - tradeProtocol.applyMailboxMessage(decryptedMessageWithPubKey, this); + if (decryptedMsgWithPubKey != null) { + tradeProtocol.applyMailboxMessage(decryptedMsgWithPubKey, this); } } @@ -280,13 +280,13 @@ abstract public class Trade implements Tradable, Model, Serializable { return depositTx; } - public void setMailboxMessage(DecryptedMessageWithPubKey decryptedMessageWithPubKey) { - log.trace("setMailboxMessage " + decryptedMessageWithPubKey); - this.decryptedMessageWithPubKey = decryptedMessageWithPubKey; + public void setMailboxMessage(DecryptedMsgWithPubKey decryptedMsgWithPubKey) { + log.trace("setMailboxMessage " + decryptedMsgWithPubKey); + this.decryptedMsgWithPubKey = decryptedMsgWithPubKey; } - public DecryptedMessageWithPubKey getMailboxMessage() { - return decryptedMessageWithPubKey; + public DecryptedMsgWithPubKey getMailboxMessage() { + return decryptedMsgWithPubKey; } public void setStorage(Storage storage) { @@ -618,7 +618,7 @@ abstract public class Trade implements Tradable, Model, Serializable { ", date=" + takeOfferDate + ", processModel=" + processModel + ", processState=" + state + - ", messageWithPubKey=" + decryptedMessageWithPubKey + + ", messageWithPubKey=" + decryptedMsgWithPubKey + ", depositTx=" + depositTx + /* ", contract=" + contract + ", contractAsJson='" + contractAsJson + '\'' +*/ diff --git a/core/src/main/java/io/bitsquare/trade/TradeManager.java b/core/src/main/java/io/bitsquare/trade/TradeManager.java index 8b49cfe112..075b4b5f1c 100644 --- a/core/src/main/java/io/bitsquare/trade/TradeManager.java +++ b/core/src/main/java/io/bitsquare/trade/TradeManager.java @@ -31,7 +31,7 @@ import io.bitsquare.p2p.P2PService; import io.bitsquare.p2p.P2PServiceListener; import io.bitsquare.p2p.messaging.DecryptedMailListener; import io.bitsquare.p2p.messaging.DecryptedMailboxListener; -import io.bitsquare.p2p.messaging.DecryptedMessageWithPubKey; +import io.bitsquare.p2p.messaging.DecryptedMsgWithPubKey; import io.bitsquare.storage.Storage; import io.bitsquare.trade.closed.ClosedTradableManager; import io.bitsquare.trade.failed.FailedTradesManager; @@ -114,8 +114,8 @@ public class TradeManager { p2PService.addDecryptedMailListener(new DecryptedMailListener() { @Override - public void onMailMessage(DecryptedMessageWithPubKey decryptedMessageWithPubKey, Address peerAddress) { - Message message = decryptedMessageWithPubKey.message; + public void onMailMessage(DecryptedMsgWithPubKey decryptedMsgWithPubKey, Address peerAddress) { + Message message = decryptedMsgWithPubKey.message; // Handler for incoming initial messages from taker if (message instanceof PayDepositRequest) { @@ -126,10 +126,10 @@ public class TradeManager { }); p2PService.addDecryptedMailboxListener(new DecryptedMailboxListener() { @Override - public void onMailboxMessageAdded(DecryptedMessageWithPubKey decryptedMessageWithPubKey, Address senderAddress) { - log.trace("onMailboxMessageAdded decryptedMessageWithPubKey: " + decryptedMessageWithPubKey); + public void onMailboxMessageAdded(DecryptedMsgWithPubKey decryptedMsgWithPubKey, Address senderAddress) { + log.trace("onMailboxMessageAdded decryptedMessageWithPubKey: " + decryptedMsgWithPubKey); log.trace("onMailboxMessageAdded senderAddress: " + senderAddress); - Message message = decryptedMessageWithPubKey.message; + Message message = decryptedMsgWithPubKey.message; if (message instanceof PayDepositRequest) { //TODO is that used???? PayDepositRequest payDepositRequest = (PayDepositRequest) message; @@ -143,7 +143,7 @@ public class TradeManager { String tradeId = ((TradeMessage) message).tradeId; Optional tradeOptional = trades.stream().filter(e -> e.getId().equals(tradeId)).findAny(); if (tradeOptional.isPresent()) - tradeOptional.get().setMailboxMessage(decryptedMessageWithPubKey); + tradeOptional.get().setMailboxMessage(decryptedMsgWithPubKey); } } }); @@ -203,7 +203,7 @@ public class TradeManager { initTrade(trade); // after we are authenticated we remove mailbox messages. - DecryptedMessageWithPubKey mailboxMessage = trade.getMailboxMessage(); + DecryptedMsgWithPubKey mailboxMessage = trade.getMailboxMessage(); if (mailboxMessage != null) { p2PService.removeEntryFromMailbox(mailboxMessage); trade.setMailboxMessage(null); diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/TradeProtocol.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/TradeProtocol.java index 2150668426..0ac5eef7d3 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/TradeProtocol.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/TradeProtocol.java @@ -22,7 +22,7 @@ import io.bitsquare.common.crypto.PubKeyRing; import io.bitsquare.p2p.Address; import io.bitsquare.p2p.Message; import io.bitsquare.p2p.messaging.DecryptedMailListener; -import io.bitsquare.p2p.messaging.DecryptedMessageWithPubKey; +import io.bitsquare.p2p.messaging.DecryptedMsgWithPubKey; import io.bitsquare.trade.OffererTrade; import io.bitsquare.trade.TakerTrade; import io.bitsquare.trade.Trade; @@ -94,10 +94,10 @@ public abstract class TradeProtocol { } - public void applyMailboxMessage(DecryptedMessageWithPubKey decryptedMessageWithPubKey, Trade trade) { - log.debug("applyMailboxMessage " + decryptedMessageWithPubKey.message); - if (decryptedMessageWithPubKey.signaturePubKey.equals(processModel.tradingPeer.getPubKeyRing().getSignaturePubKey())) - doApplyMailboxMessage(decryptedMessageWithPubKey.message, trade); + public void applyMailboxMessage(DecryptedMsgWithPubKey decryptedMsgWithPubKey, Trade trade) { + log.debug("applyMailboxMessage " + decryptedMsgWithPubKey.message); + if (decryptedMsgWithPubKey.signaturePubKey.equals(processModel.tradingPeer.getPubKeyRing().getSignaturePubKey())) + doApplyMailboxMessage(decryptedMsgWithPubKey.message, trade); else log.error("SignaturePubKey in message does not match the SignaturePubKey we have stored to that trading peer."); } diff --git a/gui/src/main/java/io/bitsquare/gui/main/account/content/password/PasswordView.java b/gui/src/main/java/io/bitsquare/gui/main/account/content/password/PasswordView.java index 27a750447b..04ba6a9541 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/account/content/password/PasswordView.java +++ b/gui/src/main/java/io/bitsquare/gui/main/account/content/password/PasswordView.java @@ -103,7 +103,8 @@ public class PasswordView extends ActivatableView { if (wallet.isEncrypted()) keyCrypterScrypt = (KeyCrypterScrypt) wallet.getKeyCrypter(); else - keyCrypterScrypt = new KeyCrypterScrypt(ScryptUtil.SCRYPT_PARAMETERS); + keyCrypterScrypt = ScryptUtil.getKeyCrypterScrypt(); + ScryptUtil.deriveKeyWithScrypt(keyCrypterScrypt, passwordField.getText(), aesKey -> { deriveStatusLabel.setText(""); diff --git a/network/src/main/java/io/bitsquare/crypto/EncryptionService.java b/network/src/main/java/io/bitsquare/crypto/EncryptionService.java index 46f861059a..c53556ca97 100644 --- a/network/src/main/java/io/bitsquare/crypto/EncryptionService.java +++ b/network/src/main/java/io/bitsquare/crypto/EncryptionService.java @@ -19,7 +19,7 @@ package io.bitsquare.crypto; import io.bitsquare.common.crypto.*; import io.bitsquare.p2p.Message; -import io.bitsquare.p2p.messaging.DecryptedMessageWithPubKey; +import io.bitsquare.p2p.messaging.DecryptedMsgWithPubKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,22 +36,19 @@ public class EncryptionService { this.keyRing = keyRing; } - public SealedAndSigned encryptAndSignMessage(PubKeyRing pubKeyRing, Message message) throws CryptoException { - log.trace("encryptAndSignMessage message = " + message); + public SealedAndSigned encryptAndSign(PubKeyRing pubKeyRing, Message message) throws CryptoException { KeyPair signatureKeyPair = keyRing.getSignatureKeyPair(); - return Encryption.encryptHybridWithSignature(message, - signatureKeyPair.getPrivate(), - signatureKeyPair.getPublic(), - pubKeyRing.getEncryptionPubKey()); + return Encryption.encryptHybridWithSignature(message, signatureKeyPair, pubKeyRing.getEncryptionPubKey()); } - public DecryptedMessageWithPubKey decryptAndVerifyMessage(SealedAndSigned sealedAndSigned) throws CryptoException { - DecryptedPayloadWithPubKey decryptedPayloadWithPubKey = Encryption.decryptHybridWithSignature(sealedAndSigned, keyRing.getEncryptionKeyPair().getPrivate()); + public DecryptedMsgWithPubKey decryptAndVerify(SealedAndSigned sealedAndSigned) throws CryptoException { + DecryptedPayloadWithPubKey decryptedPayloadWithPubKey = Encryption.decryptHybridWithSignature(sealedAndSigned, + keyRing.getEncryptionKeyPair().getPrivate()); if (decryptedPayloadWithPubKey.payload instanceof Message) { - //log.trace("Decryption needed {} ms", System.currentTimeMillis() - ts); - return new DecryptedMessageWithPubKey((Message) decryptedPayloadWithPubKey.payload, decryptedPayloadWithPubKey.sigPublicKey); + return new DecryptedMsgWithPubKey((Message) decryptedPayloadWithPubKey.payload, + decryptedPayloadWithPubKey.sigPublicKey); } else { - throw new CryptoException("messageObject is not instance of Message"); + throw new CryptoException("decryptedPayloadWithPubKey.payload is not instance of Message"); } } } diff --git a/network/src/main/java/io/bitsquare/crypto/SealedAndSignedMessage.java b/network/src/main/java/io/bitsquare/crypto/SealedAndSignedMessage.java index 9a08a69b7b..3a1d4d551f 100644 --- a/network/src/main/java/io/bitsquare/crypto/SealedAndSignedMessage.java +++ b/network/src/main/java/io/bitsquare/crypto/SealedAndSignedMessage.java @@ -3,11 +3,8 @@ package io.bitsquare.crypto; import io.bitsquare.common.crypto.SealedAndSigned; import io.bitsquare.p2p.Address; import io.bitsquare.p2p.messaging.MailboxMessage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class SealedAndSignedMessage implements MailboxMessage { - private static final Logger log = LoggerFactory.getLogger(SealedAndSignedMessage.class); public final SealedAndSigned sealedAndSigned; public final Address peerAddress; diff --git a/network/src/main/java/io/bitsquare/p2p/P2PService.java b/network/src/main/java/io/bitsquare/p2p/P2PService.java index 78eecf587a..658ab740aa 100644 --- a/network/src/main/java/io/bitsquare/p2p/P2PService.java +++ b/network/src/main/java/io/bitsquare/p2p/P2PService.java @@ -33,10 +33,7 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; import java.security.PublicKey; -import java.security.SignatureException; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; @@ -62,7 +59,7 @@ public class P2PService { private final List decryptedMailListeners = new CopyOnWriteArrayList<>(); private final List decryptedMailboxListeners = new CopyOnWriteArrayList<>(); private final List p2pServiceListeners = new CopyOnWriteArrayList<>(); - private final Map mailboxMap = new ConcurrentHashMap<>(); + private final Map mailboxMap = new ConcurrentHashMap<>(); private volatile boolean shutDownInProgress; private List
seedNodeAddresses; private List
connectedSeedNodes = new CopyOnWriteArrayList<>(); @@ -205,18 +202,18 @@ public class P2PService { HashSet set = ((DataSetMessage) message).set; set.stream().forEach(e -> dataStorage.add(e, connection.getPeerAddress())); - // TODO done in addHashSetChangedListener - // set.stream().filter(e -> e instanceof ProtectedMailboxData).forEach(e -> tryDecryptMailboxData((ProtectedMailboxData) e)); - dataReceived(); } else if (message instanceof SealedAndSignedMessage) { if (encryptionService != null) { try { SealedAndSignedMessage sealedAndSignedMessage = (SealedAndSignedMessage) message; - DecryptedMessageWithPubKey decryptedMessageWithPubKey = encryptionService.decryptAndVerifyMessage(sealedAndSignedMessage.sealedAndSigned); - UserThread.execute(() -> decryptedMailListeners.stream().forEach(e -> e.onMailMessage(decryptedMessageWithPubKey, connection.getPeerAddress()))); + DecryptedMsgWithPubKey decryptedMsgWithPubKey = encryptionService.decryptAndVerify( + sealedAndSignedMessage.sealedAndSigned); + UserThread.execute(() -> decryptedMailListeners.stream().forEach( + e -> e.onMailMessage(decryptedMsgWithPubKey, connection.getPeerAddress()))); } catch (CryptoException e) { - log.info("Decryption of SealedAndSignedMessage failed. That is expected if the message is not intended for us."); + log.info("Decryption of SealedAndSignedMessage failed. " + + "That is expected if the message is not intended for us."); } } } @@ -313,14 +310,14 @@ public class P2PService { return authenticated; } - public void removeEntryFromMailbox(DecryptedMessageWithPubKey decryptedMessageWithPubKey) { + public void removeEntryFromMailbox(DecryptedMsgWithPubKey decryptedMsgWithPubKey) { log.trace("removeEntryFromMailbox"); - ProtectedMailboxData mailboxData = mailboxMap.get(decryptedMessageWithPubKey); + ProtectedMailboxData mailboxData = mailboxMap.get(decryptedMsgWithPubKey); if (mailboxData != null && mailboxData.expirablePayload instanceof ExpirableMailboxPayload) { checkArgument(mailboxData.receiversPubKey.equals(keyRing.getSignatureKeyPair().getPublic()), "mailboxData.receiversPubKey is not matching with our key. That must not happen."); removeMailboxData((ExpirableMailboxPayload) mailboxData.expirablePayload, mailboxData.receiversPubKey); - mailboxMap.remove(decryptedMessageWithPubKey); + mailboxMap.remove(decryptedMsgWithPubKey); log.trace("Removed successfully protectedExpirableData."); } } @@ -329,7 +326,8 @@ public class P2PService { // Messaging /////////////////////////////////////////////////////////////////////////////////////////// - public void sendEncryptedMailMessage(Address peerAddress, PubKeyRing pubKeyRing, MailMessage message, SendMailMessageListener sendMailMessageListener) { + public void sendEncryptedMailMessage(Address peerAddress, PubKeyRing pubKeyRing, MailMessage message, + SendMailMessageListener sendMailMessageListener) { checkNotNull(peerAddress, "PeerAddress must not be null (sendEncryptedMailMessage)"); if (!authenticatedToFirstPeer) @@ -343,10 +341,12 @@ public class P2PService { doSendEncryptedMailMessage(peerAddress, pubKeyRing, message, sendMailMessageListener); } - private void doSendEncryptedMailMessage(Address peerAddress, PubKeyRing pubKeyRing, MailMessage message, SendMailMessageListener sendMailMessageListener) { + private void doSendEncryptedMailMessage(Address peerAddress, PubKeyRing pubKeyRing, MailMessage message, + SendMailMessageListener sendMailMessageListener) { if (encryptionService != null) { try { - SealedAndSignedMessage sealedAndSignedMessage = new SealedAndSignedMessage(encryptionService.encryptAndSignMessage(pubKeyRing, message), peerAddress); + SealedAndSignedMessage sealedAndSignedMessage = new SealedAndSignedMessage( + encryptionService.encryptAndSign(pubKeyRing, message), peerAddress); SettableFuture future = sendMessage(peerAddress, sealedAndSignedMessage); Futures.addCallback(future, new FutureCallback() { @Override @@ -367,7 +367,8 @@ public class P2PService { } } - public void sendEncryptedMailboxMessage(Address peerAddress, PubKeyRing peersPubKeyRing, MailboxMessage message, SendMailboxMessageListener sendMailboxMessageListener) { + public void sendEncryptedMailboxMessage(Address peerAddress, PubKeyRing peersPubKeyRing, + MailboxMessage message, SendMailboxMessageListener sendMailboxMessageListener) { checkNotNull(peerAddress, "PeerAddress must not be null (sendEncryptedMailboxMessage)"); checkArgument(!keyRing.getPubKeyRing().equals(peersPubKeyRing), "We got own keyring instead of that from peer"); @@ -386,10 +387,12 @@ public class P2PService { } } - private void trySendEncryptedMailboxMessage(Address peerAddress, PubKeyRing peersPubKeyRing, MailboxMessage message, SendMailboxMessageListener sendMailboxMessageListener) { + private void trySendEncryptedMailboxMessage(Address peerAddress, PubKeyRing peersPubKeyRing, + MailboxMessage message, SendMailboxMessageListener sendMailboxMessageListener) { if (encryptionService != null) { try { - SealedAndSignedMessage sealedAndSignedMessage = new SealedAndSignedMessage(encryptionService.encryptAndSignMessage(peersPubKeyRing, message), peerAddress); + SealedAndSignedMessage sealedAndSignedMessage = new SealedAndSignedMessage( + encryptionService.encryptAndSign(peersPubKeyRing, message), peerAddress); SettableFuture future = sendMessage(peerAddress, sealedAndSignedMessage); Futures.addCallback(future, new FutureCallback() { @Override @@ -430,8 +433,9 @@ public class P2PService { throw new AuthenticationException("You must be authenticated before adding data to the P2P network."); try { - return dataStorage.add(dataStorage.getDataWithSignedSeqNr(expirablePayload, keyRing.getSignatureKeyPair()), networkNode.getAddress()); - } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException e) { + return dataStorage.add(dataStorage.getDataWithSignedSeqNr(expirablePayload, + keyRing.getSignatureKeyPair()), networkNode.getAddress()); + } catch (CryptoException e) { log.error("Signing at getDataWithSignedSeqNr failed. That should never happen."); return false; } @@ -442,8 +446,9 @@ public class P2PService { throw new AuthenticationException("You must be authenticated before adding data to the P2P network."); try { - return dataStorage.add(dataStorage.getMailboxDataWithSignedSeqNr(expirableMailboxPayload, keyRing.getSignatureKeyPair(), receiversPublicKey), networkNode.getAddress()); - } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException e) { + return dataStorage.add(dataStorage.getMailboxDataWithSignedSeqNr(expirableMailboxPayload, + keyRing.getSignatureKeyPair(), receiversPublicKey), networkNode.getAddress()); + } catch (CryptoException e) { log.error("Signing at getDataWithSignedSeqNr failed. That should never happen."); return false; } @@ -453,8 +458,9 @@ public class P2PService { if (!authenticatedToFirstPeer) throw new AuthenticationException("You must be authenticated before removing data from the P2P network."); try { - return dataStorage.remove(dataStorage.getDataWithSignedSeqNr(expirablePayload, keyRing.getSignatureKeyPair()), networkNode.getAddress()); - } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException e) { + return dataStorage.remove(dataStorage.getDataWithSignedSeqNr(expirablePayload, + keyRing.getSignatureKeyPair()), networkNode.getAddress()); + } catch (CryptoException e) { log.error("Signing at getDataWithSignedSeqNr failed. That should never happen."); return false; } @@ -464,8 +470,9 @@ public class P2PService { if (!authenticatedToFirstPeer) throw new AuthenticationException("You must be authenticated before removing data from the P2P network."); try { - return dataStorage.removeMailboxData(dataStorage.getMailboxDataWithSignedSeqNr(expirableMailboxPayload, keyRing.getSignatureKeyPair(), receiversPublicKey), networkNode.getAddress()); - } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException e) { + return dataStorage.removeMailboxData(dataStorage.getMailboxDataWithSignedSeqNr(expirableMailboxPayload, + keyRing.getSignatureKeyPair(), receiversPublicKey), networkNode.getAddress()); + } catch (CryptoException e) { log.error("Signing at getDataWithSignedSeqNr failed. That should never happen."); return false; } @@ -635,21 +642,26 @@ public class P2PService { ExpirableMailboxPayload mailboxEntry = (ExpirableMailboxPayload) data; SealedAndSigned sealedAndSigned = mailboxEntry.sealedAndSignedMessage.sealedAndSigned; try { - DecryptedMessageWithPubKey decryptedMessageWithPubKey = encryptionService.decryptAndVerifyMessage(sealedAndSigned); - if (decryptedMessageWithPubKey.message instanceof MailboxMessage) { - MailboxMessage mailboxMessage = (MailboxMessage) decryptedMessageWithPubKey.message; + DecryptedMsgWithPubKey decryptedMsgWithPubKey = encryptionService.decryptAndVerify(sealedAndSigned); + if (decryptedMsgWithPubKey.message instanceof MailboxMessage) { + MailboxMessage mailboxMessage = (MailboxMessage) decryptedMsgWithPubKey.message; Address senderAddress = mailboxMessage.getSenderAddress(); checkNotNull(senderAddress, "senderAddress must not be null for mailbox messages"); log.trace("mailboxData.publicKey " + mailboxData.ownerStoragePubKey.hashCode()); - log.trace("keyRing.getStorageSignatureKeyPair().getPublic() " + keyRing.getSignatureKeyPair().getPublic().hashCode()); - log.trace("keyRing.getMsgSignatureKeyPair().getPublic() " + keyRing.getSignatureKeyPair().getPublic().hashCode()); - log.trace("keyRing.getMsgEncryptionKeyPair().getPublic() " + keyRing.getEncryptionKeyPair().getPublic().hashCode()); + log.trace("keyRing.getStorageSignatureKeyPair().getPublic() " + + keyRing.getSignatureKeyPair().getPublic().hashCode()); + log.trace("keyRing.getMsgSignatureKeyPair().getPublic() " + + keyRing.getSignatureKeyPair().getPublic().hashCode()); + log.trace("keyRing.getMsgEncryptionKeyPair().getPublic() " + + keyRing.getEncryptionKeyPair().getPublic().hashCode()); - mailboxMap.put(decryptedMessageWithPubKey, mailboxData); - log.trace("Decryption of SealedAndSignedMessage succeeded. senderAddress=" + senderAddress + " / my address=" + getAddress()); - UserThread.execute(() -> decryptedMailboxListeners.stream().forEach(e -> e.onMailboxMessageAdded(decryptedMessageWithPubKey, senderAddress))); + mailboxMap.put(decryptedMsgWithPubKey, mailboxData); + log.trace("Decryption of SealedAndSignedMessage succeeded. senderAddress=" + + senderAddress + " / my address=" + getAddress()); + UserThread.execute(() -> decryptedMailboxListeners.stream().forEach( + e -> e.onMailboxMessageAdded(decryptedMsgWithPubKey, senderAddress))); } } catch (CryptoException e) { log.trace("Decryption of SealedAndSignedMessage failed. That is expected if the message is not intended for us."); diff --git a/network/src/main/java/io/bitsquare/p2p/messaging/DecryptedMailListener.java b/network/src/main/java/io/bitsquare/p2p/messaging/DecryptedMailListener.java index 533ce41e56..409aefb481 100644 --- a/network/src/main/java/io/bitsquare/p2p/messaging/DecryptedMailListener.java +++ b/network/src/main/java/io/bitsquare/p2p/messaging/DecryptedMailListener.java @@ -4,5 +4,5 @@ import io.bitsquare.p2p.Address; public interface DecryptedMailListener { - void onMailMessage(DecryptedMessageWithPubKey decryptedMessageWithPubKey, Address peerAddress); + void onMailMessage(DecryptedMsgWithPubKey decryptedMsgWithPubKey, Address peerAddress); } diff --git a/network/src/main/java/io/bitsquare/p2p/messaging/DecryptedMailboxListener.java b/network/src/main/java/io/bitsquare/p2p/messaging/DecryptedMailboxListener.java index cd1f435952..f243886fea 100644 --- a/network/src/main/java/io/bitsquare/p2p/messaging/DecryptedMailboxListener.java +++ b/network/src/main/java/io/bitsquare/p2p/messaging/DecryptedMailboxListener.java @@ -4,5 +4,5 @@ import io.bitsquare.p2p.Address; public interface DecryptedMailboxListener { - void onMailboxMessageAdded(DecryptedMessageWithPubKey decryptedMessageWithPubKey, Address senderAddress); + void onMailboxMessageAdded(DecryptedMsgWithPubKey decryptedMsgWithPubKey, Address senderAddress); } diff --git a/network/src/main/java/io/bitsquare/p2p/messaging/DecryptedMessageWithPubKey.java b/network/src/main/java/io/bitsquare/p2p/messaging/DecryptedMsgWithPubKey.java similarity index 87% rename from network/src/main/java/io/bitsquare/p2p/messaging/DecryptedMessageWithPubKey.java rename to network/src/main/java/io/bitsquare/p2p/messaging/DecryptedMsgWithPubKey.java index 892d1338cc..24911eb910 100644 --- a/network/src/main/java/io/bitsquare/p2p/messaging/DecryptedMessageWithPubKey.java +++ b/network/src/main/java/io/bitsquare/p2p/messaging/DecryptedMsgWithPubKey.java @@ -22,14 +22,14 @@ import io.bitsquare.p2p.Message; import java.security.PublicKey; -public final class DecryptedMessageWithPubKey implements MailMessage { +public final class DecryptedMsgWithPubKey implements MailMessage { // That object is sent over the wire, so we need to take care of version compatibility. private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION; public final Message message; public final PublicKey signaturePubKey; - public DecryptedMessageWithPubKey(Message message, PublicKey signaturePubKey) { + public DecryptedMsgWithPubKey(Message message, PublicKey signaturePubKey) { this.message = message; this.signaturePubKey = signaturePubKey; } @@ -37,9 +37,9 @@ public final class DecryptedMessageWithPubKey implements MailMessage { @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof DecryptedMessageWithPubKey)) return false; + if (!(o instanceof DecryptedMsgWithPubKey)) return false; - DecryptedMessageWithPubKey that = (DecryptedMessageWithPubKey) o; + DecryptedMsgWithPubKey that = (DecryptedMsgWithPubKey) o; if (message != null ? !message.equals(that.message) : that.message != null) return false; return !(signaturePubKey != null ? !signaturePubKey.equals(that.signaturePubKey) : that.signaturePubKey != null); diff --git a/network/src/main/java/io/bitsquare/p2p/storage/ProtectedExpirableDataStorage.java b/network/src/main/java/io/bitsquare/p2p/storage/ProtectedExpirableDataStorage.java index 458a4b7d60..d5d176a5f5 100644 --- a/network/src/main/java/io/bitsquare/p2p/storage/ProtectedExpirableDataStorage.java +++ b/network/src/main/java/io/bitsquare/p2p/storage/ProtectedExpirableDataStorage.java @@ -2,6 +2,7 @@ package io.bitsquare.p2p.storage; import com.google.common.annotations.VisibleForTesting; import io.bitsquare.common.UserThread; +import io.bitsquare.common.crypto.CryptoException; import io.bitsquare.common.crypto.Hash; import io.bitsquare.common.crypto.Sig; import io.bitsquare.p2p.Address; @@ -16,7 +17,8 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.math.BigInteger; -import java.security.*; +import java.security.KeyPair; +import java.security.PublicKey; import java.util.List; import java.util.Map; import java.util.Timer; @@ -185,7 +187,8 @@ public class ProtectedExpirableDataStorage { return map; } - public ProtectedData getDataWithSignedSeqNr(ExpirablePayload payload, KeyPair ownerStoragePubKey) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException { + public ProtectedData getDataWithSignedSeqNr(ExpirablePayload payload, KeyPair ownerStoragePubKey) + throws CryptoException { BigInteger hashOfData = getHashAsBigInteger(payload); int sequenceNumber; if (sequenceNumberMap.containsKey(hashOfData)) @@ -198,8 +201,9 @@ public class ProtectedExpirableDataStorage { return new ProtectedData(payload, payload.getTTL(), ownerStoragePubKey.getPublic(), sequenceNumber, signature); } - public ProtectedMailboxData getMailboxDataWithSignedSeqNr(ExpirableMailboxPayload expirableMailboxPayload, KeyPair storageSignaturePubKey, PublicKey receiversPublicKey) - throws NoSuchAlgorithmException, SignatureException, InvalidKeyException { + public ProtectedMailboxData getMailboxDataWithSignedSeqNr(ExpirableMailboxPayload expirableMailboxPayload, + KeyPair storageSignaturePubKey, PublicKey receiversPublicKey) + throws CryptoException { BigInteger hashOfData = getHashAsBigInteger(expirableMailboxPayload); int sequenceNumber; if (sequenceNumberMap.containsKey(hashOfData)) @@ -209,7 +213,8 @@ public class ProtectedExpirableDataStorage { byte[] hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(expirableMailboxPayload, sequenceNumber)); byte[] signature = Sig.sign(storageSignaturePubKey.getPrivate(), hashOfDataAndSeqNr); - return new ProtectedMailboxData(expirableMailboxPayload, expirableMailboxPayload.getTTL(), storageSignaturePubKey.getPublic(), sequenceNumber, signature, receiversPublicKey); + return new ProtectedMailboxData(expirableMailboxPayload, expirableMailboxPayload.getTTL(), + storageSignaturePubKey.getPublic(), sequenceNumber, signature, receiversPublicKey); } public void addHashMapChangedListener(HashMapChangedListener hashMapChangedListener) { @@ -257,7 +262,7 @@ public class ProtectedExpirableDataStorage { "That should not happen. Consider it might be an attempt of fraud."); return result; - } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { + } catch (CryptoException e) { log.error("Signature verification failed at checkSignature"); return false; } diff --git a/network/src/test/java/io/bitsquare/crypto/EncryptionServiceTests.java b/network/src/test/java/io/bitsquare/crypto/EncryptionServiceTests.java index 41bb5f4b25..8113694236 100644 --- a/network/src/test/java/io/bitsquare/crypto/EncryptionServiceTests.java +++ b/network/src/test/java/io/bitsquare/crypto/EncryptionServiceTests.java @@ -24,7 +24,7 @@ import io.bitsquare.common.crypto.KeyStorage; import io.bitsquare.common.crypto.PubKeyRing; import io.bitsquare.common.util.Utilities; import io.bitsquare.p2p.Address; -import io.bitsquare.p2p.messaging.DecryptedMessageWithPubKey; +import io.bitsquare.p2p.messaging.DecryptedMsgWithPubKey; import io.bitsquare.p2p.messaging.MailboxMessage; import org.junit.After; import org.junit.Before; @@ -69,8 +69,8 @@ public class EncryptionServiceTests { public void testDecryptAndVerifyMessage() throws CryptoException { EncryptionService encryptionService = new EncryptionService(keyRing); TestMessage data = new TestMessage("test"); - SealedAndSignedMessage encrypted = new SealedAndSignedMessage(encryptionService.encryptAndSignMessage(pubKeyRing, data), null); - DecryptedMessageWithPubKey decrypted = encryptionService.decryptAndVerifyMessage(encrypted.sealedAndSigned); + SealedAndSignedMessage encrypted = new SealedAndSignedMessage(encryptionService.encryptAndSign(pubKeyRing, data), null); + DecryptedMsgWithPubKey decrypted = encryptionService.decryptAndVerify(encrypted.sealedAndSigned); assertEquals(data.data, ((TestMessage) decrypted.message).data); } diff --git a/network/src/test/java/io/bitsquare/p2p/P2PServiceTest.java b/network/src/test/java/io/bitsquare/p2p/P2PServiceTest.java index 182dd67e73..55445e627e 100644 --- a/network/src/test/java/io/bitsquare/p2p/P2PServiceTest.java +++ b/network/src/test/java/io/bitsquare/p2p/P2PServiceTest.java @@ -3,7 +3,7 @@ package io.bitsquare.p2p; import io.bitsquare.common.crypto.*; import io.bitsquare.crypto.EncryptionService; import io.bitsquare.crypto.SealedAndSignedMessage; -import io.bitsquare.p2p.messaging.DecryptedMessageWithPubKey; +import io.bitsquare.p2p.messaging.DecryptedMsgWithPubKey; import io.bitsquare.p2p.messaging.MailboxMessage; import io.bitsquare.p2p.messaging.SendMailboxMessageListener; import io.bitsquare.p2p.mocks.MockMailboxMessage; @@ -110,7 +110,7 @@ public class P2PServiceTest { } @Test - public void testAdversaryAttacks() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException { + public void testAdversaryAttacks() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException, NoSuchProviderException { p2PService3 = TestUtils.getAndAuthenticateP2PService(8003, encryptionService3, keyRing3, useLocalhost, seedNodes); MockData origData = new MockData("mockData1", keyRing1.getSignatureKeyPair().getPublic()); @@ -273,9 +273,9 @@ public class P2PServiceTest { if (message instanceof SealedAndSignedMessage) { try { SealedAndSignedMessage sealedAndSignedMessage = (SealedAndSignedMessage) message; - DecryptedMessageWithPubKey decryptedMessageWithPubKey = encryptionService2.decryptAndVerifyMessage(sealedAndSignedMessage.sealedAndSigned); - Assert.assertEquals(mockMessage, decryptedMessageWithPubKey.message); - Assert.assertEquals(p2PService2.getAddress(), ((MailboxMessage) decryptedMessageWithPubKey.message).getSenderAddress()); + DecryptedMsgWithPubKey decryptedMsgWithPubKey = encryptionService2.decryptAndVerify(sealedAndSignedMessage.sealedAndSigned); + Assert.assertEquals(mockMessage, decryptedMsgWithPubKey.message); + Assert.assertEquals(p2PService2.getAddress(), ((MailboxMessage) decryptedMsgWithPubKey.message).getSenderAddress()); latch2.countDown(); } catch (CryptoException e) { e.printStackTrace(); diff --git a/network/src/test/java/io/bitsquare/p2p/storage/ProtectedDataStorageTest.java b/network/src/test/java/io/bitsquare/p2p/storage/ProtectedDataStorageTest.java index 1562fe9a14..995324d5d0 100644 --- a/network/src/test/java/io/bitsquare/p2p/storage/ProtectedDataStorageTest.java +++ b/network/src/test/java/io/bitsquare/p2p/storage/ProtectedDataStorageTest.java @@ -80,7 +80,7 @@ public class ProtectedDataStorageTest { } @Test - public void testAddAndRemove() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException { + public void testAddAndRemove() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException, NoSuchProviderException { ProtectedData data = dataStorage1.getDataWithSignedSeqNr(mockData, storageSignatureKeyPair1); Assert.assertTrue(dataStorage1.add(data, null)); Assert.assertEquals(1, dataStorage1.getMap().size()); @@ -94,7 +94,7 @@ public class ProtectedDataStorageTest { } @Test - public void testExpirableData() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException { + public void testExpirableData() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException, NoSuchProviderException { ProtectedExpirableDataStorage.CHECK_TTL_INTERVAL = 10; // CHECK_TTL_INTERVAL is used in constructor of ProtectedExpirableDataStorage so we recreate it here dataStorage1 = new ProtectedExpirableDataStorage(routing1, new File("dummy")); @@ -129,7 +129,7 @@ public class ProtectedDataStorageTest { } @Test - public void testMultiAddRemoveProtectedData() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException { + public void testMultiAddRemoveProtectedData() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException, NoSuchProviderException { MockData mockData = new MockData("msg1", keyRing1.getSignatureKeyPair().getPublic()); ProtectedData data = dataStorage1.getDataWithSignedSeqNr(mockData, storageSignatureKeyPair1); Assert.assertTrue(dataStorage1.add(data, null)); @@ -192,10 +192,11 @@ public class ProtectedDataStorageTest { } @Test - public void testAddAndRemoveMailboxData() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException { + public void testAddAndRemoveMailboxData() throws InterruptedException, NoSuchAlgorithmException, CertificateException, + KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException, NoSuchProviderException { // sender MockMessage mockMessage = new MockMessage("MockMessage"); - SealedAndSignedMessage sealedAndSignedMessage = new SealedAndSignedMessage(encryptionService1.encryptAndSignMessage(keyRing1.getPubKeyRing(), mockMessage), null); + SealedAndSignedMessage sealedAndSignedMessage = new SealedAndSignedMessage(encryptionService1.encryptAndSign(keyRing1.getPubKeyRing(), mockMessage), null); ExpirableMailboxPayload expirableMailboxPayload = new ExpirableMailboxPayload(sealedAndSignedMessage, keyRing1.getSignatureKeyPair().getPublic(), keyRing2.getSignatureKeyPair().getPublic()); diff --git a/pom.xml b/pom.xml index eed25c2558..4507f996f8 100755 --- a/pom.xml +++ b/pom.xml @@ -122,7 +122,7 @@ org.bouncycastle bcprov-jdk15on - 1.52 + 1.53