mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-28 04:34:21 +01:00
Convert AttachmentCipherOutputStream to kotlin.
This commit is contained in:
committed by
Michelle Tang
parent
381c0e186f
commit
2e79e257a3
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Open Whisper Systems
|
||||
*
|
||||
* Licensed according to the LICENSE file in this repository.
|
||||
*/
|
||||
|
||||
package org.whispersystems.signalservice.api.crypto;
|
||||
|
||||
import org.whispersystems.signalservice.internal.util.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class AttachmentCipherOutputStream extends DigestingOutputStream {
|
||||
|
||||
private final Cipher cipher;
|
||||
private final Mac mac;
|
||||
|
||||
public AttachmentCipherOutputStream(byte[] combinedKeyMaterial,
|
||||
byte[] iv,
|
||||
OutputStream outputStream)
|
||||
throws IOException
|
||||
{
|
||||
super(outputStream);
|
||||
try {
|
||||
this.cipher = initializeCipher();
|
||||
this.mac = initializeMac();
|
||||
byte[][] keyParts = Util.split(combinedKeyMaterial, 32, 32);
|
||||
|
||||
if (iv == null) {
|
||||
this.cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyParts[0], "AES"));
|
||||
} else {
|
||||
this.cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyParts[0], "AES"), new IvParameterSpec(iv));
|
||||
}
|
||||
|
||||
this.mac.init(new SecretKeySpec(keyParts[1], "HmacSHA256"));
|
||||
|
||||
mac.update(cipher.getIV());
|
||||
super.write(cipher.getIV());
|
||||
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer) throws IOException {
|
||||
write(buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer, int offset, int length) throws IOException {
|
||||
byte[] ciphertext = cipher.update(buffer, offset, length);
|
||||
|
||||
if (ciphertext != null) {
|
||||
mac.update(ciphertext);
|
||||
super.write(ciphertext);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
byte[] input = new byte[1];
|
||||
input[0] = (byte) b;
|
||||
write(input, 0, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
byte[] ciphertext = cipher.doFinal();
|
||||
byte[] auth = mac.doFinal(ciphertext);
|
||||
|
||||
super.write(ciphertext);
|
||||
super.write(auth);
|
||||
|
||||
super.close();
|
||||
} catch (IllegalBlockSizeException | BadPaddingException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Mac initializeMac() {
|
||||
try {
|
||||
return Mac.getInstance("HmacSHA256");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Cipher initializeCipher() {
|
||||
try {
|
||||
return Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2017 Open Whisper Systems
|
||||
*
|
||||
* Licensed according to the LICENSE file in this repository.
|
||||
*/
|
||||
package org.whispersystems.signalservice.api.crypto
|
||||
|
||||
import org.whispersystems.signalservice.internal.util.Util
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
import javax.crypto.BadPaddingException
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.IllegalBlockSizeException
|
||||
import javax.crypto.Mac
|
||||
import javax.crypto.spec.IvParameterSpec
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
/**
|
||||
* An OutputStream for encrypting attachment data.
|
||||
* The output stream writes the IV, ciphertext, and HMAC in sequence.
|
||||
*
|
||||
* @param combinedKeyMaterial The key material used for encryption and authentication. It is expected to be a byte array
|
||||
* containing two parts: the first half being the AES key and the second half being the HMAC key.
|
||||
* @param iv The initialization vector (IV) for the cipher, or null to generate a random one.
|
||||
* @param outputStream The underlying output stream to write the encrypted data to.
|
||||
*/
|
||||
class AttachmentCipherOutputStream(
|
||||
combinedKeyMaterial: ByteArray,
|
||||
iv: ByteArray?,
|
||||
outputStream: OutputStream
|
||||
) : DigestingOutputStream(outputStream) {
|
||||
|
||||
private val cipher: Cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
|
||||
private val mac: Mac = Mac.getInstance("HmacSHA256")
|
||||
|
||||
init {
|
||||
val keyParts = Util.split(combinedKeyMaterial, 32, 32)
|
||||
|
||||
if (iv == null) {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(keyParts[0], "AES"))
|
||||
} else {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(keyParts[0], "AES"), IvParameterSpec(iv))
|
||||
}
|
||||
|
||||
mac.init(SecretKeySpec(keyParts[1], "HmacSHA256"))
|
||||
|
||||
mac.update(cipher.iv)
|
||||
super.write(cipher.iv)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun write(buffer: ByteArray) {
|
||||
write(buffer, 0, buffer.size)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun write(buffer: ByteArray, offset: Int, length: Int) {
|
||||
val ciphertext = cipher.update(buffer, offset, length)
|
||||
|
||||
if (ciphertext != null) {
|
||||
mac.update(ciphertext)
|
||||
super.write(ciphertext)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun write(b: Int) {
|
||||
val input = ByteArray(1)
|
||||
input[0] = b.toByte()
|
||||
write(input, 0, 1)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun close() {
|
||||
try {
|
||||
val ciphertext = cipher.doFinal()
|
||||
val auth = mac.doFinal(ciphertext)
|
||||
|
||||
super.write(ciphertext)
|
||||
super.write(auth)
|
||||
|
||||
super.close()
|
||||
} catch (e: IllegalBlockSizeException) {
|
||||
throw AssertionError(e)
|
||||
} catch (e: BadPaddingException) {
|
||||
throw AssertionError(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user