Guía para desarrolladores de Windows Information Protection (WIP)

Una aplicación habilitada diferencia entre los datos corporativos y personales y sabe qué proteger en función de las directivas de Windows Information Protection (WIP) definidas por el administrador.

En esta guía, le mostraremos cómo crear una. Cuando haya terminado, los administradores de directivas podrán confiar en la aplicación para consumir los datos de su organización. Y los empleados estarán encantados de que sus datos personales se mantengan intactos en sus dispositivos, incluso si dejan de formar parte de la administración de dispositivos móviles (MDM) de la organización o si ellos mismos la abandonan.

Nota Esta guía te ayuda a habilitar una aplicación para UWP. Si quieres habilitar una aplicación de escritorio de Windows de C++, consulta Guía para desarrolladores de Windows Information Protection (WIP) (C++).

Puedes leer más sobre WIP y aplicaciones habilitadas aquí: Windows Information Protection (WIP).

Puede encontrar un ejemplo completo aquí.

Si está listo para pasar por cada tarea, empecemos.

En primer lugar, recopile lo que necesita

Necesitará lo siguiente:

  • Una máquina virtual de prueba que ejecuta Windows 10, versión 1607 o posterior. Depurará la aplicación en esta máquina virtual de prueba.

  • Un equipo de desarrollo que ejecuta Windows 10, versión 1607 o posterior. Esta podría ser la máquina virtual de prueba si tiene Visual Studio instalado en ella.

Ha configurado el entorno de desarrollo

Hará lo siguiente:

Instalación del Asistente para desarrolladores de configuración de WIP en la máquina virtual de prueba

Use esta herramienta para configurar una directiva de Windows Information Protection en la máquina virtual de prueba.

Descargue la herramienta aquí: Asistente para desarrolladores de configuración de WIP.

Creación de una directiva de protección

Defina la directiva agregando información a cada sección del asistente para desarrolladores de configuración de WIP. Elija el icono de ayuda situado junto a cualquier configuración para obtener más información sobre cómo usarlo.

Para obtener instrucciones más generales sobre cómo usar esta herramienta, consulte la sección Notas de la versión de la página de descarga de la aplicación.

Configuración de un proyecto de Visual Studio

  1. En el equipo de desarrollo, abra el proyecto.

  2. Agregue una referencia a las extensiones de escritorio y móviles para Plataforma universal de Windows (UWP).

    Agregar extensiones de UWP

  3. Agregue esta funcionalidad al archivo de manifiesto del paquete:

       <rescap:Capability Name="enterpriseDataPolicy"/>
    

    Lectura opcional: el prefijo "rescap" significa funcionalidad restringida. Consulte Funcionalidades especiales y restringidas.

  4. Agregue este espacio de nombres al archivo de manifiesto del paquete:

      xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
    
  5. Agregue el prefijo de espacio de nombres al <ignorableNamespaces> elemento del archivo de manifiesto del paquete.

        <IgnorableNamespaces="uap mp rescap">
    

    De este modo, si la aplicación se ejecuta en una versión del sistema operativo Windows que no admite funcionalidades restringidas, Windows omitirá la enterpriseDataPolicy funcionalidad.

Configuración de la depuración remota

Instale Visual Studio Remote Tools en la máquina virtual de prueba solo si está desarrollando la aplicación en un equipo distinto de la máquina virtual. A continuación, en el equipo de desarrollo, inicie el depurador remoto y compruebe si la aplicación se ejecuta en la máquina virtual de prueba.

Consulta Instrucciones de PC remoto.

Agregue estos espacios de nombres a los archivos de código.

Agregue estas instrucciones using a la parte superior de los archivos de código(Los fragmentos de código de esta guía los usan):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Security.EnterpriseData;
using Windows.Web.Http;
using Windows.Storage.Streams;
using Windows.ApplicationModel.DataTransfer;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml;
using Windows.ApplicationModel.Activation;
using Windows.Web.Http.Filters;
using Windows.Storage;
using Windows.Data.Xml.Dom;
using Windows.Foundation.Metadata;
using Windows.Web.Http.Headers;

Determinar si se deben usar las API de WIP en la aplicación

Asegúrese de que el sistema operativo que ejecuta la aplicación admite WIP y que WIP está habilitado en el dispositivo.

bool use_WIP_APIs = false;

if ((ApiInformation.IsApiContractPresent
    ("Windows.Security.EnterpriseData.EnterpriseDataContract", 3)
    && ProtectionPolicyManager.IsProtectionEnabled))
{
    use_WIP_APIs = true;
}
else
{
    use_WIP_APIs = false;
}

No llame a las API de WIP si el sistema operativo no admite WIP o WIP no está habilitado en el dispositivo.

Leer datos empresariales

Para leer archivos protegidos, puntos de conexión de red, datos y datos del Portapapeles que acepta de un contrato de recurso compartido, la aplicación tendrá que solicitar acceso.

