diff --git a/bootstrap/src/main/java/io/bitsquare/p2p/seed/SeedNodeMain.java b/bootstrap/src/main/java/io/bitsquare/p2p/seed/SeedNodeMain.java index 8d722278ea..68feef2666 100644 --- a/bootstrap/src/main/java/io/bitsquare/p2p/seed/SeedNodeMain.java +++ b/bootstrap/src/main/java/io/bitsquare/p2p/seed/SeedNodeMain.java @@ -1,6 +1,9 @@ package io.bitsquare.p2p.seed; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + import java.security.NoSuchAlgorithmException; +import java.security.Security; public class SeedNodeMain { @@ -8,6 +11,8 @@ public class SeedNodeMain { // eg. 4444 true localhost:7777 localhost:8888 // To stop enter: q public static void main(String[] args) throws NoSuchAlgorithmException { + Security.addProvider(new BouncyCastleProvider()); + SeedNode seedNode = new SeedNode(); seedNode.processArgs(args); seedNode.createAndStartP2PService(); diff --git a/common/src/main/java/io/bitsquare/common/crypto/CryptoUtil.java b/common/src/main/java/io/bitsquare/common/crypto/CryptoUtil.java deleted file mode 100644 index 2f36198076..0000000000 --- a/common/src/main/java/io/bitsquare/common/crypto/CryptoUtil.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 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 . - */ - -package io.bitsquare.common.crypto; - -import io.bitsquare.common.util.Utilities; -import org.bitcoinj.core.Sha256Hash; -import org.bitcoinj.core.Utils; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.util.encoders.Base64; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.nio.ByteBuffer; -import java.security.*; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.X509EncodedKeySpec; - -public class CryptoUtil { - private static final Logger log = LoggerFactory.getLogger(CryptoUtil.class); - public static final String STORAGE_SIGN_KEY_ALGO = "DSA"; - public static final String MSG_SIGN_KEY_ALGO = "DSA"; - public static final String MSG_ENCR_KEY_ALGO = "RSA"; - - public static final String SYM_ENCR_KEY_ALGO = "AES"; - public static final String SYM_CIPHER = "AES"; - public static final String ASYM_CIPHER = "RSA"; //RSA/ECB/PKCS1Padding - public static final String MSG_SIGN_ALGO = "SHA1withDSA"; - - - public static KeyPair generateStorageSignatureKeyPair() throws NoSuchAlgorithmException { - long ts = System.currentTimeMillis(); - final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(STORAGE_SIGN_KEY_ALGO); - keyPairGenerator.initialize(1024); - KeyPair keyPair = keyPairGenerator.genKeyPair(); - log.trace("Generate storageSignatureKeyPair needed {} ms", System.currentTimeMillis() - ts); - return keyPair; - } - - public static KeyPair generateMsgSignatureKeyPair() throws NoSuchAlgorithmException { - long ts = System.currentTimeMillis(); - final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(MSG_SIGN_KEY_ALGO); - keyPairGenerator.initialize(1024); - KeyPair keyPair = keyPairGenerator.genKeyPair(); - log.trace("Generate msgSignatureKeyPair needed {} ms", System.currentTimeMillis() - ts); - return keyPair; - } - - public static KeyPair generateMsgEncryptionKeyPair() throws NoSuchAlgorithmException { - long ts = System.currentTimeMillis(); - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(MSG_ENCR_KEY_ALGO); - keyPairGenerator.initialize(2048); - KeyPair keyPair = keyPairGenerator.genKeyPair(); - log.trace("Generate msgEncryptionKeyPair needed {} ms", System.currentTimeMillis() - ts); - return keyPair; - } - - static { - Security.addProvider(new BouncyCastleProvider()); - } - - public static String signMessage(PrivateKey privateKey, String message) - throws SignatureException, NoSuchAlgorithmException, InvalidKeyException { - Signature sig = Signature.getInstance(MSG_SIGN_ALGO); - sig.initSign(privateKey); - sig.update(message.getBytes()); - return Base64.toBase64String(sig.sign()); - } - - public static boolean verifyMessage(PublicKey publicKey, String message, String signature) - throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { - Signature sig = Signature.getInstance(MSG_SIGN_ALGO); - sig.initVerify(publicKey); - sig.update(message.getBytes()); - return sig.verify(Base64.decode(signature)); - } - - public static byte[] signStorageData(PrivateKey privateKey, byte[] data) - throws SignatureException, NoSuchAlgorithmException, InvalidKeyException { - Signature sig = Signature.getInstance(MSG_SIGN_ALGO); - sig.initSign(privateKey); - sig.update(data); - return sig.sign(); - } - - public static boolean verifyStorageData(PublicKey publicKey, byte[] data, byte[] signature) - throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { - Signature sig = Signature.getInstance(MSG_SIGN_ALGO); - sig.initVerify(publicKey); - sig.update(data); - return sig.verify(signature); - } - - public static byte[] getHash(Integer data) { - return Sha256Hash.hash(ByteBuffer.allocate(4).putInt(data).array()); - } - - public static byte[] getHash(Object data) { - return Sha256Hash.hash(Utilities.objectToByteArray(data)); - } - - public static byte[] getHash(String message) { - return Sha256Hash.hash(Utils.formatMessageForSigning(message)); - } - - public static String getHashAsHex(String text) { - return Utils.HEX.encode(Sha256Hash.hash(Utils.formatMessageForSigning(text))); - } - - public static String pubKeyToString(PublicKey publicKey) { - final X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey.getEncoded()); - return java.util.Base64.getEncoder().encodeToString(x509EncodedKeySpec.getEncoded()); - } - - // TODO just temp for arbitrator - 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); - } -} - diff --git a/network/src/main/java/io/bitsquare/p2p/messaging/SealedAndSignedMessage.java b/common/src/main/java/io/bitsquare/common/crypto/DecryptedPayloadWithPubKey.java similarity index 50% rename from network/src/main/java/io/bitsquare/p2p/messaging/SealedAndSignedMessage.java rename to common/src/main/java/io/bitsquare/common/crypto/DecryptedPayloadWithPubKey.java index c0d3be665a..15b4e3df1d 100644 --- a/network/src/main/java/io/bitsquare/p2p/messaging/SealedAndSignedMessage.java +++ b/common/src/main/java/io/bitsquare/common/crypto/DecryptedPayloadWithPubKey.java @@ -15,54 +15,28 @@ * along with Bitsquare. If not, see . */ -package io.bitsquare.p2p.messaging; +package io.bitsquare.common.crypto; import io.bitsquare.app.Version; -import io.bitsquare.common.util.Utilities; -import javax.crypto.SealedObject; +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 SealedAndSignedMessage implements MailMessage { +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; - public final SealedObject sealedSecretKey; - public final SealedObject sealedMessage; - public final PublicKey signaturePubKey; + public final Serializable payload; + public final PublicKey sigPublicKey; - public SealedAndSignedMessage(SealedObject sealedSecretKey, SealedObject sealedMessage, PublicKey signaturePubKey) { - this.sealedSecretKey = sealedSecretKey; - this.sealedMessage = sealedMessage; - this.signaturePubKey = signaturePubKey; + public DecryptedPayloadWithPubKey(Serializable payload, PublicKey sigPublicKey) { + this.payload = payload; + this.sigPublicKey = sigPublicKey; } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof SealedAndSignedMessage)) return false; - - SealedAndSignedMessage that = (SealedAndSignedMessage) o; - - return Arrays.equals(Utilities.objectToByteArray(this), Utilities.objectToByteArray(that)); - } - - @Override - public int hashCode() { - byte[] bytes = Utilities.objectToByteArray(this); - return bytes != null ? Arrays.hashCode(bytes) : 0; - } - - @Override - public String toString() { - return "SealedAndSignedMessage{" + - "hashCode=" + 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 new file mode 100644 index 0000000000..cee57d2fc3 --- /dev/null +++ b/common/src/main/java/io/bitsquare/common/crypto/Encryption.java @@ -0,0 +1,276 @@ +/* + * 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 . + */ + +package io.bitsquare.common.crypto; + +import io.bitsquare.common.util.Utilities; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.spongycastle.util.encoders.Hex; + +import javax.crypto.*; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.Serializable; +import java.security.*; +import java.util.Arrays; + +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 HMAC = "HmacSHA256"; + + public static KeyPair generateEncryptionKeyPair() { + long ts = System.currentTimeMillis(); + try { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ENCR_KEY_ALGO); + keyPairGenerator.initialize(2048); + KeyPair keyPair = keyPairGenerator.genKeyPair(); + log.trace("Generate msgEncryptionKeyPair needed {} ms", System.currentTimeMillis() - ts); + return keyPair; + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + throw new RuntimeException("Could not create key."); + } + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Symmetric + /////////////////////////////////////////////////////////////////////////////////////////// + + public static byte[] encrypt(byte[] payload, SecretKey secretKey) throws CryptoException { + try { + Cipher cipher = Cipher.getInstance(SYM_CIPHER); + cipher.init(Cipher.ENCRYPT_MODE, secretKey); + return cipher.doFinal(payload); + } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException + | BadPaddingException | IllegalBlockSizeException e) { + e.printStackTrace(); + throw new CryptoException(e); + } + } + + public static byte[] decrypt(byte[] encryptedPayload, SecretKey secretKey) throws CryptoException { + try { + Cipher cipher = Cipher.getInstance(SYM_CIPHER); + cipher.init(Cipher.DECRYPT_MODE, secretKey); + return cipher.doFinal(encryptedPayload); + } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException + | BadPaddingException | IllegalBlockSizeException e) { + e.printStackTrace(); + throw new CryptoException(e); + } + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Hmac + /////////////////////////////////////////////////////////////////////////////////////////// + + private static byte[] getPayloadWithHmac(byte[] payload, SecretKey secretKey) { + byte[] payloadWithHmac; + try { + + ByteArrayOutputStream outputStream = null; + try { + byte[] hmac = getHmac(payload, secretKey); + outputStream = new ByteArrayOutputStream(); + outputStream.write(payload); + outputStream.write(hmac); + outputStream.flush(); + payloadWithHmac = outputStream.toByteArray().clone(); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException("Could not create hmac"); + } finally { + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException ignored) { + } + } + } + } catch (NoSuchAlgorithmException | InvalidKeyException e) { + e.printStackTrace(); + throw new RuntimeException("Could not create hmac"); + } + return payloadWithHmac; + } + + + private static boolean verifyHmac(byte[] message, byte[] hmac, SecretKey secretKey) throws CryptoException { + try { + byte[] hmacTest = getHmac(message, secretKey); + return Arrays.equals(hmacTest, hmac); + } catch (NoSuchAlgorithmException | InvalidKeyException 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); + mac.init(secretKey); + return mac.doFinal(payload); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Symmetric with Hmac + /////////////////////////////////////////////////////////////////////////////////////////// + + public static byte[] encryptPayloadWithHmac(Serializable object, SecretKey secretKey) throws CryptoException { + return encryptPayloadWithHmac(Utilities.serialize(object), secretKey); + } + + public static byte[] encryptPayloadWithHmac(byte[] payload, SecretKey secretKey) throws CryptoException { + return encrypt(getPayloadWithHmac(payload, secretKey), secretKey); + } + + public static byte[] decryptPayloadWithHmac(byte[] encryptedPayloadWithHmac, SecretKey secretKey) throws CryptoException { + byte[] payloadWithHmac = decrypt(encryptedPayloadWithHmac, secretKey); + String payloadWithHmacAsHex = Hex.toHexString(payloadWithHmac); + // first part is raw message + int length = payloadWithHmacAsHex.length(); + int sep = length - 64; + String payloadAsHex = payloadWithHmacAsHex.substring(0, sep); + // last 64 bytes is hmac + String hmacAsHex = payloadWithHmacAsHex.substring(sep, length); + if (verifyHmac(Hex.decode(payloadAsHex), Hex.decode(hmacAsHex), secretKey)) { + return Hex.decode(payloadAsHex); + } else { + throw new CryptoException("Hmac does not match."); + } + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Asymmetric + /////////////////////////////////////////////////////////////////////////////////////////// + + public static byte[] encrypt(byte[] payload, PublicKey publicKey) throws CryptoException { + try { + Cipher cipher = Cipher.getInstance(ASYM_CIPHER); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + return cipher.doFinal(payload); + } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException + | BadPaddingException | IllegalBlockSizeException e) { + e.printStackTrace(); + throw new CryptoException("Couldn't encrypt payload"); + } + } + + public static byte[] decrypt(byte[] encryptedPayload, PrivateKey privateKey) throws CryptoException { + try { + Cipher cipher = Cipher.getInstance(ASYM_CIPHER); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + return cipher.doFinal(encryptedPayload); + } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException + | BadPaddingException | IllegalBlockSizeException e) { + e.printStackTrace(); + throw new CryptoException(e); + } + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Hybrid with signature of asymmetric key + /////////////////////////////////////////////////////////////////////////////////////////// + + /** + * @param payload The data to encrypt. + * @param sigPrivateKey The private key for signing. + * @param sigPublicKey The public key used 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) + throws CryptoException { + // Create a symmetric key + SecretKey secretKey = generateSecretKey(); + + // Encrypt secretKey with receivers publicKey + byte[] encryptedSecretKey = encrypt(secretKey.getEncoded(), encryptionPublicKey); + + // Encrypt with sym key and add 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); + } + + + } + + /** + * @param sealedAndSigned The sealedAndSigned object. + * @param privateKey The private key for decryption + * @return A DecryptedPayloadWithPubKey object. + * @throws CryptoException + */ + 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) { + throw new CryptoException("Signature verification failed."); + } + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Private + /////////////////////////////////////////////////////////////////////////////////////////// + + private static SecretKey getSecretKeyFromBytes(byte[] encodedKey) { + return new SecretKeySpec(encodedKey, SYM_KEY_ALGO); + } + + private static SecretKey generateSecretKey() { + try { + KeyGenerator keyPairGenerator = KeyGenerator.getInstance(SYM_CIPHER); + keyPairGenerator.init(256); + return keyPairGenerator.generateKey(); + } catch (NoSuchAlgorithmException e) { + 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 new file mode 100644 index 0000000000..bbeffb0700 --- /dev/null +++ b/common/src/main/java/io/bitsquare/common/crypto/Hash.java @@ -0,0 +1,83 @@ +/* + * 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 . + */ + +package io.bitsquare.common.crypto; + +import com.google.common.base.Charsets; +import io.bitsquare.common.util.Utilities; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.spongycastle.util.encoders.Hex; + +import java.io.Serializable; +import java.nio.ByteBuffer; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class Hash { + private static final Logger log = LoggerFactory.getLogger(Hash.class); + + /** + * @param data Data as byte array + * @return Hash of data + */ + public static byte[] getHash(byte[] data) { + MessageDigest digest; + try { + digest = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + log.error("Could not create MessageDigest for hash. " + e.getMessage()); + throw new RuntimeException(e); + } + digest.update(data, 0, data.length); + return digest.digest(); + } + + /** + * @param data Any serializable object. Will be converted into a byte array using Java serialisation. + * @return Hash of data + */ + public static byte[] getHash(Serializable data) { + return getHash(Utilities.serialize(data)); + } + + /** + * @param message UTF-8 encoded message + * @return Hash of data + */ + public static byte[] getHash(String message) { + return getHash(message.getBytes(Charsets.UTF_8)); + } + + /** + * @param message UTF-8 encoded message + * @return Hex string of hash of data + */ + public static String getHashAsHex(String message) { + return Hex.toHexString(message.getBytes(Charsets.UTF_8)); + } + + /** + * @param data data as Integer + * @return Hash of data + */ + public static byte[] getHash(Integer data) { + return getHash(ByteBuffer.allocate(4).putInt(data).array()); + } + +} + 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 6f2f244e18..5a2d35ef7f 100644 --- a/common/src/main/java/io/bitsquare/common/crypto/KeyRing.java +++ b/common/src/main/java/io/bitsquare/common/crypto/KeyRing.java @@ -22,77 +22,42 @@ import org.slf4j.LoggerFactory; import javax.inject.Inject; import java.security.KeyPair; -import java.security.NoSuchAlgorithmException; public class KeyRing { private static final Logger log = LoggerFactory.getLogger(KeyRing.class); - // Used for signing storage data - private KeyPair storageSignatureKeyPair; // Used for signing messages sent over the wire - private KeyPair msgSignatureKeyPair; + private final KeyPair signatureKeyPair; // Used for encrypting messages sent over the wire (hybrid encryption scheme is used, so it is used only to encrypt a symmetric session key) - private KeyPair msgEncryptionKeyPair; + private final KeyPair encryptionKeyPair; - private PubKeyRing pubKeyRing; - private final KeyStorage keyStorage; + private final PubKeyRing pubKeyRing; @Inject - public KeyRing(KeyStorage keyStorage) throws CryptoException { - this.keyStorage = keyStorage; - - init(keyStorage); - } - - // consider extra thread for loading (takes about 264 ms at first startup, then load only takes nearly no time) - private void init(KeyStorage keyStorage) throws CryptoException { + public KeyRing(KeyStorage keyStorage) { if (keyStorage.allKeyFilesExist()) { - storageSignatureKeyPair = keyStorage.loadKeyPair(KeyStorage.Key.STORAGE_SIGNATURE); - msgSignatureKeyPair = keyStorage.loadKeyPair(KeyStorage.Key.MSG_SIGNATURE); - msgEncryptionKeyPair = keyStorage.loadKeyPair(KeyStorage.Key.MSG_ENCRYPTION); + signatureKeyPair = keyStorage.loadKeyPair(KeyStorage.Key.MSG_SIGNATURE); + encryptionKeyPair = keyStorage.loadKeyPair(KeyStorage.Key.MSG_ENCRYPTION); } else { // First time we create key pairs - try { - this.storageSignatureKeyPair = CryptoUtil.generateStorageSignatureKeyPair(); - this.msgSignatureKeyPair = CryptoUtil.generateMsgSignatureKeyPair(); - this.msgEncryptionKeyPair = CryptoUtil.generateMsgEncryptionKeyPair(); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - throw new CryptoException("Error at KeyRing constructor ", e); - } + signatureKeyPair = Sig.generateKeyPair(); + encryptionKeyPair = Encryption.generateEncryptionKeyPair(); keyStorage.saveKeyRing(this); } - - pubKeyRing = new PubKeyRing(storageSignatureKeyPair.getPublic(), msgSignatureKeyPair.getPublic(), msgEncryptionKeyPair.getPublic()); - } - - // For unit testing - KeyRing() throws NoSuchAlgorithmException { - keyStorage = null; - this.storageSignatureKeyPair = CryptoUtil.generateStorageSignatureKeyPair(); - this.msgSignatureKeyPair = CryptoUtil.generateMsgSignatureKeyPair(); - this.msgEncryptionKeyPair = CryptoUtil.generateMsgEncryptionKeyPair(); - pubKeyRing = new PubKeyRing(storageSignatureKeyPair.getPublic(), msgSignatureKeyPair.getPublic(), msgEncryptionKeyPair.getPublic()); - } - - KeyRing(KeyPair storageSignatureKeyPair, KeyPair msgSignatureKeyPair, KeyPair msgEncryptionKeyPair) { - this.keyStorage = null; - this.storageSignatureKeyPair = storageSignatureKeyPair; - this.msgSignatureKeyPair = msgSignatureKeyPair; - this.msgEncryptionKeyPair = msgEncryptionKeyPair; - pubKeyRing = new PubKeyRing(storageSignatureKeyPair.getPublic(), msgSignatureKeyPair.getPublic(), msgEncryptionKeyPair.getPublic()); + pubKeyRing = new PubKeyRing(signatureKeyPair.getPublic(), signatureKeyPair.getPublic(), encryptionKeyPair.getPublic()); } + //TODO public KeyPair getStorageSignatureKeyPair() { - return storageSignatureKeyPair; + return signatureKeyPair; } - public KeyPair getMsgSignatureKeyPair() { - return msgSignatureKeyPair; + public KeyPair getSignatureKeyPair() { + return signatureKeyPair; } - public KeyPair getMsgEncryptionKeyPair() { - return msgEncryptionKeyPair; + public KeyPair getEncryptionKeyPair() { + return encryptionKeyPair; } public PubKeyRing getPubKeyRing() { 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 0c82548910..f9c10a5a65 100644 --- a/common/src/main/java/io/bitsquare/common/crypto/KeyStorage.java +++ b/common/src/main/java/io/bitsquare/common/crypto/KeyStorage.java @@ -18,7 +18,6 @@ package io.bitsquare.common.crypto; import com.google.inject.Inject; -import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,14 +38,10 @@ public class KeyStorage { public static final String DIR_KEY = "key.storage.dir"; - static { - Security.addProvider(new BouncyCastleProvider()); - } - public enum Key { - STORAGE_SIGNATURE("storageSignature", CryptoUtil.STORAGE_SIGN_KEY_ALGO), - MSG_SIGNATURE("msgSignature", CryptoUtil.MSG_SIGN_KEY_ALGO), - MSG_ENCRYPTION("msgEncryption", CryptoUtil.MSG_ENCR_KEY_ALGO); + STORAGE_SIGNATURE("storageSignature", Sig.KEY_ALGO), + MSG_SIGNATURE("msgSignature", Sig.KEY_ALGO), + MSG_ENCRYPTION("msgEncryption", Encryption.ENCR_KEY_ALGO); private final String fileName; private final String algorithm; @@ -81,7 +76,7 @@ public class KeyStorage { this.storageDir = storageDir; } - public boolean allKeyFilesExist() throws CryptoException { + public boolean allKeyFilesExist() { return fileExists(KeyStorage.Key.STORAGE_SIGNATURE) && fileExists(KeyStorage.Key.MSG_SIGNATURE) && fileExists(KeyStorage.Key.MSG_ENCRYPTION); } @@ -89,7 +84,7 @@ public class KeyStorage { return new File(storageDir + "/" + key.getFileName() + "Pub.key").exists(); } - public KeyPair loadKeyPair(Key key) throws CryptoException { + public KeyPair loadKeyPair(Key key) { // long now = System.currentTimeMillis(); try { KeyFactory keyFactory = KeyFactory.getInstance(key.getAlgorithm()); @@ -106,7 +101,7 @@ public class KeyStorage { } catch (InvalidKeySpecException | IOException e) { e.printStackTrace(); log.error(e.getMessage()); - throw new CryptoException("Could not load key " + key.toString(), e); + throw new RuntimeException("Could not load key " + key.toString(), e); } File filePrivateKey = new File(storageDir + "/" + key.getFileName() + "Priv.key"); @@ -119,7 +114,7 @@ public class KeyStorage { } catch (InvalidKeySpecException | IOException e) { e.printStackTrace(); log.error(e.getMessage()); - throw new CryptoException("Could not load key " + key.toString(), e); + throw new RuntimeException("Could not load key " + key.toString(), e); } //log.info("load completed in {} msec", System.currentTimeMillis() - now); return new KeyPair(publicKey, privateKey); @@ -127,17 +122,17 @@ public class KeyStorage { } catch (NoSuchAlgorithmException e) { e.printStackTrace(); log.error(e.getMessage()); - throw new CryptoException("Could not load key " + key.toString(), e); + throw new RuntimeException("Could not load key " + key.toString(), e); } } - public void saveKeyRing(KeyRing keyRing) throws CryptoException { + public void saveKeyRing(KeyRing keyRing) { saveKeyPair(keyRing.getStorageSignatureKeyPair(), Key.STORAGE_SIGNATURE.getFileName()); - saveKeyPair(keyRing.getMsgSignatureKeyPair(), Key.MSG_SIGNATURE.getFileName()); - saveKeyPair(keyRing.getMsgEncryptionKeyPair(), Key.MSG_ENCRYPTION.getFileName()); + saveKeyPair(keyRing.getSignatureKeyPair(), Key.MSG_SIGNATURE.getFileName()); + saveKeyPair(keyRing.getEncryptionKeyPair(), Key.MSG_ENCRYPTION.getFileName()); } - public void saveKeyPair(KeyPair keyPair, String name) throws CryptoException { + public void saveKeyPair(KeyPair keyPair, String name) { if (!storageDir.exists()) storageDir.mkdir(); @@ -147,7 +142,7 @@ public class KeyStorage { } catch (IOException e) { e.printStackTrace(); log.error(e.getMessage()); - throw new CryptoException("Could not save key " + name, e); + throw new RuntimeException("Could not save key " + name, e); } PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyPair.getPrivate().getEncoded()); @@ -156,7 +151,7 @@ public class KeyStorage { } catch (IOException e) { e.printStackTrace(); log.error(e.getMessage()); - throw new CryptoException("Could not save key " + name, e); + throw new RuntimeException("Could not save key " + name, 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 05ecf93f7e..e785519e51 100644 --- a/common/src/main/java/io/bitsquare/common/crypto/PubKeyRing.java +++ b/common/src/main/java/io/bitsquare/common/crypto/PubKeyRing.java @@ -45,22 +45,22 @@ public class PubKeyRing implements Serializable { transient private PublicKey storageSignaturePubKey; transient private PublicKey msgSignaturePubKey; - transient private PublicKey msgEncryptionPubKey; + transient private PublicKey encryptionPubKey; - public PubKeyRing(PublicKey storageSignaturePubKey, PublicKey msgSignaturePubKey, PublicKey msgEncryptionPubKey) { + public PubKeyRing(PublicKey storageSignaturePubKey, PublicKey msgSignaturePubKey, PublicKey encryptionPubKey) { this.storageSignaturePubKey = storageSignaturePubKey; this.msgSignaturePubKey = msgSignaturePubKey; - this.msgEncryptionPubKey = msgEncryptionPubKey; + this.encryptionPubKey = encryptionPubKey; this.storageSignaturePubKeyBytes = new X509EncodedKeySpec(storageSignaturePubKey.getEncoded()).getEncoded(); this.msgSignaturePubKeyBytes = new X509EncodedKeySpec(msgSignaturePubKey.getEncoded()).getEncoded(); - this.msgEncryptionPubKeyBytes = new X509EncodedKeySpec(msgEncryptionPubKey.getEncoded()).getEncoded(); + this.msgEncryptionPubKeyBytes = new X509EncodedKeySpec(encryptionPubKey.getEncoded()).getEncoded(); } public PublicKey getStorageSignaturePubKey() { if (storageSignaturePubKey == null) { try { - storageSignaturePubKey = KeyFactory.getInstance(CryptoUtil.STORAGE_SIGN_KEY_ALGO).generatePublic(new X509EncodedKeySpec(storageSignaturePubKeyBytes)); + storageSignaturePubKey = KeyFactory.getInstance(Sig.KEY_ALGO).generatePublic(new X509EncodedKeySpec(storageSignaturePubKeyBytes)); } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { e.printStackTrace(); log.error(e.getMessage()); @@ -73,7 +73,7 @@ public class PubKeyRing implements Serializable { public PublicKey getMsgSignaturePubKey() { if (msgSignaturePubKey == null) { try { - msgSignaturePubKey = KeyFactory.getInstance(CryptoUtil.MSG_SIGN_KEY_ALGO).generatePublic(new X509EncodedKeySpec(msgSignaturePubKeyBytes)); + msgSignaturePubKey = KeyFactory.getInstance(Sig.KEY_ALGO).generatePublic(new X509EncodedKeySpec(msgSignaturePubKeyBytes)); } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { e.printStackTrace(); log.error(e.getMessage()); @@ -82,16 +82,16 @@ public class PubKeyRing implements Serializable { return msgSignaturePubKey; } - public PublicKey getMsgEncryptionPubKey() { - if (msgEncryptionPubKey == null) { + public PublicKey getEncryptionPubKey() { + if (encryptionPubKey == null) { try { - msgEncryptionPubKey = KeyFactory.getInstance(CryptoUtil.MSG_ENCR_KEY_ALGO).generatePublic(new X509EncodedKeySpec(msgEncryptionPubKeyBytes)); + encryptionPubKey = KeyFactory.getInstance(Encryption.ENCR_KEY_ALGO).generatePublic(new X509EncodedKeySpec(msgEncryptionPubKeyBytes)); } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { e.printStackTrace(); log.error(e.getMessage()); } } - return msgEncryptionPubKey; + return encryptionPubKey; } @Override @@ -118,9 +118,9 @@ public class PubKeyRing implements Serializable { @Override public String toString() { return "PubKeyRing{" + - "\nstorageSignaturePubKey=\n" + CryptoUtil.pubKeyToString(getStorageSignaturePubKey()) + - "\n\nmsgSignaturePubKey=\n" + CryptoUtil.pubKeyToString(getMsgSignaturePubKey()) + - "\n\nmsgEncryptionPubKey=\n" + CryptoUtil.pubKeyToString(getMsgEncryptionPubKey()) + + "\nstorageSignaturePubKey=\n" + Util.pubKeyToString(getStorageSignaturePubKey()) + + "\n\nmsgSignaturePubKey=\n" + Util.pubKeyToString(getMsgSignaturePubKey()) + + "\n\nmsgEncryptionPubKey=\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 new file mode 100644 index 0000000000..458b23a52c --- /dev/null +++ b/common/src/main/java/io/bitsquare/common/crypto/SealedAndSigned.java @@ -0,0 +1,70 @@ +/* + * 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 . + */ + +package io.bitsquare.common.crypto; + +import io.bitsquare.app.Version; + +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; + + public final byte[] encryptedSecretKey; + public final byte[] encryptedPayloadWithHmac; + public final byte[] signature; + public final PublicKey sigPublicKey; + + public SealedAndSigned(byte[] encryptedSecretKey, byte[] encryptedPayloadWithHmac, byte[] signature, PublicKey sigPublicKey) { + this.encryptedSecretKey = encryptedSecretKey; + this.encryptedPayloadWithHmac = encryptedPayloadWithHmac; + this.signature = signature; + this.sigPublicKey = sigPublicKey; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof SealedAndSigned)) return false; + + SealedAndSigned that = (SealedAndSigned) o; + + if (!Arrays.equals(encryptedSecretKey, that.encryptedSecretKey)) return false; + if (!Arrays.equals(encryptedPayloadWithHmac, that.encryptedPayloadWithHmac)) return false; + if (!Arrays.equals(signature, that.signature)) return false; + return !(sigPublicKey != null ? !sigPublicKey.equals(that.sigPublicKey) : that.sigPublicKey != null); + + } + + @Override + public int hashCode() { + int result = encryptedSecretKey != null ? Arrays.hashCode(encryptedSecretKey) : 0; + result = 31 * result + (encryptedPayloadWithHmac != null ? Arrays.hashCode(encryptedPayloadWithHmac) : 0); + result = 31 * result + (signature != null ? Arrays.hashCode(signature) : 0); + result = 31 * result + (sigPublicKey != null ? sigPublicKey.hashCode() : 0); + return result; + } + +} diff --git a/common/src/main/java/io/bitsquare/common/crypto/Sig.java b/common/src/main/java/io/bitsquare/common/crypto/Sig.java new file mode 100644 index 0000000000..3de75442fb --- /dev/null +++ b/common/src/main/java/io/bitsquare/common/crypto/Sig.java @@ -0,0 +1,121 @@ +/* + * 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 . + */ + +package io.bitsquare.common.crypto; + +import com.google.common.base.Charsets; +import org.bouncycastle.util.encoders.Base64; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.security.*; + +/** + * StorageSignatureKeyPair/STORAGE_SIGN_KEY_ALGO: That is used for signing the data to be stored to the P2P network (by flooding). + * The algo is selected because it originated from the TomP2P version which used DSA. + * Changing to EC keys might be considered. + *

+ * MsgSignatureKeyPair/MSG_SIGN_KEY_ALGO/MSG_SIGN_ALGO: That is used when sending a message to a peer which is encrypted and signed. + * Changing to EC keys might be considered. + */ +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 + + + /** + * @return keyPair + */ + public static KeyPair generateKeyPair() { + long ts = System.currentTimeMillis(); + try { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGO); + keyPairGenerator.initialize(1024); + KeyPair keyPair = keyPairGenerator.genKeyPair(); + log.trace("Generate msgSignatureKeyPair needed {} ms", System.currentTimeMillis() - ts); + return keyPair; + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + throw new RuntimeException("Could not create key."); + } + } + + + /** + * @param privateKey + * @param data + * @return + * @throws SignatureException + * @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(); + } + + /** + * @param privateKey + * @param message UTF-8 encoded message to sign + * @return Base64 encoded signature + * @throws SignatureException + * @throws NoSuchAlgorithmException + * @throws InvalidKeyException + */ + public static String sign(PrivateKey privateKey, String message) + throws SignatureException, NoSuchAlgorithmException, InvalidKeyException { + byte[] sigAsBytes = sign(privateKey, message.getBytes(Charsets.UTF_8)); + return Base64.toBase64String(sigAsBytes); + } + + /** + * @param publicKey + * @param data + * @param signature + * @return + * @throws NoSuchAlgorithmException + * @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); + } + + /** + * @param publicKey + * @param message UTF-8 encoded message + * @param signature Base64 encoded signature + * @return + * @throws NoSuchAlgorithmException + * @throws InvalidKeyException + * @throws SignatureException + */ + public static boolean verify(PublicKey publicKey, String message, String signature) + throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { + 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 new file mode 100644 index 0000000000..1c5f514241 --- /dev/null +++ b/common/src/main/java/io/bitsquare/common/crypto/Util.java @@ -0,0 +1,34 @@ +/* + * 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 . + */ + +package io.bitsquare.common.crypto; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.security.PublicKey; +import java.security.spec.X509EncodedKeySpec; + +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()); + } +} + diff --git a/common/src/main/java/io/bitsquare/common/util/Tuple2.java b/common/src/main/java/io/bitsquare/common/util/Tuple2.java index 8d2530f9e9..2e5fc4071e 100644 --- a/common/src/main/java/io/bitsquare/common/util/Tuple2.java +++ b/common/src/main/java/io/bitsquare/common/util/Tuple2.java @@ -17,7 +17,9 @@ package io.bitsquare.common.util; -public class Tuple2 { +import java.io.Serializable; + +public class Tuple2 implements Serializable { final public A first; final public B second; diff --git a/common/src/main/java/io/bitsquare/common/util/Tuple3.java b/common/src/main/java/io/bitsquare/common/util/Tuple3.java index 3229f98fd7..be08d6aa63 100644 --- a/common/src/main/java/io/bitsquare/common/util/Tuple3.java +++ b/common/src/main/java/io/bitsquare/common/util/Tuple3.java @@ -17,7 +17,9 @@ package io.bitsquare.common.util; -public class Tuple3 { +import java.io.Serializable; + +public class Tuple3 implements Serializable { final public A first; final public B second; final public C third; diff --git a/common/src/main/java/io/bitsquare/common/util/Utilities.java b/common/src/main/java/io/bitsquare/common/util/Utilities.java index 676e576ba4..22bf0ebc9c 100644 --- a/common/src/main/java/io/bitsquare/common/util/Utilities.java +++ b/common/src/main/java/io/bitsquare/common/util/Utilities.java @@ -208,13 +208,15 @@ public class Utilities { return result; }*/ - public static T byteArrayToObject(byte[] data) { + public static T deserialize(byte[] data) { ByteArrayInputStream bis = new ByteArrayInputStream(data); ObjectInput in = null; Object result = null; try { in = new ObjectInputStream(bis); result = in.readObject(); + if (!(result instanceof Serializable)) + throw new RuntimeException("Object not of type Serializable"); } catch (Exception e) { e.printStackTrace(); } finally { @@ -234,14 +236,15 @@ public class Utilities { return (T) result; } - public static byte[] objectToByteArray(Object object) { + public static byte[] serialize(Serializable object) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutput out = null; byte[] result = null; try { out = new ObjectOutputStream(bos); out.writeObject(object); - result = bos.toByteArray(); + out.flush(); + result = bos.toByteArray().clone(); } catch (IOException e) { e.printStackTrace(); } finally { @@ -249,13 +252,11 @@ public class Utilities { if (out != null) { out.close(); } - } catch (IOException ex) { - // ignore close exception + } catch (IOException ignore) { } try { bos.close(); - } catch (IOException ex) { - // ignore close exception + } catch (IOException ignore) { } } return result; diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/messages/PublishDepositTxRequest.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/messages/PublishDepositTxRequest.java index 2fef2b1c61..5b8584dded 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/messages/PublishDepositTxRequest.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/messages/PublishDepositTxRequest.java @@ -25,6 +25,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.concurrent.Immutable; +import java.util.ArrayList; import java.util.List; @Immutable @@ -68,9 +69,9 @@ public class PublishDepositTxRequest extends TradeMessage { this.openDisputeTimeAsBlockHeight = openDisputeTimeAsBlockHeight; this.checkPaymentTimeAsBlockHeight = checkPaymentTimeAsBlockHeight; - log.trace("offererPaymentAccount size " + Utilities.objectToByteArray(offererPaymentAccountContractData).length); + log.trace("offererPaymentAccount size " + Utilities.serialize(offererPaymentAccountContractData).length); log.trace("offererTradeWalletPubKey size " + offererTradeWalletPubKey.length); log.trace("preparedDepositTx size " + preparedDepositTx.length); - log.trace("offererInputs size " + Utilities.objectToByteArray(offererInputs).length); + log.trace("offererInputs size " + Utilities.serialize(new ArrayList<>(offererInputs)).length); } } diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/CreateAndSignDepositTxAsBuyer.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/CreateAndSignDepositTxAsBuyer.java index c42e31d117..64424c61c2 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/CreateAndSignDepositTxAsBuyer.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/CreateAndSignDepositTxAsBuyer.java @@ -19,7 +19,7 @@ package io.bitsquare.trade.protocol.trade.tasks.buyer; import io.bitsquare.btc.FeePolicy; import io.bitsquare.btc.data.PreparedDepositTxAndOffererInputs; -import io.bitsquare.common.crypto.CryptoUtil; +import io.bitsquare.common.crypto.Hash; import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.trade.Trade; import io.bitsquare.trade.protocol.trade.tasks.TradeTask; @@ -49,7 +49,7 @@ public class CreateAndSignDepositTxAsBuyer extends TradeTask { log.debug(trade.getContractAsJson()); log.debug("----------"); - byte[] contractHash = CryptoUtil.getHash(trade.getContractAsJson()); + byte[] contractHash = Hash.getHash(trade.getContractAsJson()); trade.setContractHash(contractHash); PreparedDepositTxAndOffererInputs result = processModel.getTradeWalletService().offererCreatesAndSignsDepositTx( true, diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SignAndPublishDepositTxAsBuyer.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SignAndPublishDepositTxAsBuyer.java index 12329e3647..4ea7c80d15 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SignAndPublishDepositTxAsBuyer.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/buyer/SignAndPublishDepositTxAsBuyer.java @@ -18,7 +18,7 @@ package io.bitsquare.trade.protocol.trade.tasks.buyer; import com.google.common.util.concurrent.FutureCallback; -import io.bitsquare.common.crypto.CryptoUtil; +import io.bitsquare.common.crypto.Hash; import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.trade.Trade; import io.bitsquare.trade.protocol.trade.tasks.TradeTask; @@ -41,7 +41,7 @@ public class SignAndPublishDepositTxAsBuyer extends TradeTask { try { runInterceptHook(); - byte[] contractHash = CryptoUtil.getHash(trade.getContractAsJson()); + byte[] contractHash = Hash.getHash(trade.getContractAsJson()); trade.setContractHash(contractHash); processModel.getTradeWalletService().takerSignsAndPublishesDepositTx( false, diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/CreateAndSignContract.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/CreateAndSignContract.java index a26fa33757..2eaf014234 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/CreateAndSignContract.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/CreateAndSignContract.java @@ -17,7 +17,7 @@ package io.bitsquare.trade.protocol.trade.tasks.offerer; -import io.bitsquare.common.crypto.CryptoUtil; +import io.bitsquare.common.crypto.Sig; import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.util.Utilities; import io.bitsquare.p2p.Address; @@ -75,7 +75,7 @@ public class CreateAndSignContract extends TradeTask { taker.getTradeWalletPubKey() ); String contractAsJson = Utilities.objectToJson(contract); - String signature = CryptoUtil.signMessage(processModel.getKeyRing().getMsgSignatureKeyPair().getPrivate(), contractAsJson); + String signature = Sig.sign(processModel.getKeyRing().getSignatureKeyPair().getPrivate(), contractAsJson); trade.setContract(contract); trade.setContractAsJson(contractAsJson); diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/ProcessPayDepositRequest.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/ProcessPayDepositRequest.java index 41e2389fd9..6a243446be 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/ProcessPayDepositRequest.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/offerer/ProcessPayDepositRequest.java @@ -17,7 +17,7 @@ package io.bitsquare.trade.protocol.trade.tasks.offerer; -import io.bitsquare.common.crypto.CryptoUtil; +import io.bitsquare.common.crypto.Hash; import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.locale.CurrencyUtil; import io.bitsquare.payment.BlockChainAccountContractData; @@ -66,7 +66,7 @@ public class ProcessPayDepositRequest extends TradeTask { // We apply the payment ID in case its a cryptoNote coin. It is created form the hash of the trade ID if (paymentAccountContractData instanceof BlockChainAccountContractData && CurrencyUtil.isCryptoNoteCoin(processModel.getOffer().getCurrencyCode())) { - String paymentId = CryptoUtil.getHashAsHex(trade.getId()).substring(0, 32); + String paymentId = Hash.getHashAsHex(trade.getId()).substring(0, 32); ((BlockChainAccountContractData) paymentAccountContractData).setPaymentId(paymentId); } diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/CreateAndSignDepositTxAsSeller.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/CreateAndSignDepositTxAsSeller.java index 957de8ea7e..dc8b059678 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/CreateAndSignDepositTxAsSeller.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/CreateAndSignDepositTxAsSeller.java @@ -19,7 +19,7 @@ package io.bitsquare.trade.protocol.trade.tasks.seller; import io.bitsquare.btc.FeePolicy; import io.bitsquare.btc.data.PreparedDepositTxAndOffererInputs; -import io.bitsquare.common.crypto.CryptoUtil; +import io.bitsquare.common.crypto.Hash; import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.trade.Trade; import io.bitsquare.trade.protocol.trade.tasks.TradeTask; @@ -44,7 +44,7 @@ public class CreateAndSignDepositTxAsSeller extends TradeTask { Coin sellerInputAmount = FeePolicy.SECURITY_DEPOSIT.add(FeePolicy.TX_FEE).add(trade.getTradeAmount()); Coin msOutputAmount = sellerInputAmount.add(FeePolicy.SECURITY_DEPOSIT); - byte[] contractHash = CryptoUtil.getHash(trade.getContractAsJson()); + byte[] contractHash = Hash.getHash(trade.getContractAsJson()); trade.setContractHash(contractHash); PreparedDepositTxAndOffererInputs result = processModel.getTradeWalletService().offererCreatesAndSignsDepositTx( false, diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/SignAndPublishDepositTxAsSeller.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/SignAndPublishDepositTxAsSeller.java index 062279d1c9..018182abe3 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/SignAndPublishDepositTxAsSeller.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/seller/SignAndPublishDepositTxAsSeller.java @@ -18,7 +18,7 @@ package io.bitsquare.trade.protocol.trade.tasks.seller; import com.google.common.util.concurrent.FutureCallback; -import io.bitsquare.common.crypto.CryptoUtil; +import io.bitsquare.common.crypto.Hash; import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.trade.Trade; import io.bitsquare.trade.protocol.trade.tasks.TradeTask; @@ -44,7 +44,7 @@ public class SignAndPublishDepositTxAsSeller extends TradeTask { log.debug("----------"); log.debug(trade.getContractAsJson()); log.debug("----------"); - byte[] contractHash = CryptoUtil.getHash(trade.getContractAsJson()); + byte[] contractHash = Hash.getHash(trade.getContractAsJson()); trade.setContractHash(contractHash); processModel.getTradeWalletService().takerSignsAndPublishesDepositTx( true, diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/taker/ProcessPublishDepositTxRequest.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/taker/ProcessPublishDepositTxRequest.java index 214ee743f9..d0282fd6bb 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/taker/ProcessPublishDepositTxRequest.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/taker/ProcessPublishDepositTxRequest.java @@ -17,7 +17,7 @@ package io.bitsquare.trade.protocol.trade.tasks.taker; -import io.bitsquare.common.crypto.CryptoUtil; +import io.bitsquare.common.crypto.Hash; import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.locale.CurrencyUtil; import io.bitsquare.payment.BlockChainAccountContractData; @@ -54,7 +54,7 @@ public class ProcessPublishDepositTxRequest extends TradeTask { // We apply the payment ID in case its a cryptoNote coin. It is created form the hash of the trade ID if (paymentAccountContractData instanceof BlockChainAccountContractData && CurrencyUtil.isCryptoNoteCoin(processModel.getOffer().getCurrencyCode())) { - String paymentId = CryptoUtil.getHashAsHex(trade.getId()).substring(0, 32); + String paymentId = Hash.getHashAsHex(trade.getId()).substring(0, 32); ((BlockChainAccountContractData) paymentAccountContractData).setPaymentId(paymentId); } diff --git a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/taker/VerifyAndSignContract.java b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/taker/VerifyAndSignContract.java index 32396a0c06..4d114cd796 100644 --- a/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/taker/VerifyAndSignContract.java +++ b/core/src/main/java/io/bitsquare/trade/protocol/trade/tasks/taker/VerifyAndSignContract.java @@ -17,7 +17,7 @@ package io.bitsquare.trade.protocol.trade.tasks.taker; -import io.bitsquare.common.crypto.CryptoUtil; +import io.bitsquare.common.crypto.Sig; import io.bitsquare.common.taskrunner.TaskRunner; import io.bitsquare.common.util.Utilities; import io.bitsquare.p2p.Address; @@ -74,13 +74,13 @@ public class VerifyAndSignContract extends TradeTask { processModel.getTradeWalletPubKey() ); String contractAsJson = Utilities.objectToJson(contract); - String signature = CryptoUtil.signMessage(processModel.getKeyRing().getMsgSignatureKeyPair().getPrivate(), contractAsJson); + String signature = Sig.sign(processModel.getKeyRing().getSignatureKeyPair().getPrivate(), contractAsJson); trade.setContract(contract); trade.setContractAsJson(contractAsJson); trade.setTakerContractSignature(signature); try { - CryptoUtil.verifyMessage(offerer.getPubKeyRing().getMsgSignaturePubKey(), + Sig.verify(offerer.getPubKeyRing().getMsgSignaturePubKey(), contractAsJson, offerer.getContractSignature()); } catch (Throwable t) { diff --git a/gui/src/main/java/io/bitsquare/app/BitsquareApp.java b/gui/src/main/java/io/bitsquare/app/BitsquareApp.java index 96cfcff31b..5fe5f9eee3 100644 --- a/gui/src/main/java/io/bitsquare/app/BitsquareApp.java +++ b/gui/src/main/java/io/bitsquare/app/BitsquareApp.java @@ -54,6 +54,7 @@ import javafx.scene.layout.StackPane; import javafx.stage.Modality; import javafx.stage.Stage; import javafx.stage.StageStyle; +import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.controlsfx.dialog.Dialogs; import org.reactfx.EventStreams; import org.reactfx.util.FxTimer; @@ -62,6 +63,7 @@ import org.springframework.core.env.Environment; import java.io.IOException; import java.nio.file.Paths; +import java.security.Security; import java.time.Duration; import java.util.ArrayList; import java.util.List; @@ -113,6 +115,8 @@ public class BitsquareApp extends Application { Thread.setDefaultUncaughtExceptionHandler(handler); Thread.currentThread().setUncaughtExceptionHandler(handler); + Security.addProvider(new BouncyCastleProvider()); + try { // Use CrashFX for report crash logs /*CrashFX.setup("Bitsquare/" + Version.VERSION, diff --git a/network/src/main/java/io/bitsquare/crypto/EncryptionService.java b/network/src/main/java/io/bitsquare/crypto/EncryptionService.java index cb254fb92d..46f861059a 100644 --- a/network/src/main/java/io/bitsquare/crypto/EncryptionService.java +++ b/network/src/main/java/io/bitsquare/crypto/EncryptionService.java @@ -17,27 +17,18 @@ package io.bitsquare.crypto; -import io.bitsquare.common.crypto.CryptoException; -import io.bitsquare.common.crypto.CryptoUtil; -import io.bitsquare.common.crypto.KeyRing; -import io.bitsquare.common.crypto.PubKeyRing; -import io.bitsquare.common.util.Utilities; +import io.bitsquare.common.crypto.*; import io.bitsquare.p2p.Message; import io.bitsquare.p2p.messaging.DecryptedMessageWithPubKey; -import io.bitsquare.p2p.messaging.SealedAndSignedMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nullable; -import javax.crypto.*; import javax.inject.Inject; -import java.io.IOException; -import java.security.*; +import java.security.KeyPair; public class EncryptionService { private static final Logger log = LoggerFactory.getLogger(EncryptionService.class); - @Nullable private final KeyRing keyRing; @Inject @@ -45,90 +36,22 @@ public class EncryptionService { this.keyRing = keyRing; } - - public SealedAndSignedMessage encryptAndSignMessage(PubKeyRing pubKeyRing, Message message) throws CryptoException { + public SealedAndSigned encryptAndSignMessage(PubKeyRing pubKeyRing, Message message) throws CryptoException { log.trace("encryptAndSignMessage message = " + message); - //long ts = System.currentTimeMillis(); - - try { - // Create symmetric key - KeyGenerator keyGenerator = KeyGenerator.getInstance(CryptoUtil.SYM_ENCR_KEY_ALGO); - // TODO consider 256 bit as key length - keyGenerator.init(128); - SecretKey secretKey = keyGenerator.generateKey(); - - // Encrypt secretKey with peers pubKey using SealedObject - Cipher cipherAsym = Cipher.getInstance(CryptoUtil.ASYM_CIPHER); - cipherAsym.init(Cipher.ENCRYPT_MODE, pubKeyRing.getMsgEncryptionPubKey()); - SealedObject sealedSecretKey = new SealedObject(secretKey, cipherAsym); - - // Sign (hash of) message and pack it into SignedObject - SignedObject signedMessage = new SignedObject(message, keyRing.getMsgSignatureKeyPair().getPrivate(), Signature.getInstance(CryptoUtil.MSG_SIGN_ALGO)); - - // // Encrypt signedMessage with secretKey using SealedObject - Cipher cipherSym = Cipher.getInstance(CryptoUtil.SYM_CIPHER); - cipherSym.init(Cipher.ENCRYPT_MODE, secretKey); - SealedObject sealedMessage = new SealedObject(signedMessage, cipherSym); - - SealedAndSignedMessage sealedAndSignedMessage = new SealedAndSignedMessage(sealedSecretKey, - sealedMessage, - keyRing.getMsgSignatureKeyPair().getPublic() - ); - //log.trace("Encryption needed {} ms", System.currentTimeMillis() - ts); - log.trace("sealedAndSignedMessage size " + Utilities.objectToByteArray(sealedAndSignedMessage).length); - return sealedAndSignedMessage; - } catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException - | IllegalBlockSizeException | IOException | SignatureException e) { - throw new CryptoException(e); - } + KeyPair signatureKeyPair = keyRing.getSignatureKeyPair(); + return Encryption.encryptHybridWithSignature(message, + signatureKeyPair.getPrivate(), + signatureKeyPair.getPublic(), + pubKeyRing.getEncryptionPubKey()); } - public DecryptedMessageWithPubKey decryptAndVerifyMessage(SealedAndSignedMessage sealedAndSignedMessage) throws CryptoException { - // long ts = System.currentTimeMillis(); - try { - if (keyRing == null) - throw new CryptoException("keyRing is null"); - - SealedObject sealedSecretKey = sealedAndSignedMessage.sealedSecretKey; - SealedObject sealedMessage = sealedAndSignedMessage.sealedMessage; - PublicKey signaturePubKey = sealedAndSignedMessage.signaturePubKey; - - // Decrypt secretKey with my privKey - Cipher cipherAsym = Cipher.getInstance(CryptoUtil.ASYM_CIPHER); - cipherAsym.init(Cipher.DECRYPT_MODE, keyRing.getMsgEncryptionKeyPair().getPrivate()); - Object secretKeyObject = sealedSecretKey.getObject(cipherAsym); - if (secretKeyObject instanceof SecretKey) { - SecretKey secretKey = (SecretKey) secretKeyObject; - - // Decrypt signedMessage with secretKey - Cipher cipherSym = Cipher.getInstance(CryptoUtil.SYM_CIPHER); - cipherSym.init(Cipher.DECRYPT_MODE, secretKey); - Object signedMessageObject = sealedMessage.getObject(cipherSym); - if (signedMessageObject instanceof SignedObject) { - SignedObject signedMessage = (SignedObject) signedMessageObject; - - // Verify message with peers pubKey - if (signedMessage.verify(signaturePubKey, Signature.getInstance(CryptoUtil.MSG_SIGN_ALGO))) { - // Get message - Object messageObject = signedMessage.getObject(); - if (messageObject instanceof Message) { - //log.trace("Decryption needed {} ms", System.currentTimeMillis() - ts); - return new DecryptedMessageWithPubKey((Message) messageObject, signaturePubKey); - } else { - throw new CryptoException("messageObject is not instance of Message"); - } - } else { - throw new CryptoException("Signature is not valid"); - } - } else { - throw new CryptoException("signedMessageObject is not instance of SignedObject"); - } - } else { - throw new CryptoException("secretKeyObject is not instance of SecretKey"); - } - } catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException | BadPaddingException | - ClassNotFoundException | IllegalBlockSizeException | IOException | SignatureException e) { - throw new CryptoException(e); + public DecryptedMessageWithPubKey decryptAndVerifyMessage(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); + } else { + throw new CryptoException("messageObject 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 new file mode 100644 index 0000000000..9a08a69b7b --- /dev/null +++ b/network/src/main/java/io/bitsquare/crypto/SealedAndSignedMessage.java @@ -0,0 +1,23 @@ +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; + + public SealedAndSignedMessage(SealedAndSigned sealedAndSigned, Address peerAddress) { + this.sealedAndSigned = sealedAndSigned; + this.peerAddress = peerAddress; + } + + @Override + public Address getSenderAddress() { + return null; + } +} diff --git a/network/src/main/java/io/bitsquare/p2p/P2PService.java b/network/src/main/java/io/bitsquare/p2p/P2PService.java index 097ed5fae0..3dad33535c 100644 --- a/network/src/main/java/io/bitsquare/p2p/P2PService.java +++ b/network/src/main/java/io/bitsquare/p2p/P2PService.java @@ -10,7 +10,9 @@ import io.bitsquare.common.UserThread; import io.bitsquare.common.crypto.CryptoException; import io.bitsquare.common.crypto.KeyRing; import io.bitsquare.common.crypto.PubKeyRing; +import io.bitsquare.common.crypto.SealedAndSigned; import io.bitsquare.crypto.EncryptionService; +import io.bitsquare.crypto.SealedAndSignedMessage; import io.bitsquare.p2p.messaging.*; import io.bitsquare.p2p.network.*; import io.bitsquare.p2p.routing.Neighbor; @@ -210,7 +212,8 @@ public class P2PService { } else if (message instanceof SealedAndSignedMessage) { if (encryptionService != null) { try { - DecryptedMessageWithPubKey decryptedMessageWithPubKey = encryptionService.decryptAndVerifyMessage((SealedAndSignedMessage) message); + SealedAndSignedMessage sealedAndSignedMessage = (SealedAndSignedMessage) message; + DecryptedMessageWithPubKey decryptedMessageWithPubKey = encryptionService.decryptAndVerifyMessage(sealedAndSignedMessage.sealedAndSigned); UserThread.execute(() -> decryptedMailListeners.stream().forEach(e -> e.onMailMessage(decryptedMessageWithPubKey, connection.getPeerAddress()))); } catch (CryptoException e) { log.info("Decryption of SealedAndSignedMessage failed. That is expected if the message is not intended for us."); @@ -343,7 +346,7 @@ public class P2PService { private void doSendEncryptedMailMessage(Address peerAddress, PubKeyRing pubKeyRing, MailMessage message, SendMailMessageListener sendMailMessageListener) { if (encryptionService != null) { try { - SealedAndSignedMessage sealedAndSignedMessage = encryptionService.encryptAndSignMessage(pubKeyRing, message); + SealedAndSignedMessage sealedAndSignedMessage = new SealedAndSignedMessage(encryptionService.encryptAndSignMessage(pubKeyRing, message), peerAddress); SettableFuture future = sendMessage(peerAddress, sealedAndSignedMessage); Futures.addCallback(future, new FutureCallback() { @Override @@ -386,7 +389,7 @@ public class P2PService { private void trySendEncryptedMailboxMessage(Address peerAddress, PubKeyRing peersPubKeyRing, MailboxMessage message, SendMailboxMessageListener sendMailboxMessageListener) { if (encryptionService != null) { try { - SealedAndSignedMessage sealedAndSignedMessage = encryptionService.encryptAndSignMessage(peersPubKeyRing, message); + SealedAndSignedMessage sealedAndSignedMessage = new SealedAndSignedMessage(encryptionService.encryptAndSignMessage(peersPubKeyRing, message), peerAddress); SettableFuture future = sendMessage(peerAddress, sealedAndSignedMessage); Futures.addCallback(future, new FutureCallback() { @Override @@ -630,9 +633,9 @@ public class P2PService { ExpirablePayload data = mailboxData.expirablePayload; if (data instanceof ExpirableMailboxPayload) { ExpirableMailboxPayload mailboxEntry = (ExpirableMailboxPayload) data; - SealedAndSignedMessage sealedAndSignedMessage = mailboxEntry.sealedAndSignedMessage; + SealedAndSigned sealedAndSigned = mailboxEntry.sealedAndSignedMessage.sealedAndSigned; try { - DecryptedMessageWithPubKey decryptedMessageWithPubKey = encryptionService.decryptAndVerifyMessage(sealedAndSignedMessage); + DecryptedMessageWithPubKey decryptedMessageWithPubKey = encryptionService.decryptAndVerifyMessage(sealedAndSigned); if (decryptedMessageWithPubKey.message instanceof MailboxMessage) { MailboxMessage mailboxMessage = (MailboxMessage) decryptedMessageWithPubKey.message; Address senderAddress = mailboxMessage.getSenderAddress(); @@ -640,8 +643,8 @@ public class P2PService { log.trace("mailboxData.publicKey " + mailboxData.ownerStoragePubKey.hashCode()); log.trace("keyRing.getStorageSignatureKeyPair().getPublic() " + keyRing.getStorageSignatureKeyPair().getPublic().hashCode()); - log.trace("keyRing.getMsgSignatureKeyPair().getPublic() " + keyRing.getMsgSignatureKeyPair().getPublic().hashCode()); - log.trace("keyRing.getMsgEncryptionKeyPair().getPublic() " + keyRing.getMsgEncryptionKeyPair().getPublic().hashCode()); + log.trace("keyRing.getMsgSignatureKeyPair().getPublic() " + keyRing.getSignatureKeyPair().getPublic().hashCode()); + log.trace("keyRing.getMsgEncryptionKeyPair().getPublic() " + keyRing.getEncryptionKeyPair().getPublic().hashCode()); mailboxMap.put(decryptedMessageWithPubKey, mailboxData); diff --git a/network/src/main/java/io/bitsquare/p2p/network/Connection.java b/network/src/main/java/io/bitsquare/p2p/network/Connection.java index b153e628bd..96514c9de6 100644 --- a/network/src/main/java/io/bitsquare/p2p/network/Connection.java +++ b/network/src/main/java/io/bitsquare/p2p/network/Connection.java @@ -355,7 +355,6 @@ public class Connection { reportIllegalRequest(IllegalRequest.MaxSizeExceeded); } } catch (IOException | ClassNotFoundException e) { - log.error("Exception" + e); inputHandlerStopped = true; handleConnectionException(e); } 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 1f56c1e0fe..458a4b7d60 100644 --- a/network/src/main/java/io/bitsquare/p2p/storage/ProtectedExpirableDataStorage.java +++ b/network/src/main/java/io/bitsquare/p2p/storage/ProtectedExpirableDataStorage.java @@ -2,7 +2,8 @@ package io.bitsquare.p2p.storage; import com.google.common.annotations.VisibleForTesting; import io.bitsquare.common.UserThread; -import io.bitsquare.common.crypto.CryptoUtil; +import io.bitsquare.common.crypto.Hash; +import io.bitsquare.common.crypto.Sig; import io.bitsquare.p2p.Address; import io.bitsquare.p2p.network.IllegalRequest; import io.bitsquare.p2p.network.MessageListener; @@ -192,8 +193,8 @@ public class ProtectedExpirableDataStorage { else sequenceNumber = 0; - byte[] hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(payload, sequenceNumber)); - byte[] signature = CryptoUtil.signStorageData(ownerStoragePubKey.getPrivate(), hashOfDataAndSeqNr); + byte[] hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(payload, sequenceNumber)); + byte[] signature = Sig.sign(ownerStoragePubKey.getPrivate(), hashOfDataAndSeqNr); return new ProtectedData(payload, payload.getTTL(), ownerStoragePubKey.getPublic(), sequenceNumber, signature); } @@ -206,8 +207,8 @@ public class ProtectedExpirableDataStorage { else sequenceNumber = 0; - byte[] hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(expirableMailboxPayload, sequenceNumber)); - byte[] signature = CryptoUtil.signStorageData(storageSignaturePubKey.getPrivate(), hashOfDataAndSeqNr); + 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); } @@ -248,9 +249,9 @@ public class ProtectedExpirableDataStorage { } private boolean checkSignature(ProtectedData data) { - byte[] hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(data.expirablePayload, data.sequenceNumber)); + byte[] hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(data.expirablePayload, data.sequenceNumber)); try { - boolean result = CryptoUtil.verifyStorageData(data.ownerStoragePubKey, hashOfDataAndSeqNr, data.signature); + boolean result = Sig.verify(data.ownerStoragePubKey, hashOfDataAndSeqNr, data.signature); if (!result) log.error("Signature verification failed at checkSignature. " + "That should not happen. Consider it might be an attempt of fraud."); @@ -317,6 +318,6 @@ public class ProtectedExpirableDataStorage { } private BigInteger getHashAsBigInteger(ExpirablePayload payload) { - return new BigInteger(CryptoUtil.getHash(payload)); + return new BigInteger(Hash.getHash(payload)); } } diff --git a/network/src/main/java/io/bitsquare/p2p/storage/data/ExpirableMailboxPayload.java b/network/src/main/java/io/bitsquare/p2p/storage/data/ExpirableMailboxPayload.java index 4fc88f254c..193d7652ad 100644 --- a/network/src/main/java/io/bitsquare/p2p/storage/data/ExpirableMailboxPayload.java +++ b/network/src/main/java/io/bitsquare/p2p/storage/data/ExpirableMailboxPayload.java @@ -1,7 +1,7 @@ package io.bitsquare.p2p.storage.data; import io.bitsquare.app.Version; -import io.bitsquare.p2p.messaging.SealedAndSignedMessage; +import io.bitsquare.crypto.SealedAndSignedMessage; import java.security.PublicKey; diff --git a/network/src/test/java/io/bitsquare/crypto/EncryptionServiceTests.java b/network/src/test/java/io/bitsquare/crypto/EncryptionServiceTests.java index 0eba125c26..41bb5f4b25 100644 --- a/network/src/test/java/io/bitsquare/crypto/EncryptionServiceTests.java +++ b/network/src/test/java/io/bitsquare/crypto/EncryptionServiceTests.java @@ -26,7 +26,6 @@ import io.bitsquare.common.util.Utilities; import io.bitsquare.p2p.Address; import io.bitsquare.p2p.messaging.DecryptedMessageWithPubKey; import io.bitsquare.p2p.messaging.MailboxMessage; -import io.bitsquare.p2p.messaging.SealedAndSignedMessage; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -70,8 +69,8 @@ public class EncryptionServiceTests { public void testDecryptAndVerifyMessage() throws CryptoException { EncryptionService encryptionService = new EncryptionService(keyRing); TestMessage data = new TestMessage("test"); - SealedAndSignedMessage encrypted = encryptionService.encryptAndSignMessage(pubKeyRing, data); - DecryptedMessageWithPubKey decrypted = encryptionService.decryptAndVerifyMessage(encrypted); + SealedAndSignedMessage encrypted = new SealedAndSignedMessage(encryptionService.encryptAndSignMessage(pubKeyRing, data), null); + DecryptedMessageWithPubKey decrypted = encryptionService.decryptAndVerifyMessage(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 6982842a0c..2221c456cf 100644 --- a/network/src/test/java/io/bitsquare/p2p/P2PServiceTest.java +++ b/network/src/test/java/io/bitsquare/p2p/P2PServiceTest.java @@ -1,13 +1,10 @@ package io.bitsquare.p2p; -import io.bitsquare.common.crypto.CryptoException; -import io.bitsquare.common.crypto.CryptoUtil; -import io.bitsquare.common.crypto.KeyRing; -import io.bitsquare.common.crypto.KeyStorage; +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.MailboxMessage; -import io.bitsquare.p2p.messaging.SealedAndSignedMessage; import io.bitsquare.p2p.messaging.SendMailboxMessageListener; import io.bitsquare.p2p.mocks.MockMailboxMessage; import io.bitsquare.p2p.network.LocalhostNetworkNode; @@ -161,8 +158,8 @@ public class P2PServiceTest { // try to manipulate seq nr. + pubKey + sig -> fails int sequenceNumberManipulated = origProtectedData.sequenceNumber + 1; - byte[] hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(origProtectedData.expirablePayload, sequenceNumberManipulated)); - byte[] signature = CryptoUtil.signStorageData(msgSignatureKeyPairAdversary.getPrivate(), hashOfDataAndSeqNr); + byte[] hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(origProtectedData.expirablePayload, sequenceNumberManipulated)); + byte[] signature = Sig.sign(msgSignatureKeyPairAdversary.getPrivate(), hashOfDataAndSeqNr); protectedDataManipulated = new ProtectedData(origProtectedData.expirablePayload, origProtectedData.ttl, msgSignatureKeyPairAdversary.getPublic(), sequenceNumberManipulated, signature); Assert.assertFalse(p2PService3.removeData(protectedDataManipulated.expirablePayload)); Thread.sleep(sleepTime); @@ -183,8 +180,8 @@ public class P2PServiceTest { // first he tries to use the orig. pubKey in the data -> fails as pub keys not matching MockData manipulatedData = new MockData("mockData1_manipulated", origData.publicKey); sequenceNumberManipulated = 0; - hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(manipulatedData, sequenceNumberManipulated)); - signature = CryptoUtil.signStorageData(msgSignatureKeyPairAdversary.getPrivate(), hashOfDataAndSeqNr); + hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(manipulatedData, sequenceNumberManipulated)); + signature = Sig.sign(msgSignatureKeyPairAdversary.getPrivate(), hashOfDataAndSeqNr); protectedDataManipulated = new ProtectedData(origProtectedData.expirablePayload, origProtectedData.ttl, msgSignatureKeyPairAdversary.getPublic(), sequenceNumberManipulated, signature); Assert.assertFalse(p2PService3.addData(protectedDataManipulated.expirablePayload)); Thread.sleep(sleepTime); @@ -195,8 +192,8 @@ public class P2PServiceTest { // then he tries to use his pubKey but orig data payload -> fails as pub keys nto matching manipulatedData = new MockData("mockData1_manipulated", msgSignatureKeyPairAdversary.getPublic()); sequenceNumberManipulated = 0; - hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(manipulatedData, sequenceNumberManipulated)); - signature = CryptoUtil.signStorageData(msgSignatureKeyPairAdversary.getPrivate(), hashOfDataAndSeqNr); + hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(manipulatedData, sequenceNumberManipulated)); + signature = Sig.sign(msgSignatureKeyPairAdversary.getPrivate(), hashOfDataAndSeqNr); protectedDataManipulated = new ProtectedData(origProtectedData.expirablePayload, origProtectedData.ttl, msgSignatureKeyPairAdversary.getPublic(), sequenceNumberManipulated, signature); Assert.assertFalse(p2PService3.addData(protectedDataManipulated.expirablePayload)); Thread.sleep(sleepTime); @@ -208,8 +205,8 @@ public class P2PServiceTest { // payload data has adversary's pubKey so he could hijack the owners data manipulatedData = new MockData("mockData1_manipulated", msgSignatureKeyPairAdversary.getPublic()); sequenceNumberManipulated = 0; - hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(manipulatedData, sequenceNumberManipulated)); - signature = CryptoUtil.signStorageData(msgSignatureKeyPairAdversary.getPrivate(), hashOfDataAndSeqNr); + hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(manipulatedData, sequenceNumberManipulated)); + signature = Sig.sign(msgSignatureKeyPairAdversary.getPrivate(), hashOfDataAndSeqNr); protectedDataManipulated = new ProtectedData(manipulatedData, origProtectedData.ttl, msgSignatureKeyPairAdversary.getPublic(), sequenceNumberManipulated, signature); Assert.assertTrue(p2PService3.addData(protectedDataManipulated.expirablePayload)); Thread.sleep(sleepTime); @@ -228,8 +225,8 @@ public class P2PServiceTest { // finally he tries both previous attempts with same data - > same as before manipulatedData = new MockData("mockData1", origData.publicKey); sequenceNumberManipulated = 0; - hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(manipulatedData, sequenceNumberManipulated)); - signature = CryptoUtil.signStorageData(msgSignatureKeyPairAdversary.getPrivate(), hashOfDataAndSeqNr); + hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(manipulatedData, sequenceNumberManipulated)); + signature = Sig.sign(msgSignatureKeyPairAdversary.getPrivate(), hashOfDataAndSeqNr); protectedDataManipulated = new ProtectedData(origProtectedData.expirablePayload, origProtectedData.ttl, msgSignatureKeyPairAdversary.getPublic(), sequenceNumberManipulated, signature); Assert.assertFalse(p2PService3.addData(protectedDataManipulated.expirablePayload)); Thread.sleep(sleepTime); @@ -239,8 +236,8 @@ public class P2PServiceTest { manipulatedData = new MockData("mockData1", msgSignatureKeyPairAdversary.getPublic()); sequenceNumberManipulated = 0; - hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(manipulatedData, sequenceNumberManipulated)); - signature = CryptoUtil.signStorageData(msgSignatureKeyPairAdversary.getPrivate(), hashOfDataAndSeqNr); + hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(manipulatedData, sequenceNumberManipulated)); + signature = Sig.sign(msgSignatureKeyPairAdversary.getPrivate(), hashOfDataAndSeqNr); protectedDataManipulated = new ProtectedData(manipulatedData, origProtectedData.ttl, msgSignatureKeyPairAdversary.getPublic(), sequenceNumberManipulated, signature); Assert.assertTrue(p2PService3.addData(protectedDataManipulated.expirablePayload)); Thread.sleep(sleepTime); @@ -275,7 +272,8 @@ public class P2PServiceTest { log.trace("message " + message); if (message instanceof SealedAndSignedMessage) { try { - DecryptedMessageWithPubKey decryptedMessageWithPubKey = encryptionService2.decryptAndVerifyMessage((SealedAndSignedMessage) message); + SealedAndSignedMessage sealedAndSignedMessage = (SealedAndSignedMessage) message; + DecryptedMessageWithPubKey decryptedMessageWithPubKey = encryptionService2.decryptAndVerifyMessage(sealedAndSignedMessage.sealedAndSigned); Assert.assertEquals(mockMessage, decryptedMessageWithPubKey.message); Assert.assertEquals(p2PService2.getAddress(), ((MailboxMessage) decryptedMessageWithPubKey.message).getSenderAddress()); latch2.countDown(); 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 8ba0689ba9..60eb105a33 100644 --- a/network/src/test/java/io/bitsquare/p2p/storage/ProtectedDataStorageTest.java +++ b/network/src/test/java/io/bitsquare/p2p/storage/ProtectedDataStorageTest.java @@ -1,15 +1,12 @@ package io.bitsquare.p2p.storage; import io.bitsquare.common.UserThread; -import io.bitsquare.common.crypto.CryptoException; -import io.bitsquare.common.crypto.CryptoUtil; -import io.bitsquare.common.crypto.KeyRing; -import io.bitsquare.common.crypto.KeyStorage; +import io.bitsquare.common.crypto.*; import io.bitsquare.common.util.Utilities; import io.bitsquare.crypto.EncryptionService; +import io.bitsquare.crypto.SealedAndSignedMessage; import io.bitsquare.p2p.Address; import io.bitsquare.p2p.TestUtils; -import io.bitsquare.p2p.messaging.SealedAndSignedMessage; import io.bitsquare.p2p.mocks.MockMessage; import io.bitsquare.p2p.network.NetworkNode; import io.bitsquare.p2p.routing.Routing; @@ -89,8 +86,8 @@ public class ProtectedDataStorageTest { Assert.assertEquals(1, dataStorage1.getMap().size()); int newSequenceNumber = data.sequenceNumber + 1; - byte[] hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); - byte[] signature = CryptoUtil.signStorageData(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); + byte[] hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); + byte[] signature = Sig.sign(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); ProtectedData dataToRemove = new ProtectedData(data.expirablePayload, data.ttl, data.ownerStoragePubKey, newSequenceNumber, signature); Assert.assertTrue(dataStorage1.remove(dataToRemove, null)); Assert.assertEquals(0, dataStorage1.getMap().size()); @@ -118,12 +115,12 @@ public class ProtectedDataStorageTest { // add with date in future data = dataStorage1.getDataWithSignedSeqNr(mockData, storageSignatureKeyPair1); int newSequenceNumber = data.sequenceNumber + 1; - byte[] hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); - byte[] signature = CryptoUtil.signStorageData(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); + byte[] hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); + byte[] signature = Sig.sign(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); ProtectedData dataWithFutureDate = new ProtectedData(data.expirablePayload, data.ttl, data.ownerStoragePubKey, newSequenceNumber, signature); dataWithFutureDate.date = new Date(new Date().getTime() + 60 * 60 * sleepTime); // force serialisation (date check is done in readObject) - ProtectedData newData = Utilities.byteArrayToObject(Utilities.objectToByteArray(dataWithFutureDate)); + ProtectedData newData = Utilities.deserialize(Utilities.serialize(dataWithFutureDate)); Assert.assertTrue(dataStorage1.add(newData, null)); Thread.sleep(5); Assert.assertEquals(1, dataStorage1.getMap().size()); @@ -139,57 +136,57 @@ public class ProtectedDataStorageTest { // remove with not updated seq nr -> failure int newSequenceNumber = 0; - byte[] hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); - byte[] signature = CryptoUtil.signStorageData(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); + byte[] hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); + byte[] signature = Sig.sign(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); ProtectedData dataToRemove = new ProtectedData(data.expirablePayload, data.ttl, data.ownerStoragePubKey, newSequenceNumber, signature); Assert.assertFalse(dataStorage1.remove(dataToRemove, null)); // remove with too high updated seq nr -> ok newSequenceNumber = 2; - hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); - signature = CryptoUtil.signStorageData(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); + hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); + signature = Sig.sign(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); dataToRemove = new ProtectedData(data.expirablePayload, data.ttl, data.ownerStoragePubKey, newSequenceNumber, signature); Assert.assertTrue(dataStorage1.remove(dataToRemove, null)); // add with updated seq nr below previous -> failure newSequenceNumber = 1; - hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); - signature = CryptoUtil.signStorageData(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); + hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); + signature = Sig.sign(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); ProtectedData dataToAdd = new ProtectedData(data.expirablePayload, data.ttl, data.ownerStoragePubKey, newSequenceNumber, signature); Assert.assertFalse(dataStorage1.add(dataToAdd, null)); // add with updated seq nr over previous -> ok newSequenceNumber = 3; - hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); - signature = CryptoUtil.signStorageData(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); + hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); + signature = Sig.sign(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); dataToAdd = new ProtectedData(data.expirablePayload, data.ttl, data.ownerStoragePubKey, newSequenceNumber, signature); Assert.assertTrue(dataStorage1.add(dataToAdd, null)); // add with same seq nr -> failure newSequenceNumber = 3; - hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); - signature = CryptoUtil.signStorageData(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); + hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); + signature = Sig.sign(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); dataToAdd = new ProtectedData(data.expirablePayload, data.ttl, data.ownerStoragePubKey, newSequenceNumber, signature); Assert.assertFalse(dataStorage1.add(dataToAdd, null)); // add with same data but higher seq nr. -> ok, ignore newSequenceNumber = 4; - hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); - signature = CryptoUtil.signStorageData(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); + hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); + signature = Sig.sign(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); dataToAdd = new ProtectedData(data.expirablePayload, data.ttl, data.ownerStoragePubKey, newSequenceNumber, signature); Assert.assertTrue(dataStorage1.add(dataToAdd, null)); // remove with with same seq nr as prev. ignored -> failed newSequenceNumber = 4; - hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); - signature = CryptoUtil.signStorageData(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); + hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); + signature = Sig.sign(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); dataToRemove = new ProtectedData(data.expirablePayload, data.ttl, data.ownerStoragePubKey, newSequenceNumber, signature); Assert.assertFalse(dataStorage1.remove(dataToRemove, null)); // remove with with higher seq nr -> ok newSequenceNumber = 5; - hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); - signature = CryptoUtil.signStorageData(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); + hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); + signature = Sig.sign(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); dataToRemove = new ProtectedData(data.expirablePayload, data.ttl, data.ownerStoragePubKey, newSequenceNumber, signature); Assert.assertTrue(dataStorage1.remove(dataToRemove, null)); } @@ -198,7 +195,7 @@ public class ProtectedDataStorageTest { public void testAddAndRemoveMailboxData() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException { // sender MockMessage mockMessage = new MockMessage("MockMessage"); - SealedAndSignedMessage sealedAndSignedMessage = encryptionService1.encryptAndSignMessage(keyRing1.getPubKeyRing(), mockMessage); + SealedAndSignedMessage sealedAndSignedMessage = new SealedAndSignedMessage(encryptionService1.encryptAndSignMessage(keyRing1.getPubKeyRing(), mockMessage), null); ExpirableMailboxPayload expirableMailboxPayload = new ExpirableMailboxPayload(sealedAndSignedMessage, keyRing1.getStorageSignatureKeyPair().getPublic(), keyRing2.getStorageSignatureKeyPair().getPublic()); @@ -210,34 +207,34 @@ public class ProtectedDataStorageTest { // receiver (storageSignatureKeyPair2) int newSequenceNumber = data.sequenceNumber + 1; - byte[] hashOfDataAndSeqNr = CryptoUtil.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); + byte[] hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNr(data.expirablePayload, newSequenceNumber)); byte[] signature; ProtectedMailboxData dataToRemove; // wrong sig -> fail - signature = CryptoUtil.signStorageData(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); + signature = Sig.sign(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr); dataToRemove = new ProtectedMailboxData(expirableMailboxPayload, data.ttl, storageSignatureKeyPair2.getPublic(), newSequenceNumber, signature, storageSignatureKeyPair2.getPublic()); Assert.assertFalse(dataStorage1.removeMailboxData(dataToRemove, null)); // wrong seq nr - signature = CryptoUtil.signStorageData(storageSignatureKeyPair2.getPrivate(), hashOfDataAndSeqNr); + signature = Sig.sign(storageSignatureKeyPair2.getPrivate(), hashOfDataAndSeqNr); dataToRemove = new ProtectedMailboxData(expirableMailboxPayload, data.ttl, storageSignatureKeyPair2.getPublic(), data.sequenceNumber, signature, storageSignatureKeyPair2.getPublic()); Assert.assertFalse(dataStorage1.removeMailboxData(dataToRemove, null)); // wrong signingKey - signature = CryptoUtil.signStorageData(storageSignatureKeyPair2.getPrivate(), hashOfDataAndSeqNr); + signature = Sig.sign(storageSignatureKeyPair2.getPrivate(), hashOfDataAndSeqNr); dataToRemove = new ProtectedMailboxData(expirableMailboxPayload, data.ttl, data.ownerStoragePubKey, newSequenceNumber, signature, storageSignatureKeyPair2.getPublic()); Assert.assertFalse(dataStorage1.removeMailboxData(dataToRemove, null)); // wrong peerPubKey - signature = CryptoUtil.signStorageData(storageSignatureKeyPair2.getPrivate(), hashOfDataAndSeqNr); + signature = Sig.sign(storageSignatureKeyPair2.getPrivate(), hashOfDataAndSeqNr); dataToRemove = new ProtectedMailboxData(expirableMailboxPayload, data.ttl, storageSignatureKeyPair2.getPublic(), newSequenceNumber, signature, storageSignatureKeyPair1.getPublic()); Assert.assertFalse(dataStorage1.removeMailboxData(dataToRemove, null)); // receiver can remove it (storageSignatureKeyPair2) -> all ok Assert.assertEquals(1, dataStorage1.getMap().size()); - signature = CryptoUtil.signStorageData(storageSignatureKeyPair2.getPrivate(), hashOfDataAndSeqNr); + signature = Sig.sign(storageSignatureKeyPair2.getPrivate(), hashOfDataAndSeqNr); dataToRemove = new ProtectedMailboxData(expirableMailboxPayload, data.ttl, storageSignatureKeyPair2.getPublic(), newSequenceNumber, signature, storageSignatureKeyPair2.getPublic()); Assert.assertTrue(dataStorage1.removeMailboxData(dataToRemove, null));