はじめに
2015年の夏、セキュリティコードの開発者は、ロシアの法律で認められた標準に準拠した暗号化を備えたAndroid用の安全なストレージを実装するという課題に直面しました。 その前に、タブレットには既にAndroidソースが存在するソリューションがありました。 これにより、GOST 89をサポートする更新されたカーネル暗号化(dm-crypt)をリリースし、GOSTライブラリを/ system / libに追加し、voldデーモンのcryptofsサブシステムにパッチを適用できました。 その結果、特定のタブレットモデルにのみ適したソリューションであり、普遍的ではありませんでした。 Androidバージョン4.4(APIレベル19)で、カスタムDocumentsProviderを登録および実装した後にデータにアクセスできるAPIが表示されたことを学習した後、モデルに依存しないこのAPIを使用してユーザー空間でGOST暗号化を使用するソリューションを作成することにしましたデバイス。
興味がある人のために-猫へようこそ。
Androidでのデータの暗号化方法
Androidデバイスの暗号化プロセスについて簡単に説明します。 暗号化は次のように有効化されます。設定→セキュリティ→タブレット/電話の暗号化、Linuxカーネルを使用して実装→dev-mapper→dm-crypt。 この機能を有効にすると、デバイスはパスワードを要求し、データの保存と暗号化を要求します(または、ユーザーの要求に応じてすべてのデータを単に削除します)。 デバイスを再起動すると、パスワード入力ウィンドウが表示され、システム設定で変数ro.crypto.stateが暗号化されます。
Androidの標準パーティション暗号化は、FDE(フルディスク暗号化)モデルに基づいています。 このモデルは、Linuxカーネルの通常のサブシステム-デバイスマッパーであり、透過的な暗号化を提供します。 データへのアクセス(/データセクションなど)は、仮想ブロックデバイス/ dev / block / dm-0を介して提供されます。各io-requestは、IVから計算される128ビットセクターキーでAES-CBCモードで暗号化または復号化します(初期化ベクトル)。
図 1:Android暗号化ロジック
この図は、キーコンテナからのPin要求のシーケンスと、syscall ioctlを介したdm-cryptコアへのマスターキーのインストールを示しています。
アクセスフレームワーク(SAF)
java-spaceでアプリケーションを使用するには、ストレージアクセスフレームワーク(SAF)またはストレージアクセスプラットフォームを使用します。 developer.android.comでは、このプラットフォームを使用するすべての機能とニュアンスが詳細に説明されていますが、ここでは主なポイントのみを強調します。
そのため、SAFはAndroidバージョン4.4(APIレベル19)に登場し、ユーザーがすべてのサプライヤのリポジトリでドキュメント、画像、その他のファイルを簡単に見つけて開くことができるようになりました。 DocumentsProviderクラスを実装し、そのメソッドのいくつかを使用することで、これらのファイルのサプライヤになることができます(これについては以下で詳しく説明します)。
SAFプラットフォーム全体は、次の要素で構成されています。
1)「クライアント」-ファイルにアクセスするか、新しいファイルを作成するアプリケーション。 Androidシステム全体では、それぞれACTION_OPEN_DOCUMENTフラグとACTION_CREATE_DOCUMENTフラグを持つインテントを使用してこれが可能です。
2)「ドキュメントプロバイダー」-上記のように、DocumentsProviderクラスのサブクラスであり、APIを介してファイルへのアクセスを実装するアプリケーション(これについては後で説明します)。
3)「選択の要素」-検索基準を満たすすべてのサプライヤーのファイルへのアクセスをユーザーに提供するシステムユーザーインターフェイス。
より詳細に。 ドキュメントプロバイダーは、ドキュメントツリーを走査するための開始点となる1つ以上のルートディレクトリを提供します。 各ルートディレクトリには一意の識別子COLUMN_ROOT_IDがあり、ルートレベル以下のコンテンツを表すドキュメント(ディレクトリ)を指します。 ルートディレクトリは動的に設計されており、さまざまなユースケースのサポートを提供します。複数のアカウント、USBドライブ上の一時ストレージ、システム/システムの開始/終了機能。
各ストレージサーバーは、一意の識別子COLUMN_DOCUMENT_IDを使用してそれらを参照する個別のファイルとディレクトリを表示します(この場合、これはファイルシステムのルートからファイル自体へのフルパスです)。 ドキュメント識別子は、デバイスの再起動に依存しない定数URIを発行するために使用されるため、一意であり、割り当て後に変更されない必要があります。
ドキュメントは、開くファイル(特定のMIMEタイプ)または他のドキュメントを含むディレクトリ(MIMEタイプMIME_TYPE_DIR)です。 各ドキュメントには、FLAG_SUPPORTS_WRITE、FLAG_SUPPORTS_DELETE、FLAG_SUPPORTS_THUMBNAILなどのCOLUMN_FLAGSフラグで記述される異なるプロパティを設定できます。
図 2:ドキュメントプロバイダーデータモデル
ドキュメントプロバイダーのデータモデルは、従来のファイル階層に基づいています。 ただし、データを保存する物理的な方法は、DocumentsProvider APIを介してアクセスできる場合、開発者の裁量に任されています。 たとえば、データにタグベースのクラウドストレージを使用できます。
次の図に注意してください。
図 3:ドキュメントプロバイダーとクライアント間の相互作用のモデル
SAFプラットフォームでは、サプライヤと顧客は直接対話しません。 クライアントは、ファイルと対話する(ファイルを読み取る、編集する、作成する、または削除する)許可を要求します。
アプリケーション(この例では写真の処理)がACTION_OPEN_DOCUMENTまたはACTION_CREATE_DOCUMENTのインテントをアクティブにすると、対話が始まります。 インテントには、たとえば「MIMEタイプのイメージを含むオープン可能なファイルを提供する」などの基準を絞り込むためのフィルターが含まれる場合があります。
意図がトリガーされると、選択のシステム要素は登録された各プロバイダーに移動し、リクエストに対応するコンテンツを持つルートディレクトリをユーザーに表示します。 selection要素は、ドキュメントプロバイダーが大きく異なる場合でも、ユーザーに標準インターフェイスを提供します。
Androidバージョン4.3以前では、別のアプリケーションからファイルを受信するアプリケーションは、ACTION_PICKやACTION_GET_CONTENTなどのインテントをアクティブにする必要があります。 その後、ユーザーはアプリケーションの1つを選択する必要があり、ユーザーがファイルを選択して受信できるインターフェイスをユーザーに提供する必要があります。
図 4:ドキュメントプロバイダーの選択ダイアログ
図 5:文書受信者選択ダイアログ
ドキュメントプロバイダーとして登録する
独自のドキュメントプロバイダーを開発する次の手順は、抽象クラスDocumentsProviderをサブクラス化することです。 少なくとも、次のメソッドを実装する必要があります。
queryRoots()
queryChildDocuments()
queryDocument()
Opendocument()
これらのメソッドの実装は厳密に必要ですが、完全に機能するアプリケーションを実装するには、他のアプリケーションを実装する必要があります。 詳細は、DocumentsProviderクラスの説明に記載されています。
ジニ
次の論理部分は、SAF実装とFATFS組み込みシステム用のオープンファイルシステムライブラリの間のレイヤーのJNI実装です。 後者は、ブロックごとにファイル(この場合はボリュームとして機能する)に読み書きするようにパッチされています。 したがって、IO要求の場合、セクター番号とセクター数を取得します。ここからIVとセクターキーを計算し、ファイルの特定のブロックを暗号化および復号化できます。 その結果、ユーザー空間でdm-cryptの類似物を取得します。
図 6:ネイティブ部分へのSAFメソッドの転送、またはその逆
次に、ボリュームとファイルを操作するメソッドを実装しました。 ボリュームを操作するには、次の機能を使用します。
Java_com_securitycode_fatfslib_FatFs_createVolume(...);
ファイルシステムライブラリを介してボリュームファイルを作成し、このファイル内に空の暗号化されたFSを作成します。
図 7:セキュアストアの作成
Java_com_securitycode_fatfslib_FatFs_getVolumeFreeSpace(...);
特定のボリュームを関数に渡すと、このボリュームの空き容量が取得されます。
Java_com_securitycode_fatfslib_FatFs_mount(...);
ボリュームをマウントするときに、FSブロックの暗号化と復号化が発生するマスターキーを設定します。
図8:セキュアストアのマウント
Java_com_securitycode_fatfslib_FatFs_unMount(...);
リソースを削除し、I / Oを完了します。
ファイルを操作するには:
Java_com_securitycode_fatfslib_FatFs_createFile(...);
空のファイルオブジェクトが、指定されたサイズとタイプ(SAFに必要)でファイルシステムに作成されます。
Java_com_securitycode_fatfslib_FatFs_getFile(...);
この関数は、SAF queryDocument(...)メソッドに必要です。
この関数では、ファイルID、そのタイプ、現在のファイルとファイル名を含むルートノードを返します。
Java_com_securitycode_fatfslib_FatFs_readFile(...);
この関数では、Javaストリームが作成され、SAFで使用され、URIとしてコンシューマに渡されます。
Java_com_securitycode_fatfslib_FatFs_writeFile(...);
前の関数と同様に、この場合のみコンシューマーになります。
図9:アプリケーション一般画面
図10:ストレージコンテンツ
おわりに
上記のすべてのアクションの結果として、ユーザー空間でGOST暗号化と電子署名をサポートする暗号化ディスクを取得しました。
ご質問にお答えし、プロジェクトのすべての段階について詳細をお知らせいたします。
ソース:
1)ニコライ・エレンコフ。 Androidセキュリティ内部、第10章:デバイスセキュリティ。
2)Androidのドライブ暗号化
source.android.com/security/encryption
3)ドキュメントプロバイダーとSAF
developer.android.com/intl/en/guide/topics/providers/document-provider.html
4)FatFs-汎用FATファイルシステムモジュール
elm-chan.org/fsw/ff/00index_e.html