internal async Task <InMemoryRawDek> FetchUnwrappedAsync( DataEncryptionKeyProperties dekProperties, CosmosDiagnosticsContext diagnosticsContext, CancellationToken cancellationToken) { try { if (string.Equals(dekProperties.EncryptionAlgorithm, CosmosEncryptionAlgorithm.MdeAeadAes256CbcHmac256Randomized)) { DataEncryptionKey dek = this.InitMdeEncryptionAlgorithm(dekProperties); // TTL is not used since DEK is not cached. return(new InMemoryRawDek(dek, TimeSpan.FromMilliseconds(0))); } return(await this.DekProvider.DekCache.GetOrAddRawDekAsync( dekProperties, this.UnwrapAsync, diagnosticsContext, cancellationToken)); } catch (Exception exception) { throw EncryptionExceptionFactory.EncryptionKeyNotFoundException( $"Failed to unwrap Data Encryption Key with id: '{dekProperties.Id}'.", exception); } }
internal async Task <DataEncryptionKey> FetchUnWrappedLegacySupportedMdeDekAsync( DataEncryptionKeyProperties dekProperties, string encryptionAlgorithm, CosmosDiagnosticsContext diagnosticsContext, CancellationToken cancellationToken) { EncryptionKeyUnwrapResult unwrapResult; if (this.DekProvider.EncryptionKeyStoreProvider == null) { throw new InvalidOperationException($"For use of '{CosmosEncryptionAlgorithm.MdeAeadAes256CbcHmac256Randomized}' algorithm based DEK, " + "Encryptor or CosmosDataEncryptionKeyProvider needs to be initialized with EncryptionKeyStoreProvider."); } try { using (diagnosticsContext.CreateScope("UnwrapDataEncryptionKey")) { unwrapResult = await this.UnWrapDekMdeEncAlgoAsync( dekProperties, diagnosticsContext, cancellationToken); } return(DataEncryptionKey.Create( unwrapResult.DataEncryptionKey, encryptionAlgorithm)); } catch (Exception exception) { throw EncryptionExceptionFactory.EncryptionKeyNotFoundException( $"Failed to unwrap Data Encryption Key with id: '{dekProperties.Id}'.", exception); } }
/// <summary> /// Decryption steps /// 1. Validate version byte /// 2. (optional) Validate Authentication tag /// 3. Decrypt the message /// </summary> protected byte[] DecryptData(byte[] cipherText, bool hasAuthenticationTag) { Debug.Assert(cipherText != null); byte[] iv = new byte[BlockSizeInBytes]; int minimumCipherTextLength = hasAuthenticationTag ? MinimumCipherTextLengthInBytesWithAuthenticationTag : MinimumCipherTextLengthInBytesNoAuthenticationTag; if (cipherText.Length < minimumCipherTextLength) { throw EncryptionExceptionFactory.InvalidCipherTextSize(cipherText.Length, minimumCipherTextLength); } // Validate the version byte int startIndex = 0; if (cipherText[startIndex] != this.algorithmVersion) { // Cipher text was computed with a different algorithm version than this. throw EncryptionExceptionFactory.InvalidAlgorithmVersion(cipherText[startIndex], this.algorithmVersion); } startIndex += 1; int authenticationTagOffset = 0; // Read authentication tag if (hasAuthenticationTag) { authenticationTagOffset = startIndex; startIndex += KeySizeInBytes; // authentication tag size is KeySizeInBytes } // Read cell IV Buffer.BlockCopy(cipherText, startIndex, iv, 0, iv.Length); startIndex += iv.Length; // Read encrypted text int cipherTextOffset = startIndex; int cipherTextCount = cipherText.Length - startIndex; if (hasAuthenticationTag) { // Compute authentication tag byte[] authenticationTag = this.PrepareAuthenticationTag(iv, cipherText, cipherTextOffset, cipherTextCount); if (!SecurityUtility.CompareBytes(authenticationTag, cipherText, authenticationTagOffset, authenticationTag.Length)) { // Potentially tampered data, throw an exception throw EncryptionExceptionFactory.InvalidAuthenticationTag(); } } // Decrypt the text and return return(this.DecryptData(iv, cipherText, cipherTextOffset, cipherTextCount)); }
/// <summary> /// Derives all the required keys from the given root key /// </summary> internal AeadAes256CbcHmac256EncryptionKey(byte[] rootKey, string algorithmName) : base(rootKey) { this.algorithmName = algorithmName; int keySizeInBytes = KeySize / 8; // Key validation if (rootKey.Length != keySizeInBytes) { throw EncryptionExceptionFactory.InvalidKeySize( this.algorithmName, rootKey.Length, keySizeInBytes); } // Derive keys from the root key // // Derive encryption key string encryptionKeySalt = string.Format( EncryptionKeySaltFormat, this.algorithmName, KeySize); byte[] buff1 = new byte[keySizeInBytes]; SecurityUtility.GetHMACWithSHA256(Encoding.Unicode.GetBytes(encryptionKeySalt), this.RootKey, buff1); this.encryptionKey = new SymmetricKey(buff1); // Derive mac key string macKeySalt = string.Format(MacKeySaltFormat, this.algorithmName, KeySize); byte[] buff2 = new byte[keySizeInBytes]; SecurityUtility.GetHMACWithSHA256(Encoding.Unicode.GetBytes(macKeySalt), this.RootKey, buff2); this.macKey = new SymmetricKey(buff2); // Derive iv key string ivKeySalt = string.Format(IvKeySaltFormat, this.algorithmName, KeySize); byte[] buff3 = new byte[keySizeInBytes]; SecurityUtility.GetHMACWithSHA256(Encoding.Unicode.GetBytes(ivKeySalt), this.RootKey, buff3); this.ivKey = new SymmetricKey(buff3); }
internal async Task <DataEncryptionKeyProperties> FetchDataEncryptionKeyPropertiesAsync( string id, CosmosDiagnosticsContext diagnosticsContext, CancellationToken cancellationToken) { try { DataEncryptionKeyProperties dekProperties = await this.DekProvider.DekCache.GetOrAddDekPropertiesAsync( id, this.ReadResourceAsync, diagnosticsContext, cancellationToken); return(dekProperties); } catch (CosmosException exception) { throw EncryptionExceptionFactory.EncryptionKeyNotFoundException( $"Failed to retrieve Data Encryption Key with id: '{id}'.", exception); } }
/// <summary> /// For providing support to Encrypt/Decrypt items using Legacy DEK with MDE based algorithm. /// UnWrap using Legacy Key Provider and Init MDE Encryption Algorithm with Unwrapped Key. /// </summary> /// <param name="dekProperties"> DEK Properties </param> /// <param name="cancellationToken"> Cancellation Token </param> /// <returns> Data Encryption Key </returns> internal async Task <DataEncryptionKey> FetchUnWrappedMdeSupportedLegacyDekAsync( DataEncryptionKeyProperties dekProperties, CancellationToken cancellationToken) { if (this.DekProvider.EncryptionKeyWrapProvider == null) { throw new InvalidOperationException($"For use of '{CosmosEncryptionAlgorithm.AEAes256CbcHmacSha256Randomized}' algorithm based DEK, " + "Encryptor or CosmosDataEncryptionKeyProvider needs to be initialized with EncryptionKeyWrapProvider."); } EncryptionKeyUnwrapResult unwrapResult; try { // unwrap with original wrap provider unwrapResult = await this.DekProvider.EncryptionKeyWrapProvider.UnwrapKeyAsync( dekProperties.WrappedDataEncryptionKey, dekProperties.EncryptionKeyWrapMetadata, cancellationToken); } catch (Exception exception) { throw EncryptionExceptionFactory.EncryptionKeyNotFoundException( $"Failed to unwrap Data Encryption Key with id: '{dekProperties.Id}'.", exception); } // Init PlainDataEncryptionKey and then Init MDE Algorithm using PlaintextDataEncryptionKey. // PlaintextDataEncryptionKey derives DataEncryptionkey to Init a Raw Root Key received via Legacy WrapProvider Unwrap result. PlaintextDataEncryptionKey plaintextDataEncryptionKey = new PlaintextDataEncryptionKey( dekProperties.EncryptionKeyWrapMetadata.GetName(dekProperties.EncryptionKeyWrapMetadata), unwrapResult.DataEncryptionKey); return(new MdeEncryptionAlgorithm( plaintextDataEncryptionKey, Data.Encryption.Cryptography.EncryptionType.Randomized)); }