方法: Windows Phone アプリケーションでデータを暗号化する

2012/02/09

このトピックでは、Data Protection API (DPAPI) を使用して、パスワード、接続文字列、PIN などの機密データを Windows Phone アプリケーション内で暗号化および復号化する方法について説明します。

機密データを電話の分離ストレージ内に保存するとセキュリティを確保できません。復号化キーが同じ電話上に存在していると、どれほどキーを隠しても、データを暗号化する効果が得られません。DPAPI は、ユーザー資格情報と電話資格情報を使用してデータを暗号化および復号化することで、暗号化キーを明示的に生成したり保管したりする問題を解決します。Protect および Unprotect メソッドを通じて DPAPI にアクセスするための ProtectedData クラスを使用することができます。データの暗号化には Protect メソッドを使用し、複合化には Unprotect メソッドを使用します。Windows Phone デバイスでアプリケーションを最初に実行する際に復号キーが作成されます。各アプリケーションはそれぞれ独自の復号化キーを持つことになります。ProtectUnprotect を呼び出すと、復号化キーが黙示的に使用され、すべてのデータの機密性が各アプリケーション内に維持されます。キーは、アプリケーションが更新されても同じままです。

暗号化する大量のデータがあり、そのデータが Windows Phone のローカル データベースに保存されている場合、個別のデータを暗号化するのではなく、データベース全体を暗号化します。データベース全体を暗号化するには、Password パラメーターを使用します。詳細については、「Windows Phone のローカル データベース接続文字列」を参照してください。

この手順では、アプリケーションを作成し、Protect メソッドを使用して PIN を暗号化し、分離ストレージに保管し、その後 Unprotect メソッドを使用して復号化します。

Protect メソッドは、暗号化するデータとエントロピー情報をパラメーターとして取ります。エントロピー情報とは、暗号をより複雑化するために指定できる追加のバイト アレイです。複雑さを高める必要がなければ null に設定します。このトピックでは null に設定されています。Protect メソッドを使用するときにエントロピー値を指定する場合は、Unprotect メソッドを使用してデータを複合化するときにも同じ値を使用する必要があります。

Unprotect メソッドは、Protect メソッドを使用して暗号化されたデータと、データ暗号化の際に使用されたエントロピー情報をパラメーターとして取ります。Protect メソッドと Unprotect メソッドで使用されるデータ パラメーターとエントロピー パラメーターは、byte[] 型でなければなりません。

アプリケーションの準備

  1. Visual Studio 2010 Express for Windows Phone で、[ファイル] メニューの [新しいプロジェクト] をクリックして新しいプロジェクトを作成します。

  2. [新しいプロジェクト] ウィンドウが表示されます。Visual C# のテンプレートを展開してから、Silverlight for Windows Phone のテンプレートを選択します。

  3. Windows Phone アプリケーション テンプレートを選択します。[名前] ボックスに選択した名前を入力します。

  4. [OK] をクリックします。[新しい Windows Phone アプリケーション] ウィンドウが表示されます。

  5. [対象の Windows Phone OS バージョン] メニューで、[Windows Phone 7.1] が選択されていることを確認します。

  6. [OK] をクリックします。新しいプロジェクトが作成され、Visual Studio のデザイナー ウィンドウに MainPage.xaml が表示されます。

  7. MainPage.xaml で、LayoutRoot という名前のグリッドを次のコードで置き換えます。このコードにより、PIN を入力するための TextBox コントロールと、PIN を保存および取得するための 2 つのボタンが作成されます。

<!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="Encryption Example" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="PageTitle" Text="app login page" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto" />
                <RowDefinition />
                <RowDefinition Height="auto" />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            
            <TextBlock Grid.Row="0" Text="Pin" Margin="10" />
            <TextBox x:Name="TBPin" Height="75" Width="300" HorizontalAlignment="Left" Margin="83,22,0,44" Grid.Row="1" />
            <Button x:Name="BtnStore" Content="Store" Grid.Row="1" Click="BtnStore_Click" Margin="-6,123,6,58" Grid.RowSpan="3" />
            <Button x:Name="BtnRetrieve" Content="Retrieve" Grid.Row="3" Click="BtnRetrieve_Click" Margin="-6,111,6,72" Grid.RowSpan="2" />
        </Grid>
    </Grid>