Windows Information Protection concede permiso a la aplicación si la aplicación está en la lista de permitidos de la directiva de protección.

Esta sección:

Leer datos desde un archivo

Paso 1: Obtener el identificador de archivo

    Windows.Storage.StorageFolder storageFolder =
        Windows.Storage.ApplicationData.Current.LocalFolder;

    Windows.Storage.StorageFile file =
        await storageFolder.GetFileAsync(fileName);

Paso 2: Determinar si la aplicación puede abrir el archivo

Llama a FileProtectionManager.GetProtectionInfoAsync para determinar si la aplicación puede abrir el archivo.

FileProtectionInfo protectionInfo = await FileProtectionManager.GetProtectionInfoAsync(file);

if ((protectionInfo.Status != FileProtectionStatus.Protected &&
    protectionInfo.Status != FileProtectionStatus.Unprotected))
{
    return false;
}
else if (protectionInfo.Status == FileProtectionStatus.Revoked)
{
    // Code goes here to handle this situation. Perhaps, show UI
    // saying that the user's data has been revoked.
}

Un valor FileProtectionStatus de Protected significa que el archivo está protegido y la aplicación puede abrirlo porque la aplicación está en la lista de permitidos de la directiva.

Un valor FileProtectionStatus de UnProtected significa que el archivo no está protegido y la aplicación puede abrir el archivo incluso la aplicación no está en la lista de permitidos de la directiva.

API
FileProtectionManager.GetProtectionInfoAsync
FileProtectionInfo
FileProtectionStatus
ProtectionPolicyManager.IsIdentityManaged

Paso 3: Leer el archivo en una secuencia o búfer

Leer el archivo en una secuencia

var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);

Leer el archivo en un búfer

var buffer = await Windows.Storage.FileIO.ReadBufferAsync(file);

Leer datos de un punto de conexión de red

Cree un contexto de subproceso protegido para leer desde un punto de conexión empresarial.

Paso 1: Obtención de la identidad del punto de conexión de red

Uri resourceURI = new Uri("http://contoso.com/stockData.xml");

Windows.Networking.HostName hostName =
    new Windows.Networking.HostName(resourceURI.Host);

string identity = await ProtectionPolicyManager.
    GetPrimaryManagedIdentityForNetworkEndpointAsync(hostName);

Si la directiva no administra el punto de conexión, obtendrá una cadena vacía.

API
ProtectionPolicyManager.GetPrimaryManagedIdentityForNetworkEndpointAsync

Paso 2: Crear un contexto de subproceso protegido

Si la directiva administra el punto de conexión, cree un contexto de subproceso protegido. Esto etiqueta todas las conexiones de red que realice en el mismo subproceso a la identidad.

También proporciona acceso a los recursos de red empresarial administrados por esa directiva.

if (!string.IsNullOrEmpty(identity))
{
    using (ThreadNetworkContext threadNetworkContext =
            ProtectionPolicyManager.CreateCurrentThreadNetworkContext(identity))
    {
        return await GetDataFromNetworkRedirectHelperMethod(resourceURI);
    }
}
else
{
    return await GetDataFromNetworkRedirectHelperMethod(resourceURI);
}

En este ejemplo se encierra las llamadas de socket en un using bloque. Si no lo hace, asegúrese de cerrar el contexto del subproceso después de recuperar el recurso. Consulte ThreadNetworkContext.Close.

No cree ningún archivo personal en ese subproceso protegido porque esos archivos se cifrarán automáticamente.

El método ProtectionPolicyManager.CreateCurrentThreadNetworkContext devuelve un objeto ThreadNetworkContext si la directiva administra o no el punto de conexión. Si la aplicación controla los recursos personales y empresariales, llame a ProtectionPolicyManager.CreateCurrentThreadNetworkContext para todas las identidades. Después de obtener el recurso, elimine ThreadNetworkContext para borrar cualquier etiqueta de identidad del subproceso actual.

API
ProtectionPolicyManager.GetForCurrentView
ProtectionPolicyManager.Identity
ProtectionPolicyManager.CreateCurrentThreadNetworkContext

Paso 3: Leer el recurso en un búfer

private static async Task<IBuffer> GetDataFromNetworkHelperMethod(Uri resourceURI)
{
    HttpClient client;

    client = new HttpClient();

    try { return await client.GetBufferAsync(resourceURI); }

    catch (Exception) { return null; }
}

(Opcional) Usar un token de encabezado en lugar de crear un contexto de subproceso protegido

public static async Task<IBuffer> GetDataFromNetworkbyUsingHeader(Uri resourceURI)
{
    HttpClient client;

    Windows.Networking.HostName hostName =
        new Windows.Networking.HostName(resourceURI.Host);

    string identity = await ProtectionPolicyManager.
        GetPrimaryManagedIdentityForNetworkEndpointAsync(hostName);

    if (!string.IsNullOrEmpty(identity))
    {
        client = new HttpClient();

        HttpRequestHeaderCollection headerCollection = client.DefaultRequestHeaders;

        headerCollection.Add("X-MS-Windows-HttpClient-EnterpriseId", identity);

        return await GetDataFromNetworkbyUsingHeaderHelperMethod(client, resourceURI);
    }
    else
    {
        client = new HttpClient();
        return await GetDataFromNetworkbyUsingHeaderHelperMethod(client, resourceURI);
    }

}

private static async Task<IBuffer> GetDataFromNetworkbyUsingHeaderHelperMethod(HttpClient client, Uri resourceURI)
{

    try { return await client.GetBufferAsync(resourceURI); }

    catch (Exception) { return null; }
}

Controlar redireccionamientos de página

A veces, un servidor web redirigirá el tráfico a una versión más actual de un recurso.

Para controlar esto, realice solicitudes hasta que el estado de respuesta de la solicitud tenga un valor de Aceptar.

A continuación, use el URI de esa respuesta para obtener la identidad del punto de conexión. Esta es una manera de hacerlo:

private static async Task<IBuffer> GetDataFromNetworkRedirectHelperMethod(Uri resourceURI)
{
    HttpClient client = null;

    HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter();
    filter.AllowAutoRedirect = false;

    client = new HttpClient(filter);

    HttpResponseMessage response = null;

        HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, resourceURI);
        response = await client.SendRequestAsync(message);

    if (response.StatusCode == HttpStatusCode.MultipleChoices ||
        response.StatusCode == HttpStatusCode.MovedPermanently ||
        response.StatusCode == HttpStatusCode.Found ||
        response.StatusCode == HttpStatusCode.SeeOther ||
        response.StatusCode == HttpStatusCode.NotModified ||
        response.StatusCode == HttpStatusCode.UseProxy ||
        response.StatusCode == HttpStatusCode.TemporaryRedirect ||
        response.StatusCode == HttpStatusCode.PermanentRedirect)
    {
        message = new HttpRequestMessage(HttpMethod.Get, message.RequestUri);
        response = await client.SendRequestAsync(message);

        try { return await response.Content.ReadAsBufferAsync(); }

        catch (Exception) { return null; }
    }
    else
    {
        try { return await response.Content.ReadAsBufferAsync(); }

        catch (Exception) { return null; }
    }
}

API
ProtectionPolicyManager.GetPrimaryManagedIdentityForNetworkEndpointAsync
ProtectionPolicyManager.CreateCurrentThreadNetworkContext
ProtectionPolicyManager.GetForCurrentView
ProtectionPolicyManager.Identity

Leer datos del Portapapeles

Obtener permiso para usar datos del Portapapeles

Para obtener datos del Portapapeles, pida permiso a Windows. Use DataPackageView.RequestAccessAsync para hacerlo.

public static async Task PasteText(TextBox textBox)
{
    DataPackageView dataPackageView = Clipboard.GetContent();

    if (dataPackageView.Contains(StandardDataFormats.Text))
    {
        ProtectionPolicyEvaluationResult result = await dataPackageView.RequestAccessAsync();

        if (result == ProtectionPolicyEvaluationResult..Allowed)
        {
            string contentsOfClipboard = await dataPackageView.GetTextAsync();
            textBox.Text = contentsOfClipboard;
        }
    }
}

API
DataPackageView.RequestAccessAsync

Ocultar o deshabilitar características que usan datos del Portapapeles

Determine si la vista actual tiene permiso para obtener datos que se encuentra en el Portapapeles.

Si no es así, puede deshabilitar u ocultar controles que permitan a los usuarios pegar información del Portapapeles o obtener una vista previa de su contenido.

private bool IsClipboardAllowedAsync()
{
    ProtectionPolicyEvaluationResult protectionPolicyEvaluationResult = ProtectionPolicyEvaluationResult.Blocked;

    DataPackageView dataPackageView = Clipboard.GetContent();

    if (dataPackageView.Contains(StandardDataFormats.Text))

        protectionPolicyEvaluationResult =
            ProtectionPolicyManager.CheckAccess(dataPackageView.Properties.EnterpriseId,
                ProtectionPolicyManager.GetForCurrentView().Identity);

    return (protectionPolicyEvaluationResult == ProtectionPolicyEvaluationResult.Allowed |
        protectionPolicyEvaluationResult == ProtectionPolicyEvaluationResult.ConsentRequired);
}

API
ProtectionPolicyEvaluationResult
ProtectionPolicyManager.GetForCurrentView
ProtectionPolicyManager.Identity

Impedir que se solicite a los usuarios un cuadro de diálogo de consentimiento

Un nuevo documento no es personal ni empresarial. Es sólo nuevo. Si un usuario pega los datos empresariales en él, Windows aplica la directiva y se le pide al usuario un cuadro de diálogo de consentimiento. Este código impide que esto suceda. Esta tarea no consiste en ayudar a proteger los datos. Es más sobre evitar que los usuarios reciban el cuadro de diálogo de consentimiento en los casos en los que la aplicación crea un nuevo elemento.

