/// <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>();

#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);
            }
        }
        private static T ReadAndResolveWithEdmTypeResolver <T>(Dictionary <string, string> entityAttributes, Func <string, string, DateTimeOffset, IDictionary <string, EntityProperty>, string, T> resolver, Func <string, string, string, string, EdmType> propertyResolver, string etag, Type type, OperationContext ctx, bool disablePropertyResolverCache, TableRequestOptions options)
        {
            string pk = null;
            string rk = null;

            byte[]         cek            = null;
            EncryptionData encryptionData = null;
            DateTimeOffset ts             = new DateTimeOffset();
            Dictionary <string, EntityProperty> properties = new Dictionary <string, EntityProperty>();
            Dictionary <string, EdmType>        propertyResolverDictionary = null;
            HashSet <string> encryptedPropertyDetailsSet = null;

            if (type != null)
            {
#if WINDOWS_DESKTOP && !WINDOWS_PHONE
                if (!disablePropertyResolverCache)
                {
                    propertyResolverDictionary = TableEntity.PropertyResolverCache.GetOrAdd(type, TableOperationHttpResponseParsers.CreatePropertyResolverDictionary);
                }
                else
                {
                    propertyResolverDictionary = TableOperationHttpResponseParsers.CreatePropertyResolverDictionary(type);
                }
#else
                propertyResolverDictionary = TableOperationHttpResponseParsers.CreatePropertyResolverDictionary(type);
#endif
            }

            // Decrypt the metadata property value to get the names of encrypted properties so that they can be parsed correctly below.
            if (options.EncryptionPolicy != null)
            {
                string metadataValue    = null;
                string keyPropertyValue = null;

                if (entityAttributes.TryGetValue(Constants.EncryptionConstants.TableEncryptionPropertyDetails, out metadataValue) &&
                    entityAttributes.TryGetValue(Constants.EncryptionConstants.TableEncryptionKeyDetails, out keyPropertyValue))
                {
                    EntityProperty propertyDetailsProperty = EntityProperty.CreateEntityPropertyFromObject(metadataValue, EdmType.Binary);
                    EntityProperty keyProperty             = EntityProperty.CreateEntityPropertyFromObject(keyPropertyValue, EdmType.String);

                    entityAttributes.TryGetValue(TableConstants.PartitionKey, out pk);
                    entityAttributes.TryGetValue(TableConstants.RowKey, out rk);
                    cek = options.EncryptionPolicy.DecryptMetadataAndReturnCEK(pk, rk, keyProperty, propertyDetailsProperty, out encryptionData);

                    properties.Add(Constants.EncryptionConstants.TableEncryptionPropertyDetails, propertyDetailsProperty);

                    byte[] binaryVal = propertyDetailsProperty.BinaryValue;
                    encryptedPropertyDetailsSet = JsonConvert.DeserializeObject <HashSet <string> >(Encoding.UTF8.GetString(binaryVal, 0, binaryVal.Length));
                }
                else
                {
                    if (options.RequireEncryption.HasValue && options.RequireEncryption.Value)
                    {
                        throw new StorageException(SR.EncryptionDataNotPresentError, null)
                              {
                                  IsRetryable = false
                              };
                    }
                }
            }

            foreach (KeyValuePair <string, string> prop in entityAttributes)
            {
                if (prop.Key == TableConstants.PartitionKey)
                {
                    pk = (string)prop.Value;
                }
                else if (prop.Key == TableConstants.RowKey)
                {
                    rk = (string)prop.Value;
                }
                else if (prop.Key == TableConstants.Timestamp)
                {
                    ts = DateTimeOffset.Parse(prop.Value, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
                    if (etag == null)
                    {
                        etag = GetETagFromTimestamp(prop.Value);
                    }
                }
                else if (prop.Key == Constants.EncryptionConstants.TableEncryptionKeyDetails)
                {
                    // This and the following check are required because in JSON no-metadata, the type information for the properties are not returned and users are
                    // not expected to provide a type for them. So based on how the user defined property resolvers treat unknown properties, we might get unexpected results.
                    properties.Add(prop.Key, EntityProperty.CreateEntityPropertyFromObject(prop.Value, EdmType.String));
                }
                else if (prop.Key == Constants.EncryptionConstants.TableEncryptionPropertyDetails)
                {
                    if (!properties.ContainsKey(Constants.EncryptionConstants.TableEncryptionPropertyDetails))
                    {
                        // If encryption policy is not set, then add the value as-is to the dictionary.
                        properties.Add(prop.Key, EntityProperty.CreateEntityPropertyFromObject(prop.Value, EdmType.Binary));
                    }
                    else
                    {
                        // Do nothing. Already handled above.
                    }
                }
                else
                {
                    if (propertyResolver != null)
                    {
                        Logger.LogVerbose(ctx, SR.UsingUserProvidedPropertyResolver);
                        try
                        {
                            EdmType edmType = propertyResolver(pk, rk, prop.Key, prop.Value);
                            Logger.LogVerbose(ctx, SR.AttemptedEdmTypeForTheProperty, prop.Key, edmType);
                            try
                            {
                                CreateEntityPropertyFromObject(properties, encryptedPropertyDetailsSet, prop, edmType);
                            }
                            catch (FormatException ex)
                            {
                                throw new StorageException(string.Format(CultureInfo.InvariantCulture, SR.FailParseProperty, prop.Key, prop.Value, edmType), ex)
                                      {
                                          IsRetryable = false
                                      };
                            }
                        }
                        catch (StorageException)
                        {
                            throw;
                        }
                        catch (Exception ex)
                        {
                            throw new StorageException(SR.PropertyResolverThrewError, ex)
                                  {
                                      IsRetryable = false
                                  };
                        }
                    }
                    else if (type != null)
                    {
                        Logger.LogVerbose(ctx, SR.UsingDefaultPropertyResolver);
                        EdmType edmType;
                        if (propertyResolverDictionary != null)
                        {
                            propertyResolverDictionary.TryGetValue(prop.Key, out edmType);
                            Logger.LogVerbose(ctx, SR.AttemptedEdmTypeForTheProperty, prop.Key, edmType);
                            CreateEntityPropertyFromObject(properties, encryptedPropertyDetailsSet, prop, edmType);
                        }
                    }
                    else
                    {
                        Logger.LogVerbose(ctx, SR.NoPropertyResolverAvailable);
                        CreateEntityPropertyFromObject(properties, encryptedPropertyDetailsSet, prop, EdmType.String);
                    }
                }
            }

            // If encryption policy is set on options, try to decrypt the entity.
            if (options.EncryptionPolicy != null && encryptionData != null)
            {
                properties = options.EncryptionPolicy.DecryptEntity(properties, encryptedPropertyDetailsSet, pk, rk, cek, encryptionData);
            }

            return(resolver(pk, rk, ts, properties, etag));
        }
        private static T ReadAndResolve <T>(ODataEntry entry, Func <string, string, DateTimeOffset, IDictionary <string, EntityProperty>, string, T> resolver, TableRequestOptions options)
        {
            string pk = null;
            string rk = null;

            byte[]         cek = null;
            DateTimeOffset ts  = new DateTimeOffset();
            Dictionary <string, EntityProperty> properties = new Dictionary <string, EntityProperty>();

            foreach (ODataProperty prop in entry.Properties)
            {
                string propName = prop.Name;
                if (propName == TableConstants.PartitionKey)
                {
                    pk = (string)prop.Value;
                }
                else if (propName == TableConstants.RowKey)
                {
                    rk = (string)prop.Value;
                }
                else if (propName == TableConstants.Timestamp)
                {
                    ts = new DateTimeOffset((DateTime)prop.Value);
                }
                else
                {
                    properties.Add(propName, EntityProperty.CreateEntityPropertyFromObject(prop.Value));
                }
            }

            // If encryption policy is set on options, try to decrypt the entity.
            EntityProperty propertyDetailsProperty;
            EntityProperty keyProperty;

            if (options.EncryptionPolicy != null)
            {
                if (properties.TryGetValue(Constants.EncryptionConstants.TableEncryptionPropertyDetails, out propertyDetailsProperty) &&
                    properties.TryGetValue(Constants.EncryptionConstants.TableEncryptionKeyDetails, out keyProperty))
                {
                    // Decrypt the metadata property value to get the names of encrypted properties.
                    EncryptionData encryptionData = null;
                    cek = options.EncryptionPolicy.DecryptMetadataAndReturnCEK(pk, rk, keyProperty, propertyDetailsProperty, out encryptionData);

                    byte[]           binaryVal = propertyDetailsProperty.BinaryValue;
                    HashSet <string> encryptedPropertyDetailsSet = JsonConvert.DeserializeObject <HashSet <string> >(Encoding.UTF8.GetString(binaryVal, 0, binaryVal.Length));

                    properties = options.EncryptionPolicy.DecryptEntity(properties, encryptedPropertyDetailsSet, pk, rk, cek, encryptionData);
                }
                else
                {
                    if (options.RequireEncryption.HasValue && options.RequireEncryption.Value)
                    {
                        throw new StorageException(SR.EncryptionDataNotPresentError, null)
                              {
                                  IsRetryable = false
                              };
                    }
                }
            }

            return(resolver(pk, rk, ts, properties, entry.ETag));
        }
Beispiel #4
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).GetAwaiter().GetResult());

                        CommonUtility.AssertNotNull("keyEncryptionKey", keyEncryptionKey);
                        contentEncryptionKey = CommonUtility.RunWithoutSynchronizationContext(() => keyEncryptionKey.UnwrapKeyAsync(encryptionData.WrappedContentKey.EncryptedKey, encryptionData.WrappedContentKey.Algorithm, CancellationToken.None).GetAwaiter().GetResult());
                    }
                    else
                    {
                        if (this.Key.Kid == encryptionData.WrappedContentKey.KeyId)
                        {
                            contentEncryptionKey = CommonUtility.RunWithoutSynchronizationContext(() => this.Key.UnwrapKeyAsync(encryptionData.WrappedContentKey.EncryptedKey, encryptionData.WrappedContentKey.Algorithm, CancellationToken.None).GetAwaiter().GetResult());
                        }
                        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
                      };
            }
        }
