diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/Util.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/Util.kt index ff33a58e91b..71a0aae0fba 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/Util.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/Util.kt @@ -33,18 +33,16 @@ import android.view.View import com.annimon.stream.Stream import com.google.android.mms.pdu_alt.CharacterSets import com.google.android.mms.pdu_alt.EncodedStringValue +import network.loki.messenger.R +import org.session.libsignal.utilities.Log +import org.thoughtcrime.securesms.components.ComposeText import java.io.ByteArrayOutputStream import java.io.IOException import java.io.UnsupportedEncodingException -import java.security.SecureRandom -import java.util.Arrays import java.util.Collections import java.util.concurrent.TimeUnit import kotlin.math.max import kotlin.math.min -import network.loki.messenger.R -import org.session.libsignal.utilities.Log -import org.thoughtcrime.securesms.components.ComposeText object Util { private val TAG: String = Log.tag(Util::class.java) @@ -248,32 +246,6 @@ object Util { return result } - fun getSecretBytes(size: Int): ByteArray { - return getSecretBytes(SecureRandom(), size) - } - - fun getSecretBytes(secureRandom: SecureRandom, size: Int): ByteArray { - val secret = ByteArray(size) - secureRandom.nextBytes(secret) - return secret - } - - fun getRandomElement(elements: Array): T { - return elements[SecureRandom().nextInt(elements.size)] - } - - fun getRandomElement(elements: List): T { - return elements[SecureRandom().nextInt(elements.size)] - } - - fun equals(a: Any?, b: Any?): Boolean { - return a === b || (a != null && a == b) - } - - fun hashCode(vararg objects: Any?): Int { - return objects.contentHashCode() - } - fun uri(uri: String?): Uri? { return if (uri == null) null else Uri.parse(uri) diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/AttachmentSecretProvider.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/AttachmentSecretProvider.java index 0344551cab8..1602ab3fcfa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/AttachmentSecretProvider.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/AttachmentSecretProvider.java @@ -1,14 +1,14 @@ package org.thoughtcrime.securesms.crypto; +import static org.session.libsignal.utilities.Util.SECURE_RANDOM; + import android.content.Context; import android.os.Build; import androidx.annotation.NonNull; import org.session.libsession.utilities.TextSecurePreferences; -import java.security.SecureRandom; - /** * A provider that is responsible for creating or retrieving the AttachmentSecret model. * @@ -81,9 +81,8 @@ private AttachmentSecret getEncryptedAttachmentSecret(@NonNull String serialized } private AttachmentSecret createAndStoreAttachmentSecret(@NonNull Context context) { - SecureRandom random = new SecureRandom(); byte[] secret = new byte[32]; - random.nextBytes(secret); + SECURE_RANDOM.nextBytes(secret); AttachmentSecret attachmentSecret = new AttachmentSecret(null, null, secret); storeAttachmentSecret(context, attachmentSecret); diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/DatabaseSecretProvider.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/DatabaseSecretProvider.java index 0ad22c3a909..44bb33161c2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/DatabaseSecretProvider.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/DatabaseSecretProvider.java @@ -1,6 +1,8 @@ package org.thoughtcrime.securesms.crypto; +import static org.session.libsignal.utilities.Util.SECURE_RANDOM; + import android.content.Context; import android.os.Build; import androidx.annotation.NonNull; @@ -8,7 +10,6 @@ import org.session.libsession.utilities.TextSecurePreferences; import java.io.IOException; -import java.security.SecureRandom; public class DatabaseSecretProvider { @@ -60,9 +61,8 @@ private DatabaseSecret getEncryptedDatabaseSecret(@NonNull String serializedEncr } private DatabaseSecret createAndStoreDatabaseSecret(@NonNull Context context) { - SecureRandom random = new SecureRandom(); byte[] secret = new byte[32]; - random.nextBytes(secret); + SECURE_RANDOM.nextBytes(secret); DatabaseSecret databaseSecret = new DatabaseSecret(secret); diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/ModernEncryptingPartOutputStream.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/ModernEncryptingPartOutputStream.java index ab4efe84a9d..0bd62f21431 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/ModernEncryptingPartOutputStream.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/ModernEncryptingPartOutputStream.java @@ -1,6 +1,8 @@ package org.thoughtcrime.securesms.crypto; +import static org.session.libsignal.utilities.Util.SECURE_RANDOM; + import androidx.annotation.NonNull; import android.util.Pair; @@ -11,7 +13,6 @@ import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.CipherOutputStream; @@ -31,7 +32,7 @@ public static Pair createFor(@NonNull AttachmentSecret att throws IOException { byte[] random = new byte[32]; - new SecureRandom().nextBytes(random); + SECURE_RANDOM.nextBytes(random); try { Mac mac = Mac.getInstance("HmacSHA256"); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java index 66d01114ef1..6e1f72c5680 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java @@ -1,5 +1,7 @@ package org.thoughtcrime.securesms.database; +import static org.session.libsignal.utilities.Util.SECURE_RANDOM; + import android.annotation.SuppressLint; import android.content.ContentValues; import android.content.Context; @@ -26,7 +28,6 @@ import org.thoughtcrime.securesms.util.BitmapUtil; import java.io.Closeable; -import java.security.SecureRandom; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -303,7 +304,7 @@ public void updateProfilePicture(String groupID, Bitmap newValue) { public void updateProfilePicture(String groupID, byte[] newValue) { long avatarId; - if (newValue != null) avatarId = Math.abs(new SecureRandom().nextLong()); + if (newValue != null) avatarId = Math.abs(SECURE_RANDOM.nextLong()); else avatarId = 0; @@ -458,12 +459,6 @@ public void setActive(String groupId, boolean active) { database.update(TABLE_NAME, values, GROUP_ID + " = ?", new String[] {groupId}); } - public byte[] allocateGroupId() { - byte[] groupId = new byte[16]; - new SecureRandom().nextBytes(groupId); - return groupId; - } - public boolean hasGroup(@NonNull String groupId) { try (Cursor cursor = databaseHelper.getReadableDatabase().rawQuery( "SELECT 1 FROM " + TABLE_NAME + " WHERE " + GROUP_ID + " = ? LIMIT 1", diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt index 9d3a6c9c184..5a2a9155de0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt @@ -46,11 +46,11 @@ import org.session.libsession.utilities.IdentityKeyMismatchList import org.session.libsession.utilities.NetworkFailure import org.session.libsession.utilities.NetworkFailureList import org.session.libsession.utilities.TextSecurePreferences.Companion.isReadReceiptsEnabled -import org.session.libsession.utilities.Util.toIsoBytes import org.session.libsession.utilities.recipients.Recipient import org.session.libsignal.utilities.JsonUtil import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.ThreadUtils.queue +import org.session.libsignal.utilities.Util.SECURE_RANDOM import org.session.libsignal.utilities.guava.Optional import org.thoughtcrime.securesms.attachments.MmsNotificationAttachment import org.thoughtcrime.securesms.database.SmsDatabase.InsertListener @@ -66,7 +66,6 @@ import org.thoughtcrime.securesms.mms.SlideDeck import org.thoughtcrime.securesms.util.asSequence import java.io.Closeable import java.io.IOException -import java.security.SecureRandom import java.util.LinkedList class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : MessagingDatabase(context, databaseHelper) { @@ -1200,7 +1199,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa inner class OutgoingMessageReader(private val message: OutgoingMediaMessage?, private val threadId: Long) { - private val id = SecureRandom().nextLong() + private val id = SECURE_RANDOM.nextLong() val current: MessageRecord get() { val slideDeck = SlideDeck(context, message!!.attachments) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java index 84b94418342..f02498112fa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -17,6 +17,8 @@ */ package org.thoughtcrime.securesms.database; +import static org.session.libsignal.utilities.Util.SECURE_RANDOM; + import android.content.ContentValues; import android.content.Context; import android.database.Cursor; @@ -49,7 +51,6 @@ import org.thoughtcrime.securesms.dependencies.DatabaseComponent; import java.io.Closeable; import java.io.IOException; -import java.security.SecureRandom; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; @@ -784,7 +785,7 @@ public class OutgoingMessageReader { public OutgoingMessageReader(OutgoingTextMessage message, long threadId) { this.message = message; this.threadId = threadId; - this.id = new SecureRandom().nextLong(); + this.id = SECURE_RANDOM.nextLong(); } public MessageRecord getCurrent() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/glide/PaddedHeadersInterceptor.java b/app/src/main/java/org/thoughtcrime/securesms/glide/PaddedHeadersInterceptor.java index 5d0ab584b76..9c347eb414e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/glide/PaddedHeadersInterceptor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/glide/PaddedHeadersInterceptor.java @@ -1,9 +1,10 @@ package org.thoughtcrime.securesms.glide; +import static org.session.libsignal.utilities.Util.SECURE_RANDOM; + import androidx.annotation.NonNull; import java.io.IOException; -import java.security.SecureRandom; import okhttp3.Headers; import okhttp3.Interceptor; @@ -30,15 +31,15 @@ public class PaddedHeadersInterceptor implements Interceptor { private @NonNull Headers getPaddedHeaders(@NonNull Headers headers) { return headers.newBuilder() - .add(PADDING_HEADER, getRandomString(new SecureRandom(), MIN_RANDOM_BYTES, MAX_RANDOM_BYTES)) + .add(PADDING_HEADER, getRandomString(MIN_RANDOM_BYTES, MAX_RANDOM_BYTES)) .build(); } - private static @NonNull String getRandomString(@NonNull SecureRandom secureRandom, int minLength, int maxLength) { - char[] buffer = new char[secureRandom.nextInt(maxLength - minLength) + minLength]; + private static @NonNull String getRandomString(int minLength, int maxLength) { + char[] buffer = new char[SECURE_RANDOM.nextInt(maxLength - minLength) + minLength]; for (int i = 0 ; i < buffer.length; i++) { - buffer[i] = (char) (secureRandom.nextInt(74) + 48); // Random char from 0-Z + buffer[i] = (char) (SECURE_RANDOM.nextInt(74) + 48); // Random char from 0-Z } return new String(buffer); diff --git a/app/src/main/java/org/thoughtcrime/securesms/logging/LogFile.java b/app/src/main/java/org/thoughtcrime/securesms/logging/LogFile.java index 909f19e08c0..cfe6cc38093 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/logging/LogFile.java +++ b/app/src/main/java/org/thoughtcrime/securesms/logging/LogFile.java @@ -1,6 +1,7 @@ package org.thoughtcrime.securesms.logging; import static org.session.libsignal.crypto.CipherUtil.CIPHER_LOCK; +import static org.session.libsignal.utilities.Util.SECURE_RANDOM; import androidx.annotation.NonNull; @@ -17,7 +18,6 @@ import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; @@ -64,7 +64,7 @@ public static class Writer { } void writeEntry(@NonNull String entry) throws IOException { - new SecureRandom().nextBytes(ivBuffer); + SECURE_RANDOM.nextBytes(ivBuffer); byte[] plaintext = entry.getBytes(); try { diff --git a/app/src/main/java/org/thoughtcrime/securesms/logging/LogSecretProvider.java b/app/src/main/java/org/thoughtcrime/securesms/logging/LogSecretProvider.java index aabd2811db0..763a2a430d4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/logging/LogSecretProvider.java +++ b/app/src/main/java/org/thoughtcrime/securesms/logging/LogSecretProvider.java @@ -1,5 +1,7 @@ package org.thoughtcrime.securesms.logging; +import static org.session.libsignal.utilities.Util.SECURE_RANDOM; + import android.content.Context; import android.os.Build; import androidx.annotation.NonNull; @@ -9,7 +11,6 @@ import org.session.libsession.utilities.TextSecurePreferences; import java.io.IOException; -import java.security.SecureRandom; class LogSecretProvider { @@ -40,9 +41,8 @@ private static byte[] parseEncryptedSecret(String secret) { } private static byte[] createAndStoreSecret(@NonNull Context context) { - SecureRandom random = new SecureRandom(); byte[] secret = new byte[32]; - random.nextBytes(secret); + SECURE_RANDOM.nextBytes(secret); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { KeyStoreHelper.SealedData encryptedSecret = KeyStoreHelper.seal(secret); diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/Slide.kt b/app/src/main/java/org/thoughtcrime/securesms/mms/Slide.kt index e284c1ce22d..05d8167d9a7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mms/Slide.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mms/Slide.kt @@ -21,7 +21,6 @@ import android.content.res.Resources import android.net.Uri import androidx.annotation.DrawableRes import com.squareup.phrase.Phrase -import java.security.SecureRandom import network.loki.messenger.R import org.session.libsession.messaging.sending_receiving.attachments.Attachment import org.session.libsession.messaging.sending_receiving.attachments.AttachmentTransferProgress @@ -29,6 +28,7 @@ import org.session.libsession.messaging.sending_receiving.attachments.UriAttachm import org.session.libsession.utilities.StringSubstitutionConstants.EMOJI_KEY import org.session.libsession.utilities.Util.equals import org.session.libsession.utilities.Util.hashCode +import org.session.libsignal.utilities.Util.SECURE_RANDOM import org.session.libsignal.utilities.guava.Optional import org.thoughtcrime.securesms.conversation.v2.Util import org.thoughtcrime.securesms.util.MediaUtil @@ -160,7 +160,7 @@ abstract class Slide(@JvmField protected val context: Context, protected val att ): Attachment { val resolvedType = Optional.fromNullable(MediaUtil.getMimeType(context, uri)).or(defaultMime) - val fastPreflightId = SecureRandom().nextLong().toString() + val fastPreflightId = SECURE_RANDOM.nextLong().toString() return UriAttachment( uri, if (hasThumbnail) uri else null, diff --git a/app/src/main/java/org/thoughtcrime/securesms/net/ChunkedDataFetcher.java b/app/src/main/java/org/thoughtcrime/securesms/net/ChunkedDataFetcher.java index af37b863944..e50846b1c96 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/net/ChunkedDataFetcher.java +++ b/app/src/main/java/org/thoughtcrime/securesms/net/ChunkedDataFetcher.java @@ -1,5 +1,7 @@ package org.thoughtcrime.securesms.net; +import static org.session.libsignal.utilities.Util.SECURE_RANDOM; + import androidx.annotation.NonNull; import android.text.TextUtils; @@ -15,7 +17,6 @@ import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; -import java.security.SecureRandom; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -54,7 +55,7 @@ public RequestController fetch(@NonNull String url, long contentLength, @NonNull private RequestController fetchChunksWithUnknownTotalSize(@NonNull String url, @NonNull Callback callback) { CompositeRequestController compositeController = new CompositeRequestController(); - long chunkSize = new SecureRandom().nextInt(1024) + 1024; + long chunkSize = SECURE_RANDOM.nextInt(1024) + 1024; Request request = new Request.Builder() .url(url) .cacheControl(NO_CACHE) diff --git a/app/src/main/java/org/thoughtcrime/securesms/permissions/Permissions.java b/app/src/main/java/org/thoughtcrime/securesms/permissions/Permissions.java index 88ee67cb4de..9b6950bf7ad 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/permissions/Permissions.java +++ b/app/src/main/java/org/thoughtcrime/securesms/permissions/Permissions.java @@ -1,9 +1,9 @@ package org.thoughtcrime.securesms.permissions; +import static org.session.libsignal.utilities.Util.SECURE_RANDOM; + import android.app.Activity; -import android.app.AlertDialog; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; @@ -11,9 +11,7 @@ import android.provider.Settings; import android.util.DisplayMetrics; import android.view.Display; -import android.view.ViewGroup; import android.view.WindowManager; -import android.widget.Button; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; @@ -28,13 +26,10 @@ import org.thoughtcrime.securesms.util.LRUCache; import java.lang.ref.WeakReference; -import java.security.SecureRandom; import java.util.Arrays; import java.util.List; import java.util.Map; -import network.loki.messenger.R; - public class Permissions { private static final Map OUTSTANDING = new LRUCache<>(2); @@ -172,7 +167,7 @@ private void executePermissionsRequestWithRationale(PermissionsRequest request) } private void executePermissionsRequest(PermissionsRequest request) { - int requestCode = new SecureRandom().nextInt(65434) + 100; + int requestCode = SECURE_RANDOM.nextInt(65434) + 100; synchronized (OUTSTANDING) { OUTSTANDING.put(requestCode, request); diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt index fc98070ca40..dc1011d970a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/SettingsActivity.kt @@ -62,6 +62,7 @@ import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.recipients.Recipient import org.session.libsession.utilities.truncateIdForDisplay import org.session.libsignal.utilities.Log +import org.session.libsignal.utilities.Util.SECURE_RANDOM import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.avatar.AvatarSelection import org.thoughtcrime.securesms.components.ProfilePictureView @@ -90,7 +91,6 @@ import org.thoughtcrime.securesms.util.NetworkUtils import org.thoughtcrime.securesms.util.push import org.thoughtcrime.securesms.util.show import java.io.File -import java.security.SecureRandom import javax.inject.Inject @AndroidEntryPoint @@ -294,7 +294,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { val userConfig = configFactory.user AvatarHelper.setAvatar(this, Address.fromSerialized(TextSecurePreferences.getLocalNumber(this)!!), profilePicture) - prefs.setProfileAvatarId(SecureRandom().nextInt() ) + prefs.setProfileAvatarId(SECURE_RANDOM.nextInt() ) ProfileKeyUtil.setEncodedProfileKey(this, encodedProfileKey) // Attempt to grab the details we require to update the profile picture diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.kt index b61edbb6d26..24ea2a390fd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.kt @@ -1,8 +1,10 @@ package org.thoughtcrime.securesms.webrtc import android.content.Context +import org.session.libsignal.crypto.shuffledRandom import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.SettableFuture +import org.session.libsignal.utilities.Util.SECURE_RANDOM import org.thoughtcrime.securesms.webrtc.video.Camera import org.thoughtcrime.securesms.webrtc.video.CameraEventListener import org.thoughtcrime.securesms.webrtc.video.CameraState @@ -22,9 +24,7 @@ import org.webrtc.SurfaceTextureHelper import org.webrtc.VideoSink import org.webrtc.VideoSource import org.webrtc.VideoTrack -import java.security.SecureRandom import java.util.concurrent.ExecutionException -import kotlin.random.asKotlinRandom class PeerConnectionWrapper(private val context: Context, private val factory: PeerConnectionFactory, @@ -49,8 +49,7 @@ class PeerConnectionWrapper(private val context: Context, private var isInitiator = false private fun initPeerConnection() { - val random = SecureRandom().asKotlinRandom() - val iceServers = listOf("freyr","angus","hereford","holstein", "brahman").shuffled(random).take(2).map { sub -> + val iceServers = listOf("freyr","angus","hereford","holstein", "brahman").shuffledRandom().take(2).map { sub -> PeerConnection.IceServer.builder("turn:$sub.getsession.org") .setUsername("session202111") .setPassword("053c268164bc7bd7") diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/RetrieveProfileAvatarJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/RetrieveProfileAvatarJob.kt index 54efa1c80bd..d82f29446dd 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/RetrieveProfileAvatarJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/RetrieveProfileAvatarJob.kt @@ -12,11 +12,11 @@ import org.session.libsession.utilities.Util.equals import org.session.libsession.utilities.recipients.Recipient import org.session.libsignal.streams.ProfileCipherInputStream import org.session.libsignal.utilities.Log +import org.session.libsignal.utilities.Util.SECURE_RANDOM import java.io.File import java.io.FileInputStream import java.io.FileOutputStream import java.io.InputStream -import java.security.SecureRandom import java.util.concurrent.ConcurrentSkipListSet class RetrieveProfileAvatarJob(private val profileAvatar: String?, val recipientAddress: Address): Job { @@ -64,7 +64,7 @@ class RetrieveProfileAvatarJob(private val profileAvatar: String?, val recipient Log.w(TAG, "Removing profile avatar for: " + recipient.address.serialize()) if (recipient.isLocalNumber) { - setProfileAvatarId(context, SecureRandom().nextInt()) + setProfileAvatarId(context, SECURE_RANDOM.nextInt()) setProfilePictureURL(context, null) } @@ -83,7 +83,7 @@ class RetrieveProfileAvatarJob(private val profileAvatar: String?, val recipient decryptDestination.renameTo(AvatarHelper.getAvatarFile(context, recipient.address)) if (recipient.isLocalNumber) { - setProfileAvatarId(context, SecureRandom().nextInt()) + setProfileAvatarId(context, SECURE_RANDOM.nextInt()) setProfilePictureURL(context, profileAvatar) } diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/ClosedGroupPollerV2.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/ClosedGroupPollerV2.kt index 293fbc8d8ab..c9b7abefbc4 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/ClosedGroupPollerV2.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/ClosedGroupPollerV2.kt @@ -10,7 +10,7 @@ import org.session.libsession.messaging.jobs.JobQueue import org.session.libsession.messaging.jobs.MessageReceiveParameters import org.session.libsession.snode.SnodeAPI import org.session.libsession.utilities.GroupUtil -import org.session.libsignal.crypto.getRandomElementOrNull +import org.session.libsignal.crypto.secureRandomOrNull import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.Namespace import org.session.libsignal.utilities.defaultRequiresAuth @@ -104,7 +104,7 @@ class ClosedGroupPollerV2 { fun poll(groupPublicKey: String): Promise { if (!isPolling(groupPublicKey)) { return Promise.of(Unit) } val promise = SnodeAPI.getSwarm(groupPublicKey).bind { swarm -> - val snode = swarm.getRandomElementOrNull() ?: throw InsufficientSnodesException() // Should be cryptographically secure + val snode = swarm.secureRandomOrNull() ?: throw InsufficientSnodesException() // Should be cryptographically secure if (!isPolling(groupPublicKey)) { throw PollingCanceledException() } val currentForkInfo = SnodeAPI.forkInfo when { diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/Poller.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/Poller.kt index 2b7c8159eac..f57aa1f0f78 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/Poller.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/Poller.kt @@ -19,8 +19,6 @@ import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.jobs.BatchMessageReceiveJob import org.session.libsession.messaging.jobs.JobQueue import org.session.libsession.messaging.jobs.MessageReceiveParameters -import org.session.libsession.messaging.messages.control.SharedConfigurationMessage -import org.session.libsession.messaging.sending_receiving.MessageReceiver import org.session.libsession.snode.RawResponse import org.session.libsession.snode.SnodeAPI import org.session.libsession.snode.SnodeModule @@ -29,7 +27,7 @@ import org.session.libsignal.utilities.Base64 import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.Namespace import org.session.libsignal.utilities.Snode -import java.security.SecureRandom +import org.session.libsignal.utilities.Util.SECURE_RANDOM import java.util.Timer import java.util.TimerTask import kotlin.time.Duration.Companion.days @@ -106,7 +104,7 @@ class Poller(private val configFactory: ConfigFactoryProtocol, debounceTimer: Ti val swarm = SnodeModule.shared.storage.getSwarm(userPublicKey) ?: setOf() val unusedSnodes = swarm.subtract(usedSnodes) if (unusedSnodes.isNotEmpty()) { - val index = SecureRandom().nextInt(unusedSnodes.size) + val index = SECURE_RANDOM.nextInt(unusedSnodes.size) val nextSnode = unusedSnodes.elementAt(index) usedSnodes.add(nextSnode) Log.d(TAG, "Polling $nextSnode.") diff --git a/libsession/src/main/java/org/session/libsession/messaging/utilities/MessageWrapper.kt b/libsession/src/main/java/org/session/libsession/messaging/utilities/MessageWrapper.kt index 569b9c62c19..71cd587b450 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/MessageWrapper.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/MessageWrapper.kt @@ -28,7 +28,7 @@ object MessageWrapper { val webSocketMessage = createWebSocketMessage(envelope) return webSocketMessage.toByteArray() } catch (e: Exception) { - throw if (e is Error) { e } else { Error.FailedToWrapData } + throw if (e is Error) e else Error.FailedToWrapData } } @@ -49,15 +49,15 @@ object MessageWrapper { private fun createWebSocketMessage(envelope: Envelope): WebSocketMessage { try { - val requestBuilder = WebSocketRequestMessage.newBuilder() - requestBuilder.verb = "PUT" - requestBuilder.path = "/api/v1/message" - requestBuilder.id = SecureRandom.getInstance("SHA1PRNG").nextLong() - requestBuilder.body = envelope.toByteString() - val messageBuilder = WebSocketMessage.newBuilder() - messageBuilder.request = requestBuilder.build() - messageBuilder.type = WebSocketMessage.Type.REQUEST - return messageBuilder.build() + return WebSocketMessage.newBuilder().apply { + request = WebSocketRequestMessage.newBuilder().apply { + verb = "PUT" + path = "/api/v1/message" + id = SecureRandom.getInstance("SHA1PRNG").nextLong() + body = envelope.toByteString() + }.build() + type = WebSocketMessage.Type.REQUEST + }.build() } catch (e: Exception) { Log.d("Loki", "Failed to wrap envelope in web socket message: ${e.message}.") throw Error.FailedToWrapEnvelopeInWebSocketMessage diff --git a/libsession/src/main/java/org/session/libsession/snode/OnionRequestAPI.kt b/libsession/src/main/java/org/session/libsession/snode/OnionRequestAPI.kt index ead454eb446..9ff541a9d5c 100644 --- a/libsession/src/main/java/org/session/libsession/snode/OnionRequestAPI.kt +++ b/libsession/src/main/java/org/session/libsession/snode/OnionRequestAPI.kt @@ -10,11 +10,10 @@ import okhttp3.Request import org.session.libsession.messaging.file_server.FileServerApi import org.session.libsession.utilities.AESGCM import org.session.libsession.utilities.AESGCM.EncryptionResult -import org.session.libsession.utilities.Util import org.session.libsession.utilities.getBodyForOnionRequest import org.session.libsession.utilities.getHeadersForOnionRequest -import org.session.libsignal.crypto.getRandomElement -import org.session.libsignal.crypto.getRandomElementOrNull +import org.session.libsignal.crypto.secureRandom +import org.session.libsignal.crypto.secureRandomOrNull import org.session.libsignal.database.LokiAPIDatabaseProtocol import org.session.libsignal.utilities.Base64 import org.session.libsignal.utilities.Broadcaster @@ -149,7 +148,7 @@ object OnionRequestAPI { val reusableGuardSnodeCount = reusableGuardSnodes.count() if (unusedSnodes.count() < (targetGuardSnodeCount - reusableGuardSnodeCount)) { throw InsufficientSnodesException() } fun getGuardSnode(): Promise { - val candidate = unusedSnodes.getRandomElementOrNull() + val candidate = unusedSnodes.secureRandomOrNull() ?: return Promise.ofFail(InsufficientSnodesException()) unusedSnodes = unusedSnodes.minus(candidate) Log.d("Loki", "Testing guard snode: $candidate.") @@ -191,7 +190,7 @@ object OnionRequestAPI { // Don't test path snodes as this would reveal the user's IP to them guardSnodes.minus(reusableGuardSnodes).map { guardSnode -> val result = listOf( guardSnode ) + (0 until (pathSize - 1)).mapIndexed() { index, _ -> - var pathSnode = unusedSnodes.getRandomElement() + var pathSnode = unusedSnodes.secureRandom() // remove the snode from the unused list and return it unusedSnodes = unusedSnodes.minus(pathSnode) @@ -228,9 +227,9 @@ object OnionRequestAPI { OnionRequestAPI.guardSnodes = guardSnodes fun getPath(paths: List): Path { return if (snodeToExclude != null) { - paths.filter { !it.contains(snodeToExclude) }.getRandomElement() + paths.filter { !it.contains(snodeToExclude) }.secureRandom() } else { - paths.getRandomElement() + paths.secureRandom() } } when { @@ -273,7 +272,7 @@ object OnionRequestAPI { path.removeAt(snodeIndex) val unusedSnodes = SnodeAPI.snodePool.minus(oldPaths.flatten()) if (unusedSnodes.isEmpty()) { throw InsufficientSnodesException() } - path.add(unusedSnodes.getRandomElement()) + path.add(unusedSnodes.secureRandom()) // Don't test the new snode as this would reveal the user's IP oldPaths.removeAt(pathIndex) val newPaths = oldPaths + listOf( path ) diff --git a/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt b/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt index 034ef0e7d23..6a27312f7c3 100644 --- a/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt +++ b/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt @@ -18,7 +18,8 @@ import nl.komponents.kovenant.task import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.utilities.MessageWrapper import org.session.libsession.messaging.utilities.SodiumUtilities.sodium -import org.session.libsignal.crypto.getRandomElement +import org.session.libsignal.crypto.secureRandom +import org.session.libsignal.crypto.shuffledRandom import org.session.libsignal.database.LokiAPIDatabaseProtocol import org.session.libsignal.protos.SignalServiceProtos import org.session.libsignal.utilities.Base64 @@ -30,6 +31,7 @@ import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.Namespace import org.session.libsignal.utilities.Snode import org.session.libsignal.utilities.ThreadUtils +import org.session.libsignal.utilities.Util.SECURE_RANDOM import org.session.libsignal.utilities.prettifiedDescription import org.session.libsignal.utilities.retryIfNeeded import java.security.SecureRandom @@ -209,7 +211,7 @@ object SnodeAPI { Log.d("Loki", "Persisting snode pool to database.") this.snodePool = snodePool try { - deferred.resolve(snodePool.getRandomElement()) + deferred.resolve(snodePool.secureRandom()) } catch (exception: Exception) { Log.d("Loki", "Got an empty snode pool from: $target.") deferred.reject(SnodeAPI.Error.Generic) @@ -224,7 +226,7 @@ object SnodeAPI { } return deferred.promise } else { - return Promise.of(snodePool.getRandomElement()) + return Promise.of(snodePool.secureRandom()) } } @@ -241,8 +243,8 @@ object SnodeAPI { } internal fun getSingleTargetSnode(publicKey: String): Promise { - // SecureRandom() should be cryptographically secure - return getSwarm(publicKey).map { it.shuffled(SecureRandom()).random() } + // SecureRandom should be cryptographically secure + return getSwarm(publicKey).map { it.shuffledRandom().random() } } // Public API diff --git a/libsession/src/main/java/org/session/libsession/utilities/Util.kt b/libsession/src/main/java/org/session/libsession/utilities/Util.kt index 929f53e305e..1293547703e 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/Util.kt +++ b/libsession/src/main/java/org/session/libsession/utilities/Util.kt @@ -13,6 +13,7 @@ import android.text.TextUtils import android.text.style.StyleSpan import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.Base64 +import org.session.libsignal.utilities.Util.SECURE_RANDOM import java.io.* import java.nio.charset.StandardCharsets import java.security.SecureRandom @@ -292,15 +293,10 @@ object Util { @JvmStatic fun getSecretBytes(size: Int): ByteArray { val secret = ByteArray(size) - getSecureRandom().nextBytes(secret) + SECURE_RANDOM.nextBytes(secret) return secret } - @JvmStatic - fun getSecureRandom(): SecureRandom { - return SecureRandom() - } - @JvmStatic fun getFirstNonEmpty(vararg values: String?): String? { for (value in values) { @@ -317,18 +313,14 @@ object Util { } @JvmStatic - fun getRandomElement(elements: Array): T { - return elements[SecureRandom().nextInt(elements.size)] - } + fun getRandomElement(elements: Array): T = elements[SECURE_RANDOM.nextInt(elements.size)] @JvmStatic fun getBoldedString(value: String?): CharSequence { if (value.isNullOrEmpty()) { return "" } - val spanned = SpannableString(value) - spanned.setSpan(StyleSpan(Typeface.BOLD), 0, - spanned.length, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) - return spanned + return SpannableString(value).also { + it.setSpan(StyleSpan(Typeface.BOLD), 0, it.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + } } @JvmStatic diff --git a/libsignal/src/main/java/org/session/libsignal/crypto/Random.kt b/libsignal/src/main/java/org/session/libsignal/crypto/Random.kt index 4f7687307b7..c32eb78595b 100644 --- a/libsignal/src/main/java/org/session/libsignal/crypto/Random.kt +++ b/libsignal/src/main/java/org/session/libsignal/crypto/Random.kt @@ -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 Collection.getRandomElementOrNull(): T? { +fun Collection.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 Collection.getRandomElement(): T { - return getRandomElementOrNull()!! +fun Collection.secureRandom(): T { + return secureRandomOrNull()!! } + +fun Collection.shuffledRandom(): List = shuffled(SECURE_RANDOM) diff --git a/libsignal/src/main/java/org/session/libsignal/streams/ProfileCipherOutputStream.java b/libsignal/src/main/java/org/session/libsignal/streams/ProfileCipherOutputStream.java index f47a5f72b69..43734605ae0 100644 --- a/libsignal/src/main/java/org/session/libsignal/streams/ProfileCipherOutputStream.java +++ b/libsignal/src/main/java/org/session/libsignal/streams/ProfileCipherOutputStream.java @@ -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 void flush() throws IOException { private byte[] generateNonce() { byte[] nonce = new byte[12]; - new SecureRandom().nextBytes(nonce); + SECURE_RANDOM.nextBytes(nonce); return nonce; } diff --git a/libsignal/src/main/java/org/session/libsignal/utilities/HTTP.kt b/libsignal/src/main/java/org/session/libsignal/utilities/HTTP.kt index fd4a3f37028..4f8b20f7c6e 100644 --- a/libsignal/src/main/java/org/session/libsignal/utilities/HTTP.kt +++ b/libsignal/src/main/java/org/session/libsignal/utilities/HTTP.kt @@ -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 { 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 { 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 } diff --git a/libsignal/src/main/java/org/session/libsignal/utilities/Util.java b/libsignal/src/main/java/org/session/libsignal/utilities/Util.java index 2c9436485ff..3b3b7aa5e6b 100644 --- a/libsignal/src/main/java/org/session/libsignal/utilities/Util.java +++ b/libsignal/src/main/java/org/session/libsignal/utilities/Util.java @@ -12,12 +12,10 @@ 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 static byte[] trim(byte[] input, int length) { } 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 static byte[] getSecretBytes(int size) { } } - 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 static String readFully(InputStream in) throws IOException { 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 static int toIntExact(long value) { } return (int)value; } - - public static List immutableList(T... elements) { - return Collections.unmodifiableList(Arrays.asList(elements.clone())); - } - }