private async void PasteText(bool isNewEmptyDocument)
{
    DataPackageView dataPackageView = Clipboard.GetContent();

    if (dataPackageView.Contains(StandardDataFormats.Text))
    {
        if (!string.IsNullOrEmpty(dataPackageView.Properties.EnterpriseId))
        {
            if (isNewEmptyDocument)
            {
                ProtectionPolicyManager.TryApplyProcessUIPolicy(dataPackageView.Properties.EnterpriseId);
                string contentsOfClipboard = contentsOfClipboard = await dataPackageView.GetTextAsync();
                // add this string to the new item or document here.          

            }
            else
            {
                ProtectionPolicyEvaluationResult result = await dataPackageView.RequestAccessAsync();

                if (result == ProtectionPolicyEvaluationResult.Allowed)
                {
                    string contentsOfClipboard = contentsOfClipboard = await dataPackageView.GetTextAsync();
                    // add this string to the new item or document here.
                }
            }
        }
    }
}

API
DataPackageView.RequestAccessAsync
ProtectionPolicyEvaluationResult
ProtectionPolicyManager.TryApplyProcessUIPolicy

Leer datos de un contrato de recurso compartido

Cuando los empleados elijan la aplicación para compartir su información, la aplicación abrirá un nuevo elemento que contiene ese contenido.

Como hemos mencionado anteriormente, un nuevo elemento no es personal ni empresarial. Es sólo nuevo. Si el código agrega contenido empresarial al elemento, Windows aplica la directiva y se solicita al usuario un cuadro de diálogo de consentimiento. Este código impide que esto suceda.

protected override async void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
    bool isNewEmptyDocument = true;
    string identity = "corp.microsoft.com";

    ShareOperation shareOperation = args.ShareOperation;
    if (shareOperation.Data.Contains(StandardDataFormats.Text))
    {
        if (!string.IsNullOrEmpty(shareOperation.Data.Properties.EnterpriseId))
        {
            if (isNewEmptyDocument)
                // If this is a new and empty document, and we're allowed to access
                // the data, then we can avoid popping the consent dialog
                ProtectionPolicyManager.TryApplyProcessUIPolicy(shareOperation.Data.Properties.EnterpriseId);
            else
            {
                // In this case, we can't optimize the workflow, so we just
                // request consent from the user in this case.

                ProtectionPolicyEvaluationResult protectionPolicyEvaluationResult = await shareOperation.Data.RequestAccessAsync();

                if (protectionPolicyEvaluationResult == ProtectionPolicyEvaluationResult.Allowed)
                {
                    string text = await shareOperation.Data.GetTextAsync();

                    // Do something with that text.
                }
            }
        }
        else
        {
            // If the data has no enterprise identity, then we already have access.
            string text = await shareOperation.Data.GetTextAsync();

            // Do something with that text.
        }

    }

}

API
ProtectionPolicyManager.RequestAccessAsync
ProtectionPolicyEvaluationResult
ProtectionPolicyManager.TryApplyProcessUIPolicy

Protección de datos empresariales

Proteja los datos empresariales que abandonan la aplicación. Los datos dejan la aplicación al mostrarla en una página, guardarla en un punto de conexión de red o archivo, o a través de un contrato de recurso compartido.

Esta sección:

Protección de datos que aparecen en páginas

Al mostrar datos en una página, indíquele a Windows qué tipo de datos es (personal o empresarial). Para ello, etiquete la vista de aplicación actual o etiquete todo el proceso de la aplicación.

Al etiquetar la vista o el proceso, Windows aplica la directiva en ella. Esto ayuda a evitar pérdidas de datos resultantes de acciones que la aplicación no controla. Por ejemplo, en un equipo, un usuario podría usar CTRL-V para copiar información empresarial desde una vista y, a continuación, pegar esa información en otra aplicación. Windows protege contra eso. Windows también ayuda a aplicar contratos de recursos compartidos.

Etiquetar la vista de aplicación actual

Haga esto si la aplicación tiene varias vistas en las que algunas vistas consumen datos empresariales y algunos consumen datos personales.


// tag as enterprise data. "identity" the string that contains the enterprise ID.
// You'd get that from a file, network endpoint, or clipboard data package.
ProtectionPolicyManager.GetForCurrentView().Identity = identity;

// tag as personal data.
ProtectionPolicyManager.GetForCurrentView().Identity = String.Empty;

API
ProtectionPolicyManager.GetForCurrentView
ProtectionPolicyManager.Identity

Etiquetar el proceso

Haga esto si todas las vistas de la aplicación funcionarán solo con un tipo de datos (personal o empresarial).

Esto evita que tenga que administrar vistas etiquetadas de forma independiente.



// tag as enterprise data. "identity" the string that contains the enterprise ID.
// You'd get that from a file, network endpoint, or clipboard data package.
bool result =
            ProtectionPolicyManager.TryApplyProcessUIPolicy(identity);