Beispiel #5
0
 private static bool AreEqual(EncryptionData left, EncryptionData right)
 => left.EncryptionMode.Equals(right.EncryptionMode, StringComparison.InvariantCulture) &&
 AreEqual(left.WrappedContentKey, right.WrappedContentKey) &&
 AreEqual(left.EncryptionAgent, right.EncryptionAgent) &&
 left.ContentEncryptionIV.SequenceEqual(right.ContentEncryptionIV) &&
 AreEqual(left.KeyWrappingMetadata, right.KeyWrappingMetadata);
Beispiel #6
0
        private static ErrorCode SetupEncryption(AuthenticationToken token, out string errorMsg, ClientPeer peer, InitRequest initRequest)
        {
            if (log.IsDebugEnabled)
            {
                log.DebugFormat("setting up encryption. p:{0}", peer);
            }

            var encryptionDataDict = token.EncryptionData;

            errorMsg = string.Empty;

            if (encryptionDataDict == null)
            {
                if (log.IsWarnEnabled)
                {
                    log.WarnFormat(logSetupCountGuard, "AuthOnInitHandler: expected encryption data not provided. appId:{0}/{1}, p:{2}",
                                   token.ApplicationId, token.ApplicationVersion, peer);
                }

                errorMsg = string.Format(ErrorMessages.InvalidEncryptionData, "expected encryption data not provided");
                return(ErrorCode.InvalidEncryptionParameters);
            }

            var encryptionData = new EncryptionData(peer.Protocol, encryptionDataDict);

            if (!encryptionData.IsValid)
            {
                if (log.IsWarnEnabled)
                {
                    log.WarnFormat(logSetupCountGuard,
                                   "AuthOnInitHandler: Invalid encryption data. ErrorMsg:{4}. appId:{0}/{1}, data:{2}, p:{3}",
                                   token.ApplicationId, token.ApplicationVersion, JsonConvert.SerializeObject(encryptionDataDict), peer, encryptionData.GetErrorMessage());
                }
                errorMsg = string.Format(ErrorMessages.InvalidEncryptionData, encryptionData.GetErrorMessage());
                return(ErrorCode.InvalidEncryptionParameters);
            }

            var mode = (EncryptionModes)encryptionData.EncryptionMode;

            try
            {
                switch (mode)
                {
                case EncryptionModes.PayloadEncryption:
                case EncryptionModes.PayloadEncryptionWithIV:
                case EncryptionModes.PayloadEncryptionWithIVHMAC:
                    SetupUserDataEncryptionWithoutDH(encryptionData, peer);
                    break;

                case EncryptionModes.DatagramEncyption:
                case EncryptionModes.DatagramEncyptionWithRandomInitialNumbers:
                case EncryptionModes.DatagramEncyptionGCMWithRandomInitialNumbers:
                    if (peer.NetworkProtocol != NetworkProtocolType.Udp)
                    {
                        errorMsg = ErrorMessages.EncryptionModeMismatch;
                        return(ErrorCode.InvalidEncryptionParameters);
                    }

                    SetupUdpEncryption(encryptionData, peer, initRequest);
                    break;

                default:
                {
                    if (log.IsWarnEnabled)
                    {
                        log.WarnFormat(logSetupCountGuard,
                                       $"AuthOnInitHandler: Unknown encryption mode: '{mode}'. appId:{0}/{1}, data:{2}, p:{3}",
                                       token.ApplicationId, token.ApplicationVersion, JsonConvert.SerializeObject(encryptionDataDict), peer);
                    }
                    errorMsg = string.Format(ErrorMessages.InvalidEncryptionData, $"Unknown Encryption mode {mode}");
                    return(ErrorCode.InvalidEncryptionParameters);
                }
                }
            }
            catch (Exception e)
            {
                errorMsg = e.ToString();
                var msg = string.Format("AuthOnInitHandler: Exception during encryption setup. appId:{0}/{1}, Data: {2}, p:{3}",
                                        token.ApplicationId, token.ApplicationVersion, JsonConvert.SerializeObject(encryptionDataDict), peer);

                log.Error(logExceptionCountGuard, msg, e);
                return(ErrorCode.InvalidEncryptionParameters);
            }
            return(ErrorCode.Ok);
        }
        /// <summary>
        /// Return a decrypted entity. This method is used for decrypting entity properties.
        /// </summary>
        internal Dictionary<string, EntityProperty> DecryptEntity(IDictionary<string, EntityProperty> properties, HashSet<string> encryptedPropertyDetailsSet, string partitionKey, string rowKey, byte[] contentEncryptionKey, EncryptionData encryptionData)
        {
            try
            {
                Dictionary<string, EntityProperty> decryptedProperties = new Dictionary<string, EntityProperty>();

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

                                foreach (KeyValuePair<string, EntityProperty> kvp in properties)
                                {
                                    if (kvp.Key == Constants.EncryptionConstants.TableEncryptionKeyDetails || kvp.Key == Constants.EncryptionConstants.TableEncryptionPropertyDetails)
                                    {
                                        // Do nothing. Do not add to the result properties.
                                    }
                                    else if (encryptedPropertyDetailsSet.Contains(kvp.Key))
                                    {
                                        byte[] columnIV = sha256.ComputeHash(CommonUtility.BinaryAppend(encryptionData.ContentEncryptionIV, Encoding.UTF8.GetBytes(string.Join(partitionKey, rowKey, kvp.Key))));
                                        Array.Resize<byte>(ref columnIV, 16);
                                        myAes.IV = columnIV;

                                        byte[] src = kvp.Value.BinaryValue;
                                        using (ICryptoTransform transform = myAes.CreateDecryptor())
                                        {
                                            byte[] dest = transform.TransformFinalBlock(src, 0, src.Length);
                                            string destString = Encoding.UTF8.GetString(dest, 0, dest.Length);
                                            decryptedProperties.Add(kvp.Key, new EntityProperty(destString));
                                        }
                                    }
                                    else
                                    {
                                        decryptedProperties.Add(kvp.Key, kvp.Value);
                                    }
                                }
                            }
                        }

                        return decryptedProperties;

                    default:
                        throw new StorageException(SR.InvalidEncryptionAlgorithm, null) { IsRetryable = false };
                }
            }
            catch (JsonException ex)
            {
                throw new StorageException(SR.EncryptionMetadataError, ex) { IsRetryable = false };
            }
            catch (StorageException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new StorageException(SR.DecryptionLogicError, ex) { IsRetryable = false };
            }
        }
Beispiel #8
0
        /// <summary>
        /// Return an encrypted entity. This method is used for encrypting entity properties.
        /// </summary>
        internal Dictionary <string, EntityProperty> EncryptEntity(IDictionary <string, EntityProperty> properties, string partitionKey, string rowKey, Func <string, string, string, bool> encryptionResolver)
        {
            CommonUtility.AssertNotNull("properties", properties);

            // The Key should be set on the policy for encryption. Otherwise, throw an error.
            if (this.Key == null)
            {
                throw new InvalidOperationException(SR.KeyMissingError, null);
            }

            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;

            Dictionary <string, EntityProperty> encryptedProperties = new Dictionary <string, EntityProperty>();
            HashSet <string> encryptionPropertyDetailsSet           = new HashSet <string>();

#if WINDOWS_DESKTOP && !WINDOWS_PHONE
            using (AesCryptoServiceProvider myAes = new AesCryptoServiceProvider())
            {
                using (SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider())
#else
            using (AesManaged myAes = new AesManaged())
            {
                using (SHA256Managed sha256 = new SHA256Managed())
#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);

                    foreach (KeyValuePair <string, EntityProperty> kvp in properties)
                    {
                        if (encryptionResolver != null && encryptionResolver(partitionKey, rowKey, kvp.Key))
                        {
                            // Throw if users try to encrypt null properties. This could happen in the DynamicTableEntity case
                            // where a user adds a new property as follows - ent.Properties.Add("foo2", null);
                            if (kvp.Value == null)
                            {
                                throw new InvalidOperationException(SR.EncryptingNullPropertiesNotAllowed);
                            }

                            kvp.Value.IsEncrypted = true;
                        }

                        // IsEncrypted is set to true when either the EncryptPropertyAttribute is set on a property or when it is
                        // specified in the encryption resolver or both.
                        if (kvp.Value != null && kvp.Value.IsEncrypted)
                        {
                            // Throw if users try to encrypt non-string properties.
                            if (kvp.Value.PropertyType != EdmType.String)
                            {
                                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.UnsupportedPropertyTypeForEncryption, kvp.Value.PropertyType));
                            }

                            byte[] columnIV = sha256.ComputeHash(CommonUtility.BinaryAppend(encryptionData.ContentEncryptionIV, Encoding.UTF8.GetBytes(string.Join(partitionKey, rowKey, kvp.Key))));
                            Array.Resize <byte>(ref columnIV, 16);
                            myAes.IV = columnIV;

                            using (ICryptoTransform transform = myAes.CreateEncryptor())
                            {
                                // Throw if users try to encrypt null properties. This could happen in the DynamicTableEntity or POCO
                                // case when the property value is null.
                                if (kvp.Value.IsNull)
                                {
                                    throw new InvalidOperationException(SR.EncryptingNullPropertiesNotAllowed);
                                }

                                byte[] src  = Encoding.UTF8.GetBytes(kvp.Value.StringValue);
                                byte[] dest = transform.TransformFinalBlock(src, 0, src.Length);

                                // Store the encrypted properties as binary values on the service instead of base 64 encoded strings because strings are stored as a sequence of
                                // WCHARs thereby further reducing the allowed size by half. During retrieve, it is handled by the response parsers correctly
                                // even when the service does not return the type for JSON no-metadata.
                                encryptedProperties.Add(kvp.Key, new EntityProperty(dest));
                                encryptionPropertyDetailsSet.Add(kvp.Key);
                            }
                        }
                        else
                        {
                            encryptedProperties.Add(kvp.Key, kvp.Value);
                        }
                    }

                    // Encrypt the property details set and add it to entity properties.
                    byte[] metadataIV = sha256.ComputeHash(CommonUtility.BinaryAppend(encryptionData.ContentEncryptionIV, Encoding.UTF8.GetBytes(string.Join(partitionKey, rowKey, Constants.EncryptionConstants.TableEncryptionPropertyDetails))));
                    Array.Resize <byte>(ref metadataIV, 16);
                    myAes.IV = metadataIV;

                    using (ICryptoTransform transform = myAes.CreateEncryptor())
                    {
                        byte[] src  = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(encryptionPropertyDetailsSet));
                        byte[] dest = transform.TransformFinalBlock(src, 0, src.Length);
                        encryptedProperties.Add(Constants.EncryptionConstants.TableEncryptionPropertyDetails, new EntityProperty(dest));
                    }
                }
            }

            // Add the key details to entity properties.
            encryptedProperties.Add(Constants.EncryptionConstants.TableEncryptionKeyDetails, new EntityProperty(JsonConvert.SerializeObject(encryptionData)));
            return(encryptedProperties);
        }
