2015-07-28 22:00:54 +02:00
package eu.siacs.conversations.crypto.axolotl ;
import android.support.annotation.NonNull ;
import android.support.annotation.Nullable ;
import android.util.Log ;
import org.whispersystems.libaxolotl.AxolotlAddress ;
import org.whispersystems.libaxolotl.DuplicateMessageException ;
2015-12-19 15:44:11 +01:00
import org.whispersystems.libaxolotl.IdentityKey ;
2015-07-28 22:00:54 +02:00
import org.whispersystems.libaxolotl.InvalidKeyException ;
import org.whispersystems.libaxolotl.InvalidKeyIdException ;
import org.whispersystems.libaxolotl.InvalidMessageException ;
import org.whispersystems.libaxolotl.InvalidVersionException ;
import org.whispersystems.libaxolotl.LegacyMessageException ;
import org.whispersystems.libaxolotl.NoSessionException ;
import org.whispersystems.libaxolotl.SessionCipher ;
import org.whispersystems.libaxolotl.UntrustedIdentityException ;
import org.whispersystems.libaxolotl.protocol.CiphertextMessage ;
import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage ;
import org.whispersystems.libaxolotl.protocol.WhisperMessage ;
import eu.siacs.conversations.Config ;
import eu.siacs.conversations.entities.Account ;
2016-11-19 13:34:54 +01:00
public class XmppAxolotlSession implements Comparable < XmppAxolotlSession > {
2015-07-28 22:00:54 +02:00
private final SessionCipher cipher ;
private final SQLiteAxolotlStore sqLiteAxolotlStore ;
private final AxolotlAddress remoteAddress ;
private final Account account ;
2015-12-19 15:44:11 +01:00
private IdentityKey identityKey ;
2015-07-31 23:28:09 +02:00
private Integer preKeyId = null ;
private boolean fresh = true ;
2015-07-28 22:00:54 +02:00
2015-12-19 15:44:11 +01:00
public XmppAxolotlSession ( Account account , SQLiteAxolotlStore store , AxolotlAddress remoteAddress , IdentityKey identityKey ) {
2015-07-28 22:00:54 +02:00
this ( account , store , remoteAddress ) ;
2015-12-19 15:44:11 +01:00
this . identityKey = identityKey ;
2015-07-28 22:00:54 +02:00
}
public XmppAxolotlSession ( Account account , SQLiteAxolotlStore store , AxolotlAddress remoteAddress ) {
this . cipher = new SessionCipher ( store , remoteAddress ) ;
this . remoteAddress = remoteAddress ;
this . sqLiteAxolotlStore = store ;
this . account = account ;
}
public Integer getPreKeyId ( ) {
return preKeyId ;
}
public void resetPreKeyId ( ) {
preKeyId = null ;
}
public String getFingerprint ( ) {
2015-12-19 15:44:11 +01:00
return identityKey = = null ? null : identityKey . getFingerprint ( ) . replaceAll ( " \\ s " , " " ) ;
}
public IdentityKey getIdentityKey ( ) {
return identityKey ;
2015-07-28 22:00:54 +02:00
}
2015-07-31 23:28:09 +02:00
public AxolotlAddress getRemoteAddress ( ) {
return remoteAddress ;
}
public boolean isFresh ( ) {
return fresh ;
}
public void setNotFresh ( ) {
this . fresh = false ;
}
2016-11-14 22:27:41 +01:00
protected void setTrust ( FingerprintStatus status ) {
2016-11-17 20:09:42 +01:00
sqLiteAxolotlStore . setFingerprintStatus ( getFingerprint ( ) , status ) ;
2015-07-28 22:00:54 +02:00
}
2016-11-17 22:28:45 +01:00
public FingerprintStatus getTrust ( ) {
2016-11-14 22:27:41 +01:00
FingerprintStatus status = sqLiteAxolotlStore . getFingerprintStatus ( getFingerprint ( ) ) ;
return ( status = = null ) ? FingerprintStatus . createActiveUndecided ( ) : status ;
2015-07-28 22:00:54 +02:00
}
@Nullable
2017-01-09 20:20:02 +01:00
public byte [ ] processReceiving ( AxolotlKey encryptedKey ) {
2015-07-28 22:00:54 +02:00
byte [ ] plaintext = null ;
2016-11-14 22:27:41 +01:00
FingerprintStatus status = getTrust ( ) ;
if ( ! status . isCompromised ( ) ) {
try {
2015-07-28 22:00:54 +02:00
try {
2017-01-09 20:20:02 +01:00
PreKeyWhisperMessage message = new PreKeyWhisperMessage ( encryptedKey . key ) ;
2016-11-14 22:27:41 +01:00
if ( ! message . getPreKeyId ( ) . isPresent ( ) ) {
Log . w ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " PreKeyWhisperMessage did not contain a PreKeyId " ) ;
return null ;
}
Log . i ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " PreKeyWhisperMessage received, new session ID: " + message . getSignedPreKeyId ( ) + " / " + message . getPreKeyId ( ) ) ;
IdentityKey msgIdentityKey = message . getIdentityKey ( ) ;
if ( this . identityKey ! = null & & ! this . identityKey . equals ( msgIdentityKey ) ) {
Log . e ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " Had session with fingerprint " + this . getFingerprint ( ) + " , received message with fingerprint " + msgIdentityKey . getFingerprint ( ) ) ;
} else {
this . identityKey = msgIdentityKey ;
2015-07-28 22:00:54 +02:00
plaintext = cipher . decrypt ( message ) ;
2016-11-14 22:27:41 +01:00
preKeyId = message . getPreKeyId ( ) . get ( ) ;
2015-07-28 22:00:54 +02:00
}
2016-11-14 22:27:41 +01:00
} catch ( InvalidMessageException | InvalidVersionException e ) {
Log . i ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " WhisperMessage received " ) ;
2017-01-09 20:20:02 +01:00
WhisperMessage message = new WhisperMessage ( encryptedKey . key ) ;
2016-11-14 22:27:41 +01:00
plaintext = cipher . decrypt ( message ) ;
} catch ( InvalidKeyException | InvalidKeyIdException | UntrustedIdentityException e ) {
2015-07-28 22:00:54 +02:00
Log . w ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " Error decrypting axolotl header, " + e . getClass ( ) . getName ( ) + " : " + e . getMessage ( ) ) ;
}
2016-11-14 22:27:41 +01:00
} catch ( LegacyMessageException | InvalidMessageException | DuplicateMessageException | NoSessionException e ) {
Log . w ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " Error decrypting axolotl header, " + e . getClass ( ) . getName ( ) + " : " + e . getMessage ( ) ) ;
}
2015-07-28 22:00:54 +02:00
2016-11-14 22:27:41 +01:00
if ( plaintext ! = null ) {
if ( ! status . isActive ( ) ) {
setTrust ( status . toActive ( ) ) ;
2015-07-28 22:00:54 +02:00
}
2016-11-14 22:27:41 +01:00
}
2015-07-28 22:00:54 +02:00
}
return plaintext ;
}
@Nullable
2017-01-09 20:20:02 +01:00
public AxolotlKey processSending ( @NonNull byte [ ] outgoingMessage ) {
2016-11-14 22:27:41 +01:00
FingerprintStatus status = getTrust ( ) ;
if ( status . isTrustedAndActive ( ) ) {
2015-07-28 22:00:54 +02:00
CiphertextMessage ciphertextMessage = cipher . encrypt ( outgoingMessage ) ;
2017-01-09 20:20:02 +01:00
return new AxolotlKey ( ciphertextMessage . serialize ( ) , ciphertextMessage . getType ( ) = = CiphertextMessage . PREKEY_TYPE ) ;
2015-07-28 22:00:54 +02:00
} else {
return null ;
}
}
2016-11-18 21:49:52 +01:00
public Account getAccount ( ) {
return account ;
}
2016-11-19 13:34:54 +01:00
@Override
public int compareTo ( XmppAxolotlSession o ) {
return getTrust ( ) . compareTo ( o . getTrust ( ) ) ;
}
2017-01-09 20:20:02 +01:00
public static class AxolotlKey {
public final byte [ ] key ;
public final boolean prekey ;
public AxolotlKey ( byte [ ] key , boolean prekey ) {
this . key = key ;
this . prekey = prekey ;
}
}
2015-07-28 22:00:54 +02:00
}