Пример #1
0
        /// <summary>
        /// Return an encrypted base64 encoded message along with encryption related metadata given a plain text message.
        /// </summary>
        /// <param name="inputMessage">The input message in bytes.</param>
        /// <returns>The encrypted message that will be uploaded to the service.</returns>
        internal string EncryptMessage(byte[] inputMessage)
        {
            CommonUtility.AssertNotNull("inputMessage", inputMessage);

            if (this.Key == null)
            {
                throw new InvalidOperationException(SR.KeyMissingError, null);
            }

            CloudQueueEncryptedMessage encryptedMessage = new CloudQueueEncryptedMessage();
            EncryptionData             encryptionData   = new EncryptionData();

            encryptionData.EncryptionAgent     = new EncryptionAgent(Constants.EncryptionConstants.EncryptionProtocolV1, EncryptionAlgorithm.AES_CBC_256);
            encryptionData.KeyWrappingMetadata = new Dictionary <string, string>();
            encryptionData.KeyWrappingMetadata[Constants.EncryptionConstants.AgentMetadataKey] = Constants.EncryptionConstants.AgentMetadataValue;

#if WINDOWS_DESKTOP && !WINDOWS_PHONE
            using (AesCryptoServiceProvider myAes = new AesCryptoServiceProvider())
#else
            using (AesManaged myAes = new AesManaged())
#endif
            {
                encryptionData.ContentEncryptionIV = myAes.IV;

                // Wrap always happens locally, irrespective of local or cloud key. So it is ok to call it synchronously.
                Tuple <byte[], string> wrappedKey = CommonUtility.RunWithoutSynchronizationContext(() => this.Key.WrapKeyAsync(myAes.Key, null /* algorithm */, CancellationToken.None).Result);
                encryptionData.WrappedContentKey = new WrappedKey(this.Key.Kid, wrappedKey.Item1, wrappedKey.Item2);

                using (ICryptoTransform encryptor = myAes.CreateEncryptor())
                {
                    encryptedMessage.EncryptedMessageContents = Convert.ToBase64String(encryptor.TransformFinalBlock(inputMessage, 0, inputMessage.Length));
                }

                encryptedMessage.EncryptionData = encryptionData;
                return(JsonConvert.SerializeObject(encryptedMessage));
            }
        }
Пример #2
0
        /// <summary>
        /// Returns a plain text message given an encrypted message.
        /// </summary>
        /// <param name="inputMessage">The encrypted message.</param>
        /// <param name="requireEncryption">A value to indicate that the data read from the server should be encrypted.</param>
        /// <returns>The plain text message bytes.</returns>
        internal byte[] DecryptMessage(string inputMessage, bool?requireEncryption)
        {
            CommonUtility.AssertNotNull("inputMessage", inputMessage);

            try
            {
                CloudQueueEncryptedMessage encryptedMessage = JsonConvert.DeserializeObject <CloudQueueEncryptedMessage>(inputMessage);

                if (requireEncryption.HasValue && requireEncryption.Value && encryptedMessage.EncryptionData == null)
                {
                    throw new StorageException(SR.EncryptionDataNotPresentError, null)
                          {
                              IsRetryable = false
                          };
                }

                if (encryptedMessage.EncryptionData != null)
                {
                    EncryptionData encryptionData = encryptedMessage.EncryptionData;

                    CommonUtility.AssertNotNull("ContentEncryptionIV", encryptionData.ContentEncryptionIV);
                    CommonUtility.AssertNotNull("EncryptedKey", encryptionData.WrappedContentKey.EncryptedKey);

                    // Throw if the encryption protocol on the message doesn't match the version that this client library understands
                    // and is able to decrypt.
                    if (encryptionData.EncryptionAgent.Protocol != Constants.EncryptionConstants.EncryptionProtocolV1)
                    {
                        throw new StorageException(SR.EncryptionProtocolVersionInvalid, null)
                              {
                                  IsRetryable = false
                              };
                    }

                    // Throw if neither the key nor the key resolver are set.
                    if (this.Key == null && this.KeyResolver == null)
                    {
                        throw new StorageException(SR.KeyAndResolverMissingError, null)
                              {
                                  IsRetryable = false
                              };
                    }

                    byte[] contentEncryptionKey = null;

                    // 1. Invoke the key resolver if specified to get the key. If the resolver is specified but does not have a
                    // mapping for the key id, an error should be thrown. This is important for key rotation scenario.
                    // 2. If resolver is not specified but a key is specified, match the key id on the key and and use it.
                    // Calling UnwrapKeyAsync synchronously is fine because for the storage client scenario, unwrap happens
                    // locally. No service call is made.
                    if (this.KeyResolver != null)
                    {
                        IKey keyEncryptionKey = CommonUtility.RunWithoutSynchronizationContext(() => this.KeyResolver.ResolveKeyAsync(encryptionData.WrappedContentKey.KeyId, CancellationToken.None).Result);

                        CommonUtility.AssertNotNull("keyEncryptionKey", keyEncryptionKey);
                        contentEncryptionKey = CommonUtility.RunWithoutSynchronizationContext(() => keyEncryptionKey.UnwrapKeyAsync(encryptionData.WrappedContentKey.EncryptedKey, encryptionData.WrappedContentKey.Algorithm, CancellationToken.None).Result);
                    }
                    else
                    {
                        if (this.Key.Kid == encryptionData.WrappedContentKey.KeyId)
                        {
                            contentEncryptionKey = CommonUtility.RunWithoutSynchronizationContext(() => this.Key.UnwrapKeyAsync(encryptionData.WrappedContentKey.EncryptedKey, encryptionData.WrappedContentKey.Algorithm, CancellationToken.None).Result);
                        }
                        else
                        {
                            throw new StorageException(SR.KeyMismatch, null)
                                  {
                                      IsRetryable = false
                                  };
                        }
                    }

                    switch (encryptionData.EncryptionAgent.EncryptionAlgorithm)
                    {
                    case EncryptionAlgorithm.AES_CBC_256:
#if WINDOWS_DESKTOP && !WINDOWS_PHONE
                        using (AesCryptoServiceProvider myAes = new AesCryptoServiceProvider())
#else
                        using (AesManaged myAes = new AesManaged())
#endif
                        {
                            myAes.Key = contentEncryptionKey;
                            myAes.IV  = encryptionData.ContentEncryptionIV;

                            byte[] src = Convert.FromBase64String(encryptedMessage.EncryptedMessageContents);
                            using (ICryptoTransform decryptor = myAes.CreateDecryptor())
                            {
                                return(decryptor.TransformFinalBlock(src, 0, src.Length));
                            }
                        }

                    default:
                        throw new StorageException(SR.InvalidEncryptionAlgorithm, null)
                              {
                                  IsRetryable = false
                              };
                    }
                }
                else
                {
                    return(Convert.FromBase64String(encryptedMessage.EncryptedMessageContents));
                }
            }
            catch (JsonException ex)
            {
                throw new StorageException(SR.EncryptedMessageDeserializingError, ex)
                      {
                          IsRetryable = false
                      };
            }
            catch (StorageException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new StorageException(SR.DecryptionLogicError, ex)
                      {
                          IsRetryable = false
                      };
            }
        }