org.whispersystems.libsignal.state.SessionRecord Java Examples

The following examples show how to use org.whispersystems.libsignal.state.SessionRecord. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: SessionDatabase.java    From mollyim-android with GNU General Public License v3.0 6 votes vote down vote up
public @Nullable SessionRecord load(@NonNull RecipientId recipientId, int deviceId) {
  SQLiteDatabase database = databaseHelper.getReadableDatabase();

  try (Cursor cursor = database.query(TABLE_NAME, new String[]{RECORD},
                                      RECIPIENT_ID + " = ? AND " + DEVICE + " = ?",
                                      new String[] {recipientId.serialize(), String.valueOf(deviceId)},
                                      null, null, null))
  {
    if (cursor != null && cursor.moveToFirst()) {
      try {
        return new SessionRecord(cursor.getBlob(cursor.getColumnIndexOrThrow(RECORD)));
      } catch (IOException e) {
        Log.w(TAG, e);
      }
    }
  }

  return null;
}
 
Example #2
Source File: SessionDatabase.java    From mollyim-android with GNU General Public License v3.0 6 votes vote down vote up
public @NonNull List<SessionRow> getAllFor(@NonNull RecipientId recipientId) {
  SQLiteDatabase   database = databaseHelper.getReadableDatabase();
  List<SessionRow> results  = new LinkedList<>();

  try (Cursor cursor = database.query(TABLE_NAME, null,
                                      RECIPIENT_ID + " = ?",
                                      new String[] {recipientId.serialize()},
                                      null, null, null))
  {
    while (cursor != null && cursor.moveToNext()) {
      try {
        results.add(new SessionRow(recipientId,
                                   cursor.getInt(cursor.getColumnIndexOrThrow(DEVICE)),
                                   new SessionRecord(cursor.getBlob(cursor.getColumnIndexOrThrow(RECORD)))));
      } catch (IOException e) {
        Log.w(TAG, e);
      }
    }
  }

  return results;
}
 
Example #3
Source File: SessionDatabase.java    From mollyim-android with GNU General Public License v3.0 6 votes vote down vote up
public @NonNull List<SessionRow> getAll() {
  SQLiteDatabase   database = databaseHelper.getReadableDatabase();
  List<SessionRow> results  = new LinkedList<>();

  try (Cursor cursor = database.query(TABLE_NAME, null, null, null, null, null, null)) {
    while (cursor != null && cursor.moveToNext()) {
      try {
        results.add(new SessionRow(RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID))),
                                   cursor.getInt(cursor.getColumnIndexOrThrow(DEVICE)),
                                   new SessionRecord(cursor.getBlob(cursor.getColumnIndexOrThrow(RECORD)))));
      } catch (IOException e) {
        Log.w(TAG, e);
      }
    }
  }

  return results;
}
 
Example #4
Source File: IdentityUtil.java    From mollyim-android with GNU General Public License v3.0 6 votes vote down vote up
public static void saveIdentity(Context context, String user, IdentityKey identityKey) {
  synchronized (SESSION_LOCK) {
    IdentityKeyStore      identityKeyStore = new TextSecureIdentityKeyStore(context);
    SessionStore          sessionStore     = new TextSecureSessionStore(context);
    SignalProtocolAddress address          = new SignalProtocolAddress(user, 1);

    if (identityKeyStore.saveIdentity(address, identityKey)) {
      if (sessionStore.containsSession(address)) {
        SessionRecord sessionRecord = sessionStore.loadSession(address);
        sessionRecord.archiveCurrentState();

        sessionStore.storeSession(address, sessionRecord);
      }
    }
  }
}
 
Example #5
Source File: IdentityUtil.java    From bcm-android with GNU General Public License v3.0 6 votes vote down vote up
public static void saveIdentity(Context context, AccountContext accountContext, String number, IdentityKey identityKey, boolean nonBlockingApproval) {
    synchronized (SESSION_LOCK) {
        TextSecureIdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(context, accountContext);
        SessionStore sessionStore = new TextSecureSessionStore(context, accountContext);
        SignalProtocolAddress address = new SignalProtocolAddress(number, 1);

        if (identityKeyStore.saveIdentity(address, identityKey, nonBlockingApproval)) {
            if (sessionStore.containsSession(address)) {
                SessionRecord sessionRecord = sessionStore.loadSession(address);
                sessionRecord.archiveCurrentState();

                sessionStore.storeSession(address, sessionRecord);
            }
        }
    }
}
 