PIN を暗号化するには

  1. 次の using ディレクティブを MainPage.xaml.cs ファイルの先頭に追加します。

    using System.IO;
    using System.IO.IsolatedStorage;
    using System.Text;
    using System.Security.Cryptography;
    
    
  2. 以下のコードを MainPage クラスに追加して、プライベート文字列変数を作成します。この変数は、後で PIN を分離ストレージに格納するときに使用します。

    private string FilePath = "pinfile";
    
    
  3. 次のコードを MainPage クラスに追加して、BtnStore_Click イベント ハンドラーを作成します。このコードは、PIN を byte[] に変換し、Protect メソッドを使用して暗号化して、WritePinToFile() プライベート メソッドを使用して分離ストレージに格納します。

    private void BtnStore_Click(object sender, RoutedEventArgs e)
    {
        // Convert the PIN to a byte[].
        byte[] PinByte = Encoding.UTF8.GetBytes(TBPin.Text);
    
        // Encrypt the PIN by using the Protect() method.
        byte[] ProtectedPinByte = ProtectedData.Protect(PinByte, null);
    
        // Store the encrypted PIN in isolated storage.
        this.WritePinToFile(ProtectedPinByte);
    
        TBPin.Text = "";
    
    }
    
    
  4. 次のコードを MainPage クラスに追加し、WritePinToFile() という名前のプライベート メソッドを作成します。このメソッドは、パラメーターとして byte[] 型の暗号化された PIN を受け取ります。その後で、PIN をアプリケーションの分離ストレージ内のファイルに格納します。

    private void WritePinToFile(byte[] pinData)
    {
        // Create a file in the application's isolated storage.
        IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
        IsolatedStorageFileStream writestream = new IsolatedStorageFileStream(FilePath, System.IO.FileMode.Create, System.IO.FileAccess.Write, file);
    
        // Write pinData to the file.
        Stream writer = new StreamWriter(writestream).BaseStream;
        writer.Write(pinData, 0, pinData.Length);
        writer.Close();
        writestream.Close();
    }
    
    

データを復号するには

  1. 次のコードを MainPage クラスに追加して、BtnRetrieve_Click イベント ハンドラーを作成します。このコードは、PIN を分離ストレージから取得し、Unprotect メソッドを使用して復号化し、文字列に変換します。次に、PIN がテキスト ボックスに表示されます。分離ストレージから PIN を取得するプロセスは、ReadPinFromFile() という名前のプライベート メソッド内に実装されます。

    private void BtnRetrieve_Click(object sender, RoutedEventArgs e)
    {
        // Retrieve the PIN from isolated storage.
        byte[] ProtectedPinByte = this.ReadPinFromFile();
    
        // Decrypt the PIN by using the Unprotect method.
        byte[] PinByte = ProtectedData.Unprotect(ProtectedPinByte, null);
    
        // Convert the PIN from byte to string and display it in the text box.
        TBPin.Text = Encoding.UTF8.GetString(PinByte, 0, PinByte.Length);
    
    }
    
    
  2. 次のコードを MainPage クラスに追加し、ReadPinFromFile() という名前のプライベート メソッドを作成します。このメソッドは、WritePinToFile() メソッドで作成されたファイルにアクセスし、そのファイルから PIN を読み取ります。

    private byte[] ReadPinFromFile()
    {
        // Access the file in the application's isolated storage.
        IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
        IsolatedStorageFileStream readstream = new IsolatedStorageFileStream(FilePath, System.IO.FileMode.Open, FileAccess.Read, file);
    
        // Read the PIN from the file.
        Stream reader =  new StreamReader(readstream).BaseStream;
        byte[] pinArray = new byte[reader.Length];
    
        reader.Read(pinArray, 0, pinArray.Length);
        reader.Close();
        readstream.Close();
    
        return pinArray;
    }
    
    

表示: