Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/sdk 4214/Encryption v2 #719

Merged
merged 79 commits into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
a195d02
task(SDK-4206) - Adds AES-GCM crypt class
Anush-Shand Dec 18, 2024
4b494d4
feat(SDK-4214): fixes conflict in cherry pick
Anush-Shand Dec 19, 2024
0b233b6
chore(SDK-4214): adds arg names and when instead of if else
CTLalit Dec 26, 2024
f7583df
feat(SDK-4214): sanitises code
CTLalit Dec 26, 2024
2207291
feat(SDK-4214): replaces trim with substring
CTLalit Dec 26, 2024
aff0d53
chore(SDK-4214): code readability.
CTLalit Dec 26, 2024
38ae018
feat(SDK-4214): Simplifies encryption logic
CTLalit Dec 27, 2024
c049136
task(SDK-4214) - Adds logic for encryption migration based on new app…
Anush-Shand Dec 30, 2024
991d27c
task(SDK-4214) - Fixes migrationStep
Anush-Shand Dec 30, 2024
a6d26eb
task(SDK-4214) - Fixes migrationStep for InApp data
Anush-Shand Dec 30, 2024
2d0628b
task(SDK-4214) - Cleanup and readability
Anush-Shand Dec 30, 2024
6e3f12f
task(SDK-4214) - Cleanup and formatting
Anush-Shand Dec 30, 2024
ac38ef2
task(SDK-4214) - Improves readability
Anush-Shand Dec 30, 2024
d8a9f6f
task(SDK-4214) - More syntactic sugar
Anush-Shand Dec 30, 2024
1a91c44
task(SDK-4214) - Makes prefix and postfix more complex to make it les…
Anush-Shand Dec 30, 2024
18ca5e3
task(SDK-4214) - Adds logic for saving data if AES -> plaintext passe…
Anush-Shand Dec 30, 2024
bab4cbb
task(SDK-4214) - Addresses comments
Anush-Shand Dec 30, 2024
cd76103
task(SDK-4214) - Adds support for API 21 and 22
Anush-Shand Dec 30, 2024
d58f5a8
task(SDK-4206) - Adds AES-GCM crypt class
Anush-Shand Dec 18, 2024
1a5ba2c
feat(SDK-4214): fixes conflict in cherry pick
Anush-Shand Dec 19, 2024
c39e449
chore(SDK-4214): adds arg names and when instead of if else
CTLalit Dec 26, 2024
1ef433a
feat(SDK-4214): sanitises code
CTLalit Dec 26, 2024
301c7d1
feat(SDK-4214): replaces trim with substring
CTLalit Dec 26, 2024
ef8961c
chore(SDK-4214): code readability.
CTLalit Dec 26, 2024
b967d51
feat(SDK-4214): Simplifies encryption logic
CTLalit Dec 27, 2024
e6ebd3f
task(SDK-4214) - Adds logic for encryption migration based on new app…
Anush-Shand Dec 30, 2024
931265c
task(SDK-4214) - Fixes migrationStep
Anush-Shand Dec 30, 2024
16ff5dc
task(SDK-4214) - Fixes migrationStep for InApp data
Anush-Shand Dec 30, 2024
2e7235d
task(SDK-4214) - Cleanup and readability
Anush-Shand Dec 30, 2024
ccf969e
task(SDK-4214) - Cleanup and formatting
Anush-Shand Dec 30, 2024
4927e76
task(SDK-4214) - Improves readability
Anush-Shand Dec 30, 2024
3478caf
task(SDK-4214) - More syntactic sugar
Anush-Shand Dec 30, 2024
51b5331
task(SDK-4214) - Makes prefix and postfix more complex to make it les…
Anush-Shand Dec 30, 2024
e716536
task(SDK-4214) - Adds logic for saving data if AES -> plaintext passe…
Anush-Shand Dec 30, 2024
be361df
task(SDK-4214) - Addresses comments
Anush-Shand Dec 30, 2024
2573cd8
task(SDK-4214) - Adds support for API 21 and 22
Anush-Shand Dec 30, 2024
e16ea55
Merge remote-tracking branch 'origin/feat/SDK-4214/trunk' into feat/S…
Anush-Shand Dec 31, 2024
e862c45
feat(SDK-4214): Fixes compilation error
CTLalit Dec 31, 2024
b7b0a78
Merge remote-tracking branch 'origin/feat/SDK-4214/trunk' into feat/S…
Anush-Shand Dec 31, 2024
6cc98c7
task(SDK-4214) - Migrates to new format for cgk
Anush-Shand Jan 1, 2025
ecfbea0
task(SDK-4214) - Injects cryptHandler as necessary
Anush-Shand Jan 2, 2025
4bf92db
task(SDK-4214) - Prevents unnecessary calls to store cachedGUIDSKey i…
Anush-Shand Jan 2, 2025
b41446e
task(SDK-4214) - Prevents passing null to .decrypt()
Anush-Shand Jan 2, 2025
be91902
task(SDK-4214) - Adds algo to .decrypt()
Anush-Shand Jan 2, 2025
b3deee2
task(SDK-4214) - Adds algo to .decrypt()
Anush-Shand Jan 2, 2025
7477c44
task(SDK-4214) - Adds algo to .encrypt()
Anush-Shand Jan 2, 2025
9ba9df9
task(SDK-4214) - Reduces number of calls to .decrypt
Anush-Shand Jan 2, 2025
543b345
feat/SDK-4215/Refactoring to make Crypt feature testable
CTLalit Jan 3, 2025
3009ed6
task(SDK-4214) - Removes logic from enum class and adds to a function
Anush-Shand Jan 3, 2025
eaf271a
task(SDK-4214) - Adds todo
Anush-Shand Jan 3, 2025
9a5998f
task(SDK-4214) - Refactors LoginInfoProvider round1
Anush-Shand Jan 3, 2025
e6e870e
task(SDK-4214) - Adds a common check for isTextEncrypted()
Anush-Shand Jan 3, 2025
7a5c859
task(SDK-4214) - Adds comments
Anush-Shand Jan 3, 2025
708aa82
task(SDK-4214) - Makes migrationresult internal
Anush-Shand Jan 3, 2025
ddfff07
task(SDK-4214) - Improves comments
Anush-Shand Jan 3, 2025
ffe0de7
task(SDK-4214) - Improves comments
Anush-Shand Jan 3, 2025
ea5c228
task(SDK-4214) - Fixes migration logic, firstUpgrade should always run
Anush-Shand Jan 3, 2025
ceb5fcc
task(SDK-4214) - Adds a log to indicate no migration needed
Anush-Shand Jan 3, 2025
a30ca08
feat(SDK-4214): bubbles up crypt factory
CTLalit Jan 3, 2025
33ac099
feat(SDK-4214): makes classes internal
CTLalit Jan 3, 2025
57e0897
test(SDK-4215): fixes compilation errors in tests
CTLalit Jan 3, 2025
6ce7d10
test(SDK-4215): fixes login controller test
CTLalit Jan 3, 2025
75abc45
Merge branch 'develop' into feat/SDK-4214/trunk
Anush-Shand Jan 3, 2025
95b5b0f
task(SDK-4214) - Fixes an issue where migration was shortcircuited be…
Anush-Shand Jan 3, 2025
8855892
test(SDK-4215): fixes crypthandler test
CTLalit Jan 5, 2025
8c78871
task(SDK-4214) - Fixes an issue where migration from AES failed but o…
Anush-Shand Jan 5, 2025
9e1b7d4
Merge remote-tracking branch 'origin/feat/SDK-4214/trunk' into feat/S…
Anush-Shand Jan 5, 2025
e7653f9
feat(SDK-4215): moves pref code to repo layer
CTLalit Jan 6, 2025
3ebe726
feat(SDK-4215): moves repo out of main thread + cleanup
CTLalit Jan 6, 2025
227caa2
feat(SDK-4215): removes try catch from migration steps
CTLalit Jan 6, 2025
8b90180
feat(SDK-4215): removes try catch from migration steps 2
CTLalit Jan 6, 2025
cebf9fc
chore(SDK-4215): adds space
CTLalit Jan 6, 2025
2125890
task(SDK-4214) - Fixes an issue where IV was 16 bytes instead of 12 f…
Anush-Shand Jan 6, 2025
21f295b
task(SDK-4214) - Deletes the data if it can't be decrypted from AES
Anush-Shand Jan 6, 2025
59d7f61
test(SDK-4215): fixes test clevertapapitest
CTLalit Jan 6, 2025
7b0c461
task(SDK-4214) - Fixes logs
Anush-Shand Jan 6, 2025
b899f6f
tests(SDK-4214) - Fixes LoginInfoProviderTest
Anush-Shand Jan 6, 2025
502b3f9
tests(SDK-4214) - Fixes LoginInfoProviderTest and ignores other
Anush-Shand Jan 6, 2025
3d45ab4
task(SDK-4214) - Fixes log
Anush-Shand Jan 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.clevertap.android.sdk
import android.content.Context
import com.clevertap.android.sdk.CTPreferenceCache.Companion.getInstance
import com.clevertap.android.sdk.StoreProvider.Companion.getInstance
import com.clevertap.android.sdk.cryption.CryptFactory
import com.clevertap.android.sdk.cryption.CryptHandler
import com.clevertap.android.sdk.cryption.CryptMigrator
import com.clevertap.android.sdk.cryption.CryptRepository
Expand Down Expand Up @@ -94,11 +95,15 @@ internal object CleverTapFactory {
context = context,
accountId = config.accountId
)
val cryptFactory = CryptFactory(
context = context,
accountId = config.accountId
)
val cryptHandler = CryptHandler(
encryptionLevel = fromInt(value = config.encryptionLevel),
accountID = config.accountId,
context = context,
repository = repository
repository = repository,
cryptFactory = cryptFactory
)
val dataMigrationRepository = DataMigrationRepository(
context = context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,13 @@ import javax.crypto.spec.SecretKeySpec
/**
* This class implements the AES Cryption algorithm
*/
class AESCrypt(val accountID: String) : Crypt() {
class AESCrypt(accountID: String) : Crypt() {
/**
* This method returns the key-password to be used for encryption/decryption
*
* @return key-password
*/
private fun generateKeyPassword(): String {
return APP_ID_KEY_PREFIX + accountID + APP_ID_KEY_SUFFIX
}
private val keyPassword: String = APP_ID_KEY_PREFIX + accountID + APP_ID_KEY_SUFFIX

/**
* This method is used internally to encrypt the plain text
Expand All @@ -32,9 +30,9 @@ class AESCrypt(val accountID: String) : Crypt() {
*/
override fun encryptInternal(plainText: String): String? {
return performCryptOperation(
Cipher.ENCRYPT_MODE, generateKeyPassword(), plainText.toByteArray(
StandardCharsets.UTF_8
)
mode = Cipher.ENCRYPT_MODE,
password = keyPassword,
text = plainText.toByteArray(StandardCharsets.UTF_8)
)?.let { encryptedBytes ->
encryptedBytes.contentToString()
}
Expand All @@ -49,7 +47,11 @@ class AESCrypt(val accountID: String) : Crypt() {
*/
override fun decryptInternal(cipherText: String): String? {
return parseCipherText(cipherText)?.let { bytes ->
performCryptOperation(Cipher.DECRYPT_MODE, generateKeyPassword(), bytes)
performCryptOperation(
mode = Cipher.DECRYPT_MODE,
password = keyPassword,
text = bytes
)
}?.let { decryptedBytes ->
String(decryptedBytes, StandardCharsets.UTF_8)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,28 @@ class AESGCMCrypt(private val context: Context) : Crypt() {
}
}

private data class AESGCMCryptResult(val iv: ByteArray, val encryptedBytes: ByteArray)
private data class AESGCMCryptResult(
val iv: ByteArray,
val encryptedBytes: ByteArray
) {
override fun equals(other: Any?): Boolean {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these ever used?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already auto generated by data class. Is there any difference?

if (this === other) return true
if (javaClass != other?.javaClass) return false

other as AESGCMCryptResult

if (!iv.contentEquals(other.iv)) return false
if (!encryptedBytes.contentEquals(other.encryptedBytes)) return false

return true
}

override fun hashCode(): Int {
var result = iv.contentHashCode()
result = 31 * result + encryptedBytes.contentHashCode()
return result
}
}

// Utility extension functions for Base64 encoding/decoding
private fun ByteArray.toBase64(): String = Base64.encodeToString(this, Base64.NO_WRAP)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
package com.clevertap.android.sdk.cryption

import android.content.Context
import com.clevertap.android.sdk.cryption.CryptHandler.EncryptionAlgorithm

/**
* This class is a factory class to generate a Crypt object based on the EncryptionAlgorithm
*/
class CryptFactory {
internal class CryptFactory(
private val context: Context,
private val accountId: String
) {

// Cache to hold instances of Crypt for different encryption algorithms.
private val cryptInstances: MutableMap<EncryptionAlgorithm, Crypt> = mutableMapOf()

companion object {
@JvmStatic
fun getCrypt(type: CryptHandler.EncryptionAlgorithm, accountID: String, context: Context): Crypt {
fun getCrypt(type: EncryptionAlgorithm, accountID: String, context: Context): Crypt {
return when (type) {
CryptHandler.EncryptionAlgorithm.AES -> AESCrypt(accountID)
CryptHandler.EncryptionAlgorithm.AES_GCM -> AESGCMCrypt(context)
EncryptionAlgorithm.AES -> AESCrypt(accountID)
EncryptionAlgorithm.AES_GCM -> AESGCMCrypt(context)
}
}
}

/**
* Retrieves or creates a Crypt instance for the specified algorithm.
*
* @param algorithm - The encryption algorithm to use.
* @return The Crypt instance for the specified algorithm.
*/
fun getCryptInstance(algorithm: EncryptionAlgorithm): Crypt {
return cryptInstances.getOrPut(algorithm) { getCrypt(algorithm, accountId, context) }
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.clevertap.android.sdk.cryption

import android.content.Context
import com.clevertap.android.sdk.Constants
import com.clevertap.android.sdk.Constants.AES_GCM_SUFFIX
import com.clevertap.android.sdk.Constants.AES_GCM_PREFIX
Expand All @@ -13,16 +12,13 @@ import com.clevertap.android.sdk.Constants.AES_PREFIX
* @param encryptionLevel - The encryption level to use.
* @param accountID - The account ID for which the cryptographic operations are performed.
*/
class CryptHandler(
internal class CryptHandler constructor(
private val encryptionLevel: EncryptionLevel,
private val accountID: String,
private val context: Context,
private val repository: CryptRepository
private val repository: CryptRepository,
private val cryptFactory: CryptFactory
) {

// Cache to hold instances of Crypt for different encryption algorithms.
private val cryptInstances: MutableMap<EncryptionAlgorithm, Crypt> = mutableMapOf()

/**
* Supported encryption algorithms.
*/
Expand All @@ -45,19 +41,22 @@ class CryptHandler(
algorithm: EncryptionAlgorithm = EncryptionAlgorithm.AES_GCM
): String? {

if(isTextEncrypted(plainText))
if (isTextEncrypted(plainText)) {
return plainText
}

// Use AES_GCM algorithm by default.
val crypt = getCryptInstance(algorithm)
val crypt = cryptFactory.getCryptInstance(algorithm)
when (encryptionLevel) {
EncryptionLevel.MEDIUM -> {
// Encrypt only if the key is valid
if (key in Constants.MEDIUM_CRYPT_KEYS) {
return crypt.encryptInternal(plainText)
}
}
else -> return plainText
else -> {
return plainText
}
}
return plainText
}
Expand All @@ -80,7 +79,7 @@ class CryptHandler(
return cipherText
}

val crypt = getCryptInstance(algorithm)
val crypt = cryptFactory.getCryptInstance(algorithm)
when (encryptionLevel) {
EncryptionLevel.MEDIUM -> {
// Decrypt only if the key is valid.
Expand All @@ -101,8 +100,11 @@ class CryptHandler(
* @param plainText - The text to encrypt.
* @return The encrypted text, or null if encryption fails.
*/
fun encrypt(plainText: String, algorithm: EncryptionAlgorithm = EncryptionAlgorithm.AES_GCM): String? {
val crypt = getCryptInstance(algorithm)
fun encrypt(
plainText: String,
algorithm: EncryptionAlgorithm = EncryptionAlgorithm.AES_GCM
): String? {
val crypt = cryptFactory.getCryptInstance(algorithm)
return crypt.encryptInternal(plainText)
}

Expand All @@ -113,21 +115,14 @@ class CryptHandler(
* @return The decrypted text, or null if decryption fails.
*/
@JvmOverloads
fun decrypt(cipherText: String, algorithm: EncryptionAlgorithm = EncryptionAlgorithm.AES_GCM): String? {
val crypt = getCryptInstance(algorithm)
fun decrypt(
cipherText: String,
algorithm: EncryptionAlgorithm = EncryptionAlgorithm.AES_GCM
): String? {
val crypt = cryptFactory.getCryptInstance(algorithm)
return crypt.decryptInternal(cipherText)
}

/**
* Retrieves or creates a Crypt instance for the specified algorithm.
*
* @param algorithm - The encryption algorithm to use.
* @return The Crypt instance for the specified algorithm.
*/
private fun getCryptInstance(algorithm: EncryptionAlgorithm): Crypt {
return cryptInstances.getOrPut(algorithm) { CryptFactory.getCrypt(algorithm, accountID, context) }
}

/**
* Updates the encryption state in case of failure while processing new data.
*
Expand Down