Beispiel #9
0
 public bool Compare(EncryptionData other) => other.Password == Password &&
 other.KeySalt.CompareArrayItems(KeySalt.ToArray()) &&
 other.IvSalt.CompareArrayItems(IvSalt.ToArray());
Beispiel #10
0
 public SerializableEncryptionData(EncryptionData encryptionData)
 {
     Password = encryptionData.Password;
     KeySalt  = encryptionData.KeySalt.ToList();
     IvSalt   = encryptionData.IvSalt.ToList();
 }
        private static async ValueTask <EncryptionData> CallEndpoint(Stream?encrypted, Stream?decrypted, string endpoint)
        {
            using HttpContent content             = new StringContent(JsonSerializer.Serialize(await EncryptionData.From(encrypted, decrypted)));
            content.Headers.ContentType.MediaType = "application/json";
            HttpResponseMessage response = await Client.PostAsync(endpoint, content);

            return(JsonSerializer.Deserialize <EncryptionData>(await response.Content.ReadAsStringAsync(), SerializerOptions));
        }
        private static async Task UpdateClientsideKeyEncryptionKeyInternal(
            BlobClient client,
            UpdateClientSideKeyEncryptionKeyOptions options,
            bool async,
            CancellationToken cancellationToken)
        {
            // argument validation
            Argument.AssertNotNull(client, nameof(client));
            ClientSideEncryptionOptions operationEncryptionOptions = options?.EncryptionOptionsOverride
                                                                     ?? client.ClientSideEncryption
                                                                     ?? throw new ArgumentException($"{nameof(ClientSideEncryptionOptions)} are not configured on this client and none were provided for the operation.");

            Argument.AssertNotNull(operationEncryptionOptions.KeyEncryptionKey, nameof(ClientSideEncryptionOptions.KeyEncryptionKey));
            Argument.AssertNotNull(operationEncryptionOptions.KeyResolver, nameof(ClientSideEncryptionOptions.KeyResolver));
            Argument.AssertNotNull(operationEncryptionOptions.KeyWrapAlgorithm, nameof(ClientSideEncryptionOptions.KeyWrapAlgorithm));

            using (client.ClientConfiguration.Pipeline.BeginLoggingScope(nameof(BlobClient)))
            {
                client.ClientConfiguration.Pipeline.LogMethodEnter(
                    nameof(BlobBaseClient),
                    message:
                    $"{nameof(Uri)}: {client.Uri}\n" +
                    $"{nameof(options.Conditions)}: {options?.Conditions}");

                DiagnosticScope scope = client.ClientConfiguration.ClientDiagnostics.CreateScope($"{nameof(BlobClient)}.{nameof(UpdateClientSideKeyEncryptionKey)}");

                try
                {
                    // hold onto etag, metadata, encryptiondata
                    BlobProperties getPropertiesResponse = await client.GetPropertiesInternal(options?.Conditions, async, cancellationToken).ConfigureAwait(false);

                    ETag etag = getPropertiesResponse.ETag;
                    IDictionary <string, string> metadata = getPropertiesResponse.Metadata;
                    EncryptionData encryptionData         = BlobClientSideDecryptor.GetAndValidateEncryptionDataOrDefault(metadata)
                                                            ?? throw new InvalidOperationException("Resource has no client-side encryption key to rotate.");

                    // rotate keywrapping
                    byte[] newWrappedKey = await WrapKeyInternal(
                        await UnwrapKeyInternal(
                            encryptionData,
                            operationEncryptionOptions.KeyResolver,
                            async,
                            cancellationToken).ConfigureAwait(false),
                        operationEncryptionOptions.KeyWrapAlgorithm,
                        operationEncryptionOptions.KeyEncryptionKey,
                        async,
                        cancellationToken).ConfigureAwait(false);

                    // set new wrapped key info and reinsert into metadata
                    encryptionData.WrappedContentKey = new KeyEnvelope
                    {
                        EncryptedKey = newWrappedKey,
                        Algorithm    = operationEncryptionOptions.KeyWrapAlgorithm,
                        KeyId        = operationEncryptionOptions.KeyEncryptionKey.KeyId
                    };
                    metadata[Constants.ClientSideEncryption.EncryptionDataKey] = EncryptionDataSerializer.Serialize(encryptionData);

                    // update blob ONLY IF ETAG MATCHES (do not take chances encryption info is now out of sync)
                    BlobRequestConditions modifiedRequestConditions = BlobRequestConditions.CloneOrDefault(options?.Conditions) ?? new BlobRequestConditions();
                    modifiedRequestConditions.IfMatch = etag;
                    await client.SetMetadataInternal(metadata, modifiedRequestConditions, async, cancellationToken).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    client.ClientConfiguration.Pipeline.LogException(ex);
                    scope.Failed(ex);
                    throw;
                }
                finally
                {
                    client.ClientConfiguration.Pipeline.LogMethodExit(nameof(BlobBaseClient));
                    scope.Dispose();
                }
            }
        }
