Switch payload encryption to AES-GCM
This also ensures that the IV is generated with proper randomness.
This commit is contained in:
parent
971aa3a11e
commit
122bc97ce2
|
@ -4,6 +4,7 @@ import android.support.annotation.NonNull;
|
|||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.whispersystems.libaxolotl.AxolotlAddress;
|
||||
import org.whispersystems.libaxolotl.DuplicateMessageException;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
|
@ -30,6 +31,7 @@ import org.whispersystems.libaxolotl.state.SessionRecord;
|
|||
import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
|
||||
import org.whispersystems.libaxolotl.util.KeyHelper;
|
||||
|
||||
import java.security.Security;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -678,6 +680,9 @@ public class AxolotlService {
|
|||
}
|
||||
|
||||
public AxolotlService(Account account, XmppConnectionService connectionService) {
|
||||
if (Security.getProvider("BC") == null) {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
}
|
||||
this.mXmppConnectionService = connectionService;
|
||||
this.account = account;
|
||||
this.axolotlStore = new SQLiteAxolotlStore(this.account, this.mXmppConnectionService);
|
||||
|
@ -1050,11 +1055,17 @@ public class AxolotlService {
|
|||
final String content;
|
||||
if (message.hasFileOnRemoteHost()) {
|
||||
content = message.getFileParams().url.toString();
|
||||
} else {
|
||||
content = message.getBody();
|
||||
}
|
||||
final XmppAxolotlMessage axolotlMessage = new XmppAxolotlMessage(message.getContact().getJid().toBareJid(),
|
||||
getOwnDeviceId(), content);
|
||||
} else {
|
||||
content = message.getBody();
|
||||
}
|
||||
final XmppAxolotlMessage axolotlMessage;
|
||||
try {
|
||||
axolotlMessage = new XmppAxolotlMessage(message.getContact().getJid().toBareJid(),
|
||||
getOwnDeviceId(), content);
|
||||
} catch (CryptoFailedException e) {
|
||||
Log.w(Config.LOGTAG, getLogprefix(account) + "Failed to encrypt message: " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
if(findSessionsforContact(message.getContact()).isEmpty()) {
|
||||
return null;
|
||||
|
@ -1143,7 +1154,12 @@ public class AxolotlService {
|
|||
byte[] payloadKey = session.processReceiving(header);
|
||||
if (payloadKey != null) {
|
||||
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Got payload key from axolotl header. Decrypting message...");
|
||||
plaintextMessage = message.decrypt(session, payloadKey, session.getFingerprint());
|
||||
try{
|
||||
plaintextMessage = message.decrypt(session, payloadKey, session.getFingerprint());
|
||||
} catch (CryptoFailedException e) {
|
||||
Log.w(Config.LOGTAG, getLogprefix(account) + "Failed to decrypt message: " + e.getMessage());
|
||||
break;
|
||||
}
|
||||
}
|
||||
Integer preKeyId = session.getPreKeyId();
|
||||
if (preKeyId != null) {
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package eu.siacs.conversations.crypto.axolotl;
|
||||
|
||||
public class CryptoFailedException extends Exception {
|
||||
public CryptoFailedException(Exception e){
|
||||
super(e);
|
||||
}
|
||||
}
|
|
@ -6,6 +6,8 @@ import android.util.Base64;
|
|||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -107,26 +109,30 @@ public class XmppAxolotlMessage {
|
|||
}
|
||||
}
|
||||
|
||||
public XmppAxolotlMessage(Jid from, int sourceDeviceId, String plaintext) {
|
||||
public XmppAxolotlMessage(Jid from, int sourceDeviceId, String plaintext) throws CryptoFailedException{
|
||||
this.from = from;
|
||||
this.sourceDeviceId = sourceDeviceId;
|
||||
this.headers = new HashSet<>();
|
||||
this.encrypt(plaintext);
|
||||
}
|
||||
|
||||
private void encrypt(String plaintext) {
|
||||
private void encrypt(String plaintext) throws CryptoFailedException {
|
||||
try {
|
||||
KeyGenerator generator = KeyGenerator.getInstance("AES");
|
||||
generator.init(128);
|
||||
SecretKey secretKey = generator.generateKey();
|
||||
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
||||
SecureRandom random = new SecureRandom();
|
||||
this.iv = new byte[16];
|
||||
random.nextBytes(iv);
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
|
||||
this.innerKey = secretKey.getEncoded();
|
||||
this.iv = cipher.getIV();
|
||||
this.ciphertext = cipher.doFinal(plaintext.getBytes());
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
|
||||
| IllegalBlockSizeException | BadPaddingException e) {
|
||||
|
||||
| IllegalBlockSizeException | BadPaddingException | NoSuchProviderException
|
||||
| InvalidAlgorithmParameterException e) {
|
||||
throw new CryptoFailedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,11 +180,11 @@ public class XmppAxolotlMessage {
|
|||
}
|
||||
|
||||
|
||||
public XmppAxolotlPlaintextMessage decrypt(AxolotlService.XmppAxolotlSession session, byte[] key, String fingerprint) {
|
||||
public XmppAxolotlPlaintextMessage decrypt(AxolotlService.XmppAxolotlSession session, byte[] key, String fingerprint) throws CryptoFailedException {
|
||||
XmppAxolotlPlaintextMessage plaintextMessage = null;
|
||||
try {
|
||||
|
||||
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
|
||||
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(iv);
|
||||
|
||||
|
@ -189,8 +195,8 @@ public class XmppAxolotlMessage {
|
|||
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
|
||||
| InvalidAlgorithmParameterException | IllegalBlockSizeException
|
||||
| BadPaddingException e) {
|
||||
throw new AssertionError(e);
|
||||
| BadPaddingException | NoSuchProviderException e) {
|
||||
throw new CryptoFailedException(e);
|
||||
}
|
||||
return plaintextMessage;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue