mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-23 18:15:22 +00:00
...and the rest
This commit is contained in:
parent
d3ce899a80
commit
a9078c8d08
@ -12,6 +12,7 @@ import org.session.libsession.messaging.sending_receiving.attachments.Attachment
|
|||||||
import org.session.libsession.utilities.Address
|
import org.session.libsession.utilities.Address
|
||||||
import org.session.libsession.utilities.Conversions
|
import org.session.libsession.utilities.Conversions
|
||||||
import org.session.libsession.utilities.Util
|
import org.session.libsession.utilities.Util
|
||||||
|
import org.session.libsignal.crypto.CipherUtil.CIPHER_LOCK
|
||||||
import org.session.libsignal.crypto.kdf.HKDFv3
|
import org.session.libsignal.crypto.kdf.HKDFv3
|
||||||
import org.session.libsignal.utilities.ByteUtil
|
import org.session.libsignal.utilities.ByteUtil
|
||||||
import org.session.libsignal.utilities.Log
|
import org.session.libsignal.utilities.Log
|
||||||
@ -243,7 +244,7 @@ object FullBackupImporter {
|
|||||||
val split = ByteUtil.split(derived, 32, 32)
|
val split = ByteUtil.split(derived, 32, 32)
|
||||||
cipherKey = split[0]
|
cipherKey = split[0]
|
||||||
macKey = split[1]
|
macKey = split[1]
|
||||||
cipher = Cipher.getInstance("AES/CTR/NoPadding")
|
cipher = synchronized(CIPHER_LOCK) { Cipher.getInstance("AES/CTR/NoPadding") }
|
||||||
mac = Mac.getInstance("HmacSHA256")
|
mac = Mac.getInstance("HmacSHA256")
|
||||||
mac.init(SecretKeySpec(macKey, "HmacSHA256"))
|
mac.init(SecretKeySpec(macKey, "HmacSHA256"))
|
||||||
counter = Conversions.byteArrayToInt(iv)
|
counter = Conversions.byteArrayToInt(iv)
|
||||||
@ -269,20 +270,26 @@ object FullBackupImporter {
|
|||||||
var length = length
|
var length = length
|
||||||
try {
|
try {
|
||||||
Conversions.intToByteArray(iv, 0, counter++)
|
Conversions.intToByteArray(iv, 0, counter++)
|
||||||
cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(iv))
|
val plaintext = synchronized(CIPHER_LOCK) {
|
||||||
mac.update(iv)
|
cipher.init(
|
||||||
val buffer = ByteArray(8192)
|
Cipher.DECRYPT_MODE,
|
||||||
while (length > 0) {
|
SecretKeySpec(cipherKey, "AES"),
|
||||||
val read = inputStream.read(buffer, 0, Math.min(buffer.size, length))
|
IvParameterSpec(iv)
|
||||||
if (read == -1) throw IOException("File ended early!")
|
)
|
||||||
mac.update(buffer, 0, read)
|
mac.update(iv)
|
||||||
val plaintext = cipher.update(buffer, 0, read)
|
val buffer = ByteArray(8192)
|
||||||
if (plaintext != null) {
|
while (length > 0) {
|
||||||
out.write(plaintext, 0, plaintext.size)
|
val read = inputStream.read(buffer, 0, Math.min(buffer.size, length))
|
||||||
|
if (read == -1) throw IOException("File ended early!")
|
||||||
|
mac.update(buffer, 0, read)
|
||||||
|
val plaintext = cipher.update(buffer, 0, read)
|
||||||
|
if (plaintext != null) {
|
||||||
|
out.write(plaintext, 0, plaintext.size)
|
||||||
|
}
|
||||||
|
length -= read
|
||||||
}
|
}
|
||||||
length -= read
|
cipher.doFinal()
|
||||||
}
|
}
|
||||||
val plaintext = cipher.doFinal()
|
|
||||||
if (plaintext != null) {
|
if (plaintext != null) {
|
||||||
out.write(plaintext, 0, plaintext.size)
|
out.write(plaintext, 0, plaintext.size)
|
||||||
}
|
}
|
||||||
@ -325,8 +332,10 @@ object FullBackupImporter {
|
|||||||
throw IOException("Bad MAC")
|
throw IOException("Bad MAC")
|
||||||
}
|
}
|
||||||
Conversions.intToByteArray(iv, 0, counter++)
|
Conversions.intToByteArray(iv, 0, counter++)
|
||||||
cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(iv))
|
val plaintext = synchronized(CIPHER_LOCK) {
|
||||||
val plaintext = cipher.doFinal(frame, 0, frame.size - 10)
|
cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(cipherKey, "AES"), IvParameterSpec(iv))
|
||||||
|
cipher.doFinal(frame, 0, frame.size - 10)
|
||||||
|
}
|
||||||
BackupFrame.parseFrom(plaintext)
|
BackupFrame.parseFrom(plaintext)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
when (e) {
|
when (e) {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package org.thoughtcrime.securesms.crypto;
|
package org.thoughtcrime.securesms.crypto;
|
||||||
|
|
||||||
|
|
||||||
|
import static org.session.libsignal.crypto.CipherUtil.CIPHER_LOCK;
|
||||||
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.security.keystore.KeyGenParameterSpec;
|
import android.security.keystore.KeyGenParameterSpec;
|
||||||
import android.security.keystore.KeyProperties;
|
import android.security.keystore.KeyProperties;
|
||||||
@ -45,44 +47,44 @@ public final class KeyStoreHelper {
|
|||||||
private static final String ANDROID_KEY_STORE = "AndroidKeyStore";
|
private static final String ANDROID_KEY_STORE = "AndroidKeyStore";
|
||||||
private static final String KEY_ALIAS = "SignalSecret";
|
private static final String KEY_ALIAS = "SignalSecret";
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
|
||||||
public static SealedData seal(@NonNull byte[] input) {
|
public static SealedData seal(@NonNull byte[] input) {
|
||||||
SecretKey secretKey = getOrCreateKeyStoreEntry();
|
SecretKey secretKey = getOrCreateKeyStoreEntry();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
synchronized (CIPHER_LOCK) {
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
||||||
|
|
||||||
byte[] iv = cipher.getIV();
|
byte[] iv = cipher.getIV();
|
||||||
byte[] data = cipher.doFinal(input);
|
byte[] data = cipher.doFinal(input);
|
||||||
|
|
||||||
return new SealedData(iv, data);
|
return new SealedData(iv, data);
|
||||||
|
}
|
||||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
|
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
|
||||||
public static byte[] unseal(@NonNull SealedData sealedData) {
|
public static byte[] unseal(@NonNull SealedData sealedData) {
|
||||||
SecretKey secretKey = getKeyStoreEntry();
|
SecretKey secretKey = getKeyStoreEntry();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
synchronized (CIPHER_LOCK) {
|
||||||
cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, sealedData.iv));
|
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, sealedData.iv));
|
||||||
|
|
||||||
return cipher.doFinal(sealedData.data);
|
return cipher.doFinal(sealedData.data);
|
||||||
|
}
|
||||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
|
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
|
||||||
private static SecretKey getOrCreateKeyStoreEntry() {
|
private static SecretKey getOrCreateKeyStoreEntry() {
|
||||||
if (hasKeyStoreEntry()) return getKeyStoreEntry();
|
if (hasKeyStoreEntry()) return getKeyStoreEntry();
|
||||||
else return createKeyStoreEntry();
|
else return createKeyStoreEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
|
||||||
private static SecretKey createKeyStoreEntry() {
|
private static SecretKey createKeyStoreEntry() {
|
||||||
try {
|
try {
|
||||||
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
|
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
|
||||||
@ -99,7 +101,6 @@ public final class KeyStoreHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
|
||||||
private static SecretKey getKeyStoreEntry() {
|
private static SecretKey getKeyStoreEntry() {
|
||||||
KeyStore keyStore = getKeyStore();
|
KeyStore keyStore = getKeyStore();
|
||||||
|
|
||||||
@ -137,7 +138,6 @@ public final class KeyStoreHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.M)
|
|
||||||
private static boolean hasKeyStoreEntry() {
|
private static boolean hasKeyStoreEntry() {
|
||||||
try {
|
try {
|
||||||
KeyStore ks = KeyStore.getInstance(ANDROID_KEY_STORE);
|
KeyStore ks = KeyStore.getInstance(ANDROID_KEY_STORE);
|
||||||
@ -202,7 +202,5 @@ public final class KeyStoreHelper {
|
|||||||
return Base64.decode(p.getValueAsString(), Base64.NO_WRAP | Base64.NO_PADDING);
|
return Base64.decode(p.getValueAsString(), Base64.NO_WRAP | Base64.NO_PADDING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package org.thoughtcrime.securesms.logging;
|
package org.thoughtcrime.securesms.logging;
|
||||||
|
|
||||||
|
import static org.session.libsignal.crypto.CipherUtil.CIPHER_LOCK;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.session.libsession.utilities.Conversions;
|
import org.session.libsession.utilities.Conversions;
|
||||||
@ -66,15 +68,17 @@ class LogFile {
|
|||||||
|
|
||||||
byte[] plaintext = entry.getBytes();
|
byte[] plaintext = entry.getBytes();
|
||||||
try {
|
try {
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(secret, "AES"), new IvParameterSpec(ivBuffer));
|
synchronized (CIPHER_LOCK) {
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(secret, "AES"), new IvParameterSpec(ivBuffer));
|
||||||
|
|
||||||
int cipherLength = cipher.getOutputSize(plaintext.length);
|
int cipherLength = cipher.getOutputSize(plaintext.length);
|
||||||
byte[] ciphertext = ciphertextBuffer.get(cipherLength);
|
byte[] ciphertext = ciphertextBuffer.get(cipherLength);
|
||||||
cipherLength = cipher.doFinal(plaintext, 0, plaintext.length, ciphertext);
|
cipherLength = cipher.doFinal(plaintext, 0, plaintext.length, ciphertext);
|
||||||
|
|
||||||
outputStream.write(ivBuffer);
|
outputStream.write(ivBuffer);
|
||||||
outputStream.write(Conversions.intToByteArray(cipherLength));
|
outputStream.write(Conversions.intToByteArray(cipherLength));
|
||||||
outputStream.write(ciphertext, 0, cipherLength);
|
outputStream.write(ciphertext, 0, cipherLength);
|
||||||
|
}
|
||||||
|
|
||||||
outputStream.flush();
|
outputStream.flush();
|
||||||
} catch (ShortBufferException | InvalidAlgorithmParameterException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) {
|
} catch (ShortBufferException | InvalidAlgorithmParameterException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) {
|
||||||
@ -134,10 +138,11 @@ class LogFile {
|
|||||||
Util.readFully(inputStream, ciphertext, length);
|
Util.readFully(inputStream, ciphertext, length);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(secret, "AES"), new IvParameterSpec(ivBuffer));
|
synchronized (CIPHER_LOCK) {
|
||||||
byte[] plaintext = cipher.doFinal(ciphertext, 0, length);
|
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(secret, "AES"), new IvParameterSpec(ivBuffer));
|
||||||
|
byte[] plaintext = cipher.doFinal(ciphertext, 0, length);
|
||||||
return new String(plaintext);
|
return new String(plaintext);
|
||||||
|
}
|
||||||
} catch (InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
|
} catch (InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
package org.session.libsignal.streams;
|
package org.session.libsignal.streams;
|
||||||
|
|
||||||
|
import static org.session.libsignal.crypto.CipherUtil.CIPHER_LOCK;
|
||||||
|
|
||||||
import org.session.libsignal.exceptions.InvalidMacException;
|
import org.session.libsignal.exceptions.InvalidMacException;
|
||||||
import org.session.libsignal.exceptions.InvalidMessageException;
|
import org.session.libsignal.exceptions.InvalidMessageException;
|
||||||
import org.session.libsignal.utilities.Util;
|
import org.session.libsignal.utilities.Util;
|
||||||
@ -92,19 +94,15 @@ public class AttachmentCipherInputStream extends FilterInputStream {
|
|||||||
byte[] iv = new byte[BLOCK_SIZE];
|
byte[] iv = new byte[BLOCK_SIZE];
|
||||||
readFully(iv);
|
readFully(iv);
|
||||||
|
|
||||||
this.cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
synchronized (CIPHER_LOCK) {
|
||||||
this.cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(cipherKey, "AES"), new IvParameterSpec(iv));
|
this.cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||||
|
this.cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(cipherKey, "AES"), new IvParameterSpec(iv));
|
||||||
|
}
|
||||||
|
|
||||||
this.done = false;
|
this.done = false;
|
||||||
this.totalRead = 0;
|
this.totalRead = 0;
|
||||||
this.totalDataSize = totalDataSize;
|
this.totalDataSize = totalDataSize;
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException | InvalidAlgorithmParameterException e) {
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (InvalidKeyException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (NoSuchPaddingException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
} catch (InvalidAlgorithmParameterException e) {
|
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,15 +139,12 @@ public class AttachmentCipherInputStream extends FilterInputStream {
|
|||||||
|
|
||||||
private int readFinal(byte[] buffer, int offset, int length) throws IOException {
|
private int readFinal(byte[] buffer, int offset, int length) throws IOException {
|
||||||
try {
|
try {
|
||||||
int flourish = cipher.doFinal(buffer, offset);
|
synchronized (CIPHER_LOCK) {
|
||||||
|
int flourish = cipher.doFinal(buffer, offset);
|
||||||
done = true;
|
done = true;
|
||||||
return flourish;
|
return flourish;
|
||||||
} catch (IllegalBlockSizeException e) {
|
}
|
||||||
throw new IOException(e);
|
} catch (IllegalBlockSizeException | ShortBufferException | BadPaddingException e) {
|
||||||
} catch (BadPaddingException e) {
|
|
||||||
throw new IOException(e);
|
|
||||||
} catch (ShortBufferException e) {
|
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,9 +229,7 @@ public class AttachmentCipherInputStream extends FilterInputStream {
|
|||||||
throw new InvalidMacException("Digest doesn't match!");
|
throw new InvalidMacException("Digest doesn't match!");
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException | ArithmeticException e) {
|
||||||
throw new InvalidMacException(e);
|
|
||||||
} catch (ArithmeticException e) {
|
|
||||||
throw new InvalidMacException(e);
|
throw new InvalidMacException(e);
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
|
Loading…
Reference in New Issue
Block a user