Beispiel #13
0
        public NWSEncryptionTests()
        {
            Address address = new Address();

            address.Name           = "My STORE";
            address.StreetAddress1 = "1 MY STREET";
            address.City           = "MYTOWN";
            address.PostalCode     = "90210";
            address.State          = "KY";
            address.Country        = "USA";

            AcceptorConfig acceptorConfig = new AcceptorConfig();

            acceptorConfig.Address = address;

            // data code values
            acceptorConfig.CardDataInputCapability  = CardDataInputCapability.ContactlessEmv_ContactEmv_MagStripe_KeyEntry;
            acceptorConfig.TerminalOutputCapability = TerminalOutputCapability.Printing_Display;

            // hardware software config values
            acceptorConfig.HardwareLevel = "34";
            acceptorConfig.SoftwareLevel = "21205710";

            // pos configuration values
            acceptorConfig.SupportsPartialApproval            = true;
            acceptorConfig.SupportsShutOffAmount              = true;
            acceptorConfig.SupportsReturnBalance              = true;
            acceptorConfig.SupportsDiscoverNetworkReferenceId = true;
            acceptorConfig.SupportsAvsCnvVoidReferrals        = true;
            acceptorConfig.SupportedEncryptionType            = EncryptionType.TEP2;

            // gateway config
            NetworkGatewayConfig config = new NetworkGatewayConfig(NetworkGatewayType.NWS);

            config.ServiceUrl        = "test.txns-c.secureexchange.net";
            config.PrimaryPort       = 15031;
            config.SecondaryEndpoint = "test.txns-e.secureexchange.net";
            config.SecondaryPort     = 15031;
            config.CompanyId         = "SPSA";
            config.TerminalId        = "NWSDOTNET01";
            config.AcceptorConfig    = acceptorConfig;
            config.EnableLogging     = true;
            config.StanProvider      = StanGenerator.GetInstance();
            config.BatchProvider     = BatchProvider.GetInstance();

            ServicesContainer.ConfigureService(config);

            // AMEX
            //card = TestCards.AmexManualEncrypted();
            ////cardWithCvn = TestCards.AmexManualEncrypted();
            ////cardWithCvn.Cvn = "9072488";
            //track = TestCards.AmexSwipeEncrypted();

            // DISCOVER
            card = TestCards.DiscoverManualEncrypted();
            //cardWithCvn = TestCards.DiscoverManualEncrypted();
            //cardWithCvn.Cvn = "703";
            track = TestCards.DiscoverSwipeEncryptedV2();

            // MASTERCARD
            //card = TestCards.MasterCardManualEncrypted();
            ////cardWithCvn = TestCards.MasterCardManualEncrypted();
            ////cardWithCvn.Cvn = "7803754";
            //track = TestCards.MasterCardSwipeEncryptedV2();

            // VISA
            //card = TestCards.VisaManualEncrypted(true, true);
            ////cardWithCvn = TestCards.VisaManualEncrypted();
            ////cardWithCvn.Cvn = "7803754";
            //track = TestCards.VisaSwipeEncryptedV2();

            // DEBIT
            debit                = new DebitTrackData();
            debit.Value          = ";6090001234567891=2112120000000000001?";
            debit.PinBlock       = "62968D2481D231E1A504010024A00014";
            debit.EncryptionData = EncryptionData.Version2("/wECAQEEAoFGAgEH4gcOTDT6jRZwb3NAc2VjdXJlZXhjaGFuZ2UubmV0m+/d4SO9TEshhRGUUQzVBrBvP/Os1qFx+6zdQp1ejjUCoDmzoUMbil9UG73zBxxTOy25f3Px0p8joyCh8PEWhADz1BkROJT3q6JnocQE49yYBHuFK0obm5kqUcYPfTY09vPOpmN+wp45gJY9PhkJF5XvPsMlcxX4/JhtCshegz4AYrcU/sFnI+nDwhy295BdOkVN1rn00jwCbRcE900kj3UsFfyc", "2");
        }
Beispiel #14
0
        private async void btnNext_Click(object sender, EventArgs e)
        {
            try
            {
                if (isConfirmUser)
                {
                    //Do for confirm user
                    if (isValidConfirmUser())
                    {
                        lblWait.Visible = true;


                        string username = confirmUser1.txtUserName.Text.Trim();
                        oUser = await user.SelectUser(username);

                        if (oUser != null)
                        {
                            //Show the security question
                            lblWait.Visible = false;
                            //Set the question
                            securityQuestion1.lblQuestion.Text = GetQuestion(oUser.Question);
                            securityQuestion1.BringToFront();
                            isConfirmUser = false;
                            isQuestion    = true;
                            return;
                        }
                        else
                        {
                            lblWait.Visible = false;
                            MessageBox.Show("Invalid Username. You are not a registered user", "Invalid User", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                    }
                }


                if (isQuestion)
                {
                    //Do for question.
                    if (isValidQuestion())
                    {
                        lblWait.Visible = true;
                        string userAnswer = securityQuestion1.txtAnswer.Text.Trim().ToLower();
                        if (EncryptionData.ValidateEncryptedData(userAnswer, oUser.Answer))
                        {
                            //Move to the next step
                            lblWait.Visible = false;
                            isQuestion      = false;
                            isPassword      = true;
                            userPassword1.BringToFront();
                            btnNext.Text = "Change";
                            return;
                        }
                        else
                        {
                            lblWait.Visible = false;
                            MessageBox.Show("Invalid Answer. Please provide a valid answer.", "Invalid Answer", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                    }
                }


                if (isPassword)
                {
                    //Change the user's password
                    if (isValidPassword())
                    {
                        string newPassword = userPassword1.txtPassword.Text.Trim();
                        oUser.Password = newPassword;
                        if (await user.ChangePassword(oUser))
                        {
                            Logger.WriteToFile(oUser.FullName, "successfully changed password");
                            MessageBox.Show("Password has been successfully changed", "Change Password", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            this.Close();
                        }
                        else
                        {
                            MessageBox.Show("Unable to change password", "Please try again", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Sorry an error occured. \n{ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
Beispiel #15
0
        internal byte[] DecryptMetadataAndReturnCEK(string partitionKey, string rowKey, EntityProperty encryptionKeyProperty, EntityProperty propertyDetailsProperty, out EncryptionData encryptionData, out bool isJavaV1)
        {
            // Throw if neither the key nor the resolver are set.
            if (this.Key == null && this.KeyResolver == null)
            {
                throw new StorageException(SR.KeyAndResolverMissingError, null)
                      {
                          IsRetryable = false
                      };
            }

            try
            {
                encryptionData = JsonConvert.DeserializeObject <EncryptionData>(encryptionKeyProperty.StringValue);
                EncryptionData encryptionDataCopy = encryptionData; // This is necessary because you cannot use "out" variables in a lambda.

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

                // Throw if the encryption protocol on the entity 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
                          };
                }

                isJavaV1 = (encryptionData.EncryptionAgent.Protocol == Constants.EncryptionConstants.EncryptionProtocolV1) &&
                           ((encryptionData.KeyWrappingMetadata == null) ||
                            (encryptionData.KeyWrappingMetadata.ContainsKey(Constants.EncryptionConstants.AgentMetadataKey) &&
                             encryptionData.KeyWrappingMetadata[Constants.EncryptionConstants.AgentMetadataKey].Contains("Java")));

                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(encryptionDataCopy.WrappedContentKey.KeyId, CancellationToken.None).Result);

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

                // Decrypt the property details set and add it to entity properties.
#if WINDOWS_DESKTOP && !WINDOWS_PHONE
                using (AesCryptoServiceProvider myAes = new AesCryptoServiceProvider())
                {
                    using (SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider())
#else
                using (AesManaged myAes = new AesManaged())
                {
                    using (SHA256Managed sha256 = new SHA256Managed())
#endif
                    {
                        // Here we are correcting for a bug in Java's v1 encryption.
                        // Java v1 constructed the IV as PK + RK + column name.  Other libraries use RK + PK + column name.
                        string IVString   = isJavaV1 ? string.Concat(partitionKey, rowKey, Constants.EncryptionConstants.TableEncryptionPropertyDetails) : string.Concat(rowKey, partitionKey, Constants.EncryptionConstants.TableEncryptionPropertyDetails);
                        byte[] metadataIV = sha256.ComputeHash(CommonUtility.BinaryAppend(encryptionData.ContentEncryptionIV, Encoding.UTF8.GetBytes(IVString)));
                        Array.Resize <byte>(ref metadataIV, 16);
                        myAes.IV  = metadataIV;
                        myAes.Key = contentEncryptionKey;

                        using (ICryptoTransform transform = myAes.CreateDecryptor())
                        {
                            byte[] src = propertyDetailsProperty.BinaryValue;
                            propertyDetailsProperty.BinaryValue = transform.TransformFinalBlock(src, 0, src.Length);
                        }
                    }
                }

                return(contentEncryptionKey);
            }
            catch (JsonException ex)
            {
                throw new StorageException(SR.EncryptionMetadataError, ex)
                      {
                          IsRetryable = false
                      };
            }
            catch (StorageException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new StorageException(SR.DecryptionLogicError, ex)
                      {
                          IsRetryable = false
                      };
            }
        }
Beispiel #16
0
        /// <summary>
        /// Return a decrypted entity. This method is used for decrypting entity properties.
        /// </summary>
        internal Dictionary <string, EntityProperty> DecryptEntity(IDictionary <string, EntityProperty> properties, HashSet <string> encryptedPropertyDetailsSet, string partitionKey, string rowKey, byte[] contentEncryptionKey, EncryptionData encryptionData, bool isJavav1)
        {
            try
            {
                Dictionary <string, EntityProperty> decryptedProperties = new Dictionary <string, EntityProperty>();

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

                            foreach (KeyValuePair <string, EntityProperty> kvp in properties)
                            {
                                if (kvp.Key == Constants.EncryptionConstants.TableEncryptionKeyDetails || kvp.Key == Constants.EncryptionConstants.TableEncryptionPropertyDetails)
                                {
                                    // Do nothing. Do not add to the result properties.
                                }
                                else if (encryptedPropertyDetailsSet.Contains(kvp.Key))
                                {
                                    byte[] columnIV = sha256.ComputeHash(CommonUtility.BinaryAppend(encryptionData.ContentEncryptionIV, Encoding.UTF8.GetBytes(isJavav1 ? string.Concat(partitionKey, rowKey, kvp.Key) : string.Concat(rowKey, partitionKey, kvp.Key))));
                                    Array.Resize <byte>(ref columnIV, 16);
                                    myAes.IV = columnIV;

                                    byte[] src = kvp.Value.BinaryValue;
                                    using (ICryptoTransform transform = myAes.CreateDecryptor())
                                    {
                                        byte[] dest       = transform.TransformFinalBlock(src, 0, src.Length);
                                        string destString = Encoding.UTF8.GetString(dest, 0, dest.Length);
                                        decryptedProperties.Add(kvp.Key, new EntityProperty(destString));
                                    }
                                }
                                else
                                {
                                    decryptedProperties.Add(kvp.Key, kvp.Value);
                                }
                            }
                        }
                    }

                    return(decryptedProperties);

                default:
                    throw new StorageException(SR.InvalidEncryptionAlgorithm, null)
                          {
                              IsRetryable = false
                          };
                }
            }
            catch (JsonException ex)
            {
                throw new StorageException(SR.EncryptionMetadataError, ex)
                      {
                          IsRetryable = false
                      };
            }
            catch (StorageException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new StorageException(SR.DecryptionLogicError, ex)
                      {
                          IsRetryable = false
                      };
            }
        }
Beispiel #17
0
        public static IDictionary <string, EntityProperty> DecryptEntityProperties(
            IDictionary <string, EntityProperty> properties,
            TableRequestOptions options,
            ResourceResponse <Document> response)
        {
            // If encryption policy is set on options, try to decrypt the entity.
            EntityProperty propertyDetailsProperty;
            EntityProperty keyProperty;

            byte[] cek = null;
            string pk  = response.Resource.GetPropertyValue <string>(StellarConstants.PartitionKeyPropertyName);
            string rk  = response.Resource.Id;

            if (properties.TryGetValue(Constants.EncryptionConstants.TableEncryptionPropertyDetails, out propertyDetailsProperty) &&
                properties.TryGetValue(Constants.EncryptionConstants.TableEncryptionKeyDetails, out keyProperty))
            {
                // Decrypt the metadata property value to get the names of encrypted properties.
                EncryptionData encryptionData = null;
                bool           isJavaV1       = false;

                // Convert the base 64 encoded TableEncryptionPropertyDetails string stored in DocumentDB to binary
                propertyDetailsProperty = EntityProperty.CreateEntityPropertyFromObject(propertyDetailsProperty.StringValue, EdmType.Binary);

                cek = options.EncryptionPolicy.DecryptMetadataAndReturnCEK(pk, rk, keyProperty, propertyDetailsProperty, out encryptionData, out isJavaV1);

                byte[]           binaryVal = propertyDetailsProperty.BinaryValue;
                HashSet <string> encryptedPropertyDetailsSet;

                encryptedPropertyDetailsSet = EntityHelpers.ParseEncryptedPropertyDetailsSet(isJavaV1, binaryVal);

                // The encrypted properties are stored in DocumentDB as base 64 encoded strings. Convert them to binary.
                Dictionary <string, EntityProperty> binEncryptedProperties = new Dictionary <string, EntityProperty>();

                foreach (KeyValuePair <string, EntityProperty> kvp in properties)
                {
                    if (encryptedPropertyDetailsSet.Contains(kvp.Key))
                    {
                        EntityProperty binEncryptedProperty = EntityProperty.CreateEntityPropertyFromObject(kvp.Value.StringValue, EdmType.Binary);
                        binEncryptedProperties[kvp.Key] = binEncryptedProperty;
                    }
                }

                foreach (KeyValuePair <string, EntityProperty> kvp in binEncryptedProperties)
                {
                    properties[kvp.Key] = binEncryptedProperties[kvp.Key];
                }

                properties = options.EncryptionPolicy.DecryptEntity(properties, encryptedPropertyDetailsSet, pk, rk, cek, encryptionData, isJavaV1);
            }
            else
            {
                if (options.RequireEncryption.HasValue && options.RequireEncryption.Value)
                {
                    throw new StorageException(SR.EncryptionDataNotPresentError, null)
                          {
                              IsRetryable = false
                          };
                }
            }

            return(properties);
        }
        internal byte[] DecryptMetadataAndReturnCEK(string partitionKey, string rowKey, EntityProperty encryptionKeyProperty, EntityProperty propertyDetailsProperty, out EncryptionData encryptionData)
        {
            // Throw if neither the key nor the resolver are set.
            if (this.Key == null && this.KeyResolver == null)
            {
                throw new StorageException(SR.KeyAndResolverMissingError, null) { IsRetryable = false };
            }

            try
            {
                encryptionData = JsonConvert.DeserializeObject<EncryptionData>(encryptionKeyProperty.StringValue);

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

                // Throw if the encryption protocol on the entity 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 };
                }

                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 = this.KeyResolver.ResolveKeyAsync(encryptionData.WrappedContentKey.KeyId, CancellationToken.None).Result;

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

                // Decrypt the property details set and add it to entity properties.
#if WINDOWS_DESKTOP && !WINDOWS_PHONE
                using (AesCryptoServiceProvider myAes = new AesCryptoServiceProvider())
                {
                    using (SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider())
#else
                using (AesManaged myAes = new AesManaged())
                {
                    using (SHA256Managed sha256 = new SHA256Managed())
#endif
                    {
                        byte[] metadataIV = sha256.ComputeHash(CommonUtility.BinaryAppend(encryptionData.ContentEncryptionIV, Encoding.UTF8.GetBytes(string.Join(partitionKey, rowKey, Constants.EncryptionConstants.TableEncryptionPropertyDetails))));
                        Array.Resize<byte>(ref metadataIV, 16);
                        myAes.IV = metadataIV;
                        myAes.Key = contentEncryptionKey;

                        using (ICryptoTransform transform = myAes.CreateDecryptor())
                        {
                            byte[] src = propertyDetailsProperty.BinaryValue;
                            propertyDetailsProperty.BinaryValue = transform.TransformFinalBlock(src, 0, src.Length);
                        }
                    }
                }

                return contentEncryptionKey;
            }
            catch (JsonException ex)
            {
                throw new StorageException(SR.EncryptionMetadataError, ex) { IsRetryable = false };
            }
            catch (StorageException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new StorageException(SR.DecryptionLogicError, ex) { IsRetryable = false };
            }
        }
Beispiel #19
0
        public NWSDebitTests()
        {
            Address address = new Address {
                Name           = "My STORE",
                StreetAddress1 = "1 MY STREET",
                City           = "MYTOWN",
                PostalCode     = "90210",
                State          = "KY",
                Country        = "USA"
            };

            AcceptorConfig acceptorConfig = new AcceptorConfig {
                Address = address,

                // data code values
                CardDataInputCapability            = CardDataInputCapability.ContactlessEmv_ContactEmv_MagStripe_KeyEntry,
                TerminalOutputCapability           = TerminalOutputCapability.Printing_Display,
                CardHolderAuthenticationCapability = CardHolderAuthenticationCapability.PIN,

                //CardHolderAuthenticationEntity = CardHolderAuthenticationEntity.AuthorizingAgent,
                //OperatingEnvironment = OperatingEnvironment.OnPremises_CardAcceptor_Unattended,

                // hardware software config values
                HardwareLevel = "34",
                SoftwareLevel = "21205710",

                // pos configuration values
                SupportsPartialApproval            = true,
                SupportsShutOffAmount              = true,
                SupportsReturnBalance              = true,
                SupportsDiscoverNetworkReferenceId = true,
                SupportsAvsCnvVoidReferrals        = true
            };

            // gateway config
            NetworkGatewayConfig config = new NetworkGatewayConfig(NetworkGatewayType.NWS)
            {
                ServiceUrl        = "test.txns-c.secureexchange.net",
                PrimaryPort       = 15031,
                SecondaryEndpoint = "test.txns-e.secureexchange.net",
                SecondaryPort     = 15031,
                CompanyId         = "SPSA",
                TerminalId        = "NWSDOTNET01",
                UniqueDeviceId    = "0001",
                AcceptorConfig    = acceptorConfig,
                EnableLogging     = true,
                StanProvider      = StanGenerator.GetInstance(),
                BatchProvider     = BatchProvider.GetInstance()
            };

            ServicesContainer.ConfigureService(config);

            // with merchant type
            config.MerchantType = "5542";
            ServicesContainer.ConfigureService(config, "ICR");

            // forced timeout
            config.ForceGatewayTimeout = true;
            ServicesContainer.ConfigureService(config, "timeout");

            // debit card

            track = new DebitTrackData
            {
                Value          = "4355567063338=2012101HJNw/ewskBgnZqkL",
                PinBlock       = "62968D2481D231E1A504010024A00014",
                EncryptionData = EncryptionData.Version2("/wECAQEEAoFGAgEH4gcOTDT6jRZwb3NAc2VjdXJlZXhjaGFuZ2UubmV0m+/d4SO9TEshhRGUUQzVBrBvP/Os1qFx+6zdQp1ejjUCoDmzoUMbil9UG73zBxxTOy25f3Px0p8joyCh8PEWhADz1BkROJT3q6JnocQE49yYBHuFK0obm5kqUcYPfTY09vPOpmN+wp45gJY9PhkJF5XvPsMlcxX4/JhtCshegz4AYrcU/sFnI+nDwhy295BdOkVN1rn00jwCbRcE900kj3UsFfyc", "2")
            };
        }
        /// <summary>
        /// Return an encrypted entity. This method is used for encrypting entity properties.
        /// </summary>
        internal Dictionary<string, EntityProperty> EncryptEntity(IDictionary<string, EntityProperty> properties, string partitionKey, string rowKey, Func<string, string, string, bool> encryptionResolver)
        {
            CommonUtility.AssertNotNull("properties", properties);

            // The Key should be set on the policy for encryption. Otherwise, throw an error.
            if (this.Key == null)
            {
                throw new InvalidOperationException(SR.KeyMissingError, null);
            }

            EncryptionData encryptionData = new EncryptionData();
            encryptionData.EncryptionAgent = new EncryptionAgent(Constants.EncryptionConstants.EncryptionProtocolV1, EncryptionAlgorithm.AES_CBC_256);
            encryptionData.KeyWrappingMetadata = new Dictionary<string, string>();

            Dictionary<string, EntityProperty> encryptedProperties = new Dictionary<string, EntityProperty>();
            HashSet<string> encryptionPropertyDetailsSet = new HashSet<string>();

#if WINDOWS_DESKTOP && !WINDOWS_PHONE
            using (AesCryptoServiceProvider myAes = new AesCryptoServiceProvider())
            {
                using (SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider())
#else
            using (AesManaged myAes = new AesManaged())
            {
                using (SHA256Managed sha256 = new SHA256Managed())
#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 = this.Key.WrapKeyAsync(myAes.Key, null /* algorithm */, CancellationToken.None).Result;
                    encryptionData.WrappedContentKey = new WrappedKey(this.Key.Kid, wrappedKey.Item1, wrappedKey.Item2);

                    foreach (KeyValuePair<string, EntityProperty> kvp in properties)
                    {
                        if (encryptionResolver != null && encryptionResolver(partitionKey, rowKey, kvp.Key))
                        {
                            // Throw if users try to encrypt null properties. This could happen in the DynamicTableEntity case
                            // where a user adds a new property as follows - ent.Properties.Add("foo2", null);
                            if (kvp.Value == null)
                            {
                                throw new InvalidOperationException(SR.EncryptingNullPropertiesNotAllowed);
                            }

                            kvp.Value.IsEncrypted = true;
                        }

                        // IsEncrypted is set to true when either the EncryptPropertyAttribute is set on a property or when it is 
                        // specified in the encryption resolver or both.
                        if (kvp.Value != null && kvp.Value.IsEncrypted)
                        {
                            // Throw if users try to encrypt non-string properties.
                            if (kvp.Value.PropertyType != EdmType.String)
                            {
                                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.UnsupportedPropertyTypeForEncryption, kvp.Value.PropertyType));
                            }

                            byte[] columnIV = sha256.ComputeHash(CommonUtility.BinaryAppend(encryptionData.ContentEncryptionIV, Encoding.UTF8.GetBytes(string.Join(partitionKey, rowKey, kvp.Key))));
                            Array.Resize<byte>(ref columnIV, 16);
                            myAes.IV = columnIV;

                            using (ICryptoTransform transform = myAes.CreateEncryptor())
                            {
                                // Throw if users try to encrypt null properties. This could happen in the DynamicTableEntity or POCO
                                // case when the property value is null.
                                if (kvp.Value.IsNull)
                                {
                                    throw new InvalidOperationException(SR.EncryptingNullPropertiesNotAllowed);
                                }

                                byte[] src = Encoding.UTF8.GetBytes(kvp.Value.StringValue);
                                byte[] dest = transform.TransformFinalBlock(src, 0, src.Length);

                                // Store the encrypted properties as binary values on the service instead of base 64 encoded strings because strings are stored as a sequence of 
                                // WCHARs thereby further reducing the allowed size by half. During retrieve, it is handled by the response parsers correctly 
                                // even when the service does not return the type for JSON no-metadata.
                                encryptedProperties.Add(kvp.Key, new EntityProperty(dest));
                                encryptionPropertyDetailsSet.Add(kvp.Key);
                            }
                        }
                        else
                        {
                            encryptedProperties.Add(kvp.Key, kvp.Value);
                        }
                    }

                    // Encrypt the property details set and add it to entity properties.
                    byte[] metadataIV = sha256.ComputeHash(CommonUtility.BinaryAppend(encryptionData.ContentEncryptionIV, Encoding.UTF8.GetBytes(string.Join(partitionKey, rowKey, Constants.EncryptionConstants.TableEncryptionPropertyDetails))));
                    Array.Resize<byte>(ref metadataIV, 16);
                    myAes.IV = metadataIV;

                    using (ICryptoTransform transform = myAes.CreateEncryptor())
                    {
                        byte[] src = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(encryptionPropertyDetailsSet));
                        byte[] dest = transform.TransformFinalBlock(src, 0, src.Length);
                        encryptedProperties.Add(Constants.EncryptionConstants.TableEncryptionPropertyDetails, new EntityProperty(dest));
                    }
                }
            }

            // Add the key details to entity properties.
            encryptedProperties.Add(Constants.EncryptionConstants.TableEncryptionKeyDetails, new EntityProperty(JsonConvert.SerializeObject(encryptionData)));
            return encryptedProperties;
        }
Beispiel #21
0
        private static void SetupUserDataEncryptionWithoutDH(EncryptionData encryptionData, ClientPeer peer)
        {
#pragma warning disable 618
            peer.SetupPayloadEncryption(encryptionData.EncryptionSecret);
#pragma warning restore 618
        }