Example #6
Source File: IdentityUtil.java    From bcm-android with GNU General Public License v3.0 6 votes vote down vote up
public static void saveIdentity(Context context, AccountContext accountContext, String number, IdentityKey identityKey) {
    synchronized (SESSION_LOCK) {
        IdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(context, accountContext);
        SessionStore sessionStore = new TextSecureSessionStore(context, accountContext);
        SignalProtocolAddress address = new SignalProtocolAddress(number, 1);

        if (identityKeyStore.saveIdentity(address, identityKey)) {
            if (sessionStore.containsSession(address)) {
                SessionRecord sessionRecord = sessionStore.loadSession(address);
                sessionRecord.archiveCurrentState();

                sessionStore.storeSession(address, sessionRecord);
            }
        }
    }
}
 
Example #7
Source File: SessionUtil.java    From bcm-android with GNU General Public License v3.0 6 votes vote down vote up
public static void archiveSiblingSessions(Context context, AccountContext accountContext, SignalProtocolAddress address) {
    SessionStore sessionStore = new TextSecureSessionStore(context, accountContext);
    List<Integer> devices = sessionStore.getSubDeviceSessions(address.getName());
    devices.add(1);

    for (int device : devices) {
        if (device != address.getDeviceId()) {
            SignalProtocolAddress sibling = new SignalProtocolAddress(address.getName(), device);

            if (sessionStore.containsSession(sibling)) {
                SessionRecord sessionRecord = sessionStore.loadSession(sibling);
                sessionRecord.archiveCurrentState();
                sessionStore.storeSession(sibling, sessionRecord);
            }
        }
    }
}
 
Example #8
Source File: TextSecureSessionStore.java    From bcm-android with GNU General Public License v3.0 6 votes vote down vote up
@Override
public void storeSession(@NonNull SignalProtocolAddress address, @NonNull SessionRecord record) {
    synchronized (FILE_LOCK) {
        try {
            RandomAccessFile sessionFile = new RandomAccessFile(getSessionFile(address), "rw");
            FileChannel out = sessionFile.getChannel();

            out.position(0);
            writeInteger(CURRENT_VERSION, out);
            writeBlob(record.serialize(), out);
            out.truncate(out.position());

            sessionFile.close();
        } catch (IOException e) {
            throw new AssertionError(e);
        }
    }
}
 
Example #9
Source File: TextSecureSessionStore.java    From bcm-android with GNU General Public License v3.0 6 votes vote down vote up
public void migrateSessions() {
    synchronized (FILE_LOCK) {
        File directory = getSessionDirectory();

        for (File session : directory.listFiles()) {
            if (session.isFile()) {
                SignalProtocolAddress address = getAddressName(session);

                if (address != null) {
                    SessionRecord sessionRecord = loadSession(address);
                    storeSession(address, sessionRecord);
                }
            }
        }
    }
}
 
Example #10
Source File: TextSecureSessionStore.java    From bcm-android with GNU General Public License v3.0 6 votes vote down vote up
public void archiveAllSessions() {
    synchronized (FILE_LOCK) {
        File directory = getSessionDirectory();

        for (File session : directory.listFiles()) {
            if (session.isFile()) {
                SignalProtocolAddress address = getAddressName(session);

                if (address != null) {
                    SessionRecord sessionRecord = loadSession(address);
                    sessionRecord.archiveCurrentState();
                    storeSession(address, sessionRecord);
                }
            }
        }
    }
}
 
