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());
}