diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java index 62076ed3f6..88b3cd518a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java @@ -32,7 +32,6 @@ import androidx.multidex.MultiDexApplication; import com.google.firebase.iid.FirebaseInstanceId; import org.conscrypt.Conscrypt; -import org.jetbrains.annotations.NotNull; import org.session.libsession.messaging.MessagingConfiguration; import org.session.libsession.messaging.avatars.AvatarHelper; import org.session.libsession.utilities.SSKEnvironment; @@ -49,7 +48,6 @@ import org.thoughtcrime.securesms.sskenvironment.ReadReceiptManager; import org.thoughtcrime.securesms.sskenvironment.TypingStatusRepository; import org.thoughtcrime.securesms.components.TypingStatusSender; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; -import org.thoughtcrime.securesms.crypto.MasterSecretUtil; import org.thoughtcrime.securesms.crypto.ProfileKeyUtil; import org.session.libsession.messaging.threads.Address; import org.thoughtcrime.securesms.database.DatabaseFactory; @@ -127,6 +125,8 @@ import static nl.komponents.kovenant.android.KovenantAndroid.stopKovenant; */ public class ApplicationContext extends MultiDexApplication implements DependencyInjector, DefaultLifecycleObserver { + public static final String PREFERENCES_NAME = "SecureSMS-Preferences"; + private static final String TAG = ApplicationContext.class.getSimpleName(); private ExpiringMessageManager expiringMessageManager; @@ -535,7 +535,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc TextSecurePreferences.setIsUsingFCM(this, isUsingFCM); TextSecurePreferences.setProfileName(this, displayName); } - MasterSecretUtil.clear(this); + getSharedPreferences(PREFERENCES_NAME, 0).edit().clear().commit(); if (!deleteDatabase("signal.db")) { Log.d("Loki", "Failed to delete database."); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java b/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java index 950d6495d3..f19ba41fb5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java @@ -9,8 +9,6 @@ import androidx.annotation.MainThread; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.view.ViewCompat; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; import android.text.format.DateUtils; import android.util.AttributeSet; import android.view.KeyEvent; @@ -29,11 +27,9 @@ import android.widget.Toast; import org.thoughtcrime.securesms.components.emoji.EmojiKeyboardProvider; import org.thoughtcrime.securesms.components.emoji.EmojiToggle; import org.thoughtcrime.securesms.components.emoji.MediaKeyboard; -import org.thoughtcrime.securesms.conversation.ConversationStickerSuggestionAdapter; import org.thoughtcrime.securesms.database.model.StickerRecord; import org.session.libsignal.utilities.logging.Log; import org.thoughtcrime.securesms.loki.utilities.MentionUtilities; -import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.mms.SlideDeck; @@ -48,7 +44,6 @@ import org.session.libsignal.utilities.concurrent.ListenableFuture; import org.session.libsignal.utilities.concurrent.SettableFuture; import org.session.libsignal.libsignal.util.guava.Optional; -import java.util.List; import java.util.concurrent.TimeUnit; import network.loki.messenger.R; @@ -56,15 +51,13 @@ import network.loki.messenger.R; public class InputPanel extends LinearLayout implements MicrophoneRecorderView.Listener, KeyboardAwareLinearLayout.OnKeyboardShownListener, - EmojiKeyboardProvider.EmojiEventListener, - ConversationStickerSuggestionAdapter.EventListener + EmojiKeyboardProvider.EmojiEventListener { private static final String TAG = InputPanel.class.getSimpleName(); private static final int FADE_TIME = 150; - private RecyclerView stickerSuggestion; private QuoteView quoteView; private LinkPreviewView linkPreview; private EmojiToggle mediaKeyboard; @@ -82,8 +75,6 @@ public class InputPanel extends LinearLayout private @Nullable Listener listener; private boolean emojiVisible; - private ConversationStickerSuggestionAdapter stickerSuggestionAdapter; - public InputPanel(Context context) { super(context); } @@ -103,7 +94,6 @@ public class InputPanel extends LinearLayout View quoteDismiss = findViewById(R.id.quote_dismiss); - this.stickerSuggestion = findViewById(R.id.input_panel_sticker_suggestion); this.quoteView = findViewById(R.id.quote_view); this.linkPreview = findViewById(R.id.link_preview); this.mediaKeyboard = findViewById(R.id.emoji_toggle); @@ -139,11 +129,6 @@ public class InputPanel extends LinearLayout listener.onLinkPreviewCanceled(); } }); - - stickerSuggestionAdapter = new ConversationStickerSuggestionAdapter(GlideApp.with(this), this); - - stickerSuggestion.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false)); - stickerSuggestion.setAdapter(stickerSuggestionAdapter); } public void setListener(final @NonNull Listener listener) { @@ -206,24 +191,6 @@ public class InputPanel extends LinearLayout this.mediaKeyboard.attach(mediaKeyboard); } - public void setStickerSuggestions(@NonNull List stickers) { - stickerSuggestion.setVisibility(stickers.isEmpty() ? View.GONE : View.VISIBLE); - stickerSuggestionAdapter.setStickers(stickers); - } - - public void showMediaKeyboardToggle(boolean show) { - emojiVisible = show; - mediaKeyboard.setVisibility(show ? View.VISIBLE : GONE); - } - - public void setMediaKeyboardToggleMode(boolean isSticker) { - mediaKeyboard.setStickerMode(isSticker); - } - - public View getMediaKeyboardToggleAnchorView() { - return mediaKeyboard; - } - @Override public void onRecordPermissionRequired() { if (listener != null) listener.onRecorderPermissionRequired(); @@ -335,13 +302,6 @@ public class InputPanel extends LinearLayout composeText.insertEmoji(emoji); } - @Override - public void onStickerSuggestionClicked(@NonNull StickerRecord sticker) { - if (listener != null) { - listener.onStickerSuggestionSelected(sticker); - } - } - private int readDimen(@DimenRes int dimenRes) { return getResources().getDimensionPixelSize(dimenRes); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/ThreadPhotoRailView.java b/app/src/main/java/org/thoughtcrime/securesms/components/ThreadPhotoRailView.java deleted file mode 100644 index 27ec12fbc7..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/ThreadPhotoRailView.java +++ /dev/null @@ -1,125 +0,0 @@ -package org.thoughtcrime.securesms.components; - - -import android.content.Context; -import android.database.Cursor; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.DefaultItemAnimator; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; - -import network.loki.messenger.R; - - -import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter; -import org.thoughtcrime.securesms.database.MediaDatabase; -import org.thoughtcrime.securesms.mms.GlideRequests; -import org.thoughtcrime.securesms.mms.Slide; -import org.thoughtcrime.securesms.util.MediaUtil; - -import org.session.libsession.utilities.ViewUtil; - -public class ThreadPhotoRailView extends FrameLayout { - - @NonNull private final RecyclerView recyclerView; - @Nullable private OnItemClickedListener listener; - - public ThreadPhotoRailView(Context context) { - this(context, null); - } - - public ThreadPhotoRailView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public ThreadPhotoRailView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - - inflate(context, R.layout.recipient_preference_photo_rail, this); - - this.recyclerView = ViewUtil.findById(this, R.id.photo_list); - this.recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)); - this.recyclerView.setItemAnimator(new DefaultItemAnimator()); - this.recyclerView.setNestedScrollingEnabled(false); - } - - public void setListener(@Nullable OnItemClickedListener listener) { - this.listener = listener; - - if (this.recyclerView.getAdapter() != null) { - ((ThreadPhotoRailAdapter)this.recyclerView.getAdapter()).setListener(listener); - } - } - - public void setCursor(@NonNull GlideRequests glideRequests, @Nullable Cursor cursor) { - this.recyclerView.setAdapter(new ThreadPhotoRailAdapter(getContext(), glideRequests, cursor, this.listener)); - } - - private static class ThreadPhotoRailAdapter extends CursorRecyclerViewAdapter { - - @SuppressWarnings("unused") - private static final String TAG = ThreadPhotoRailAdapter.class.getSimpleName(); - - @NonNull private final GlideRequests glideRequests; - - @Nullable private OnItemClickedListener clickedListener; - - private ThreadPhotoRailAdapter(@NonNull Context context, - @NonNull GlideRequests glideRequests, - @Nullable Cursor cursor, - @Nullable OnItemClickedListener listener) - { - super(context, cursor); - this.glideRequests = glideRequests; - this.clickedListener = listener; - } - - @Override - public ThreadPhotoViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) { - View itemView = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.recipient_preference_photo_rail_item, parent, false); - - return new ThreadPhotoViewHolder(itemView); - } - - @Override - public void onBindItemViewHolder(ThreadPhotoViewHolder viewHolder, @NonNull Cursor cursor) { - ThumbnailView imageView = viewHolder.imageView; - MediaDatabase.MediaRecord mediaRecord = MediaDatabase.MediaRecord.from(getContext(), cursor); - Slide slide = MediaUtil.getSlideForAttachment(getContext(), mediaRecord.getAttachment()); - - if (slide != null) { - imageView.setImageResource(glideRequests, slide, false, false); - } - - imageView.setOnClickListener(v -> { - if (clickedListener != null) clickedListener.onItemClicked(mediaRecord); - }); - } - - public void setListener(@Nullable OnItemClickedListener listener) { - this.clickedListener = listener; - } - - static class ThreadPhotoViewHolder extends RecyclerView.ViewHolder { - - ThumbnailView imageView; - - ThreadPhotoViewHolder(View itemView) { - super(itemView); - - this.imageView = ViewUtil.findById(itemView, R.id.thumbnail); - } - } - } - - public interface OnItemClickedListener { - void onItemClicked(MediaDatabase.MediaRecord mediaRecord); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/TooltipPopup.java b/app/src/main/java/org/thoughtcrime/securesms/components/TooltipPopup.java deleted file mode 100644 index 3e4e8cccad..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/TooltipPopup.java +++ /dev/null @@ -1,226 +0,0 @@ -package org.thoughtcrime.securesms.components; - -import android.content.Context; -import android.graphics.PorterDuff; -import android.os.Build; -import androidx.annotation.ColorInt; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.StringRes; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewTreeObserver; -import android.widget.ImageView; -import android.widget.PopupWindow; -import android.widget.TextView; - -import org.thoughtcrime.securesms.mms.GlideApp; - -import org.session.libsession.utilities.ThemeUtil; - -import network.loki.messenger.R; - -/** - * Class for creating simple tooltips to show throughout the app. Utilizes a popup window so you - * don't have to worry about view hierarchies or anything. - */ -public class TooltipPopup extends PopupWindow { - - public static final int POSITION_ABOVE = 0; - public static final int POSITION_BELOW = 1; - public static final int POSITION_START = 2; - public static final int POSITION_END = 3; - - private static final int POSITION_LEFT = 4; - private static final int POSITION_RIGHT = 5; - - private final View anchor; - private final ImageView arrow; - private final int position; - - public static Builder forTarget(@NonNull View anchor) { - return new Builder(anchor); - } - - private TooltipPopup(@NonNull View anchor, - int rawPosition, - @NonNull String text, - @ColorInt int backgroundTint, - @ColorInt int textColor, - @Nullable Object iconGlideModel, - @Nullable OnDismissListener dismissListener) - { - super(LayoutInflater.from(anchor.getContext()).inflate(R.layout.tooltip, null), - ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - - this.anchor = anchor; - this.position = getRtlPosition(anchor.getContext(), rawPosition); - - switch (rawPosition) { - case POSITION_ABOVE: arrow = getContentView().findViewById(R.id.tooltip_arrow_bottom); break; - case POSITION_BELOW: arrow = getContentView().findViewById(R.id.tooltip_arrow_top); break; - case POSITION_START: arrow = getContentView().findViewById(R.id.tooltip_arrow_end); break; - case POSITION_END: arrow = getContentView().findViewById(R.id.tooltip_arrow_start); break; - default: throw new AssertionError("Invalid position!"); - } - - arrow.setVisibility(View.VISIBLE); - - TextView textView = getContentView().findViewById(R.id.tooltip_text); - textView.setText(text); - - if (textColor != 0) { - textView.setTextColor(textColor); - } - - View bubble = getContentView().findViewById(R.id.tooltip_bubble); - - if (backgroundTint == 0) { - bubble.getBackground().setColorFilter(ThemeUtil.getThemedColor(anchor.getContext(), R.attr.tooltip_default_color), PorterDuff.Mode.MULTIPLY); - arrow.setColorFilter(ThemeUtil.getThemedColor(anchor.getContext(), R.attr.tooltip_default_color), PorterDuff.Mode.MULTIPLY); - } else { - bubble.getBackground().setColorFilter(backgroundTint, PorterDuff.Mode.MULTIPLY); - arrow.setColorFilter(backgroundTint, PorterDuff.Mode.MULTIPLY); - } - - if (iconGlideModel != null) { - ImageView iconView = getContentView().findViewById(R.id.tooltip_icon); - iconView.setVisibility(View.VISIBLE); - GlideApp.with(anchor.getContext()).load(iconGlideModel).into(iconView); - } - - if (Build.VERSION.SDK_INT >= 21) { - setElevation(10); - } - - getContentView().setOnClickListener(v -> dismiss()); - - setOnDismissListener(dismissListener); - setBackgroundDrawable(null); - setOutsideTouchable(true); - } - - private void show() { - if (anchor.getWidth() == 0 && anchor.getHeight() == 0) { - anchor.post(this::show); - return; - } - - getContentView().measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), - View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); - - int tooltipSpacing = anchor.getContext().getResources().getDimensionPixelOffset(R.dimen.tooltip_popup_margin); - - int xoffset; - int yoffset; - - switch (position) { - case POSITION_ABOVE: - xoffset = 0; - yoffset = -(2 * anchor.getWidth() + tooltipSpacing); - onLayout(() -> setArrowHorizontalPosition(arrow, anchor)); - break; - case POSITION_BELOW: - xoffset = 0; - yoffset = tooltipSpacing; - onLayout(() -> setArrowHorizontalPosition(arrow, anchor)); - break; - case POSITION_LEFT: - xoffset = -getContentView().getMeasuredWidth() - tooltipSpacing; - yoffset = -(getContentView().getMeasuredHeight()/2 + anchor.getHeight()/2); - break; - case POSITION_RIGHT: - xoffset = anchor.getWidth() + tooltipSpacing; - yoffset = -(getContentView().getMeasuredHeight()/2 + anchor.getHeight()/2); - break; - default: - throw new AssertionError("Invalid tooltip position!"); - } - - showAsDropDown(anchor, xoffset, yoffset); - } - - private void onLayout(@NonNull Runnable runnable) { - getContentView().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - getContentView().getViewTreeObserver().removeOnGlobalLayoutListener(this); - runnable.run(); - } - }); - } - - private static void setArrowHorizontalPosition(@NonNull View arrow, @NonNull View anchor) { - int arrowCenterX = getAbsolutePosition(arrow)[0] + arrow.getWidth()/2; - int anchorCenterX = getAbsolutePosition(anchor)[0] + anchor.getWidth()/2; - - arrow.setX(anchorCenterX - arrowCenterX); - } - - private static int[] getAbsolutePosition(@NonNull View view) { - int[] position = new int[2]; - view.getLocationOnScreen(position); - return position; - } - - private static int getRtlPosition(@NonNull Context context, int position) { - if (position == POSITION_ABOVE || position == POSITION_BELOW) { - return position; - } else if (context.getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) { - return position == POSITION_START ? POSITION_RIGHT : POSITION_LEFT; - } else { - return position == POSITION_START ? POSITION_LEFT : POSITION_RIGHT; - } - } - - public static class Builder { - - private final View anchor; - - private int backgroundTint; - private int textColor; - private int textResId; - private Object iconGlideModel; - private OnDismissListener dismissListener; - - private Builder(@NonNull View anchor) { - this.anchor = anchor; - } - - public Builder setBackgroundTint(int color) { - this.backgroundTint = color; - return this; - } - - public Builder setTextColor(int color) { - this.textColor = color; - return this; - } - - public Builder setText(@StringRes int stringResId) { - this.textResId = stringResId; - return this; - } - - public Builder setIconGlideModel(Object model) { - this.iconGlideModel = model; - return this; - } - - public Builder setOnDismissListener(OnDismissListener dismissListener) { - this.dismissListener = dismissListener; - return this; - } - - public TooltipPopup show(int position) { - String text = anchor.getContext().getString(textResId); - TooltipPopup tooltip = new TooltipPopup(anchor, position, text, backgroundTint, textColor, iconGlideModel, dismissListener); - - tooltip.show(); - - return tooltip; - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/contactshare/Selectable.java b/app/src/main/java/org/thoughtcrime/securesms/contactshare/Selectable.java deleted file mode 100644 index d85bd3c7d9..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/contactshare/Selectable.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.thoughtcrime.securesms.contactshare; - -public interface Selectable { - void setSelected(boolean selected); - boolean isSelected(); -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java index 85a8c61d79..b2872f313a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -117,7 +117,6 @@ import org.thoughtcrime.securesms.contacts.ContactAccessor; import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData; import org.thoughtcrime.securesms.contactshare.ContactUtil; import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher; -import org.thoughtcrime.securesms.crypto.SecurityEvent; import org.session.libsession.messaging.threads.Address; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DraftDatabase; @@ -345,7 +344,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity broadcastReceivers.add(broadcastReceiver); LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, new IntentFilter("clockOutOfSync")); - initializeReceivers(); initializeActionBar(); initializeViews(); initializeResources(); @@ -1534,19 +1532,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } } - private void initializeReceivers() { - securityUpdateReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - initializeSecurity(true, isDefaultSms); - } - }; - - registerReceiver(securityUpdateReceiver, - new IntentFilter(SecurityEvent.SECURITY_UPDATE_EVENT), - KeyCachingService.KEY_PERMISSION, null); - } - //////// Helper Methods private void addAttachment(int type) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationStickerSuggestionAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationStickerSuggestionAdapter.java deleted file mode 100644 index 606dbad44f..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationStickerSuggestionAdapter.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.thoughtcrime.securesms.conversation; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; - -import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; - - -import org.thoughtcrime.securesms.database.model.StickerRecord; -import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri; -import org.thoughtcrime.securesms.mms.GlideRequests; - -import java.util.ArrayList; -import java.util.List; - -import network.loki.messenger.R; - -public class ConversationStickerSuggestionAdapter extends RecyclerView.Adapter { - - private final GlideRequests glideRequests; - private final EventListener eventListener; - private final List stickers; - - public ConversationStickerSuggestionAdapter(@NonNull GlideRequests glideRequests, @NonNull EventListener eventListener) { - this.glideRequests = glideRequests; - this.eventListener = eventListener; - this.stickers = new ArrayList<>(); - } - - @Override - public @NonNull StickerSuggestionViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { - return new StickerSuggestionViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.sticker_suggestion_list_item, viewGroup, false)); - } - - @Override - public void onBindViewHolder(@NonNull StickerSuggestionViewHolder viewHolder, int i) { - viewHolder.bind(glideRequests, eventListener, stickers.get(i)); - } - - @Override - public void onViewRecycled(@NonNull StickerSuggestionViewHolder holder) { - holder.recycle(); - } - - @Override - public int getItemCount() { - return stickers.size(); - } - - public void setStickers(@NonNull List stickers) { - this.stickers.clear(); - this.stickers.addAll(stickers); - notifyDataSetChanged(); - } - - static class StickerSuggestionViewHolder extends RecyclerView.ViewHolder { - - private final ImageView image; - - StickerSuggestionViewHolder(@NonNull View itemView) { - super(itemView); - this.image = itemView.findViewById(R.id.sticker_suggestion_item_image); - } - - void bind(@NonNull GlideRequests glideRequests, @NonNull EventListener eventListener, @NonNull StickerRecord sticker) { - glideRequests.load(new DecryptableUri(sticker.getUri())) - .transition(DrawableTransitionOptions.withCrossFade()) - .into(image); - - itemView.setOnClickListener(v -> { - eventListener.onStickerSuggestionClicked(sticker); - }); - } - - void recycle() { - itemView.setOnClickListener(null); - } - } - - public interface EventListener { - void onStickerSuggestionClicked(@NonNull StickerRecord sticker); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/AsymmetricMasterSecret.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/AsymmetricMasterSecret.java deleted file mode 100644 index 58e0e48c1e..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/AsymmetricMasterSecret.java +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (C) 2011 Whisper Systems - * Copyright (C) 2013 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.thoughtcrime.securesms.crypto; - -import org.session.libsignal.libsignal.ecc.ECPrivateKey; -import org.session.libsignal.libsignal.ecc.ECPublicKey; - -/** - * When a user first initializes TextSecure, a few secrets - * are generated. These are: - * - * 1) A 128bit symmetric encryption key. - * 2) A 160bit symmetric MAC key. - * 3) An ECC keypair. - * - * The first two, along with the ECC keypair's private key, are - * then encrypted on disk using PBE. - * - * This class represents the ECC keypair. - * - * @author Moxie Marlinspike - * - */ - -public class AsymmetricMasterSecret { - - private final ECPublicKey djbPublicKey; - private final ECPrivateKey djbPrivateKey; - - - public AsymmetricMasterSecret(ECPublicKey djbPublicKey, ECPrivateKey djbPrivateKey) - { - this.djbPublicKey = djbPublicKey; - this.djbPrivateKey = djbPrivateKey; - } - - public ECPublicKey getDjbPublicKey() { - return djbPublicKey; - } - - - public ECPrivateKey getPrivateKey() { - return djbPrivateKey; - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/InvalidPassphraseException.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/InvalidPassphraseException.java deleted file mode 100644 index f73c984d62..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/InvalidPassphraseException.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (C) 2011 Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.thoughtcrime.securesms.crypto; - -public class InvalidPassphraseException extends Exception { - - public InvalidPassphraseException() { - super(); - // TODO Auto-generated constructor stub - } - - public InvalidPassphraseException(String detailMessage) { - super(detailMessage); - // TODO Auto-generated constructor stub - } - - public InvalidPassphraseException(Throwable throwable) { - super(throwable); - // TODO Auto-generated constructor stub - } - - public InvalidPassphraseException(String detailMessage, Throwable throwable) { - super(detailMessage, throwable); - // TODO Auto-generated constructor stub - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/MasterCipher.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/MasterCipher.java deleted file mode 100644 index 837722ddd7..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/MasterCipher.java +++ /dev/null @@ -1,226 +0,0 @@ -/** - * Copyright (C) 2011 Whisper Systems - * Copyright (C) 2013 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.thoughtcrime.securesms.crypto; - -import androidx.annotation.NonNull; - -import org.session.libsignal.libsignal.InvalidMessageException; -import org.session.libsignal.libsignal.ecc.Curve; -import org.session.libsignal.libsignal.ecc.ECPrivateKey; -import org.session.libsignal.utilities.logging.Log; - -import org.session.libsignal.utilities.Base64; -import org.session.libsignal.utilities.Hex; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.Mac; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -/** - * Class that handles encryption for local storage. - * - * The protocol format is roughly: - * - * 1) 16 byte random IV. - * 2) AES-CBC(plaintext) - * 3) HMAC-SHA1 of 1 and 2 - * - * @author Moxie Marlinspike - */ - -public class MasterCipher { - - private static final String TAG = MasterCipher.class.getSimpleName(); - - private final MasterSecret masterSecret; - private final Cipher encryptingCipher; - private final Cipher decryptingCipher; - private final Mac hmac; - - public MasterCipher(MasterSecret masterSecret) { - try { - this.masterSecret = masterSecret; - this.encryptingCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - this.decryptingCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - this.hmac = Mac.getInstance("HmacSHA1"); - } catch (NoSuchPaddingException | NoSuchAlgorithmException nspe) { - throw new AssertionError(nspe); - } - } - - public byte[] encryptKey(ECPrivateKey privateKey) { - return encryptBytes(privateKey.serialize()); - } - - public String encryptBody(@NonNull String body) { - return encryptAndEncodeBytes(body.getBytes()); - } - - public String decryptBody(String body) throws InvalidMessageException { - return new String(decodeAndDecryptBytes(body)); - } - - public ECPrivateKey decryptKey(byte[] key) - throws org.session.libsignal.libsignal.InvalidKeyException - { - try { - return Curve.decodePrivatePoint(decryptBytes(key)); - } catch (InvalidMessageException ime) { - throw new org.session.libsignal.libsignal.InvalidKeyException(ime); - } - } - - public byte[] decryptBytes(@NonNull byte[] decodedBody) throws InvalidMessageException { - try { - Mac mac = getMac(masterSecret.getMacKey()); - byte[] encryptedBody = verifyMacBody(mac, decodedBody); - - Cipher cipher = getDecryptingCipher(masterSecret.getEncryptionKey(), encryptedBody); - byte[] encrypted = getDecryptedBody(cipher, encryptedBody); - - return encrypted; - } catch (GeneralSecurityException ge) { - throw new InvalidMessageException(ge); - } - } - - public byte[] encryptBytes(byte[] body) { - try { - Cipher cipher = getEncryptingCipher(masterSecret.getEncryptionKey()); - Mac mac = getMac(masterSecret.getMacKey()); - - byte[] encryptedBody = getEncryptedBody(cipher, body); - byte[] encryptedAndMacBody = getMacBody(mac, encryptedBody); - - return encryptedAndMacBody; - } catch (GeneralSecurityException ge) { - Log.w("bodycipher", ge); - return null; - } - - } - - public boolean verifyMacFor(String content, byte[] theirMac) { - byte[] ourMac = getMacFor(content); - Log.i(TAG, "Our Mac: " + Hex.toString(ourMac)); - Log.i(TAG, "Thr Mac: " + Hex.toString(theirMac)); - return Arrays.equals(ourMac, theirMac); - } - - public byte[] getMacFor(String content) { - Log.w(TAG, "Macing: " + content); - try { - Mac mac = getMac(masterSecret.getMacKey()); - return mac.doFinal(content.getBytes()); - } catch (GeneralSecurityException ike) { - throw new AssertionError(ike); - } - } - - private byte[] decodeAndDecryptBytes(String body) throws InvalidMessageException { - try { - byte[] decodedBody = Base64.decode(body); - return decryptBytes(decodedBody); - } catch (IOException e) { - throw new InvalidMessageException("Bad Base64 Encoding...", e); - } - } - - private String encryptAndEncodeBytes(@NonNull byte[] bytes) { - byte[] encryptedAndMacBody = encryptBytes(bytes); - return Base64.encodeBytes(encryptedAndMacBody); - } - - private byte[] verifyMacBody(@NonNull Mac hmac, @NonNull byte[] encryptedAndMac) throws InvalidMessageException { - if (encryptedAndMac.length < hmac.getMacLength()) { - throw new InvalidMessageException("length(encrypted body + MAC) < length(MAC)"); - } - - byte[] encrypted = new byte[encryptedAndMac.length - hmac.getMacLength()]; - System.arraycopy(encryptedAndMac, 0, encrypted, 0, encrypted.length); - - byte[] remoteMac = new byte[hmac.getMacLength()]; - System.arraycopy(encryptedAndMac, encryptedAndMac.length - remoteMac.length, remoteMac, 0, remoteMac.length); - - byte[] localMac = hmac.doFinal(encrypted); - - if (!Arrays.equals(remoteMac, localMac)) - throw new InvalidMessageException("MAC doesen't match."); - - return encrypted; - } - - private byte[] getDecryptedBody(Cipher cipher, byte[] encryptedBody) throws IllegalBlockSizeException, BadPaddingException { - return cipher.doFinal(encryptedBody, cipher.getBlockSize(), encryptedBody.length - cipher.getBlockSize()); - } - - private byte[] getEncryptedBody(Cipher cipher, byte[] body) throws IllegalBlockSizeException, BadPaddingException { - byte[] encrypted = cipher.doFinal(body); - byte[] iv = cipher.getIV(); - - byte[] ivAndBody = new byte[iv.length + encrypted.length]; - System.arraycopy(iv, 0, ivAndBody, 0, iv.length); - System.arraycopy(encrypted, 0, ivAndBody, iv.length, encrypted.length); - - return ivAndBody; - } - - private Mac getMac(SecretKeySpec key) throws NoSuchAlgorithmException, InvalidKeyException { - // Mac hmac = Mac.getInstance("HmacSHA1"); - hmac.init(key); - - return hmac; - } - - private byte[] getMacBody(Mac hmac, byte[] encryptedBody) { - byte[] mac = hmac.doFinal(encryptedBody); - byte[] encryptedAndMac = new byte[encryptedBody.length + mac.length]; - - System.arraycopy(encryptedBody, 0, encryptedAndMac, 0, encryptedBody.length); - System.arraycopy(mac, 0, encryptedAndMac, encryptedBody.length, mac.length); - - return encryptedAndMac; - } - - private Cipher getDecryptingCipher(SecretKeySpec key, byte[] encryptedBody) throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException { - // Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - IvParameterSpec iv = new IvParameterSpec(encryptedBody, 0, decryptingCipher.getBlockSize()); - decryptingCipher.init(Cipher.DECRYPT_MODE, key, iv); - - return decryptingCipher; - } - - private Cipher getEncryptingCipher(SecretKeySpec key) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException { - // Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - encryptingCipher.init(Cipher.ENCRYPT_MODE, key); - - return encryptingCipher; - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/MasterSecret.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/MasterSecret.java deleted file mode 100644 index ad8881bd18..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/MasterSecret.java +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Copyright (C) 2011 Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.thoughtcrime.securesms.crypto; - -import android.os.Parcel; -import android.os.Parcelable; - -import javax.crypto.spec.SecretKeySpec; -import java.util.Arrays; - -/** - * When a user first initializes TextSecure, a few secrets - * are generated. These are: - * - * 1) A 128bit symmetric encryption key. - * 2) A 160bit symmetric MAC key. - * 3) An ECC keypair. - * - * The first two, along with the ECC keypair's private key, are - * then encrypted on disk using PBE. - * - * This class represents 1 and 2. - * - * @author Moxie Marlinspike - */ - -public class MasterSecret implements Parcelable { - - private final SecretKeySpec encryptionKey; - private final SecretKeySpec macKey; - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - @Override - public MasterSecret createFromParcel(Parcel in) { - return new MasterSecret(in); - } - - @Override - public MasterSecret[] newArray(int size) { - return new MasterSecret[size]; - } - }; - - public MasterSecret(SecretKeySpec encryptionKey, SecretKeySpec macKey) { - this.encryptionKey = encryptionKey; - this.macKey = macKey; - } - - private MasterSecret(Parcel in) { - byte[] encryptionKeyBytes = new byte[in.readInt()]; - in.readByteArray(encryptionKeyBytes); - - byte[] macKeyBytes = new byte[in.readInt()]; - in.readByteArray(macKeyBytes); - - this.encryptionKey = new SecretKeySpec(encryptionKeyBytes, "AES"); - this.macKey = new SecretKeySpec(macKeyBytes, "HmacSHA1"); - - // SecretKeySpec does an internal copy in its constructor. - Arrays.fill(encryptionKeyBytes, (byte) 0x00); - Arrays.fill(macKeyBytes, (byte)0x00); - } - - - public SecretKeySpec getEncryptionKey() { - return this.encryptionKey; - } - - public SecretKeySpec getMacKey() { - return this.macKey; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(encryptionKey.getEncoded().length); - out.writeByteArray(encryptionKey.getEncoded()); - out.writeInt(macKey.getEncoded().length); - out.writeByteArray(macKey.getEncoded()); - } - - @Override - public int describeContents() { - return 0; - } - - public MasterSecret parcelClone() { - Parcel thisParcel = Parcel.obtain(); - Parcel thatParcel = Parcel.obtain(); - byte[] bytes = null; - - thisParcel.writeValue(this); - bytes = thisParcel.marshall(); - - thatParcel.unmarshall(bytes, 0, bytes.length); - thatParcel.setDataPosition(0); - - MasterSecret that = (MasterSecret)thatParcel.readValue(MasterSecret.class.getClassLoader()); - - thisParcel.recycle(); - thatParcel.recycle(); - - return that; - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/MasterSecretUtil.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/MasterSecretUtil.java deleted file mode 100644 index 5bb289c0e7..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/MasterSecretUtil.java +++ /dev/null @@ -1,375 +0,0 @@ -/** - * Copyright (C) 2011 Whisper Systems - * Copyright (C) 2013 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.thoughtcrime.securesms.crypto; - -import android.content.Context; -import android.content.SharedPreferences; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import android.text.TextUtils; - -import org.session.libsignal.libsignal.InvalidKeyException; -import org.session.libsignal.libsignal.ecc.Curve; -import org.session.libsignal.libsignal.ecc.ECKeyPair; -import org.session.libsignal.libsignal.ecc.ECPrivateKey; -import org.session.libsignal.libsignal.ecc.ECPublicKey; -import org.session.libsignal.utilities.logging.Log; - -import org.session.libsignal.utilities.Base64; -import org.session.libsession.utilities.Util; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.spec.InvalidKeySpecException; -import java.util.Arrays; - -import javax.crypto.Cipher; -import javax.crypto.KeyGenerator; -import javax.crypto.Mac; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.PBEParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -/** - * Helper class for generating and securely storing a MasterSecret. - * - * @author Moxie Marlinspike - */ - -public class MasterSecretUtil { - - public static final String UNENCRYPTED_PASSPHRASE = "unencrypted"; - public static final String PREFERENCES_NAME = "SecureSMS-Preferences"; - - private static final String ASYMMETRIC_LOCAL_PUBLIC_DJB = "asymmetric_master_secret_curve25519_public"; - private static final String ASYMMETRIC_LOCAL_PRIVATE_DJB = "asymmetric_master_secret_curve25519_private"; - - public static MasterSecret changeMasterSecretPassphrase(Context context, - MasterSecret masterSecret, - String newPassphrase) - { - try { - byte[] combinedSecrets = Util.combine(masterSecret.getEncryptionKey().getEncoded(), - masterSecret.getMacKey().getEncoded()); - - byte[] encryptionSalt = generateSalt(); - int iterations = generateIterationCount(newPassphrase, encryptionSalt); - byte[] encryptedMasterSecret = encryptWithPassphrase(encryptionSalt, iterations, combinedSecrets, newPassphrase); - byte[] macSalt = generateSalt(); - byte[] encryptedAndMacdMasterSecret = macWithPassphrase(macSalt, iterations, encryptedMasterSecret, newPassphrase); - - save(context, "encryption_salt", encryptionSalt); - save(context, "mac_salt", macSalt); - save(context, "passphrase_iterations", iterations); - save(context, "master_secret", encryptedAndMacdMasterSecret); - save(context, "passphrase_initialized", true); - - return masterSecret; - } catch (GeneralSecurityException gse) { - throw new AssertionError(gse); - } - } - - public static MasterSecret changeMasterSecretPassphrase(Context context, - String originalPassphrase, - String newPassphrase) - throws InvalidPassphraseException - { - MasterSecret masterSecret = getMasterSecret(context, originalPassphrase); - changeMasterSecretPassphrase(context, masterSecret, newPassphrase); - - return masterSecret; - } - - public static MasterSecret getMasterSecret(Context context, String passphrase) - throws InvalidPassphraseException - { - try { - byte[] encryptedAndMacdMasterSecret = retrieve(context, "master_secret"); - byte[] macSalt = retrieve(context, "mac_salt"); - int iterations = retrieve(context, "passphrase_iterations", 100); - byte[] encryptedMasterSecret = verifyMac(macSalt, iterations, encryptedAndMacdMasterSecret, passphrase); - byte[] encryptionSalt = retrieve(context, "encryption_salt"); - byte[] combinedSecrets = decryptWithPassphrase(encryptionSalt, iterations, encryptedMasterSecret, passphrase); - byte[] encryptionSecret = Util.split(combinedSecrets, 16, 20)[0]; - byte[] macSecret = Util.split(combinedSecrets, 16, 20)[1]; - - return new MasterSecret(new SecretKeySpec(encryptionSecret, "AES"), - new SecretKeySpec(macSecret, "HmacSHA1")); - } catch (GeneralSecurityException e) { - Log.w("keyutil", e); - return null; //XXX - } catch (IOException e) { - Log.w("keyutil", e); - return null; //XXX - } - } - - public static AsymmetricMasterSecret getAsymmetricMasterSecret(@NonNull Context context, - @Nullable MasterSecret masterSecret) - { - try { - byte[] djbPublicBytes = retrieve(context, ASYMMETRIC_LOCAL_PUBLIC_DJB); - byte[] djbPrivateBytes = retrieve(context, ASYMMETRIC_LOCAL_PRIVATE_DJB); - - ECPublicKey djbPublicKey = null; - ECPrivateKey djbPrivateKey = null; - - if (djbPublicBytes != null) { - djbPublicKey = Curve.decodePoint(djbPublicBytes, 0); - } - - if (masterSecret != null) { - MasterCipher masterCipher = new MasterCipher(masterSecret); - - if (djbPrivateBytes != null) { - djbPrivateKey = masterCipher.decryptKey(djbPrivateBytes); - } - } - - return new AsymmetricMasterSecret(djbPublicKey, djbPrivateKey); - } catch (InvalidKeyException | IOException ike) { - throw new AssertionError(ike); - } - } - - public static AsymmetricMasterSecret generateAsymmetricMasterSecret(Context context, - MasterSecret masterSecret) - { - MasterCipher masterCipher = new MasterCipher(masterSecret); - ECKeyPair keyPair = Curve.generateKeyPair(); - - save(context, ASYMMETRIC_LOCAL_PUBLIC_DJB, keyPair.getPublicKey().serialize()); - save(context, ASYMMETRIC_LOCAL_PRIVATE_DJB, masterCipher.encryptKey(keyPair.getPrivateKey())); - - return new AsymmetricMasterSecret(keyPair.getPublicKey(), keyPair.getPrivateKey()); - } - - public static MasterSecret generateMasterSecret(Context context, String passphrase) { - try { - byte[] encryptionSecret = generateEncryptionSecret(); - byte[] macSecret = generateMacSecret(); - byte[] masterSecret = Util.combine(encryptionSecret, macSecret); - byte[] encryptionSalt = generateSalt(); - int iterations = generateIterationCount(passphrase, encryptionSalt); - byte[] encryptedMasterSecret = encryptWithPassphrase(encryptionSalt, iterations, masterSecret, passphrase); - byte[] macSalt = generateSalt(); - byte[] encryptedAndMacdMasterSecret = macWithPassphrase(macSalt, iterations, encryptedMasterSecret, passphrase); - - save(context, "encryption_salt", encryptionSalt); - save(context, "mac_salt", macSalt); - save(context, "passphrase_iterations", iterations); - save(context, "master_secret", encryptedAndMacdMasterSecret); - save(context, "passphrase_initialized", true); - - return new MasterSecret(new SecretKeySpec(encryptionSecret, "AES"), - new SecretKeySpec(macSecret, "HmacSHA1")); - } catch (GeneralSecurityException e) { - Log.w("keyutil", e); - return null; - } - } - - public static boolean hasAsymmericMasterSecret(Context context) { - SharedPreferences settings = context.getSharedPreferences(PREFERENCES_NAME, 0); - return settings.contains(ASYMMETRIC_LOCAL_PUBLIC_DJB); - } - - public static boolean isPassphraseInitialized(Context context) { - SharedPreferences preferences = context.getSharedPreferences(PREFERENCES_NAME, 0); - return preferences.getBoolean("passphrase_initialized", false); - } - - public static void clear(Context context) { - context.getSharedPreferences(PREFERENCES_NAME, 0).edit().clear().commit(); - } - - private static void save(Context context, String key, int value) { - if (!context.getSharedPreferences(PREFERENCES_NAME, 0) - .edit() - .putInt(key, value) - .commit()) - { - throw new AssertionError("failed to save a shared pref in MasterSecretUtil"); - } - } - - private static void save(Context context, String key, byte[] value) { - if (!context.getSharedPreferences(PREFERENCES_NAME, 0) - .edit() - .putString(key, Base64.encodeBytes(value)) - .commit()) - { - throw new AssertionError("failed to save a shared pref in MasterSecretUtil"); - } - } - - private static void save(Context context, String key, boolean value) { - if (!context.getSharedPreferences(PREFERENCES_NAME, 0) - .edit() - .putBoolean(key, value) - .commit()) - { - throw new AssertionError("failed to save a shared pref in MasterSecretUtil"); - } - } - - private static byte[] retrieve(Context context, String key) throws IOException { - SharedPreferences settings = context.getSharedPreferences(PREFERENCES_NAME, 0); - String encodedValue = settings.getString(key, ""); - - if (TextUtils.isEmpty(encodedValue)) return null; - else return Base64.decode(encodedValue); - } - - private static int retrieve(Context context, String key, int defaultValue) throws IOException { - SharedPreferences settings = context.getSharedPreferences(PREFERENCES_NAME, 0); - return settings.getInt(key, defaultValue); - } - - private static byte[] generateEncryptionSecret() { - try { - KeyGenerator generator = KeyGenerator.getInstance("AES"); - generator.init(128); - - SecretKey key = generator.generateKey(); - return key.getEncoded(); - } catch (NoSuchAlgorithmException ex) { - Log.w("keyutil", ex); - return null; - } - } - - private static byte[] generateMacSecret() { - try { - KeyGenerator generator = KeyGenerator.getInstance("HmacSHA1"); - return generator.generateKey().getEncoded(); - } catch (NoSuchAlgorithmException e) { - Log.w("keyutil", e); - return null; - } - } - - private static byte[] generateSalt() { - SecureRandom random = new SecureRandom(); - byte[] salt = new byte[16]; - random.nextBytes(salt); - - return salt; - } - - private static int generateIterationCount(String passphrase, byte[] salt) { - int TARGET_ITERATION_TIME = 50; //ms - int MINIMUM_ITERATION_COUNT = 100; //default for low-end devices - int BENCHMARK_ITERATION_COUNT = 10000; //baseline starting iteration count - - try { - PBEKeySpec keyspec = new PBEKeySpec(passphrase.toCharArray(), salt, BENCHMARK_ITERATION_COUNT); - SecretKeyFactory skf = SecretKeyFactory.getInstance("PBEWITHSHA1AND128BITAES-CBC-BC"); - - long startTime = System.currentTimeMillis(); - skf.generateSecret(keyspec); - long finishTime = System.currentTimeMillis(); - - int scaledIterationTarget = (int) (((double)BENCHMARK_ITERATION_COUNT / (double)(finishTime - startTime)) * TARGET_ITERATION_TIME); - - if (scaledIterationTarget < MINIMUM_ITERATION_COUNT) return MINIMUM_ITERATION_COUNT; - else return scaledIterationTarget; - } catch (NoSuchAlgorithmException e) { - Log.w("MasterSecretUtil", e); - return MINIMUM_ITERATION_COUNT; - } catch (InvalidKeySpecException e) { - Log.w("MasterSecretUtil", e); - return MINIMUM_ITERATION_COUNT; - } - } - - private static SecretKey getKeyFromPassphrase(String passphrase, byte[] salt, int iterations) - throws GeneralSecurityException - { - PBEKeySpec keyspec = new PBEKeySpec(passphrase.toCharArray(), salt, iterations); - SecretKeyFactory skf = SecretKeyFactory.getInstance("PBEWITHSHA1AND128BITAES-CBC-BC"); - return skf.generateSecret(keyspec); - } - - private static Cipher getCipherFromPassphrase(String passphrase, byte[] salt, int iterations, int opMode) - throws GeneralSecurityException - { - SecretKey key = getKeyFromPassphrase(passphrase, salt, iterations); - Cipher cipher = Cipher.getInstance(key.getAlgorithm()); - cipher.init(opMode, key, new PBEParameterSpec(salt, iterations)); - - return cipher; - } - - private static byte[] encryptWithPassphrase(byte[] encryptionSalt, int iterations, byte[] data, String passphrase) - throws GeneralSecurityException - { - Cipher cipher = getCipherFromPassphrase(passphrase, encryptionSalt, iterations, Cipher.ENCRYPT_MODE); - return cipher.doFinal(data); - } - - private static byte[] decryptWithPassphrase(byte[] encryptionSalt, int iterations, byte[] data, String passphrase) - throws GeneralSecurityException, IOException - { - Cipher cipher = getCipherFromPassphrase(passphrase, encryptionSalt, iterations, Cipher.DECRYPT_MODE); - return cipher.doFinal(data); - } - - private static Mac getMacForPassphrase(String passphrase, byte[] salt, int iterations) - throws GeneralSecurityException - { - SecretKey key = getKeyFromPassphrase(passphrase, salt, iterations); - byte[] pbkdf2 = key.getEncoded(); - SecretKeySpec hmacKey = new SecretKeySpec(pbkdf2, "HmacSHA1"); - Mac hmac = Mac.getInstance("HmacSHA1"); - hmac.init(hmacKey); - - return hmac; - } - - private static byte[] verifyMac(byte[] macSalt, int iterations, byte[] encryptedAndMacdData, String passphrase) throws InvalidPassphraseException, GeneralSecurityException, IOException { - Mac hmac = getMacForPassphrase(passphrase, macSalt, iterations); - - byte[] encryptedData = new byte[encryptedAndMacdData.length - hmac.getMacLength()]; - System.arraycopy(encryptedAndMacdData, 0, encryptedData, 0, encryptedData.length); - - byte[] givenMac = new byte[hmac.getMacLength()]; - System.arraycopy(encryptedAndMacdData, encryptedAndMacdData.length-hmac.getMacLength(), givenMac, 0, givenMac.length); - - byte[] localMac = hmac.doFinal(encryptedData); - - if (Arrays.equals(givenMac, localMac)) return encryptedData; - else throw new InvalidPassphraseException("MAC Error"); - } - - private static byte[] macWithPassphrase(byte[] macSalt, int iterations, byte[] data, String passphrase) throws GeneralSecurityException { - Mac hmac = getMacForPassphrase(passphrase, macSalt, iterations); - byte[] mac = hmac.doFinal(data); - byte[] result = new byte[data.length + mac.length]; - - System.arraycopy(data, 0, result, 0, data.length); - System.arraycopy(mac, 0, result, data.length, mac.length); - - return result; - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/ProfileKeyUtil.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/ProfileKeyUtil.java index 6fd6e9a4c1..d3260bb0c5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/ProfileKeyUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/ProfileKeyUtil.java @@ -13,10 +13,6 @@ import java.io.IOException; public class ProfileKeyUtil { - public static synchronized boolean hasProfileKey(@NonNull Context context) { - return TextSecurePreferences.getProfileKey(context) != null; - } - public static synchronized @NonNull byte[] getProfileKey(@NonNull Context context) { try { String encodedProfileKey = TextSecurePreferences.getProfileKey(context); @@ -40,11 +36,6 @@ public class ProfileKeyUtil { } } - public static synchronized @NonNull byte[] rotateProfileKey(@NonNull Context context) { - TextSecurePreferences.setProfileKey(context, null); - return getProfileKey(context); - } - public static synchronized @NonNull String generateEncodedProfileKey(@NonNull Context context) { return Util.getSecret(32); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/PublicKey.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/PublicKey.java deleted file mode 100644 index 84c012290c..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/PublicKey.java +++ /dev/null @@ -1,104 +0,0 @@ -/** - * Copyright (C) 2011 Whisper Systems - * Copyright (C) 2013 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.thoughtcrime.securesms.crypto; - -import org.session.libsignal.utilities.logging.Log; -import org.session.libsignal.utilities.Hex; -import org.session.libsession.utilities.Util; -import org.session.libsignal.libsignal.InvalidKeyException; -import org.session.libsignal.libsignal.ecc.Curve; -import org.session.libsignal.libsignal.ecc.ECPublicKey; -import org.session.libsession.utilities.Conversions; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -public class PublicKey { - - private static final String TAG = PublicKey.class.getSimpleName(); - - public static final int KEY_SIZE = 3 + ECPublicKey.KEY_SIZE; - - private final ECPublicKey publicKey; - private int id; - - public PublicKey(PublicKey publicKey) { - this.id = publicKey.id; - - // FIXME :: This not strictly an accurate copy constructor. - this.publicKey = publicKey.publicKey; - } - - public PublicKey(int id, ECPublicKey publicKey) { - this.publicKey = publicKey; - this.id = id; - } - - public PublicKey(byte[] bytes, int offset) throws InvalidKeyException { - Log.i(TAG, "PublicKey Length: " + (bytes.length - offset)); - - if ((bytes.length - offset) < KEY_SIZE) - throw new InvalidKeyException("Provided bytes are too short."); - - this.id = Conversions.byteArrayToMedium(bytes, offset); - this.publicKey = Curve.decodePoint(bytes, offset + 3); - } - - public PublicKey(byte[] bytes) throws InvalidKeyException { - this(bytes, 0); - } - - public int getType() { - return publicKey.getType(); - } - - public void setId(int id) { - this.id = id; - } - - public int getId() { - return id; - } - - public ECPublicKey getKey() { - return publicKey; - } - - public String getFingerprint() { - return Hex.toString(getFingerprintBytes()); - } - - public byte[] getFingerprintBytes() { - try { - MessageDigest md = MessageDigest.getInstance("SHA-1"); - return md.digest(serialize()); - } catch (NoSuchAlgorithmException nsae) { - Log.w("LocalKeyPair", nsae); - throw new IllegalArgumentException("SHA-1 isn't supported!"); - } - } - - public byte[] serialize() { - byte[] keyIdBytes = Conversions.mediumToByteArray(id); - byte[] serializedPoint = publicKey.serialize(); - - Log.i(TAG, "Serializing public key point: " + Hex.toString(serializedPoint)); - - return Util.combine(keyIdBytes, serializedPoint); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/SecurityEvent.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/SecurityEvent.java deleted file mode 100644 index bd5be68741..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/SecurityEvent.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.thoughtcrime.securesms.crypto; - -import android.content.Context; -import android.content.Intent; - -import org.session.libsession.messaging.threads.recipients.Recipient; -import org.thoughtcrime.securesms.service.KeyCachingService; - -/** - * This class processes key exchange interactions. - * - * @author Moxie Marlinspike - */ - -public class SecurityEvent { - - public static final String SECURITY_UPDATE_EVENT = "org.thoughtcrime.securesms.KEY_EXCHANGE_UPDATE"; - - public static void broadcastSecurityUpdateEvent(Context context) { - Intent intent = new Intent(SECURITY_UPDATE_EVENT); - intent.setPackage(context.getPackageName()); - context.sendBroadcast(intent, KeyCachingService.KEY_PERMISSION); - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java b/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java index 759c98b482..85a34df8c9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java @@ -103,11 +103,6 @@ public class MessageSender { } } - public static void resendGroupMessage(Context context, MessageRecord messageRecord, Address filterAddress) { - if (!messageRecord.isMms()) throw new AssertionError("Not Group"); - sendGroupPush(context, messageRecord.getRecipient(), messageRecord.getId(), filterAddress); - } - public static void resend(Context context, MessageRecord messageRecord) { long messageId = messageRecord.getId(); boolean forceSms = messageRecord.isForcedSms();