Skip to content

Commit

Permalink
Generate "prekeys" at push registration time.
Browse files Browse the repository at this point in the history
This generates a large number of key exchange messages and
registers them with the server during signup.
  • Loading branch information
moxie0 committed Jan 6, 2014
1 parent cfb7b8f commit 2042ca6
Show file tree
Hide file tree
Showing 25 changed files with 1,012 additions and 106 deletions.
16 changes: 16 additions & 0 deletions library/src/org/whispersystems/textsecure/push/PreKeyList.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.whispersystems.textsecure.push;

import java.util.List;

public class PreKeyList {

private List<String> keys;

public PreKeyList(List<String> keys) {
this.keys = keys;
}

public List<String> getKeys() {
return keys;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public class PushServiceSocket {
private static final String CREATE_ACCOUNT_VOICE_PATH = "/v1/accounts/voice/%s";
private static final String VERIFY_ACCOUNT_PATH = "/v1/accounts/code/%s";
private static final String REGISTER_GCM_PATH = "/v1/accounts/gcm/";
private static final String PREKEY_PATH = "/v1/keys/";

private static final String DIRECTORY_PATH = "/v1/directory/";
private static final String MESSAGE_PATH = "/v1/messages/";
Expand Down Expand Up @@ -105,6 +106,11 @@ private void sendMessage(OutgoingPushMessage message) throws IOException {
throw new IOException("Got send failure: " + response.getFailure().get(0));
}

public void registerPreKeys(PreKeyList keys) throws IOException {
makeRequest(PREKEY_PATH, "PUT", new Gson().toJson(keys));
}


private List<PushAttachmentPointer> sendAttachments(List<PushAttachmentData> attachments)
throws IOException
{
Expand Down
Binary file added libs/protobuf-java-2.4.1.jar
Binary file not shown.
3 changes: 3 additions & 0 deletions protobuf/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

all:
protoc --java_out=../src/ PreKeyEntity.proto
9 changes: 9 additions & 0 deletions protobuf/PreKeyEntity.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package textsecure;

option java_package = "org.thoughtcrime.securesms.encoded";
option java_outer_classname = "PreKeyProtos";

message PreKeyEntity {
optional uint64 id = 1;
optional bytes key = 2;
}
44 changes: 44 additions & 0 deletions res/layout/registration_progress_activity.xml
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,50 @@
android:textSize="16.0sp" />
</TableRow>

<TableRow>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center" >


<ImageView
android:id="@+id/generating_keys_complete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:paddingLeft="4dip"
android:paddingRight="4dip"
android:src="@drawable/check_dark"
android:visibility="invisible"
android:contentDescription="Check"/>

<ProgressBar
android:id="@+id/generating_keys_progress"
style="?android:attr/android:progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:indeterminate="true"
android:paddingLeft="4dip"
android:paddingRight="4dip"
android:visibility="invisible" />
</FrameLayout>

<TextView
android:id="@+id/generating_keys_text"
style="@style/Registration.Constant"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="4.0dip"
android:paddingRight="8.0dip"
android:text="@string/registration_progress_activity__generating_keys"
android:textSize="16.0sp" />
</TableRow>

<TableRow>

<FrameLayout
Expand Down
1 change: 1 addition & 0 deletions res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@
<string name="registration_progress_activity__sms_verification_failed">SMS verification
failed.
</string>
<string name="registration_progress_activity__generating_keys">Generating keys...</string>

<!-- recipients_panel -->
<string name="recipients_panel__to">To</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,9 @@ protected Integer doInBackground(Void... params) {
}
}.execute();
} else {
startActivity(new Intent(ApplicationPreferencesActivity.this, RegistrationActivity.class));
Intent intent = new Intent(ApplicationPreferencesActivity.this, RegistrationActivity.class);
intent.putExtra("master_secret", getIntent().getParcelableExtra("master_secret"));
startActivity(intent);
}

return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.crypto.PreKeyUtil;
import org.thoughtcrime.securesms.util.MemoryCleaner;
import org.thoughtcrime.securesms.util.VersionTracker;
import org.whispersystems.textsecure.util.Util;
Expand Down
5 changes: 5 additions & 0 deletions src/org/thoughtcrime/securesms/RegistrationActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.Phonenumber;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.textsecure.util.PhoneNumberFormatter;
import org.whispersystems.textsecure.util.Util;
Expand All @@ -47,6 +48,8 @@ public class RegistrationActivity extends SherlockActivity {
private Button createButton;
private Button skipButton;

private MasterSecret masterSecret;

@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Expand All @@ -70,6 +73,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
}

private void initializeResources() {
this.masterSecret = getIntent().getParcelableExtra("master_secret");
this.countrySpinner = (Spinner)findViewById(R.id.country_spinner);
this.countryCode = (TextView)findViewById(R.id.country_code);
this.number = (TextView)findViewById(R.id.number);
Expand Down Expand Up @@ -191,6 +195,7 @@ public void onClick(View v) {
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(self, RegistrationProgressActivity.class);
intent.putExtra("e164number", e164number);
intent.putExtra("master_secret", masterSecret);
startActivity(intent);
finish();
}
Expand Down
45 changes: 44 additions & 1 deletion src/org/thoughtcrime/securesms/RegistrationProgressActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@
import android.widget.Toast;

import com.actionbarsherlock.app.SherlockActivity;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.service.RegistrationService;
import org.whispersystems.textsecure.push.PushServiceSocket;
import org.whispersystems.textsecure.push.RateLimitException;
import org.thoughtcrime.securesms.service.RegistrationService;
import org.whispersystems.textsecure.util.PhoneNumberFormatter;
import org.whispersystems.textsecure.util.Util;

Expand All @@ -58,15 +59,19 @@ public class RegistrationProgressActivity extends SherlockActivity {
private ProgressBar registrationProgress;
private ProgressBar connectingProgress;
private ProgressBar verificationProgress;
private ProgressBar generatingKeysProgress;
private ProgressBar gcmRegistrationProgress;


private ImageView connectingCheck;
private ImageView verificationCheck;
private ImageView generatingKeysCheck;
private ImageView gcmRegistrationCheck;

private TextView connectingText;
private TextView verificationText;
private TextView registrationTimerText;
private TextView generatingKeysText;
private TextView gcmRegistrationText;

private Button verificationFailureButton;
Expand All @@ -76,6 +81,7 @@ public class RegistrationProgressActivity extends SherlockActivity {

private EditText codeEditText;

private MasterSecret masterSecret;
private volatile boolean visible;

@Override
Expand Down Expand Up @@ -118,19 +124,23 @@ private void initializeServiceBinding() {
}

private void initializeResources() {
this.masterSecret = getIntent().getParcelableExtra("master_secret");
this.registrationLayout = (LinearLayout)findViewById(R.id.registering_layout);
this.verificationFailureLayout = (LinearLayout)findViewById(R.id.verification_failure_layout);
this.connectivityFailureLayout = (LinearLayout)findViewById(R.id.connectivity_failure_layout);
this.registrationProgress = (ProgressBar) findViewById(R.id.registration_progress);
this.connectingProgress = (ProgressBar) findViewById(R.id.connecting_progress);
this.verificationProgress = (ProgressBar) findViewById(R.id.verification_progress);
this.generatingKeysProgress = (ProgressBar) findViewById(R.id.generating_keys_progress);
this.gcmRegistrationProgress = (ProgressBar) findViewById(R.id.gcm_registering_progress);
this.connectingCheck = (ImageView) findViewById(R.id.connecting_complete);
this.verificationCheck = (ImageView) findViewById(R.id.verification_complete);
this.generatingKeysCheck = (ImageView) findViewById(R.id.generating_keys_complete);
this.gcmRegistrationCheck = (ImageView) findViewById(R.id.gcm_registering_complete);
this.connectingText = (TextView) findViewById(R.id.connecting_text);
this.verificationText = (TextView) findViewById(R.id.verification_text);
this.registrationTimerText = (TextView) findViewById(R.id.registration_timer);
this.generatingKeysText = (TextView) findViewById(R.id.generating_keys_text);
this.gcmRegistrationText = (TextView) findViewById(R.id.gcm_registering_text);
this.verificationFailureButton = (Button) findViewById(R.id.verification_failure_edit_button);
this.connectivityFailureButton = (Button) findViewById(R.id.connectivity_failure_edit_button);
Expand Down Expand Up @@ -181,6 +191,7 @@ private void handleStateIdle() {
Intent intent = new Intent(this, RegistrationService.class);
intent.setAction(RegistrationService.REGISTER_NUMBER_ACTION);
intent.putExtra("e164number", getNumberDirective());
intent.putExtra("master_secret", masterSecret);
startService(intent);
} else {
startActivity(new Intent(this, RegistrationActivity.class));
Expand All @@ -196,10 +207,13 @@ private void handleStateConnecting() {
this.connectingCheck.setVisibility(View.INVISIBLE);
this.verificationProgress.setVisibility(View.INVISIBLE);
this.verificationCheck.setVisibility(View.INVISIBLE);
this.generatingKeysProgress.setVisibility(View.INVISIBLE);
this.generatingKeysCheck.setVisibility(View.INVISIBLE);
this.gcmRegistrationProgress.setVisibility(View.INVISIBLE);
this.gcmRegistrationCheck.setVisibility(View.INVISIBLE);
this.connectingText.setTextColor(FOCUSED_COLOR);
this.verificationText.setTextColor(UNFOCUSED_COLOR);
this.generatingKeysText.setTextColor(UNFOCUSED_COLOR);
this.gcmRegistrationText.setTextColor(UNFOCUSED_COLOR);
this.timeoutProgressLayout.setVisibility(View.VISIBLE);
}
Expand All @@ -212,15 +226,38 @@ private void handleStateVerifying() {
this.connectingCheck.setVisibility(View.VISIBLE);
this.verificationProgress.setVisibility(View.VISIBLE);
this.verificationCheck.setVisibility(View.INVISIBLE);
this.generatingKeysProgress.setVisibility(View.INVISIBLE);
this.generatingKeysCheck.setVisibility(View.INVISIBLE);
this.gcmRegistrationProgress.setVisibility(View.INVISIBLE);
this.gcmRegistrationCheck.setVisibility(View.INVISIBLE);
this.connectingText.setTextColor(UNFOCUSED_COLOR);
this.verificationText.setTextColor(FOCUSED_COLOR);
this.generatingKeysText.setTextColor(UNFOCUSED_COLOR);
this.gcmRegistrationText.setTextColor(UNFOCUSED_COLOR);
this.registrationProgress.setVisibility(View.VISIBLE);
this.timeoutProgressLayout.setVisibility(View.VISIBLE);
}

private void handleStateGeneratingKeys() {
this.registrationLayout.setVisibility(View.VISIBLE);
this.verificationFailureLayout.setVisibility(View.GONE);
this.connectivityFailureLayout.setVisibility(View.GONE);
this.connectingProgress.setVisibility(View.INVISIBLE);
this.connectingCheck.setVisibility(View.VISIBLE);
this.verificationProgress.setVisibility(View.INVISIBLE);
this.verificationCheck.setVisibility(View.VISIBLE);
this.generatingKeysProgress.setVisibility(View.VISIBLE);
this.generatingKeysCheck.setVisibility(View.INVISIBLE);
this.gcmRegistrationProgress.setVisibility(View.INVISIBLE);
this.gcmRegistrationCheck.setVisibility(View.INVISIBLE);
this.connectingText.setTextColor(UNFOCUSED_COLOR);
this.verificationText.setTextColor(UNFOCUSED_COLOR);
this.generatingKeysText.setTextColor(FOCUSED_COLOR);
this.gcmRegistrationText.setTextColor(UNFOCUSED_COLOR);
this.registrationProgress.setVisibility(View.INVISIBLE);
this.timeoutProgressLayout.setVisibility(View.INVISIBLE);
}

private void handleStateGcmRegistering() {
this.registrationLayout.setVisibility(View.VISIBLE);
this.verificationFailureLayout.setVisibility(View.GONE);
Expand All @@ -229,10 +266,13 @@ private void handleStateGcmRegistering() {
this.connectingCheck.setVisibility(View.VISIBLE);
this.verificationProgress.setVisibility(View.INVISIBLE);
this.verificationCheck.setVisibility(View.VISIBLE);
this.generatingKeysProgress.setVisibility(View.INVISIBLE);
this.generatingKeysCheck.setVisibility(View.VISIBLE);
this.gcmRegistrationProgress.setVisibility(View.VISIBLE);
this.gcmRegistrationCheck.setVisibility(View.INVISIBLE);
this.connectingText.setTextColor(UNFOCUSED_COLOR);
this.verificationText.setTextColor(UNFOCUSED_COLOR);
this.generatingKeysText.setTextColor(UNFOCUSED_COLOR);
this.gcmRegistrationText.setTextColor(FOCUSED_COLOR);
this.registrationProgress.setVisibility(View.INVISIBLE);
this.timeoutProgressLayout.setVisibility(View.INVISIBLE);
Expand Down Expand Up @@ -351,6 +391,7 @@ public void handleMessage(Message message) {
case RegistrationState.STATE_CONNECTING: handleStateConnecting(); break;
case RegistrationState.STATE_VERIFYING: handleStateVerifying(); break;
case RegistrationState.STATE_TIMER: handleTimerUpdate(); break;
case RegistrationState.STATE_GENERATING_KEYS: handleStateGeneratingKeys(); break;
case RegistrationState.STATE_GCM_REGISTERING: handleStateGcmRegistering(); break;
case RegistrationState.STATE_TIMEOUT: handleVerificationTimeout(state); break;
case RegistrationState.STATE_COMPLETE: handleVerificationComplete(); break;
Expand Down Expand Up @@ -429,6 +470,7 @@ protected void onPostExecute(Integer result) {
intent.setAction(RegistrationService.VOICE_REGISTER_ACTION);
intent.putExtra("e164number", e164number);
intent.putExtra("password", password);
intent.putExtra("master_secret", masterSecret);
startService(intent);
break;
case NETWORK_ERROR:
Expand Down Expand Up @@ -504,6 +546,7 @@ protected void onPostExecute(Integer result) {
intent.setAction(RegistrationService.VOICE_REQUESTED_ACTION);
intent.putExtra("e164number", e164number);
intent.putExtra("password", password);
intent.putExtra("master_secret", masterSecret);
startService(intent);

callButton.setEnabled(false);
Expand Down
7 changes: 5 additions & 2 deletions src/org/thoughtcrime/securesms/RoutingActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ private void handleUpgradeDatabase() {
}

private void handlePushRegistration() {
Intent intent = new Intent(this, RegistrationActivity.class);
Intent intent = getPushRegistrationIntent();
intent.putExtra("next_intent", getConversationListIntent());
startActivity(intent);
finish();
Expand Down Expand Up @@ -150,7 +150,10 @@ private Intent getConversationListIntent() {
}

private Intent getPushRegistrationIntent() {
return new Intent(this, RegistrationActivity.class);
Intent intent = new Intent(this, RegistrationActivity.class);
intent.putExtra("master_secret", masterSecret);

return intent;
}

private int getApplicationState() {
Expand Down
24 changes: 6 additions & 18 deletions src/org/thoughtcrime/securesms/crypto/IdentityKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@
*/
package org.thoughtcrime.securesms.crypto;

import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;
import org.thoughtcrime.securesms.util.Hex;

import android.os.Parcel;
import android.os.Parcelable;

import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.thoughtcrime.securesms.util.Hex;

/**
* A class for representing an identity key.
*
Expand All @@ -45,7 +44,7 @@ public IdentityKey[] newArray(int size) {
}
};

public static final int SIZE = 1 + 33;
public static final int SIZE = 1 + KeyUtil.POINT_SIZE;
private static final int VERSION = 1;

private ECPublicKeyParameters publicKey;
Expand Down Expand Up @@ -75,19 +74,8 @@ private void initializeFromSerialized(byte[] bytes, int offset) throws InvalidKe

if (version > VERSION)
throw new InvalidKeyException("Unsupported key version: " + version);

byte[] pointBytes = new byte[PublicKey.POINT_SIZE];
System.arraycopy(bytes, offset+1, pointBytes, 0, pointBytes.length);

ECPoint Q;

try {
Q = KeyUtil.decodePoint(pointBytes);
} catch (RuntimeException re) {
throw new InvalidKeyException(re);
}

this.publicKey = new ECPublicKeyParameters(Q, KeyUtil.domainParameters);

this.publicKey = KeyUtil.decodePoint(bytes, offset+1);
}

public byte[] serialize() {
Expand Down
Loading

0 comments on commit 2042ca6

Please sign in to comment.