اسرار رمزنگاری هاردکد شده

دسته OWASP: MASVS-CRYPTO: رمزنگاری

نمای کلی

توسعه دهندگان از رمزنگاری برای محافظت از محرمانه بودن و یکپارچگی داده ها با استفاده از الگوریتم های قوی استفاده می کنند. با این حال، ذخیره‌سازی کلید اغلب کمتر مورد استفاده قرار می‌گیرد، و یافتن آن‌ها در برنامه به‌عنوان یک آرایه رشته یا بایت در کد یا در یک فایل دارایی مانند strings.xml معمول است. اگر اسرار در هر یک از فایل های برنامه فاش شود، این برخلاف اصل کرچوف است و می توان مدل امنیتی را شکسته در نظر گرفت.

تاثیر

مهاجمی که به ابزارهای مهندسی معکوس دسترسی دارد می‌تواند یک راز سخت‌کد شده را به راحتی بازیابی کند. بسته به شرایط، تأثیر ممکن است متفاوت باشد، اما در بسیاری از موارد منجر به مسائل امنیتی عمده، مانند دسترسی به داده‌های حساس می‌شود.

کاهش

برای کاهش این مشکل، زمانی که می‌خواهید اعتبارنامه‌های سراسری سیستم را داشته باشید، از KeyChain API استفاده کنید، یا ارائه‌دهنده Android Keystore به یک برنامه اجازه دهد اعتبار خود را ذخیره کند که فقط خود برنامه می‌تواند به آن دسترسی داشته باشد.

قطعه کد زیر نحوه ذخیره و استفاده از یک کلید متقارن را با استفاده از KeyStore نشان می دهد:

کاتلین

private val ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore"
private val ANDROID_KEY_STORE_ALIAS = "AES_KEY_DEMO"

@Throws(
    KeyStoreException::class,
    NoSuchAlgorithmException::class,
    NoSuchProviderException::class,
    InvalidAlgorithmParameterException::class
)
private fun createAndStoreSecretKey() {
    val builder: KeyGenParameterSpec.Builder = KeyGenParameterSpec.Builder(
        ANDROID_KEY_STORE_ALIAS,
        KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
    )
    val keySpec: KeyGenParameterSpec = builder
        .setKeySize(256)
        .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
        .setRandomizedEncryptionRequired(true)
        .build()
    val aesKeyGenerator: KeyGenerator =
        KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE_PROVIDER)
    aesKeyGenerator.init(keySpec)
    val key: SecretKey = aesKeyGenerator.generateKey()
}

@Throws(
    KeyStoreException::class,
    UnrecoverableEntryException::class,
    NoSuchAlgorithmException::class,
    CertificateException::class,
    IOException::class,
    NoSuchPaddingException::class,
    InvalidKeyException::class,
    IllegalBlockSizeException::class,
    BadPaddingException::class
)
private fun encryptWithKeyStore(plainText: String): ByteArray? {
    // Initialize KeyStore
    val keyStore: KeyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER)
    keyStore.load(null)
    // Retrieve the key with alias androidKeyStoreAlias created before
    val keyEntry: KeyStore.SecretKeyEntry =
        keyStore.getEntry(ANDROID_KEY_STORE_ALIAS, null) as KeyStore.SecretKeyEntry
    val key: SecretKey = keyEntry.secretKey
    // Use the secret key at your convenience
    val cipher: Cipher = Cipher.getInstance("AES/GCM/NoPadding")
    cipher.init(Cipher.ENCRYPT_MODE, key)
    return cipher.doFinal(plainText.toByteArray())
}

جاوا

static private final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
static private final String ANDROID_KEY_STORE_ALIAS = "AES_KEY_DEMO";

private void createAndStoreSecretKey() throws KeyStoreException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
    KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(
        ANDROID_KEY_STORE_ALIAS,
        KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT);
    KeyGenParameterSpec keySpec = builder
        .setKeySize(256)
        .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
        .setRandomizedEncryptionRequired(true)
        .build();
    KeyGenerator aesKeyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE_PROVIDER);
    aesKeyGenerator.init(keySpec);
    SecretKey key = aesKeyGenerator.generateKey();
}

private byte[] encryptWithKeyStore(final String plainText) throws KeyStoreException, UnrecoverableEntryException, NoSuchAlgorithmException, CertificateException, IOException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
    // Initialize KeyStore
    KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
    keyStore.load(null);
    // Retrieve the key with alias ANDROID_KEY_STORE_ALIAS created before
    KeyStore.SecretKeyEntry keyEntry = (KeyStore.SecretKeyEntry) keyStore.getEntry(ANDROID_KEY_STORE_ALIAS, null);
    SecretKey key = keyEntry.getSecretKey();
    // Use the secret key at your convenience
    final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    cipher.init(Cipher.ENCRYPT_MODE, key);
    return cipher.doFinal(plainText.getBytes());
}

منابع