All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.metaeffekt.artifact.analysis.flow.ng.crypt.EncryptedEntryOutputStream Maven / Gradle / Ivy

/*
 * Copyright 2021-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.metaeffekt.artifact.analysis.flow.ng.crypt;

import com.metaeffekt.artifact.analysis.flow.ng.ContentAlgorithmParam;
import org.apache.commons.io.output.CloseShieldOutputStream;

import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.security.*;
import java.util.Objects;
import java.util.zip.ZipOutputStream;

/**
 * Used for creating new entries in a ZipOutputStream and encrypt them.
* See its counterpart {@link DecryptedEntryInputStream}. */ public class EncryptedEntryOutputStream extends FilterOutputStream implements AutoCloseable { private boolean closed = false; /** * Stored only so we can run closeEntry at the end */ private final ZipOutputStream underlyingZipStream; private EncryptedEntryOutputStream(ZipOutputStream underlyingZipStream, Cipher cipher) { // wrap the underlying stream to encrypt this entry super(new CipherOutputStream(CloseShieldOutputStream.wrap(underlyingZipStream), cipher)); this.underlyingZipStream = underlyingZipStream; } private static byte[] getIv() { // 16-byte iv (and may rely on this length) byte[] rawContentEncryptionIv = new byte[16]; SecureRandom secureRandom = new SecureRandom(); // generate a new IV each time we write secureRandom.nextBytes(rawContentEncryptionIv); return rawContentEncryptionIv; } /** * Creates a Cipher object for use in encryption.
* Generates a new IV each time it's called. * * @param algoParam specified algorithms for use in content encryption * @param contentEncryptionKey the symmetric key for encryption of content * @return returns the cipher for use in encryption of one data stream * @throws NoSuchAlgorithmException throws exception in the event of failure * @throws InvalidKeyException throws exception in the event of failure * @throws NoSuchProviderException throws exception in the event of failure * @throws NoSuchPaddingException throws exception in the event of failure * @throws InvalidAlgorithmParameterException throws exception in the event of failure */ private static Cipher createEncryptionCipher(ContentAlgorithmParam algoParam, ContentEncryptionKey contentEncryptionKey) throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, InvalidKeyException { Objects.requireNonNull(algoParam); Objects.requireNonNull(contentEncryptionKey); final Key key = new SecretKeySpec(contentEncryptionKey.getRaw(), algoParam.getAlgorithm() + algoParam.getMode() ); Cipher cipher = Cipher.getInstance(algoParam.getAlgorithm() + algoParam.getMode(), algoParam.getProvider()); byte[] iv = getIv(); cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv)); return cipher; } /** * Creates a new entry with encryption. Uses the provided arguments and generates a new random IV. * * @param zipOutputStream where the new entry will be written * @param contentEncryptionKey the content key to use * @param algorithmParam parametrization for what encryption algorithm to use. should be set to default * @return returns a new object, directly usable as a sink for data that will be written to the file * @throws InvalidAlgorithmParameterException throws on error * @throws NoSuchPaddingException throws on error * @throws NoSuchAlgorithmException throws on error * @throws NoSuchProviderException throws on error * @throws InvalidKeyException throws on error * @throws IOException throws on error */ public static EncryptedEntryOutputStream createEncryptionOutputStream(ZipOutputStream zipOutputStream, ContentAlgorithmParam algorithmParam, ContentEncryptionKey contentEncryptionKey) throws InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, IOException { Cipher cipher = createEncryptionCipher(algorithmParam, contentEncryptionKey); // the nonce needs separate transmission but NOT in AAD thanks to EAX's guarantees zipOutputStream.write(cipher.getIV()); zipOutputStream.flush(); return new EncryptedEntryOutputStream(zipOutputStream, cipher); } /** * Closes the current entry in the underlying ZipOutputStream but DOES NOT close the stream. * @throws IOException throws on failure to close the encapsulated cipher stream */ @Override public void close() throws IOException { // make it possible to use these in try-with-resources to avoid unclosed entries if (!this.closed) { this.closed = true; // closes the cipher stream super.close(); // closing this helper object should just close the zip entry, not the zip file try { underlyingZipStream.closeEntry(); } catch (IOException e) { // closing an entry should not fail throw new RuntimeException(e); } } } public boolean isClosed() { return closed; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy