/// <summary> /// Update the request's ObjectMetadata with the necessary information for decrypting the object. /// </summary> /// <param name="request"> /// AmazonWebServiceRequest encrypted using the given instruction /// </param> /// <param name="instructions"> /// Non-null instruction used to encrypt the data in this AmazonWebServiceRequest . /// </param> /// <param name="encryptionClient">Encryption client used for put objects</param> internal static void UpdateMetadataWithEncryptionInstructionsV2(AmazonWebServiceRequest request, EncryptionInstructions instructions, AmazonS3EncryptionClientBase encryptionClient) { var keyBytesToStoreInMetadata = instructions.EncryptedEnvelopeKey; var base64EncodedEnvelopeKey = Convert.ToBase64String(keyBytesToStoreInMetadata); var ivToStoreInMetadata = instructions.InitializationVector; var base64EncodedIv = Convert.ToBase64String(ivToStoreInMetadata); MetadataCollection metadata = null; var putObjectRequest = request as PutObjectRequest; if (putObjectRequest != null) { metadata = putObjectRequest.Metadata; } var initiateMultipartrequest = request as InitiateMultipartUploadRequest; if (initiateMultipartrequest != null) { metadata = initiateMultipartrequest.Metadata; } if (metadata != null) { metadata.Add(XAmzWrapAlg, instructions.WrapAlgorithm); metadata.Add(XAmzTagLen, DefaultTagBitsLength.ToString()); metadata.Add(XAmzKeyV2, base64EncodedEnvelopeKey); metadata.Add(XAmzCekAlg, instructions.CekAlgorithm); metadata.Add(XAmzIV, base64EncodedIv); metadata.Add(XAmzMatDesc, JsonMapper.ToJson(instructions.MaterialsDescription)); } }
/// <summary> /// Generates an instruction that will be used to encrypt an object /// using materials with the KMSKeyID set. /// </summary> /// <param name="kmsClient"> /// Used to call KMS to generate a data key. /// </param> /// <param name="materials"> /// The encryption materials to be used to encrypt and decrypt data. /// </param> /// <returns> /// The instruction that will be used to encrypt an object. /// </returns> internal static async System.Threading.Tasks.Task <EncryptionInstructions> GenerateInstructionsForKMSMaterialsV2Async(IAmazonKeyManagementService kmsClient, EncryptionMaterialsV2 materials) { if (materials.KMSKeyID == null) { throw new ArgumentNullException(nameof(materials.KMSKeyID), KmsKeyIdNullMessage); } switch (materials.KmsType) { case KmsType.KmsContext: { var nonce = new byte[DefaultNonceSize]; // Generate nonce, and get both the key and the encrypted key from KMS. RandomNumberGenerator.Create().GetBytes(nonce); var result = await kmsClient.GenerateDataKeyAsync(materials.KMSKeyID, materials.MaterialsDescription, KMSKeySpec).ConfigureAwait(false); var instructions = new EncryptionInstructions(materials.MaterialsDescription, result.KeyPlaintext, result.KeyCiphertext, nonce, XAmzWrapAlgKmsContextValue, XAmzAesGcmCekAlgValue); return(instructions); } default: throw new NotSupportedException($"{materials.KmsType} is not supported for KMS Key Id {materials.KMSKeyID}"); } }
/// <summary> /// Build encryption instructions for UploadPartEncryptionContext /// </summary> /// <param name="context">UploadPartEncryptionContext which contains instructions used for encrypting multipart object</param> /// <param name="encryptionMaterials">EncryptionMaterials which contains material used for encrypting multipart object</param> /// <returns></returns> internal static EncryptionInstructions BuildEncryptionInstructionsForInstructionFileV2(UploadPartEncryptionContext context, EncryptionMaterialsBase encryptionMaterials) { var instructions = new EncryptionInstructions(encryptionMaterials.MaterialsDescription, context.EnvelopeKey, context.EncryptedEnvelopeKey, context.FirstIV, context.WrapAlgorithm, context.CekAlgorithm); return(instructions); }
//wrap encrypted stream into AESDecriptionStream wrapper internal static Stream DecryptStream(Stream encryptedStream, EncryptionInstructions encryptionInstructions) { AESDecryptionStream aesDecryptStream; aesDecryptStream = new AESDecryptionStream(encryptedStream, encryptionInstructions.EnvelopeKey, encryptionInstructions.InitializationVector); return(aesDecryptStream); }
/// <summary> /// Returns encryption instructions to encrypt content with AES/GCM/NoPadding algorithm /// Creates encryption key used for AES/GCM/NoPadding and encrypt it with AES/GCM /// Encrypted key follows nonce(12 bytes) + key cipher text(16 or 32 bytes) + tag(16 bytes) format /// Tag is appended by the AES/GCM cipher with encryption process /// </summary> /// <param name="materials"></param> /// <returns></returns> private static EncryptionInstructions EncryptEnvelopeKeyUsingSymmetricKeyV2(EncryptionMaterialsV2 materials) { var aes = materials.SymmetricProvider as Aes; if (aes == null) { throw new NotSupportedException("AES is the only supported algorithm with this method."); } switch (materials.SymmetricProviderType) { case SymmetricAlgorithmType.AesGcm: { var aesObject = Aes.Create(); var nonce = aesObject.IV.Take(DefaultNonceSize).ToArray(); var associatedText = Encoding.UTF8.GetBytes(XAmzAesGcmCekAlgValue); var cipher = AesGcmUtils.CreateCipher(true, materials.SymmetricProvider.Key, DefaultTagBitsLength, nonce, associatedText); var envelopeKey = cipher.DoFinal(aesObject.Key); var encryptedEnvelopeKey = nonce.Concat(envelopeKey).ToArray(); var instructions = new EncryptionInstructions(materials.MaterialsDescription, aesObject.Key, encryptedEnvelopeKey, nonce, XAmzWrapAlgAesGcmValue, XAmzAesGcmCekAlgValue); return(instructions); } default: { throw new NotSupportedException($"{materials.SymmetricProviderType} isn't supported with SymmetricProvider"); } } }
private static EncryptionInstructions EncryptEnvelopeKeyUsingAsymmetricKeyPairV2(EncryptionMaterialsV2 materials) { var rsa = materials.AsymmetricProvider as RSA; if (rsa == null) { throw new NotSupportedException("RSA is the only supported algorithm with this method."); } switch (materials.AsymmetricProviderType) { case AsymmetricAlgorithmType.RsaOaepSha1: { var aesObject = Aes.Create(); var nonce = aesObject.IV.Take(DefaultNonceSize).ToArray(); var envelopeKeyToEncrypt = EnvelopeKeyForDataKey(aesObject.Key); var cipher = RsaUtils.CreateRsaOaepSha1Cipher(true, rsa); var encryptedEnvelopeKey = cipher.DoFinal(envelopeKeyToEncrypt); var instructions = new EncryptionInstructions(materials.MaterialsDescription, aesObject.Key, encryptedEnvelopeKey, nonce, XAmzWrapAlgRsaOaepSha1, XAmzAesGcmCekAlgValue); return(instructions); } default: { throw new NotSupportedException($"{materials.AsymmetricProviderType} isn't supported with AsymmetricProvider"); } } }
/// <summary> /// Returns an updated stream where the stream contains the encrypted object contents. /// The specified instruction will be used to encrypt data. /// </summary> /// <param name="toBeEncrypted"> /// The stream whose contents are to be encrypted. /// </param> /// <param name="instructions"> /// The instruction that will be used to encrypt the object data. /// </param> /// <returns> /// Encrypted stream, i.e input stream wrapped into encrypted stream /// </returns> internal static Stream EncryptRequestUsingInstruction(Stream toBeEncrypted, EncryptionInstructions instructions) { //wrap input stream into AESEncryptionPutObjectStream wrapper AESEncryptionPutObjectStream aesEStream; aesEStream = new AESEncryptionPutObjectStream(toBeEncrypted, instructions.EnvelopeKey, instructions.InitializationVector); return(aesEStream); }
/// <summary> /// Builds an instruction object from the instruction file. /// </summary> /// <param name="response"> Instruction file GetObject response</param> /// <param name="materials"> /// The non-null encryption materials to be used to encrypt and decrypt Envelope key. /// </param> /// <returns> /// A non-null instruction object containing encryption information. /// </returns> internal static EncryptionInstructions BuildInstructionsUsingInstructionFileV2(GetObjectResponse response, EncryptionMaterialsBase materials) { using (TextReader textReader = new StreamReader(response.ResponseStream)) { var jsonData = JsonMapper.ToObject(textReader); if (jsonData[XAmzKeyV2] != null) { // The envelope contains data in V2 format var encryptedEnvelopeKey = Base64DecodedDataValue(jsonData, XAmzKeyV2); var decryptedEnvelopeKey = DecryptNonKmsEnvelopeKeyV2(encryptedEnvelopeKey, materials); var initializationVector = Base64DecodedDataValue(jsonData, XAmzIV); var materialDescription = JsonMapper.ToObject <Dictionary <string, string> >((string)jsonData[XAmzMatDesc]); var cekAlgorithm = StringValue(jsonData, XAmzCekAlg); var wrapAlgorithm = StringValue(jsonData, XAmzWrapAlg); var instructions = new EncryptionInstructions(materialDescription, decryptedEnvelopeKey, null, initializationVector, wrapAlgorithm, cekAlgorithm); return(instructions); } else if (jsonData[XAmzKey] != null) { // The envelope contains data in V1 format var encryptedEnvelopeKey = Base64DecodedDataValue(jsonData, XAmzKey); var decryptedEnvelopeKey = DecryptNonKMSEnvelopeKey(encryptedEnvelopeKey, materials); var initializationVector = Base64DecodedDataValue(jsonData, XAmzIV); var materialDescription = JsonMapper.ToObject <Dictionary <string, string> >((string)jsonData[XAmzMatDesc]); var instructions = new EncryptionInstructions(materialDescription, decryptedEnvelopeKey, null, initializationVector); return(instructions); } else if (jsonData[EncryptedEnvelopeKey] != null) { // The envelope contains data in older format var encryptedEnvelopeKey = Base64DecodedDataValue(jsonData, EncryptedEnvelopeKey); var decryptedEnvelopeKey = DecryptNonKMSEnvelopeKey(encryptedEnvelopeKey, materials); var initializationVector = Base64DecodedDataValue(jsonData, IV); return(new EncryptionInstructions(materials.MaterialsDescription, decryptedEnvelopeKey, initializationVector)); } else { throw new ArgumentException("Missing parameters required for decryption"); } } }
/// <summary> /// Update the request's ObjectMetadata with the necessary information for decrypting the object. /// </summary> /// <param name="request"> /// AmazonWebServiceRequest encrypted using the given instruction /// </param> /// <param name="instructions"> /// Non-null instruction used to encrypt the data in this AmazonWebServiceRequest. /// </param> /// <param name="useV2Metadata"> /// If true use V2 metadata format, otherwise use V1. /// </param> internal static void UpdateMetadataWithEncryptionInstructions(AmazonWebServiceRequest request, EncryptionInstructions instructions, bool useV2Metadata) { byte[] keyBytesToStoreInMetadata = instructions.EncryptedEnvelopeKey; string base64EncodedEnvelopeKey = Convert.ToBase64String(keyBytesToStoreInMetadata); byte[] IVToStoreInMetadata = instructions.InitializationVector; string base64EncodedIV = Convert.ToBase64String(IVToStoreInMetadata); MetadataCollection metadata = null; var putObjectRequest = request as PutObjectRequest; if (putObjectRequest != null) { metadata = putObjectRequest.Metadata; } var initiateMultipartrequest = request as InitiateMultipartUploadRequest; if (initiateMultipartrequest != null) { metadata = initiateMultipartrequest.Metadata; } if (metadata != null) { if (useV2Metadata) { metadata.Add(XAmzKeyV2, base64EncodedEnvelopeKey); metadata.Add(XAmzWrapAlg, instructions.WrapAlgorithm); metadata.Add(XAmzCekAlg, instructions.CekAlgorithm); } else { metadata.Add(XAmzKey, base64EncodedEnvelopeKey); } metadata.Add(XAmzIV, base64EncodedIV); metadata.Add(XAmzMatDesc, JsonMapper.ToJson(instructions.MaterialsDescription)); } }
/// <summary> /// Build encryption instructions for UploadPartEncryptionContext /// </summary> /// <param name="context">UploadPartEncryptionContext which contains instructions used for encrypting multipart object</param> /// <param name="encryptionMaterials">EncryptionMaterials which contains material used for encrypting multipart object</param> /// <returns></returns> internal static EncryptionInstructions BuildEncryptionInstructionsForInstructionFile(UploadPartEncryptionContext context, EncryptionMaterials encryptionMaterials) { var instructions = new EncryptionInstructions(encryptionMaterials.MaterialsDescription, context.EnvelopeKey, context.EncryptedEnvelopeKey, context.FirstIV); return(instructions); }
/// <summary> /// Updates object where the object /// input stream contains the decrypted contents. /// </summary> /// <param name="response"> /// The getObject response whose contents are to be decrypted. /// </param> /// <param name="instructions"> /// The instruction that will be used to encrypt the object data. /// </param> internal static void DecryptObjectUsingInstructionsV2(GetObjectResponse response, EncryptionInstructions instructions) { response.ResponseStream = new AesGcmDecryptStream(response.ResponseStream, instructions.EnvelopeKey, instructions.InitializationVector, DefaultTagBitsLength); }
/// <summary> /// Returns an updated input stream where the input stream contains the encrypted object contents. /// The specified instruction will be used to encrypt data. /// </summary> /// <param name="toBeEncrypted"> /// The stream whose contents are to be encrypted. /// </param> /// <param name="instructions"> /// The instruction that will be used to encrypt the object data. /// </param> /// <returns> /// Encrypted stream, i.e input stream wrapped into encrypted stream /// </returns> internal static Stream EncryptUploadPartRequestUsingInstructionsV2(Stream toBeEncrypted, EncryptionInstructions instructions) { //wrap input stream into AesGcmEncryptCachingStream wrapper Stream aesGcmEncryptStream = new AesGcmEncryptCachingStream(toBeEncrypted, instructions.EnvelopeKey, instructions.InitializationVector, DefaultTagBitsLength); return(aesGcmEncryptStream); }
internal static PutObjectRequest CreateInstructionFileRequestV2(AmazonWebServiceRequest request, EncryptionInstructions instructions) { var keyBytesToStoreInInstructionFile = instructions.EncryptedEnvelopeKey; var base64EncodedEnvelopeKey = Convert.ToBase64String(keyBytesToStoreInInstructionFile); var ivToStoreInInstructionFile = instructions.InitializationVector; var base64EncodedIv = Convert.ToBase64String(ivToStoreInInstructionFile); var jsonData = new JsonData { [XAmzTagLen] = DefaultTagBitsLength.ToString(), [XAmzKeyV2] = base64EncodedEnvelopeKey, [XAmzCekAlg] = instructions.CekAlgorithm, [XAmzWrapAlg] = instructions.WrapAlgorithm, [XAmzIV] = base64EncodedIv, [XAmzMatDesc] = JsonMapper.ToJson(instructions.MaterialsDescription) }; var contentBody = jsonData.ToJson(); var putObjectRequest = request as PutObjectRequest; if (putObjectRequest != null) { return(GetInstructionFileRequest(putObjectRequest.BucketName, putObjectRequest.Key, EncryptionInstructionFileV2Suffix, contentBody)); } var completeMultiPartRequest = request as CompleteMultipartUploadRequest; if (completeMultiPartRequest != null) { return(GetInstructionFileRequest(completeMultiPartRequest.BucketName, completeMultiPartRequest.Key, EncryptionInstructionFileV2Suffix, contentBody)); } return(null); }
internal static PutObjectRequest CreateInstructionFileRequest(AmazonWebServiceRequest request, EncryptionInstructions instructions) { byte[] keyBytesToStoreInInstructionFile = instructions.EncryptedEnvelopeKey; string base64EncodedEnvelopeKey = Convert.ToBase64String(keyBytesToStoreInInstructionFile); byte[] IVToStoreInInstructionFile = instructions.InitializationVector; string base64EncodedIV = Convert.ToBase64String(IVToStoreInInstructionFile); JsonData jsonData = new JsonData(); jsonData["EncryptedEnvelopeKey"] = base64EncodedEnvelopeKey; jsonData["IV"] = base64EncodedIV; var contentBody = jsonData.ToJson(); var putObjectRequest = request as PutObjectRequest; if (putObjectRequest != null) { return(GetInstructionFileRequest(putObjectRequest.BucketName, putObjectRequest.Key, EncryptionInstructionFileSuffix, contentBody)); } var completeMultiPartRequest = request as CompleteMultipartUploadRequest; if (completeMultiPartRequest != null) { return(GetInstructionFileRequest(completeMultiPartRequest.BucketName, completeMultiPartRequest.Key, EncryptionInstructionFileSuffix, contentBody)); } return(null); }
/// <summary> /// Returns an updated stream where the stream contains the encrypted object contents. /// The specified instruction will be used to encrypt data. /// </summary> /// <param name="toBeEncrypted"> /// The stream whose contents are to be encrypted. /// </param> /// <param name="instructions"> /// The instruction that will be used to encrypt the object data. /// </param> /// <returns> /// Encrypted stream, i.e input stream wrapped into encrypted stream /// </returns> internal static Stream EncryptRequestUsingInstructionV2(Stream toBeEncrypted, EncryptionInstructions instructions) { Stream gcmEncryptStream = new AesGcmEncryptStream(toBeEncrypted, instructions.EnvelopeKey, instructions.InitializationVector, DefaultTagBitsLength); return(gcmEncryptStream); }
/// <summary> /// Updates object where the object /// input stream contains the decrypted contents. /// </summary> /// <param name="response"> /// The getObject response whose contents are to be decrypted. /// </param> /// <param name="instructions"> /// The instruction that will be used to encrypt the object data. /// </param> internal static void DecryptObjectUsingInstructions(GetObjectResponse response, EncryptionInstructions instructions) { response.ResponseStream = DecryptStream(response.ResponseStream, instructions); }
/// <summary> /// Returns an updated stream where the stream contains the encrypted object contents. /// The specified instruction will be used to encrypt data. /// </summary> /// <param name="toBeEncrypted"> /// The stream whose contents are to be encrypted. /// </param> /// <param name="instructions"> /// The instruction that will be used to encrypt the object data. /// </param> /// <param name="shouldUseCachingStream"> /// Flag indicating if the caching stream should be used or not. /// </param> /// <returns> /// Encrypted stream, i.e input stream wrapped into encrypted stream /// </returns> internal static Stream EncryptRequestUsingInstructionV2(Stream toBeEncrypted, EncryptionInstructions instructions, bool shouldUseCachingStream) { Stream gcmEncryptStream = (shouldUseCachingStream ? new AesGcmEncryptCachingStream(toBeEncrypted, instructions.EnvelopeKey, instructions.InitializationVector, DefaultTagBitsLength) : new AesGcmEncryptStream(toBeEncrypted, instructions.EnvelopeKey, instructions.InitializationVector, DefaultTagBitsLength) ); return(gcmEncryptStream); }