2015-07-28 20:00:54 +00: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 14:44:11 +00:00
import org.whispersystems.libaxolotl.IdentityKey ;
2015-07-28 20:00:54 +00: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 ;
public class XmppAxolotlSession {
private final SessionCipher cipher ;
private final SQLiteAxolotlStore sqLiteAxolotlStore ;
private final AxolotlAddress remoteAddress ;
private final Account account ;
2015-12-19 14:44:11 +00:00
private IdentityKey identityKey ;
2015-07-31 21:28:09 +00:00
private Integer preKeyId = null ;
private boolean fresh = true ;
2015-07-28 20:00:54 +00:00
2015-12-19 14:44:11 +00:00
public XmppAxolotlSession ( Account account , SQLiteAxolotlStore store , AxolotlAddress remoteAddress , IdentityKey identityKey ) {
2015-07-28 20:00:54 +00:00
this ( account , store , remoteAddress ) ;
2015-12-19 14:44:11 +00:00
this . identityKey = identityKey ;
2015-07-28 20:00:54 +00: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 14:44:11 +00:00
return identityKey = = null ? null : identityKey . getFingerprint ( ) . replaceAll ( " \\ s " , " " ) ;
}
public IdentityKey getIdentityKey ( ) {
return identityKey ;
2015-07-28 20:00:54 +00:00
}
2015-07-31 21:28:09 +00:00
public AxolotlAddress getRemoteAddress ( ) {
return remoteAddress ;
}
public boolean isFresh ( ) {
return fresh ;
}
public void setNotFresh ( ) {
this . fresh = false ;
}
2016-11-14 21:27:41 +00:00
protected void setTrust ( FingerprintStatus status ) {
sqLiteAxolotlStore . setFingerprintTrust ( getFingerprint ( ) , status ) ;
2015-07-28 20:00:54 +00:00
}
2016-11-14 21:27:41 +00:00
protected FingerprintStatus getTrust ( ) {
FingerprintStatus status = sqLiteAxolotlStore . getFingerprintStatus ( getFingerprint ( ) ) ;
return ( status = = null ) ? FingerprintStatus . createActiveUndecided ( ) : status ;
2015-07-28 20:00:54 +00:00
}
@Nullable
2015-07-31 19:12:34 +00:00
public byte [ ] processReceiving ( byte [ ] encryptedKey ) {
2015-07-28 20:00:54 +00:00
byte [ ] plaintext = null ;
2016-11-14 21:27:41 +00:00
FingerprintStatus status = getTrust ( ) ;
if ( ! status . isCompromised ( ) ) {
try {
2015-07-28 20:00:54 +00:00
try {
2016-11-14 21:27:41 +00:00
PreKeyWhisperMessage message = new PreKeyWhisperMessage ( encryptedKey ) ;
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 20:00:54 +00:00
plaintext = cipher . decrypt ( message ) ;
2016-11-14 21:27:41 +00:00
preKeyId = message . getPreKeyId ( ) . get ( ) ;
2015-07-28 20:00:54 +00:00
}
2016-11-14 21:27:41 +00:00
} catch ( InvalidMessageException | InvalidVersionException e ) {
Log . i ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " WhisperMessage received " ) ;
WhisperMessage message = new WhisperMessage ( encryptedKey ) ;
plaintext = cipher . decrypt ( message ) ;
} catch ( InvalidKeyException | InvalidKeyIdException | UntrustedIdentityException e ) {
2015-07-28 20:00:54 +00:00
Log . w ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " Error decrypting axolotl header, " + e . getClass ( ) . getName ( ) + " : " + e . getMessage ( ) ) ;
}
2016-11-14 21:27:41 +00: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 20:00:54 +00:00
2016-11-14 21:27:41 +00:00
if ( plaintext ! = null ) {
if ( ! status . isActive ( ) ) {
setTrust ( status . toActive ( ) ) ;
2015-07-28 20:00:54 +00:00
}
2016-11-14 21:27:41 +00:00
}
2015-07-28 20:00:54 +00:00
}
return plaintext ;
}
@Nullable
2015-07-31 19:12:34 +00:00
public byte [ ] processSending ( @NonNull byte [ ] outgoingMessage ) {
2016-11-14 21:27:41 +00:00
FingerprintStatus status = getTrust ( ) ;
if ( status . isTrustedAndActive ( ) ) {
2015-07-28 20:00:54 +00:00
CiphertextMessage ciphertextMessage = cipher . encrypt ( outgoingMessage ) ;
2015-07-31 19:12:34 +00:00
return ciphertextMessage . serialize ( ) ;
2015-07-28 20:00:54 +00:00
} else {
return null ;
}
}
}