Example #11
Source File: VerifyIdentityActivity.java    From Silence with GNU General Public License v3.0 6 votes vote down vote up
private @Nullable IdentityKey getRemoteIdentityKey(MasterSecret masterSecret, Recipient recipient) {
  int subscriptionId = SubscriptionManagerCompat.getDefaultMessagingSubscriptionId().or(-1);
  IdentityKeyParcelable identityKeyParcelable = getIntent().getParcelableExtra("remote_identity");

  if (identityKeyParcelable != null) {
    return identityKeyParcelable.get();
  }

  SessionStore   sessionStore   = new SilenceSessionStore(this, masterSecret, subscriptionId);
  SignalProtocolAddress axolotlAddress = new SignalProtocolAddress(recipient.getNumber(), 1);
  SessionRecord  record         = sessionStore.loadSession(axolotlAddress);

  if (record == null) {
    return null;
  }

  return record.getSessionState().getRemoteIdentityKey();
}
 
Example #12
Source File: SessionBuilder.java    From Silence with GNU General Public License v3.0 6 votes vote down vote up
/**
 * Initiate a new session by sending an initial KeyExchangeMessage to the recipient.
 *
 * @return the KeyExchangeMessage to deliver.
 */
public KeyExchangeMessage process() {
  synchronized (SessionCipher.SESSION_LOCK) {
    try {
      int             sequence         = KeyHelper.getRandomSequence(65534) + 1;
      int             flags            = KeyExchangeMessage.INITIATE_FLAG;
      ECKeyPair       baseKey          = Curve.generateKeyPair();
      ECKeyPair       ratchetKey       = Curve.generateKeyPair();
      IdentityKeyPair identityKey      = identityKeyStore.getIdentityKeyPair();
      byte[]          baseKeySignature = Curve.calculateSignature(identityKey.getPrivateKey(), baseKey.getPublicKey().serialize());
      SessionRecord   sessionRecord    = sessionStore.loadSession(remoteAddress);

      sessionRecord.getSessionState().setPendingKeyExchange(sequence, baseKey, ratchetKey, identityKey);
      sessionStore.storeSession(remoteAddress, sessionRecord);

      return new KeyExchangeMessage(CiphertextMessage.CURRENT_VERSION,
                                    sequence, flags, baseKey.getPublicKey(), baseKeySignature,
                                    ratchetKey.getPublicKey(), identityKey.getPublicKey());
    } catch (InvalidKeyException e) {
      throw new AssertionError(e);
    }
  }
}
 
Example #13
Source File: SilenceSessionStore.java    From Silence with GNU General Public License v3.0 6 votes vote down vote up
@Override
public void storeSession(SignalProtocolAddress address, SessionRecord record) {
  synchronized (FILE_LOCK) {
    try {
      MasterCipher     masterCipher = new MasterCipher(masterSecret);
      RandomAccessFile sessionFile  = new RandomAccessFile(getSessionFile(address), "rw");
      FileChannel      out          = sessionFile.getChannel();

      out.position(0);
      writeInteger(CURRENT_VERSION, out);
      writeBlob(masterCipher.encryptBytes(record.serialize()), out);
      out.truncate(out.position());

      sessionFile.close();
    } catch (IOException e) {
      throw new AssertionError(e);
    }
  }
}
 
Example #14
Source File: SessionBuilder.java    From libsignal-protocol-java with GNU General Public License v3.0 6 votes vote down vote up
/**
 * Build a new session from a received {@link PreKeySignalMessage}.
 *
 * After a session is constructed in this way, the embedded {@link SignalMessage}
 * can be decrypted.
 *
 * @param message The received {@link PreKeySignalMessage}.
 * @throws org.whispersystems.libsignal.InvalidKeyIdException when there is no local
 *                                                             {@link org.whispersystems.libsignal.state.PreKeyRecord}
 *                                                             that corresponds to the PreKey ID in
 *                                                             the message.
 * @throws org.whispersystems.libsignal.InvalidKeyException when the message is formatted incorrectly.
 * @throws org.whispersystems.libsignal.UntrustedIdentityException when the {@link IdentityKey} of the sender is untrusted.
 */
