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

    Android SharedPreferencesの種類

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

  2. android

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

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

  3. android

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

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

  4. android

    Android SharedPreferencesの確認方法

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

コメント

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

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

  1. android

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

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

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

    ハッシュアルゴリズムとソルト
  5. LINE Bot

    【誰でもできる!】自分用LINE BOTの作り方
PAGE TOP