// tag as personal data.
ProtectionPolicyManager.ClearProcessUIPolicy();

API
ProtectionPolicyManager.TryApplyProcessUIPolicy

Protección de datos en un archivo

Cree un archivo protegido y, a continuación, escriba en él.

Paso 1: Determinar si la aplicación puede crear un archivo de empresa

La aplicación puede crear un archivo de empresa si la directiva administra la cadena de identidad y la aplicación se encuentra en la lista permitido de esa directiva.

  if (!ProtectionPolicyManager.IsIdentityManaged(identity)) return false;

API
ProtectionPolicyManager.IsIdentityManaged

Paso 2: Crear el archivo y protegerlo a la identidad

StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
StorageFile storageFile = await storageFolder.CreateFileAsync("sample.txt",
    CreationCollisionOption.ReplaceExisting);

FileProtectionInfo fileProtectionInfo =
    await FileProtectionManager.ProtectAsync(storageFile, identity);

API
FileProtectionManager.ProtectAsync

Paso 3: Escribir esa secuencia o búfer en el archivo

Escritura de una secuencia

    if (fileProtectionInfo.Status == FileProtectionStatus.Protected)
    {
        var stream = await storageFile.OpenAsync(FileAccessMode.ReadWrite);

        using (var outputStream = stream.GetOutputStreamAt(0))
        {
            using (var dataWriter = new DataWriter(outputStream))
            {
                dataWriter.WriteString(enterpriseData);
            }
        }

    }

Escribir un búfer

     if (fileProtectionInfo.Status == FileProtectionStatus.Protected)
     {
         var buffer = Windows.Security.Cryptography.CryptographicBuffer.ConvertStringToBinary(
             enterpriseData, Windows.Security.Cryptography.BinaryStringEncoding.Utf8);

         await FileIO.WriteBufferAsync(storageFile, buffer);

      }

API
FileProtectionInfo
FileProtectionStatus

Protección de datos en un archivo como un proceso en segundo plano

Este código se puede ejecutar mientras la pantalla del dispositivo está bloqueada. Si el administrador configuró una directiva segura de protección de datos bajo bloqueo (DPL), Windows quita las claves de cifrado necesarias para acceder a los recursos protegidos de la memoria del dispositivo. Esto evita pérdidas de datos si se pierde el dispositivo. Esta misma característica también quita las claves asociadas a los archivos protegidos cuando se cierran sus identificadores.

Tendrá que usar un enfoque que mantenga abierto el identificador de archivo al crear un archivo.

Paso 1: Determinar si puede crear un archivo de empresa

Puede crear un archivo de empresa si la identidad que usa está administrada por la directiva y la aplicación se encuentra en la lista de permitidos de esa directiva.

if (!ProtectionPolicyManager.IsIdentityManaged(identity)) return false;

API
ProtectionPolicyManager.IsIdentityManaged

Paso 2: Crear un archivo y protegerlo a la identidad

FileProtectionManager.CreateProtectedAndOpenAsync crea un archivo protegido y mantiene el identificador de archivo abierto mientras se escribe en él.

StorageFolder storageFolder = ApplicationData.Current.LocalFolder;

ProtectedFileCreateResult protectedFileCreateResult =
    await FileProtectionManager.CreateProtectedAndOpenAsync(storageFolder,
        "sample.txt", identity, CreationCollisionOption.ReplaceExisting);

API
FileProtectionManager.CreateProtectedAndOpenAsync

Paso 3: Escribir una secuencia o un búfer en el archivo

En este ejemplo se escribe una secuencia en un archivo.

if (protectedFileCreateResult.ProtectionInfo.Status == FileProtectionStatus.Protected)
{
    IOutputStream outputStream =
        protectedFileCreateResult.Stream.GetOutputStreamAt(0);

    using (DataWriter writer = new DataWriter(outputStream))
    {
        writer.WriteString(enterpriseData);
        await writer.StoreAsync();
        await writer.FlushAsync();
    }

    outputStream.Dispose();
}
else if (protectedFileCreateResult.ProtectionInfo.Status == FileProtectionStatus.AccessSuspended)
{
    // Perform any special processing for the access suspended case.
}

API
ProtectedFileCreateResult.ProtectionInfo
FileProtectionStatus
ProtectedFileCreateResult.Stream

Proteger parte de un archivo

En la mayoría de los casos, es más limpio almacenar datos personales y empresariales por separado, pero puede almacenarlos en el mismo archivo si lo desea. Por ejemplo, Microsoft Outlook puede almacenar correos empresariales junto con correos personales en un único archivo de archivo.

Cifre los datos empresariales, pero no todo el archivo. De este modo, los usuarios pueden seguir usando ese archivo incluso si anulan la inscripción de MDM o sus derechos de acceso a datos empresariales se revocan. Además, la aplicación debe realizar un seguimiento de los datos que cifra para que sepa qué datos proteger cuando lee el archivo en la memoria.

