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

com.microsoft.azure.storage.blob.BlobDecryptStream Maven / Gradle / Ivy

There is a newer version: 8.6.6
Show newest version
/**
 * Copyright Microsoft Corporation
 * 
 * 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.microsoft.azure.storage.blob;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;

import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.core.Utility;

/**
 * Stream that will be used for decrypting blob ranges. It buffers 16 bytes of IV (if required) before creating a crypto
 * stream and routing the rest of the data through it.
 */
class BlobDecryptStream extends BlobOutputStream {
    private final OutputStream userStream;
    private final Map metadata;
    private long position;
    private Long userProvidedLength;
    private byte[] iv = new byte[16];
    private BlobEncryptionPolicy encryptionPolicy;
    private int discardFirst;
    private OutputStream cryptoStream;
    private boolean bufferIV;
    private boolean noPadding;
    private Boolean requireEncryption;
    
    public BlobDecryptStream(OutputStream userStream, Map metadata, Long userProvidedLength, 
            int discardFirst, boolean bufferIV, boolean noPadding, BlobEncryptionPolicy policy, 
            final Boolean requireEncryption)
    {
        this.userStream = userStream;
        this.metadata = metadata;
        this.userProvidedLength = userProvidedLength;
        this.discardFirst = discardFirst;
        this.encryptionPolicy = policy;
        this.bufferIV = bufferIV;
        this.noPadding = noPadding;
        this.requireEncryption = requireEncryption;
    }
    
    @Override
    public void close() throws IOException
    {
        this.cryptoStream.close();
    }

    @Override
    void abort() throws IOException {
        // no-op. This method is used in the case of aborting uploads, and decrypt streams are on downloads.
    }

    @Override
    public void write(byte[] data, int offset, int length) throws IOException {
        // Keep buffering until we have 16 bytes of IV.
        if (this.bufferIV && this.position < 16)
        {
            int bytesToCopy = 16 - (int)this.position;
            bytesToCopy = length > bytesToCopy ? bytesToCopy : length;
            System.arraycopy(data, offset, this.iv, (int)this.position, bytesToCopy);
            this.position += bytesToCopy;
            offset += bytesToCopy;
            length -= bytesToCopy;
        }

        // Wrap user stream with LengthLimitingStream. This stream will be used to discard the extra bytes we downloaded in order to deal with AES block size.
        // Create crypto stream around the length limiting stream once per download and start writing to it. During retries, the state is maintained and 
        // new crypto streams will not be created each time. 
        if (this.cryptoStream == null)
        {
            LengthLimitingStream lengthLimitingStream = new LengthLimitingStream(this.userStream, this.discardFirst, 
                    this.userProvidedLength);
            try {
                this.cryptoStream = this.encryptionPolicy.decryptBlob(lengthLimitingStream, this.metadata,
                        this.requireEncryption, !this.bufferIV ? null : this.iv, this.noPadding);
            }
            catch (StorageException e) {
                throw Utility.initIOException(e);
            }
        }

        // Route the remaining data through the crypto stream.
        if (length > 0)
        {
            this.cryptoStream.write(data, offset, length);
            this.position += length;
        }
    }

    @Override
    public void write(InputStream sourceStream, long writeLength) throws IOException, StorageException {
        Utility.writeToOutputStream(sourceStream, this, writeLength, false, false, null, null);
    }

    @Override
    public void flush() throws IOException {
        this.userStream.flush();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy