Skip to content

Commit

Permalink
Made FrameCryptoProvider a CryptoProvider type to allow registering o…
Browse files Browse the repository at this point in the history
…ther crypto provider types

Signed-off-by: Vikas Bansal <43470111+vikasvb90@users.noreply.github.com>
  • Loading branch information
vikasvb90 committed Aug 16, 2023
1 parent 4ea7c57 commit c54ecf3
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.common.crypto;

import org.opensearch.common.io.InputStreamContainer;

import java.io.IOException;
import java.io.InputStream;

/**
* Crypto provider abstractions for encryption and decryption of data. Allows registering multiple providers
* for defining different ways of encrypting or decrypting data.
*/
public interface CryptoProvider {

/**
* To initialise or create a new crypto metadata to be used in encryption. This is needed to set the context before
* beginning encryption.
*
* @return crypto metadata instance
*/
Object initEncryptionMetadata();

/**
* To load crypto metadata to be used in encryption from content header.
* Note that underlying information in the loaded metadata object is same as present in the object created during
* encryption but object type may differ.
*
* @return crypto metadata instance used in decryption.
*/
Object loadEncryptionMetadata(EncryptedHeaderContentSupplier encryptedHeaderContentSupplier) throws IOException;

/**
* Few encryption algorithms have certain conditions on the unit of content to be encrypted. This requires the
* content size to be re adjusted in order to fulfil these conditions for partial writes. If write requests for
* encryption of a part of content do not fulfil these conditions then encryption fails or can result in corrupted
* content depending on the algorithm used. This method exposes a means to re-adjust sizes of such writes.
*
* @param cryptoContext crypto metadata instance
* @param contentSize Size of the raw content
* @return Adjusted size of the content.
*/
long adjustContentSizeForPartialEncryption(Object cryptoContext, long contentSize);

/**
* Estimate length of the encrypted content. It should only be used to determine length of entire content after
* encryption.
*
* @param cryptoContext crypto metadata instance consisting of encryption metadata used in encryption.
* @param contentLength Size of the raw content
* @return Calculated size of the encrypted content.
*/
long estimateEncryptedLengthOfEntireContent(Object cryptoContext, long contentLength);

/**
* For given encrypted content length, estimate the length of the decrypted content.
* @param cryptoContext crypto metadata instance consisting of encryption metadata used in encryption.
* @param contentLength Size of the encrypted content
* @return Calculated size of the decrypted content.
*/
long estimateDecryptedLength(Object cryptoContext, long contentLength);

/**
* Wraps a raw InputStream with encrypting stream
*
* @param encryptionMetadata created earlier to set the crypto metadata.
* @param stream Raw InputStream to encrypt
* @return encrypting stream wrapped around raw InputStream.
*/
InputStreamContainer createEncryptingStream(Object encryptionMetadata, InputStreamContainer stream);

/**
* Provides encrypted stream for a raw stream emitted for a part of content.
*
* @param cryptoContext crypto metadata instance.
* @param stream raw stream for which encrypted stream has to be created.
* @param totalStreams Number of streams being used for the entire content.
* @param streamIdx Index of the current stream.
* @return Encrypted stream for the provided raw stream.
*/
InputStreamContainer createEncryptingStreamOfPart(Object cryptoContext, InputStreamContainer stream, int totalStreams, int streamIdx);

/**
* This method accepts an encrypted stream and provides a decrypting wrapper.
* @param encryptingStream to be decrypted.
* @return Decrypting wrapper stream
*/
InputStream createDecryptingStream(InputStream encryptingStream);

/**
* This method creates a {@link DecryptedRangedStreamProvider} which provides a wrapped stream to decrypt the
* underlying stream. This also provides adjusted range against the actual range which should be used for fetching
* and supplying the encrypted content for decryption. Extra content outside the range is trimmed down and returned
* by the decrypted stream.
* For partial reads of encrypted content, few algorithms require the range of content to be adjusted for
* successful decryption. Adjusted range may or may not be same as the provided range. If range is adjusted then
* starting offset of resultant range can be lesser than the starting offset of provided range and end
* offset can be greater than the ending offset of the provided range.
*
* @param cryptoContext crypto metadata instance.
* @param startPosOfRawContent starting position in the raw/decrypted content
* @param endPosOfRawContent ending position in the raw/decrypted content
*/
DecryptedRangedStreamProvider createDecryptingStreamOfRange(Object cryptoContext, long startPosOfRawContent, long endPosOfRawContent);
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ public DecryptedRangedStreamProvider(long[] adjustedRange, Function<InputStream,
this.decryptedStreamProvider = decryptedStreamProvider;
}


/**
* Adjusted range of partial encrypted content which needs to be used for decryption.
* @return adjusted range
Expand All @@ -38,7 +37,6 @@ public long[] getAdjustedRange() {
return adjustedRange;
}


/**
* A utility stream provider which supplies the stream responsible for decrypting the content and reading the
* desired range of decrypted content by skipping extra content which got decrypted as a result of range adjustment.
Expand All @@ -48,5 +46,4 @@ public Function<InputStream, InputStream> getDecryptedStreamProvider() {
return decryptedStreamProvider;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
package org.opensearch.encryption.frame;

import com.amazonaws.encryptionsdk.ParsedCiphertext;
import org.opensearch.common.crypto.CryptoProvider;
import org.opensearch.common.crypto.DecryptedRangedStreamProvider;
import org.opensearch.common.crypto.EncryptedHeaderContentSupplier;
import org.opensearch.encryption.frame.core.AwsCrypto;
Expand All @@ -19,7 +20,7 @@
import java.io.InputStream;
import java.util.Map;

public class FrameCryptoProvider {
public class FrameCryptoProvider implements CryptoProvider {
private final AwsCrypto awsCrypto;
private final Map<String, String> encryptionContext;

Expand Down Expand Up @@ -56,7 +57,7 @@ public Object initEncryptionMetadata() {
* @param streamSize Size of the stream to be adjusted.
* @return Adjusted size of the stream.
*/
public long adjustEncryptedStreamSize(Object cryptoContextObj, long streamSize) {
public long adjustContentSizeForPartialEncryption(Object cryptoContextObj, long streamSize) {
EncryptionMetadata encryptionMetadata = validateEncryptionMetadata(cryptoContextObj);
return (streamSize - (streamSize % encryptionMetadata.getFrameSize())) + encryptionMetadata.getFrameSize();
}
Expand All @@ -68,7 +69,7 @@ public long adjustEncryptedStreamSize(Object cryptoContextObj, long streamSize)
* @param contentLength Size of the raw content
* @return Calculated size of the encrypted stream for the provided raw stream.
*/
public long estimateEncryptedLength(Object cryptoMetadataObj, long contentLength) {
public long estimateEncryptedLengthOfEntireContent(Object cryptoMetadataObj, long contentLength) {
EncryptionMetadata encryptionMetadata = validateEncryptionMetadata(cryptoMetadataObj);
return encryptionMetadata.getCiphertextHeaderBytes().length + awsCrypto.estimateOutputSizeWithFooter(
encryptionMetadata.getFrameSize(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ private EncryptedStore verifyAndGetEncryptedContent(boolean truncateRemainderPar
}
}

long calculatedEncryptedLength = frameCryptoProvider.estimateEncryptedLength(cryptoContext, length);
long calculatedEncryptedLength = frameCryptoProvider.estimateEncryptedLengthOfEntireContent(cryptoContext, length);
assertEquals(encLength, calculatedEncryptedLength);

EncryptedStore encryptedStore = new EncryptedStore();
Expand All @@ -147,7 +147,7 @@ public void testEncryptedDecryptedLengthEstimations() {
randomIntBetween(10, 10240)
);
EncryptionMetadata cryptoContext = (EncryptionMetadata) frameCryptoProvider.initEncryptionMetadata();
long encryptedLength = frameCryptoProvider.estimateEncryptedLength(cryptoContext, n);
long encryptedLength = frameCryptoProvider.estimateEncryptedLengthOfEntireContent(cryptoContext, n);
ParsedCiphertext parsedCiphertext = new ParsedCiphertext(cryptoContext.getCiphertextHeaderBytes());
long decryptedLength = frameCryptoProvider.estimateDecryptedLength(parsedCiphertext, encryptedLength);
assertEquals(n, decryptedLength);
Expand Down

0 comments on commit c54ecf3

Please sign in to comment.