Paso 1: Agregar datos empresariales a un flujo o búfer cifrados

string enterpriseDataString = "<employees><employee><name>Bill</name><social>xxx-xxx-xxxx</social></employee></employees>";

var enterpriseData= Windows.Security.Cryptography.CryptographicBuffer.ConvertStringToBinary(
        enterpriseDataString, Windows.Security.Cryptography.BinaryStringEncoding.Utf8);

BufferProtectUnprotectResult result =
   await DataProtectionManager.ProtectAsync(enterpriseData, identity);

enterpriseData= result.Buffer;

API
DataProtectionManager.ProtectAsync
BufferProtectUnprotectResult.buffer

Paso 2: Agregar datos personales a una secuencia o búfer sin cifrar

string personalDataString = "<recipies><recipe><name>BillsCupCakes</name><cooktime>30</cooktime></recipe></recipies>";

var personalData = Windows.Security.Cryptography.CryptographicBuffer.ConvertStringToBinary(
    personalDataString, Windows.Security.Cryptography.BinaryStringEncoding.Utf8);

Paso 3: Escribir flujos o búferes en un archivo

StorageFolder storageFolder = ApplicationData.Current.LocalFolder;

StorageFile storageFile = await storageFolder.CreateFileAsync("data.xml",
    CreationCollisionOption.ReplaceExisting);

 // Write both buffers to the file and save the file.

var stream = await storageFile.OpenAsync(FileAccessMode.ReadWrite);

using (var outputStream = stream.GetOutputStreamAt(0))
{
    using (var dataWriter = new DataWriter(outputStream))
    {
        dataWriter.WriteBuffer(enterpriseData);
        dataWriter.WriteBuffer(personalData);

        await dataWriter.StoreAsync();
        await outputStream.FlushAsync();
    }
}

Paso 4: Realizar un seguimiento de la ubicación de los datos de la empresa en el archivo

Es responsabilidad de la aplicación realizar un seguimiento de los datos de ese archivo que es propiedad de la empresa.

Puede almacenar esa información en una propiedad asociada al archivo, en una base de datos o en algún texto de encabezado del archivo.

En este ejemplo, se guarda esa información en un archivo XML independiente.

StorageFile metaDataFile = await storageFolder.CreateFileAsync("metadata.xml",
   CreationCollisionOption.ReplaceExisting);

await Windows.Storage.FileIO.WriteTextAsync
    (metaDataFile, "<EnterpriseDataMarker start='0' end='" + enterpriseData.Length.ToString() +
    "'></EnterpriseDataMarker>");

Leer la parte protegida de un archivo

Aquí se muestra cómo leería los datos empresariales fuera de ese archivo.

Paso 1: Obtener la posición de los datos empresariales en el archivo

Windows.Storage.StorageFolder storageFolder =
    Windows.Storage.ApplicationData.Current.LocalFolder;

 Windows.Storage.StorageFile metaDataFile =
   await storageFolder.GetFileAsync("metadata.xml");

string metaData = await Windows.Storage.FileIO.ReadTextAsync(metaDataFile);

XmlDocument doc = new XmlDocument();

doc.LoadXml(metaData);

uint startPosition =
    Convert.ToUInt16((doc.FirstChild.Attributes.GetNamedItem("start")).InnerText);

uint endPosition =
    Convert.ToUInt16((doc.FirstChild.Attributes.GetNamedItem("end")).InnerText);

Paso 2: Abra el archivo de datos y asegúrese de que no está protegido

Windows.Storage.StorageFile dataFile =
    await storageFolder.GetFileAsync("data.xml");

FileProtectionInfo protectionInfo =
    await FileProtectionManager.GetProtectionInfoAsync(dataFile);

if (protectionInfo.Status == FileProtectionStatus.Protected)
    return false;

API
FileProtectionManager.GetProtectionInfoAsync
FileProtectionInfo
FileProtectionStatus

Paso 3: Leer los datos empresariales del archivo

var stream = await dataFile.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);

stream.Seek(startPosition);

Windows.Storage.Streams.Buffer tempBuffer = new Windows.Storage.Streams.Buffer(50000);

IBuffer enterpriseData = await stream.ReadAsync(tempBuffer, endPosition, InputStreamOptions.None);

Paso 4: Descifrar el búfer que contiene datos empresariales

DataProtectionInfo dataProtectionInfo =
   await DataProtectionManager.GetProtectionInfoAsync(enterpriseData);

if (dataProtectionInfo.Status == DataProtectionStatus.Protected)
{
    BufferProtectUnprotectResult result = await DataProtectionManager.UnprotectAsync(enterpriseData);
    enterpriseData = result.Buffer;
}
else if (dataProtectionInfo.Status == DataProtectionStatus.Revoked)
{
    // Code goes here to handle this situation. Perhaps, show UI
    // saying that the user's data has been revoked.
}

