Signal-Android/app/src/main/java/org/thoughtcrime/securesms/crypto/ModernEncryptingPartOutputS...

61 lines
2.0 KiB
Java
Raw Normal View History

package org.thoughtcrime.securesms.crypto;
2019-06-05 21:47:14 +02:00
import androidx.annotation.NonNull;
2018-02-01 22:30:33 +01:00
import android.util.Pair;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
2018-02-01 22:30:33 +01:00
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* Constructs an OutputStream that encrypts data written to it with the AttachmentSecret provided.
*
* The on-disk format is very simple, and intentionally no longer includes authentication.
*/
public class ModernEncryptingPartOutputStream {
2018-02-01 22:30:33 +01:00
public static Pair<byte[], OutputStream> createFor(@NonNull AttachmentSecret attachmentSecret, @NonNull File file, boolean inline)
throws IOException
{
2018-02-01 22:30:33 +01:00
byte[] random = new byte[32];
new SecureRandom().nextBytes(random);
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(attachmentSecret.getModernKey(), "HmacSHA256"));
FileOutputStream fileOutputStream = new FileOutputStream(file);
byte[] iv = new byte[16];
byte[] key = mac.doFinal(random);
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
2018-02-01 22:30:33 +01:00
if (inline) {
fileOutputStream.write(random);
}
return new Pair<>(random, new CipherOutputStream(fileOutputStream, cipher));
} catch (NoSuchAlgorithmException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException e) {
throw new AssertionError(e);
}
}
2020-03-26 20:38:27 +01:00
public static long getPlaintextLength(long cipherTextLength) {
return cipherTextLength - 32;
}
}