/*package*/ Optional<Integer> process(SessionRecord sessionRecord, PreKeySignalMessage message)
    throws InvalidKeyIdException, InvalidKeyException, UntrustedIdentityException
{
  IdentityKey theirIdentityKey = message.getIdentityKey();

  if (!identityKeyStore.isTrustedIdentity(remoteAddress, theirIdentityKey, IdentityKeyStore.Direction.RECEIVING)) {
    throw new UntrustedIdentityException(remoteAddress.getName(), theirIdentityKey);
  }

  Optional<Integer> unsignedPreKeyId = processV3(sessionRecord, message);

  identityKeyStore.saveIdentity(remoteAddress, theirIdentityKey);

  return unsignedPreKeyId;
}
 
Example #15
Source File: InMemorySessionStore.java    From libsignal-protocol-java with GNU General Public License v3.0 5 votes vote down vote up
@Override
public synchronized SessionRecord loadSession(SignalProtocolAddress remoteAddress) {
  try {
    if (containsSession(remoteAddress)) {
      return new SessionRecord(sessions.get(remoteAddress));
    } else {
      return new SessionRecord();
    }
  } catch (IOException e) {
    throw new AssertionError(e);
  }
}
 
Example #16
Source File: SessionBuilder.java    From libsignal-protocol-java with GNU General Public License v3.0 5 votes vote down vote up
private Optional<Integer> processV3(SessionRecord sessionRecord, PreKeySignalMessage message)
    throws UntrustedIdentityException, InvalidKeyIdException, InvalidKeyException
{

  if (sessionRecord.hasSessionState(message.getMessageVersion(), message.getBaseKey().serialize())) {
    Log.w(TAG, "We've already setup a session for this V3 message, letting bundled message fall through...");
    return Optional.absent();
  }

  ECKeyPair ourSignedPreKey = signedPreKeyStore.loadSignedPreKey(message.getSignedPreKeyId()).getKeyPair();

  BobSignalProtocolParameters.Builder parameters = BobSignalProtocolParameters.newBuilder();

  parameters.setTheirBaseKey(message.getBaseKey())
            .setTheirIdentityKey(message.getIdentityKey())
            .setOurIdentityKey(identityKeyStore.getIdentityKeyPair())
            .setOurSignedPreKey(ourSignedPreKey)
            .setOurRatchetKey(ourSignedPreKey);

  if (message.getPreKeyId().isPresent()) {
    parameters.setOurOneTimePreKey(Optional.of(preKeyStore.loadPreKey(message.getPreKeyId().get()).getKeyPair()));
  } else {
    parameters.setOurOneTimePreKey(Optional.<ECKeyPair>absent());
  }

  if (!sessionRecord.isFresh()) sessionRecord.archiveCurrentState();

  RatchetingSession.initializeSession(sessionRecord.getSessionState(), parameters.create());

  sessionRecord.getSessionState().setLocalRegistrationId(identityKeyStore.getLocalRegistrationId());
  sessionRecord.getSessionState().setRemoteRegistrationId(message.getRegistrationId());
  sessionRecord.getSessionState().setAliceBaseKey(message.getBaseKey().serialize());

  if (message.getPreKeyId().isPresent()) {
    return message.getPreKeyId();
  } else {
    return Optional.absent();
  }
}
 
Example #17
Source File: SessionCipher.java    From libsignal-protocol-java with GNU General Public License v3.0 5 votes vote down vote up
/**
 * Decrypt a message.
 *
 * @param  ciphertext The {@link SignalMessage} to decrypt.
 * @param  callback   A callback that is triggered after decryption is complete,
 *                    but before the updated session state has been committed to the session
 *                    DB.  This allows some implementations to store the committed plaintext
 *                    to a DB first, in case they are concerned with a crash happening between
 *                    the time the session state is updated but before they're able to store
 *                    the plaintext to disk.
 *
 * @return The plaintext.
 * @throws InvalidMessageException if the input is not valid ciphertext.
 * @throws DuplicateMessageException if the input is a message that has already been received.
 * @throws LegacyMessageException if the input is a message formatted by a protocol version that
 *                                is no longer supported.
 * @throws NoSessionException if there is no established session for this contact.
 */
