...and the rest

This commit is contained in:
andrew 2023-05-05 12:32:54 +09:30
parent d3ce899a80
commit a9078c8d08
4 changed files with 68 additions and 63 deletions

View File

@ -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) {

View File

@ -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);
} }
} }
} }
} }

View File

@ -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);
} }

View File

@ -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);