このドキュメントでは、Android の暗号機能の適切な使用方法について説明し、その使用例を示します。アプリの鍵のセキュリティを強化する必要がある場合は、Android Keystore システムを使用します。
Android Keystore システムでのみプロバイダを指定する
Android Keystore システムを使用している場合は、必ずプロバイダを指定してください。
ただしその他の状況では、Android が特定のアルゴリズムに対して特定のプロバイダを保証することはありません。Android Keystore システムを使用せずにプロバイダを指定すると、将来のリリースで互換性の問題が発生する可能性があります。
推奨アルゴリズムを選択する
使用するアルゴリズムを自由に選択できる場合(サードパーティのシステムとの互換性を必要としない場合など)は、次のアルゴリズムを使用することをおすすめします。
クラス | おすすめ |
---|---|
Cipher | 256 ビット鍵を使用する CBC モードまたは GCM モードの AES(AES/GCM/NoPadding など) |
MessageDigest | SHA-2 ファミリー(SHA-256 など) |
Mac | SHA-2 ファミリー HMAC(HMACSHA256 など) |
Signature | ECDSA を使用する SHA-2 ファミリー(SHA256withECDSA など) |
暗号に関する一般的な操作を実行する
次のセクションには、アプリで暗号に関する一般的な操作を行う方法を示すスニペットを記載しています。
メッセージを暗号化する
Kotlin
val plaintext: ByteArray = ... val keygen = KeyGenerator.getInstance("AES") keygen.init(256) val key: SecretKey = keygen.generateKey() val cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING") cipher.init(Cipher.ENCRYPT_MODE, key) val ciphertext: ByteArray = cipher.doFinal(plaintext) val iv: ByteArray = cipher.iv
Java
byte[] plaintext = ...; KeyGenerator keygen = KeyGenerator.getInstance("AES"); keygen.init(256); SecretKey key = keygen.generateKey(); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] ciphertext = cipher.doFinal(plaintext); byte[] iv = cipher.getIV();
メッセージのダイジェストを生成する
Kotlin
val message: ByteArray = ... val md = MessageDigest.getInstance("SHA-256") val digest: ByteArray = md.digest(message)
Java
byte[] message = ...; MessageDigest md = MessageDigest.getInstance("SHA-256"); byte[] digest = md.digest(message);
デジタル署名を生成する
署名鍵を格納する PrivateKey
オブジェクトが必要です。この鍵は、実行時に生成してアプリにバンドルされたファイルから読み取るか、必要に応じて他のソースから取得できます。
Kotlin
val message: ByteArray = ... val key: PrivateKey = ... val s = Signature.getInstance("SHA256withECDSA") .apply { initSign(key) update(message) } val signature: ByteArray = s.sign()
Java
byte[] message = ...; PrivateKey key = ...; Signature s = Signature.getInstance("SHA256withECDSA"); s.initSign(key); s.update(message); byte[] signature = s.sign();
デジタル署名を確認する
署名者の公開鍵を格納する PublicKey
オブジェクトが必要です。この公開鍵は、アプリにバンドルされたファイルから読み取るか、証明書から抽出する、または必要に応じて他のソースから取得できます。
Kotlin
val message: ByteArray = ... val signature: ByteArray = ... val key: PublicKey = ... val s = Signature.getInstance("SHA256withECDSA") .apply { initVerify(key) update(message) } val valid: Boolean = s.verify(signature)
Java
byte[] message = ...; byte[] signature = ...; PublicKey key = ...; Signature s = Signature.getInstance("SHA256withECDSA"); s.initVerify(key); s.update(message); boolean valid = s.verify(signature);
実装の複雑性
Android での暗号化の実装には、不自然に見えても互換性の問題から行われたものが細部に存在します。このセクションでは、発生する可能性が高い問題について説明します。
OAEP MGF1 メッセージ ダイジェスト
RSA OAEP 暗号は、「main」ダイジェストと MGF1 ダイジェストの 2 つの異なるダイジェストでパラメータ化されます。Cipher.getInstance("RSA/ECB/OAEPwithSHA-256andMGF1Padding")
などのダイジェスト名を含む Cipher
識別子があり、メインのダイジェストを指定し、MGF1 ダイジェストを指定しないようにしています。Android Keystore では SHA-1 が MGF1 ダイジェストに使用され、他の Android 暗号プロバイダでは 2 つのダイジェストは同じものです。
アプリで使用するダイジェストの制御を強化するには、Cipher.getInstance("RSA/ECB/OAEPPadding")
などの OAEPPadding を使用して暗号をリクエストし、OAEPParameterSpec
を init()
に渡して両方のダイジェストを明示的に選択するようにします。これを次のコードで示します。
Kotlin
val key: Key = ... val cipher = Cipher.getInstance("RSA/ECB/OAEPPadding") .apply { // To use SHA-256 the main digest and SHA-1 as the MGF1 digest init(Cipher.ENCRYPT_MODE, key, OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT)) // To use SHA-256 for both digests init(Cipher.ENCRYPT_MODE, key, OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT)) }
Java
Key key = ...; Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding"); // To use SHA-256 the main digest and SHA-1 as the MGF1 digest cipher.init(Cipher.ENCRYPT_MODE, key, new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT)); // To use SHA-256 for both digests cipher.init(Cipher.ENCRYPT_MODE, key, new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
非推奨となった機能
以下のセクションでは、非推奨となった機能について説明しています。アプリで使用しないでください。
Bouncy Castle アルゴリズム
多くのアルゴリズムにおいて、Bouncy Castle の実装は非推奨になりました。 これは、Bouncy Castle プロバイダを明示的にリクエストする場合にのみ影響します。以下に例を示します。
Kotlin
Cipher.getInstance("AES/CBC/PKCS7PADDING", "BC") // OR Cipher.getInstance("AES/CBC/PKCS7PADDING", Security.getProvider("BC"))
Java
Cipher.getInstance("AES/CBC/PKCS7PADDING", "BC"); // OR Cipher.getInstance("AES/CBC/PKCS7PADDING", Security.getProvider("BC"));
Android Keystore システムでのみプロバイダを指定することに関するセクションで説明したように、特定のプロバイダをリクエストすることは推奨されません。ガイドラインに従っていただければ、この非推奨化に伴う影響はありません。
初期化ベクトルを持たないパスワード ベースの暗号化に使用する暗号
初期化ベクトル(IV)を必要とするパスワード ベースの暗号化(PBE)に使用する暗号は、適切に構成された鍵、または明示的に渡された IV から取得できます。IV を持たず、IV が明示されていない PBE 鍵を渡す場合、Android の PBE 暗号はその時点で、IV がゼロであるとみなします。
PBE 暗号を使用する場合は、次のコード スニペットに示すように、常に明示的な IV を渡します。
Kotlin
val key: SecretKey = ... val cipher = Cipher.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC") val iv = ByteArray(16) SecureRandom().nextBytes(iv) cipher.init(Cipher.ENCRYPT_MODE, key, IvParameterSpec(iv))
Java
SecretKey key = ...; Cipher cipher = Cipher.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC"); byte[] iv = new byte[16]; new SecureRandom().nextBytes(iv); cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
暗号化プロバイダ
Android 9(API レベル 28)現在では、Crypto Java Cryptography Architecture(JCA)プロバイダは削除されています。アプリが次のメソッドを呼び出すなど、暗号化プロバイダのインスタンスをリクエストした場合、NoSuchProviderException
が発生します。
Kotlin
SecureRandom.getInstance("SHA1PRNG", "Crypto")
Java
SecureRandom.getInstance("SHA1PRNG", "Crypto");
Jetpack Security Crypto ライブラリ
Jetpack Security Crypto ライブラリは非推奨になりました。これは、アプリ モジュールの build.gradle
ファイルに次の依存関係がある場合にのみ影響します。
Groovy
dependencies { implementation "androidx.security:security-crypto:1.0.0" }
Kotlin
dependencies { implementation("androidx.security:security-crypto:1.0.0") }
サポートされているアルゴリズム
Android でサポートされている JCA アルゴリズムの識別子は以下のとおりです。
AlgorithmParameterGenerator
AlgorithmParameters
CertPathBuilder
CertPathValidator
CertStore
CertificateFactory
Cipher
KeyAgreement
KeyFactory
KeyGenerator
KeyManagerFactory
KeyPairGenerator
KeyStore
Mac
MessageDigest
SSLContext
SSLEngine.Supported
SSLSocket.Supported
SecretKeyFactory
SecureRandom
Signature
TrustManagerFactory