public byte[] decrypt(SignalMessage ciphertext, DecryptionCallback callback)
    throws InvalidMessageException, DuplicateMessageException, LegacyMessageException,
           NoSessionException, UntrustedIdentityException
{
  synchronized (SESSION_LOCK) {

    if (!sessionStore.containsSession(remoteAddress)) {
      throw new NoSessionException("No session for: " + remoteAddress);
    }

    SessionRecord sessionRecord = sessionStore.loadSession(remoteAddress);
    byte[]        plaintext     = decrypt(sessionRecord, ciphertext);

    if (!identityKeyStore.isTrustedIdentity(remoteAddress, sessionRecord.getSessionState().getRemoteIdentityKey(), IdentityKeyStore.Direction.RECEIVING)) {
      throw new UntrustedIdentityException(remoteAddress.getName(), sessionRecord.getSessionState().getRemoteIdentityKey());
    }

    identityKeyStore.saveIdentity(remoteAddress, sessionRecord.getSessionState().getRemoteIdentityKey());

    callback.handlePlaintext(plaintext);

    sessionStore.storeSession(remoteAddress, sessionRecord);

    return plaintext;
  }
}
 
Example #18
Source File: SessionCipherTest.java    From libsignal-protocol-java with GNU General Public License v3.0 5 votes vote down vote up
public void testMessageKeyLimits() throws Exception {
  SessionRecord aliceSessionRecord = new SessionRecord();
  SessionRecord bobSessionRecord   = new SessionRecord();

  initializeSessionsV3(aliceSessionRecord.getSessionState(), bobSessionRecord.getSessionState());

  SignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore();
  SignalProtocolStore bobStore   = new TestInMemorySignalProtocolStore();

  aliceStore.storeSession(new SignalProtocolAddress("+14159999999", 1), aliceSessionRecord);
  bobStore.storeSession(new SignalProtocolAddress("+14158888888", 1), bobSessionRecord);

  SessionCipher     aliceCipher    = new SessionCipher(aliceStore, new SignalProtocolAddress("+14159999999", 1));
  SessionCipher     bobCipher      = new SessionCipher(bobStore, new SignalProtocolAddress("+14158888888", 1));

  List<CiphertextMessage> inflight = new LinkedList<>();

  for (int i=0;i<2010;i++) {
    inflight.add(aliceCipher.encrypt("you've never been so hungry, you've never been so cold".getBytes()));
  }

  bobCipher.decrypt(new SignalMessage(inflight.get(1000).serialize()));
  bobCipher.decrypt(new SignalMessage(inflight.get(inflight.size()-1).serialize()));

  try {
    bobCipher.decrypt(new SignalMessage(inflight.get(0).serialize()));
    throw new AssertionError("Should have failed!");
  } catch (DuplicateMessageException dme) {
    // good
  }
}
 
Example #19
Source File: SignalOmemoRatchet.java    From Smack with Apache License 2.0 5 votes vote down vote up
SignalOmemoRatchet(OmemoManager omemoManager,
                          OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord,
                                         SessionRecord, SignalProtocolAddress, ECPublicKey, PreKeyBundle,
                                         SessionCipher> store) {
    super(omemoManager, store);
    this.storeConnector = new SignalOmemoStoreConnector(omemoManager, store);
}
 
Example #20
Source File: SignalOmemoService.java    From Smack with Apache License 2.0 5 votes vote down vote up
@Override
protected SignalOmemoRatchet instantiateOmemoRatchet(
        OmemoManager manager,
        OmemoStore<IdentityKeyPair, IdentityKey, PreKeyRecord, SignedPreKeyRecord, SessionRecord,
                SignalProtocolAddress, ECPublicKey, PreKeyBundle, SessionCipher> store) {

    return new SignalOmemoRatchet(manager, getOmemoStoreBackend());
}
 
Example #21
Source File: DatabaseBackend.java    From Conversations with GNU General Public License v3.0 5 votes vote down vote up
public void storeSession(Account account, SignalProtocolAddress contact, SessionRecord session) {
    SQLiteDatabase db = this.getWritableDatabase();
    ContentValues values = new ContentValues();
    values.put(SQLiteAxolotlStore.NAME, contact.getName());
    values.put(SQLiteAxolotlStore.DEVICE_ID, contact.getDeviceId());
    values.put(SQLiteAxolotlStore.KEY, Base64.encodeToString(session.serialize(), Base64.DEFAULT));
    values.put(SQLiteAxolotlStore.ACCOUNT, account.getUuid());
    db.insert(SQLiteAxolotlStore.SESSION_TABLENAME, null, values);
}
 
Example #22
Source File: SessionCipherTest.java    From libsignal-protocol-java with GNU General Public License v3.0 5 votes vote down vote up
public void testBasicSessionV3()
    throws InvalidKeyException, DuplicateMessageException,
    LegacyMessageException, InvalidMessageException, NoSuchAlgorithmException, NoSessionException, UntrustedIdentityException
{
  SessionRecord aliceSessionRecord = new SessionRecord();
  SessionRecord bobSessionRecord   = new SessionRecord();

  initializeSessionsV3(aliceSessionRecord.getSessionState(), bobSessionRecord.getSessionState());
  runInteraction(aliceSessionRecord, bobSessionRecord);
}
 
Example #23
Source File: SilenceSessionStore.java    From Silence with GNU General Public License v3.0 5 votes vote down vote up
@Override
public SessionRecord loadSession(SignalProtocolAddress address) {
  synchronized (FILE_LOCK) {
    try {
      MasterCipher    cipher = new MasterCipher(masterSecret);
      FileInputStream in     = new FileInputStream(getSessionFile(address));

      int versionMarker  = readInteger(in);

      if (versionMarker > CURRENT_VERSION) {
        throw new AssertionError("Unknown version: " + versionMarker);
      }

      byte[] serialized = cipher.decryptBytes(readBlob(in));
      in.close();

      if (versionMarker == SINGLE_STATE_VERSION) {
        SessionStructure sessionStructure = SessionStructure.parseFrom(serialized);
        SessionState     sessionState     = new SessionState(sessionStructure);
        return new SessionRecord(sessionState);
      } else if (versionMarker == ARCHIVE_STATES_VERSION) {
        return new SessionRecord(serialized);
      } else {
        throw new AssertionError("Unknown version: " + versionMarker);
      }
    } catch (InvalidMessageException | IOException e) {
      Log.w(TAG, "No existing session information found.");
      return new SessionRecord();
    }
  }
}
 
Example #24
Source File: KeyExchangeInitiator.java    From Silence with GNU General Public License v3.0 5 votes vote down vote up
private static boolean hasInitiatedSession(Context context, MasterSecret masterSecret,
                                           Recipients recipients, int subscriptionId)
{
  Recipient     recipient     = recipients.getPrimaryRecipient();
  SessionStore  sessionStore  = new SilenceSessionStore(context, masterSecret, subscriptionId);
  SessionRecord sessionRecord = sessionStore.loadSession(new SignalProtocolAddress(recipient.getNumber(), 1));

  return sessionRecord.getSessionState().hasPendingKeyExchange();
}
 
Example #25
Source File: SessionBuilder.java    From Silence with GNU General Public License v3.0 5 votes vote down vote up
private void processResponse(KeyExchangeMessage message)
    throws StaleKeyExchangeException, InvalidKeyException
{
  SessionRecord sessionRecord                  = sessionStore.loadSession(remoteAddress);
  SessionState  sessionState                   = sessionRecord.getSessionState();
  boolean       hasPendingKeyExchange          = sessionState.hasPendingKeyExchange();
  boolean       isSimultaneousInitiateResponse = message.isResponseForSimultaneousInitiate();

  if (!hasPendingKeyExchange || sessionState.getPendingKeyExchangeSequence() != message.getSequence()) {
    Log.w(TAG, "No matching sequence for response. Is simultaneous initiate response: " + isSimultaneousInitiateResponse);
    if (!isSimultaneousInitiateResponse) throw new StaleKeyExchangeException();
    else                                 return;
  }

  SymmetricSignalProtocolParameters.Builder parameters = SymmetricSignalProtocolParameters.newBuilder();

  parameters.setOurBaseKey(sessionRecord.getSessionState().getPendingKeyExchangeBaseKey())
            .setOurRatchetKey(sessionRecord.getSessionState().getPendingKeyExchangeRatchetKey())
            .setOurIdentityKey(sessionRecord.getSessionState().getPendingKeyExchangeIdentityKey())
            .setTheirBaseKey(message.getBaseKey())
            .setTheirRatchetKey(message.getRatchetKey())
            .setTheirIdentityKey(message.getIdentityKey());

  if (!sessionRecord.isFresh()) sessionRecord.archiveCurrentState();

  RatchetingSession.initializeSession(sessionRecord.getSessionState(), parameters.create());

  if (!Curve.verifySignature(message.getIdentityKey().getPublicKey(),
                             message.getBaseKey().serialize(),
                             message.getBaseKeySignature()))
  {
    throw new InvalidKeyException("Base key signature doesn't match!");
  }

  identityKeyStore.saveIdentity(remoteAddress, message.getIdentityKey());
  sessionStore.storeSession(remoteAddress, sessionRecord);
}
 
Example #26
Source File: SessionBuilder.java    From Silence with GNU General Public License v3.0 5 votes vote down vote up
private Optional<Integer> processV3(SessionRecord sessionRecord, PreKeySignalMessage message)
    throws UntrustedIdentityException, InvalidKeyIdException, InvalidKeyException
{

  if (sessionRecord.hasSessionState(message.getMessageVersion(), message.getBaseKey().serialize())) {
    Log.w(TAG, "We've already setup a session for this V3 message, letting bundled message fall through...");
    return Optional.absent();
  }

  ECKeyPair ourSignedPreKey = signedPreKeyStore.loadSignedPreKey(message.getSignedPreKeyId()).getKeyPair();

  BobSignalProtocolParameters.Builder parameters = BobSignalProtocolParameters.newBuilder();

  parameters.setTheirBaseKey(message.getBaseKey())
            .setTheirIdentityKey(message.getIdentityKey())
            .setOurIdentityKey(identityKeyStore.getIdentityKeyPair())
            .setOurSignedPreKey(ourSignedPreKey)
            .setOurRatchetKey(ourSignedPreKey);

  if (message.getPreKeyId().isPresent()) {
    parameters.setOurOneTimePreKey(Optional.of(preKeyStore.loadPreKey(message.getPreKeyId().get()).getKeyPair()));
  } else {
    parameters.setOurOneTimePreKey(Optional.<ECKeyPair>absent());
  }

  if (!sessionRecord.isFresh()) sessionRecord.archiveCurrentState();

  RatchetingSession.initializeSession(sessionRecord.getSessionState(), parameters.create());

  sessionRecord.getSessionState().setLocalRegistrationId(identityKeyStore.getLocalRegistrationId());
  sessionRecord.getSessionState().setRemoteRegistrationId(message.getRegistrationId());
  sessionRecord.getSessionState().setAliceBaseKey(message.getBaseKey().serialize());

  if (message.getPreKeyId().isPresent() && message.getPreKeyId().get() != Medium.MAX_VALUE) {
    return message.getPreKeyId();
  } else {
    return Optional.absent();
  }
}
 
Example #27
Source File: SessionBuilder.java    From Silence with GNU General Public License v3.0 5 votes vote down vote up
/**
 * Build a new session from a received {@link PreKeySignalMessage}.
 *
 * After a session is constructed in this way, the embedded {@link SignalMessage}
 * can be decrypted.
 *
 * @param message The received {@link PreKeySignalMessage}.
 * @throws org.whispersystems.libsignal.InvalidKeyIdException when there is no local
 *                                                             {@link org.whispersystems.libsignal.state.PreKeyRecord}
 *                                                             that corresponds to the PreKey ID in
 *                                                             the message.
 * @throws org.whispersystems.libsignal.InvalidKeyException when the message is formatted incorrectly.
 * @throws org.whispersystems.libsignal.UntrustedIdentityException when the {@link IdentityKey} of the sender is untrusted.
 */