API
DataProtectionInfo
DataProtectionManager.GetProtectionInfoAsync

Protección de datos en una carpeta

Puede crear una carpeta y protegerla. De este modo, los elementos que agregue a esa carpeta se protegen automáticamente.

private async Task<bool> CreateANewFolderAndProtectItAsync(string folderName, string identity)
{
    if (!ProtectionPolicyManager.IsIdentityManaged(identity)) return false;

    StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
    StorageFolder newStorageFolder =
        await storageFolder.CreateFolderAsync(folderName);

    FileProtectionInfo fileProtectionInfo =
        await FileProtectionManager.ProtectAsync(newStorageFolder, identity);

    if (fileProtectionInfo.Status != FileProtectionStatus.Protected)
    {
        // Protection failed.
        return false;
    }
    return true;
}

Asegúrese de que la carpeta está vacía antes de protegerla. No se puede proteger una carpeta que ya contiene elementos.

API
ProtectionPolicyManager.IsIdentityManaged
FileProtectionManager.ProtectAsync
FileProtectionInfo.Identity
FileProtectionInfo.Status

Protección de datos en un punto de conexión de red

Cree un contexto de subproceso protegido para enviar esos datos a un punto de conexión empresarial.

Paso 1: Obtención de la identidad del punto de conexión de red

Windows.Networking.HostName hostName =
    new Windows.Networking.HostName(resourceURI.Host);

string identity = await ProtectionPolicyManager.
    GetPrimaryManagedIdentityForNetworkEndpointAsync(hostName);

API
ProtectionPolicyManager.GetPrimaryManagedIdentityForNetworkEndpointAsync

Paso 2: Crear un contexto de subproceso protegido y enviar datos al punto de conexión de red

HttpClient client = null;

if (!string.IsNullOrEmpty(m_EnterpriseId))
{
    ProtectionPolicyManager.GetForCurrentView().Identity = identity;

    using (ThreadNetworkContext threadNetworkContext =
            ProtectionPolicyManager.CreateCurrentThreadNetworkContext(identity))
    {
        client = new HttpClient();
        HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Put, resourceURI);
        message.Content = new HttpStreamContent(dataToWrite);

        HttpResponseMessage response = await client.SendRequestAsync(message);

        if (response.StatusCode == HttpStatusCode.Ok)
            return true;
        else
            return false;
    }
}
else
{
    return false;
}

API
ProtectionPolicyManager.GetForCurrentView
ProtectionPolicyManager.Identity
ProtectionPolicyManager.CreateCurrentThreadNetworkContext

Protección de los datos que comparte la aplicación a través de un contrato de recurso compartido

Si desea que los usuarios compartan contenido desde la aplicación, tendrá que implementar un contrato de recurso compartido y controlar el evento DataTransferManager.DataRequested.

En el controlador de eventos, establezca el contexto de identidad de empresa en el paquete de datos.

private void OnShareSourceOperation(object sender, RoutedEventArgs e)
{
    // Register the current page as a share source (or you could do this earlier in your app).
    DataTransferManager.GetForCurrentView().DataRequested += OnDataRequested;
    DataTransferManager.ShowShareUI();
}

private void OnDataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
    if (!string.IsNullOrEmpty(this.shareSourceContent))
    {
        var protectionPolicyManager = ProtectionPolicyManager.GetForCurrentView();
        DataPackage requestData = args.Request.Data;
        requestData.Properties.Title = this.shareSourceTitle;
        requestData.Properties.EnterpriseId = protectionPolicyManager.Identity;
        requestData.SetText(this.shareSourceContent);
    }
}

API
ProtectionPolicyManager.GetForCurrentView
ProtectionPolicyManager.Identity

Proteger los archivos que se copian en otra ubicación

private async void CopyProtectionFromOneFileToAnother
    (StorageFile sourceStorageFile, StorageFile targetStorageFile)
{
    bool copyResult = await
        FileProtectionManager.CopyProtectionAsync(sourceStorageFile, targetStorageFile);

    if (!copyResult)
    {
        // Copying failed. To diagnose, you could check the file's status.
        // (call FileProtectionManager.GetProtectionInfoAsync and
        // check FileProtectionInfo.Status).
    }
}

API
FileProtectionManager.CopyProtectionAsync

Proteger los datos empresariales cuando la pantalla del dispositivo está bloqueada

Quite todos los datos confidenciales en la memoria cuando el dispositivo esté bloqueado. Cuando el usuario desbloquea el dispositivo, la aplicación puede volver a agregar esos datos de forma segura.

Controla el evento ProtectionPolicyManager.ProtectedAccessSuspending para que la aplicación sepa cuándo está bloqueada la pantalla. Este evento solo se genera si el administrador configura una protección de datos segura bajo la directiva de bloqueo. Windows quita temporalmente las claves de protección de datos que se aprovisionan en el dispositivo. Windows quita estas claves para asegurarse de que no hay acceso no autorizado a los datos cifrados mientras el dispositivo está bloqueado y posiblemente no está en posesión de su propietario.

