Merge dev and cleanup

This commit is contained in:
alansley
2024-08-06 11:30:50 +10:00
59 changed files with 1027 additions and 996 deletions

View File

@@ -1,19 +1,23 @@
package org.session.libsignal.crypto
import java.security.SecureRandom
import org.session.libsignal.utilities.Util.SECURE_RANDOM
/**
* Uses `SecureRandom` to pick an element from this collection.
*/
fun <T> Collection<T>.getRandomElementOrNull(): T? {
fun <T> Collection<T>.secureRandomOrNull(): T? {
if (isEmpty()) return null
val index = SecureRandom().nextInt(size) // SecureRandom() should be cryptographically secure
val index = SECURE_RANDOM.nextInt(size) // SecureRandom should be cryptographically secure
return elementAtOrNull(index)
}
/**
* Uses `SecureRandom` to pick an element from this collection.
*
* @throws [NullPointerException] if the [Collection] is empty
*/
fun <T> Collection<T>.getRandomElement(): T {
return getRandomElementOrNull()!!
fun <T> Collection<T>.secureRandom(): T {
return secureRandomOrNull()!!
}
fun <T> Collection<T>.shuffledRandom(): List<T> = shuffled(SECURE_RANDOM)

View File

@@ -1,13 +1,13 @@
package org.session.libsignal.streams;
import static org.session.libsignal.crypto.CipherUtil.CIPHER_LOCK;
import static org.session.libsignal.utilities.Util.SECURE_RANDOM;
import java.io.IOException;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
@@ -80,7 +80,7 @@ public class ProfileCipherOutputStream extends DigestingOutputStream {
private byte[] generateNonce() {
byte[] nonce = new byte[12];
new SecureRandom().nextBytes(nonce);
SECURE_RANDOM.nextBytes(nonce);
return nonce;
}

View File

@@ -1,5 +1,7 @@
package org.session.libsignal.utilities;
import androidx.annotation.NonNull;
/**
* <p>Encodes and decodes to and from Base64 notation.</p>
* <p>Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.</p>
@@ -714,7 +716,7 @@ public class Base64
* @throws NullPointerException if source array is null
* @since 1.4
*/
public static String encodeBytes( byte[] source ) {
public static String encodeBytes(@NonNull byte[] source ) {
// Since we're not going to have the GZIP encoding turned on,
// we're not going to have an java.io.IOException thrown, so
// we should not force the user to have to catch it.

View File

@@ -5,8 +5,7 @@ import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.Response
import java.security.SecureRandom
import org.session.libsignal.utilities.Util.SECURE_RANDOM
import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLContext
@@ -35,7 +34,7 @@ object HTTP {
override fun getAcceptedIssuers(): Array<X509Certificate> { return arrayOf() }
}
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, arrayOf( trustManager ), SecureRandom())
sslContext.init(null, arrayOf( trustManager ), SECURE_RANDOM)
OkHttpClient().newBuilder()
.sslSocketFactory(sslContext.socketFactory, trustManager)
.hostnameVerifier { _, _ -> true }
@@ -55,7 +54,7 @@ object HTTP {
override fun getAcceptedIssuers(): Array<X509Certificate> { return arrayOf() }
}
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, arrayOf( trustManager ), SecureRandom())
sslContext.init(null, arrayOf( trustManager ), SECURE_RANDOM)
return OkHttpClient().newBuilder()
.sslSocketFactory(sslContext.socketFactory, trustManager)
.hostnameVerifier { _, _ -> true }

View File

@@ -1,9 +1,25 @@
package org.session.libsignal.utilities
class Snode(val address: String, val port: Int, val publicKeySet: KeySet?, val version: String) {
import android.annotation.SuppressLint
import android.util.LruCache
/**
* Create a Snode from a "-" delimited String if valid, null otherwise.
*/
fun Snode(string: String): Snode? {
val components = string.split("-")
val address = components[0]
val port = components.getOrNull(1)?.toIntOrNull() ?: return null
val ed25519Key = components.getOrNull(2) ?: return null
val x25519Key = components.getOrNull(3) ?: return null
val version = components.getOrNull(4)?.let(Snode::Version) ?: Snode.Version.ZERO
return Snode(address, port, Snode.KeySet(ed25519Key, x25519Key), version)
}
class Snode(val address: String, val port: Int, val publicKeySet: KeySet?, val version: Version) {
val ip: String get() = address.removePrefix("https://")
public enum class Method(val rawValue: String) {
enum class Method(val rawValue: String) {
GetSwarm("get_snodes_for_pubkey"),
Retrieve("retrieve"),
SendMessage("store"),
@@ -19,17 +35,37 @@ class Snode(val address: String, val port: Int, val publicKeySet: KeySet?, val v
data class KeySet(val ed25519Key: String, val x25519Key: String)
override fun equals(other: Any?): Boolean {
return if (other is Snode) {
address == other.address && port == other.port
} else {
false
override fun equals(other: Any?) = other is Snode && address == other.address && port == other.port
override fun hashCode(): Int = address.hashCode() xor port.hashCode()
override fun toString(): String = "$address:$port"
companion object {
private val CACHE = LruCache<String, Version>(100)
@SuppressLint("NotConstructor")
@Synchronized
fun Version(value: String) = CACHE[value] ?: Snode.Version(value).also { CACHE.put(value, it) }
fun Version(parts: List<Int>) = Version(parts.joinToString("."))
}
@JvmInline
value class Version(val value: ULong) {
companion object {
val ZERO = Version(0UL)
private const val MASK_BITS = 16
private const val MASK = 0xFFFFUL
}
}
override fun hashCode(): Int {
return address.hashCode() xor port.hashCode()
}
internal constructor(value: String): this(
value.splitToSequence(".")
.take(4)
.map { it.toULongOrNull() ?: 0UL }
.foldIndexed(0UL) { i, acc, it ->
it.coerceAtMost(MASK) shl (3 - i) * MASK_BITS or acc
}
)
override fun toString(): String { return "$address:$port" }
operator fun compareTo(other: Version): Int = value.compareTo(other.value)
}
}

View File

@@ -12,12 +12,10 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class Util {
public static SecureRandom SECURE_RANDOM = new SecureRandom();
public static byte[] join(byte[]... input) {
try {
@@ -67,7 +65,7 @@ public class Util {
}
public static boolean isEmpty(String value) {
return value == null || value.trim().length() == 0;
return value == null || value.trim().isEmpty();
}
public static byte[] getSecretBytes(int size) {
@@ -80,13 +78,6 @@ public class Util {
}
}
public static byte[] getRandomLengthBytes(int maxSize) {
SecureRandom secureRandom = new SecureRandom();
byte[] result = new byte[secureRandom.nextInt(maxSize) + 1];
secureRandom.nextBytes(result);
return result;
}
public static String readFully(InputStream in) throws IOException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
@@ -98,7 +89,7 @@ public class Util {
in.close();
return new String(bout.toByteArray());
return bout.toString();
}
public static void readFully(InputStream in, byte[] buffer) throws IOException {
@@ -146,9 +137,4 @@ public class Util {
}
return (int)value;
}
public static <T> List<T> immutableList(T... elements) {
return Collections.unmodifiableList(Arrays.asList(elements.clone()));
}
}