/*package*/ Optional<Integer> process(SessionRecord sessionRecord, PreKeySignalMessage message)
    throws InvalidKeyIdException, InvalidKeyException, UntrustedIdentityException
{
  IdentityKey theirIdentityKey = message.getIdentityKey();

  if (!identityKeyStore.isTrustedIdentity(remoteAddress, theirIdentityKey, IdentityKeyStore.Direction.RECEIVING)) {
    throw new UntrustedIdentityException(remoteAddress.getName(), theirIdentityKey);
  }

  Optional<Integer> unsignedPreKeyId = processV3(sessionRecord, message);

  identityKeyStore.saveIdentity(remoteAddress, theirIdentityKey);
  return unsignedPreKeyId;
}
 
Example #28
Source File: DatabaseBackend.java    From Pix-Art-Messenger with GNU General Public License v3.0 5 votes vote down vote up
public void storeSession(Account account, SignalProtocolAddress contact, SessionRecord session) {
    SQLiteDatabase db = this.getWritableDatabase();
    ContentValues values = new ContentValues();
    values.put(SQLiteAxolotlStore.NAME, contact.getName());
    values.put(SQLiteAxolotlStore.DEVICE_ID, contact.getDeviceId());
    values.put(SQLiteAxolotlStore.KEY, Base64.encodeToString(session.serialize(), Base64.DEFAULT));
    values.put(SQLiteAxolotlStore.ACCOUNT, account.getUuid());
    db.insert(SQLiteAxolotlStore.SESSION_TABLENAME, null, values);
}
 
Example #29
Source File: SignalServiceCipher.java    From bcm-android with GNU General Public License v3.0 5 votes vote down vote up
private byte[] decrypt(SignalServiceProtos.Envelope envelope, byte[] ciphertext)
    throws InvalidVersionException, InvalidMessageException, InvalidKeyException,
           DuplicateMessageException, InvalidKeyIdException, UntrustedIdentityException,
           LegacyMessageException, NoSessionException
{
  SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.getSource(), envelope.getSourceDevice());
  SessionCipher         sessionCipher = new SessionCipher(signalProtocolStore, sourceAddress);

  byte[] paddedMessage;

  if (envelope.getType() == Type.PREKEY_BUNDLE) {
    paddedMessage = sessionCipher.decrypt(new PreKeySignalMessage(ciphertext));
      //纠正remote register id
      SessionRecord sessionRecord = signalProtocolStore.loadSession(sourceAddress);
      if (sessionRecord.getSessionState().getRemoteRegistrationId() == 0) {
          sessionRecord.getSessionState().setRemoteRegistrationId(envelope.getSourceRegistration());
          signalProtocolStore.storeSession(sourceAddress, sessionRecord);
      }

  } else if (envelope.getType() == Type.CIPHERTEXT) {
    paddedMessage = sessionCipher.decrypt(new SignalMessage(ciphertext));
  } else {
    throw new InvalidMessageException("Unknown type: " + envelope.getType());
  }

  PushTransportDetails transportDetails = new PushTransportDetails(sessionCipher.getSessionVersion());
  return transportDetails.getStrippedPaddingMessageBody(paddedMessage);
}
 
Example #30
Source File: JsonSessionStore.java    From signal-cli with GNU General Public License v3.0 5 votes vote down vote up
@Override
public synchronized void storeSession(SignalProtocolAddress address, SessionRecord record) {
    SignalServiceAddress serviceAddress = resolveSignalServiceAddress(address.getName());
    for (SessionInfo info : sessions) {
        if (info.address.matches(serviceAddress) && info.deviceId == address.getDeviceId()) {
            if (!info.address.getUuid().isPresent() || !info.address.getNumber().isPresent()) {
                info.address = serviceAddress;
            }
            info.sessionRecord = record.serialize();
            return;
        }
    }

    sessions.add(new SessionInfo(serviceAddress, address.getDeviceId(), record.serialize()));
}