android

 

Android 公開鍵暗号方式と共通鍵暗号方式を使った暗号化・復号化

公開鍵暗号方式

  • 暗号化に公開鍵、復号に秘密鍵を使う暗号方式
  • アプリ側では公開鍵を保持してデータの暗号化のみを行い、復号を異なる安全な場所(サーバーなど)で秘密鍵によって行うような用途には公開鍵暗号を使う
  • SharedPreferncesを自前で暗号化する時などにAndroid KeyStoreを使った実装がこちらに該当する

共通鍵暗号方式

  • 暗号化や復号する際、同じキー(共通鍵)を使う暗号方式

暗号方式の比較

出典:https://www.jssec.org/dl/android_securecoding_20191201/5_how_to_use_security_functions.html#%E6%9A%97%E5%8F%B7%E6%96%B9%E5%BC%8F%E3%81%AE%E9%81%B8%E6%8A%9E

Android Keystoreを用いた公開鍵暗号方式での暗号化・復号化

@Singleton
class KeyStore @Inject constructor() {
    private var keyStore: KeyStore = KeyStore.getInstance(KEY_PROVIDER)

    init {
        keyStore.load(null)
        if (!keyStore.containsAlias(kEY_STORE_ALIAS)) {
            val keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, KEY_PROVIDER)
            keyPairGenerator.initialize(
                KeyGenParameterSpec.Builder(
                    kEY_STORE_ALIAS,
                    KeyProperties.PURPOSE_DECRYPT
                )
                    .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
                    .build()
            )
            keyPairGenerator.generateKeyPair()
        }
    }

    fun encrypt(value: String): String {
        return try {
            val publicKey = keyStore.getCertificate(kEY_STORE_ALIAS)?.publicKey
            val cipher = Cipher.getInstance(TRANSFORMATION)

            cipher.init(Cipher.ENCRYPT_MODE, publicKey)
            Base64.encodeToString(cipher.doFinal(value.toByteArray(Charsets.UTF_8)), Base64.NO_WRAP)
        } catch (e: GeneralSecurityException) {
            ""
        }
    }

    fun decrypt(value: String): String {
        return try {
            val privateKey = keyStore.getKey(kEY_STORE_ALIAS, null)
            val cipher = Cipher.getInstance(TRANSFORMATION)
            val decoded = Base64.decode(value, Base64.NO_WRAP)

            cipher.init(Cipher.DECRYPT_MODE, privateKey)
            cipher.doFinal(decoded).toString(Charsets.UTF_8)
        } catch (e: GeneralSecurityException) {
            ""
        }
    }

    companion object {
        private const val KEY_PROVIDER = "AndroidKeyStore"
        private const val kEY_STORE_ALIAS = "operation-check-alias"
        private const val TRANSFORMATION = "RSA/ECB/PKCS1Padding"
    }
}

共通鍵暗号方式を使った暗号化・復号化

@Singleton
class EncryptionWithPreSharedKey @Inject constructor() {
    private var mIV: ByteArray? = null

    // TODO EncryptedValueやPreSharedKeyのような値オブジェクトを作った方が良い
    fun encrypt(
        value: String,
        key: String,
    ): String {
        var encrypted: ByteArray? = null
        val cipher = Cipher.getInstance(TRANSFORMATION)

        val secretKey = generateKey(key.toByteArray(Charsets.UTF_8))
        if (secretKey != null) {
            try {
                cipher.init(Cipher.ENCRYPT_MODE, secretKey)
                mIV = cipher.iv
                encrypted = cipher.doFinal(value.toByteArray(Charsets.UTF_8))
            } catch (e: Exception) {
                Log.d("EncryptionWithPreSharedKey encrypt", "$e")
            }
        }

        return Base64.encode(encrypted, Base64.NO_WRAP).toString(Charsets.UTF_8)
    }

    fun decrypt(
        value: String,
        key: String,
    ): String {
        var decrypted: ByteArray? = null

        try {
            val cipher = Cipher.getInstance(TRANSFORMATION)
            val secretKey = generateKey(key.toByteArray(Charsets.UTF_8))
            if (secretKey != null) {
                val ivParameterSpec = IvParameterSpec(mIV)
                cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec)
                val decodedValue = Base64.decode(value.toByteArray(), Base64.NO_WRAP)
                decrypted = cipher.doFinal(decodedValue)
            }
        } catch (e: Exception) {
            Log.d("EncryptionWithPreSharedKey decrypt", "$e")
        }
        return decrypted?.toString(Charsets.UTF_8) ?: ""
    }

    private fun generateKey(key: ByteArray): SecretKey? {
        var secretKey: SecretKey? = null
        try {
            secretKey = SecretKeySpec(key, KEY_ALGORITHM)
        } catch (e: IllegalArgumentException) {
            Log.d("EncryptionWithPreSharedKey generateKey", "$e")
        }
        return secretKey
    }

    companion object {
        private const val TRANSFORMATION = "AES/CBC/PKCS7Padding"
        private const val KEY_ALGORITHM = "AES"
    }
}

ハッシュアルゴリズムとソルト前のページ

関連記事

  1. android

    ハッシュアルゴリズムとソルト

    ハッシュについて元データに対して後述するアルゴリズムを使って、単体で…

  2. android

    Android SharedPreferencesの確認方法

    androidアプリでデータを永続化する時に使うSharedPrefe…

  3. android

    Android SharedPreferencesの種類

    Key-Valueペアの読み書きを行う時の候補です。SharedP…

  4. android

    【最短!】パッケージ名の変更方法

    どうも、フリーランスエンジニアのyoshikiです。&…

コメント

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

  1. LINE Bot

    【LINE Bot 作り方】GASでLINE Botを作るための準備
  2. android

    Android SharedPreferencesの種類
  3. android

    Android 公開鍵暗号方式と共通鍵暗号方式を使った暗号化・復号化
  4. android

    Android SharedPreferencesの確認方法
  5. android

    【最短!】パッケージ名の変更方法
PAGE TOP