Extract PreKey generation functions, don't reuse IDs when reregistering
This commit is contained in:
		
							parent
							
								
									704f2d76ba
								
							
						
					
					
						commit
						9f5b55fa7e
					
				@ -20,7 +20,10 @@ import org.apache.commons.io.IOUtils;
 | 
				
			|||||||
import org.json.JSONObject;
 | 
					import org.json.JSONObject;
 | 
				
			||||||
import org.whispersystems.libaxolotl.IdentityKeyPair;
 | 
					import org.whispersystems.libaxolotl.IdentityKeyPair;
 | 
				
			||||||
import org.whispersystems.libaxolotl.InvalidKeyException;
 | 
					import org.whispersystems.libaxolotl.InvalidKeyException;
 | 
				
			||||||
 | 
					import org.whispersystems.libaxolotl.InvalidKeyIdException;
 | 
				
			||||||
import org.whispersystems.libaxolotl.InvalidVersionException;
 | 
					import org.whispersystems.libaxolotl.InvalidVersionException;
 | 
				
			||||||
 | 
					import org.whispersystems.libaxolotl.ecc.Curve;
 | 
				
			||||||
 | 
					import org.whispersystems.libaxolotl.ecc.ECKeyPair;
 | 
				
			||||||
import org.whispersystems.libaxolotl.state.PreKeyRecord;
 | 
					import org.whispersystems.libaxolotl.state.PreKeyRecord;
 | 
				
			||||||
import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
 | 
					import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
 | 
				
			||||||
import org.whispersystems.libaxolotl.util.KeyHelper;
 | 
					import org.whispersystems.libaxolotl.util.KeyHelper;
 | 
				
			||||||
@ -39,6 +42,7 @@ import org.whispersystems.textsecure.api.util.InvalidNumberException;
 | 
				
			|||||||
import org.whispersystems.textsecure.api.util.PhoneNumberFormatter;
 | 
					import org.whispersystems.textsecure.api.util.PhoneNumberFormatter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.*;
 | 
					import java.io.*;
 | 
				
			||||||
 | 
					import java.util.LinkedList;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.concurrent.TimeUnit;
 | 
					import java.util.concurrent.TimeUnit;
 | 
				
			||||||
import java.util.concurrent.TimeoutException;
 | 
					import java.util.concurrent.TimeoutException;
 | 
				
			||||||
@ -52,6 +56,8 @@ public class Manager {
 | 
				
			|||||||
    private String username;
 | 
					    private String username;
 | 
				
			||||||
    private String password;
 | 
					    private String password;
 | 
				
			||||||
    private String signalingKey;
 | 
					    private String signalingKey;
 | 
				
			||||||
 | 
					    private int preKeyIdOffset;
 | 
				
			||||||
 | 
					    private int nextSignedPreKeyId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private boolean registered = false;
 | 
					    private boolean registered = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -87,6 +93,16 @@ public class Manager {
 | 
				
			|||||||
        if (in.has("signalingKey")) {
 | 
					        if (in.has("signalingKey")) {
 | 
				
			||||||
            signalingKey = in.getString("signalingKey");
 | 
					            signalingKey = in.getString("signalingKey");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        if (in.has("preKeyIdOffset")) {
 | 
				
			||||||
 | 
					            preKeyIdOffset = in.getInt("preKeyIdOffset");
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            preKeyIdOffset = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (in.has("nextSignedPreKeyId")) {
 | 
				
			||||||
 | 
					            nextSignedPreKeyId = in.getInt("nextSignedPreKeyId");
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            nextSignedPreKeyId = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        axolotlStore = new JsonAxolotlStore(in.getJSONObject("axolotlStore"));
 | 
					        axolotlStore = new JsonAxolotlStore(in.getJSONObject("axolotlStore"));
 | 
				
			||||||
        registered = in.getBoolean("registered");
 | 
					        registered = in.getBoolean("registered");
 | 
				
			||||||
        accountManager = new TextSecureAccountManager(URL, TRUST_STORE, username, password);
 | 
					        accountManager = new TextSecureAccountManager(URL, TRUST_STORE, username, password);
 | 
				
			||||||
@ -96,6 +112,8 @@ public class Manager {
 | 
				
			|||||||
        String out = new JSONObject().put("username", username)
 | 
					        String out = new JSONObject().put("username", username)
 | 
				
			||||||
                .put("password", password)
 | 
					                .put("password", password)
 | 
				
			||||||
                .put("signalingKey", signalingKey)
 | 
					                .put("signalingKey", signalingKey)
 | 
				
			||||||
 | 
					                .put("preKeyIdOffset", preKeyIdOffset)
 | 
				
			||||||
 | 
					                .put("nextSignedPreKeyId", nextSignedPreKeyId)
 | 
				
			||||||
                .put("axolotlStore", axolotlStore.getJson())
 | 
					                .put("axolotlStore", axolotlStore.getJson())
 | 
				
			||||||
                .put("registered", registered).toString();
 | 
					                .put("registered", registered).toString();
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
@ -133,6 +151,56 @@ public class Manager {
 | 
				
			|||||||
        registered = false;
 | 
					        registered = false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final int BATCH_SIZE = 100;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private List<PreKeyRecord> generatePreKeys() {
 | 
				
			||||||
 | 
					        List<PreKeyRecord> records = new LinkedList<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (int i = 0; i < BATCH_SIZE; i++) {
 | 
				
			||||||
 | 
					            int preKeyId = (preKeyIdOffset + i) % Medium.MAX_VALUE;
 | 
				
			||||||
 | 
					            ECKeyPair keyPair = Curve.generateKeyPair();
 | 
				
			||||||
 | 
					            PreKeyRecord record = new PreKeyRecord(preKeyId, keyPair);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            axolotlStore.storePreKey(preKeyId, record);
 | 
				
			||||||
 | 
					            records.add(record);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        preKeyIdOffset = (preKeyIdOffset + BATCH_SIZE + 1) % Medium.MAX_VALUE;
 | 
				
			||||||
 | 
					        return records;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private PreKeyRecord generateLastResortPreKey() {
 | 
				
			||||||
 | 
					        if (axolotlStore.containsPreKey(Medium.MAX_VALUE)) {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                return axolotlStore.loadPreKey(Medium.MAX_VALUE);
 | 
				
			||||||
 | 
					            } catch (InvalidKeyIdException e) {
 | 
				
			||||||
 | 
					                axolotlStore.removePreKey(Medium.MAX_VALUE);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ECKeyPair keyPair = Curve.generateKeyPair();
 | 
				
			||||||
 | 
					        PreKeyRecord record = new PreKeyRecord(Medium.MAX_VALUE, keyPair);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        axolotlStore.storePreKey(Medium.MAX_VALUE, record);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return record;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private SignedPreKeyRecord generateSignedPreKey(IdentityKeyPair identityKeyPair) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            ECKeyPair keyPair = Curve.generateKeyPair();
 | 
				
			||||||
 | 
					            byte[] signature = Curve.calculateSignature(identityKeyPair.getPrivateKey(), keyPair.getPublicKey().serialize());
 | 
				
			||||||
 | 
					            SignedPreKeyRecord record = new SignedPreKeyRecord(nextSignedPreKeyId, System.currentTimeMillis(), keyPair, signature);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            axolotlStore.storeSignedPreKey(nextSignedPreKeyId, record);
 | 
				
			||||||
 | 
					            nextSignedPreKeyId = (nextSignedPreKeyId + 1) % Medium.MAX_VALUE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return record;
 | 
				
			||||||
 | 
					        } catch (InvalidKeyException e) {
 | 
				
			||||||
 | 
					            throw new AssertionError(e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void verifyAccount(String verificationCode) throws IOException {
 | 
					    public void verifyAccount(String verificationCode) throws IOException {
 | 
				
			||||||
        verificationCode = verificationCode.replace("-", "");
 | 
					        verificationCode = verificationCode.replace("-", "");
 | 
				
			||||||
        signalingKey = Util.getSecret(52);
 | 
					        signalingKey = Util.getSecret(52);
 | 
				
			||||||
@ -141,25 +209,12 @@ public class Manager {
 | 
				
			|||||||
        //accountManager.setGcmId(Optional.of(GoogleCloudMessaging.getInstance(this).register(REGISTRATION_ID)));
 | 
					        //accountManager.setGcmId(Optional.of(GoogleCloudMessaging.getInstance(this).register(REGISTRATION_ID)));
 | 
				
			||||||
        registered = true;
 | 
					        registered = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int start = 0;
 | 
					        List<PreKeyRecord> oneTimePreKeys = generatePreKeys();
 | 
				
			||||||
        List<PreKeyRecord> oneTimePreKeys = KeyHelper.generatePreKeys(start, 100);
 | 
					 | 
				
			||||||
        for (int i = start; i < oneTimePreKeys.size(); i++) {
 | 
					 | 
				
			||||||
            axolotlStore.storePreKey(i, oneTimePreKeys.get(i));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        PreKeyRecord lastResortKey = KeyHelper.generateLastResortPreKey();
 | 
					        PreKeyRecord lastResortKey = generateLastResortPreKey();
 | 
				
			||||||
        axolotlStore.storePreKey(Medium.MAX_VALUE, lastResortKey);
 | 
					
 | 
				
			||||||
 | 
					        SignedPreKeyRecord signedPreKeyRecord = generateSignedPreKey(axolotlStore.getIdentityKeyPair());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int signedPreKeyId = 0;
 | 
					 | 
				
			||||||
        SignedPreKeyRecord signedPreKeyRecord;
 | 
					 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
            signedPreKeyRecord = KeyHelper.generateSignedPreKey(axolotlStore.getIdentityKeyPair(), signedPreKeyId);
 | 
					 | 
				
			||||||
            axolotlStore.storeSignedPreKey(signedPreKeyId, signedPreKeyRecord);
 | 
					 | 
				
			||||||
        } catch (InvalidKeyException e) {
 | 
					 | 
				
			||||||
            // Should really not happen
 | 
					 | 
				
			||||||
            System.out.println("invalid key");
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        accountManager.setPreKeys(axolotlStore.getIdentityKeyPair().getPublicKey(), lastResortKey, signedPreKeyRecord, oneTimePreKeys);
 | 
					        accountManager.setPreKeys(axolotlStore.getIdentityKeyPair().getPublicKey(), lastResortKey, signedPreKeyRecord, oneTimePreKeys);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user