Controla el evento ProtectionPolicyManager.ProtectedAccessResumed para que tu aplicación sepa cuándo se desbloquea la pantalla. Este evento se genera independientemente de si el administrador configura una protección de datos segura bajo la directiva de bloqueo.

Eliminación de datos confidenciales en la memoria cuando la pantalla está bloqueada

Proteja los datos confidenciales y cierre los flujos de archivos que la aplicación ha abierto en archivos protegidos para ayudar a garantizar que el sistema no almacena en caché ningún dato confidencial en la memoria.

En este ejemplo se guarda el contenido de un bloque de texto en un búfer cifrado y se quita el contenido de ese bloque de texto.

private async void ProtectionPolicyManager_ProtectedAccessSuspending(object sender, ProtectedAccessSuspendingEventArgs e)
{
    Deferral deferral = e.GetDeferral();

    if (ProtectionPolicyManager.GetForCurrentView().Identity != String.Empty)
    {
        IBuffer documentBodyBuffer = CryptographicBuffer.ConvertStringToBinary
           (documentTextBlock.Text, BinaryStringEncoding.Utf8);

        BufferProtectUnprotectResult result = await DataProtectionManager.ProtectAsync
            (documentBodyBuffer, ProtectionPolicyManager.GetForCurrentView().Identity);

        if (result.ProtectionInfo.Status == DataProtectionStatus.Protected)
        {
            this.protectedDocumentBuffer = result.Buffer;
            documentTextBlock.Text = null;
        }
    }

    // Close any open streams that you are actively working with
    // to make sure that we have no unprotected content in memory.

    // Optionally, code goes here to use e.Deadline to determine whether we have more
    // than 15 seconds left before the suspension deadline. If we do then process any
    // messages queued up for sending while we are still able to access them.

    deferral.Complete();
}

API
ProtectionPolicyManager.ProtectedAccessSuspending
ProtectionPolicyManager.GetForCurrentView
ProtectionPolicyManager.Identity
DataProtectionManager.ProtectAsync
BufferProtectUnprotectResult.buffer
ProtectedAccessSuspendingEventArgs.GetDeferral
Deferral.Complete

Agregar datos confidenciales cuando se desbloquea el dispositivo

ProtectionPolicyManager.ProtectedAccessResumed se genera cuando el dispositivo está desbloqueado y las claves están disponibles de nuevo en el dispositivo.

ProtectedAccessResumedEventArgs.Identities es una colección vacía si el administrador no ha configurado una protección de datos segura bajo la directiva de bloqueo.

En este ejemplo se realiza la inversa del ejemplo anterior. Descifra el búfer, agrega información de ese búfer de nuevo al cuadro de texto y, a continuación, elimina el búfer.

private async void ProtectionPolicyManager_ProtectedAccessResumed(object sender, ProtectedAccessResumedEventArgs e)
{
    if (ProtectionPolicyManager.GetForCurrentView().Identity != String.Empty)
    {
        BufferProtectUnprotectResult result = await DataProtectionManager.UnprotectAsync
            (this.protectedDocumentBuffer);

        if (result.ProtectionInfo.Status == DataProtectionStatus.Unprotected)
        {
            // Restore the unprotected version.
            documentTextBlock.Text = CryptographicBuffer.ConvertBinaryToString
                (BinaryStringEncoding.Utf8, result.Buffer);
            this.protectedDocumentBuffer = null;
        }
    }

}

API
ProtectionPolicyManager.ProtectedAccessResumed
ProtectionPolicyManager.GetForCurrentView
ProtectionPolicyManager.Identity
DataProtectionManager.UnprotectAsync
BufferProtectUnprotectResult.Status

Controlar los datos empresariales cuando se revoca el contenido protegido

Si quiere que la aplicación se notifique cuando el dispositivo no esté inscrito desde MDM o cuando el administrador de directivas revoque explícitamente el acceso a los datos empresariales, controle el evento ProtectionPolicyManager_ProtectedContentRevoked.

En este ejemplo se determina si se han revocado los datos de un buzón de correo empresarial para una aplicación de correo electrónico.

private string mailIdentity = "contoso.com";

void MailAppSetup()
{
    ProtectionPolicyManager.ProtectedContentRevoked += ProtectionPolicyManager_ProtectedContentRevoked;
    // Code goes here to set up mailbox for 'mailIdentity'.
}

private void ProtectionPolicyManager_ProtectedContentRevoked(object sender, ProtectedContentRevokedEventArgs e)
{
    if (!new System.Collections.Generic.List<string>(e.Identities).Contains
        (this.mailIdentity))
    {
        // This event is not for our identity.
        return;
    }

    // Code goes here to delete any metadata associated with 'mailIdentity'.
}

API
ProtectionPolicyManager_ProtectedContentRevoked

Ejemplo de Windows Information Protection (WIP)