Skip to content

Commit dfe35ac

Browse files
authored
Merge pull request #16 from contentpass/CHORE-handle-missing-key
Handle corrupt or missing key
2 parents a373f2e + a00f62c commit dfe35ac

File tree

3 files changed

+42
-28
lines changed

3 files changed

+42
-28
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
Our SDK is available on Maven Central.
1515

1616
```groovy
17-
implementation 'de.contentpass:contentpass-android:2.2.5'
17+
implementation 'de.contentpass:contentpass-android:2.2.6'
1818
```
1919

2020
Add this to your app's `build.gradle` file's `dependencies` element.

lib/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ kapt {
5858
extra.apply{
5959
set("PUBLISH_GROUP_ID", "de.contentpass")
6060
set("PUBLISH_ARTIFACT_ID", "contentpass-android")
61-
set("PUBLISH_VERSION", "2.2.5")
61+
set("PUBLISH_VERSION", "2.2.6")
6262
}
6363

6464
apply("${rootProject.projectDir}/scripts/publish-module.gradle")

lib/src/main/java/de/contentpass/lib/KeyStore.kt

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
package de.contentpass.lib
22

33
import android.content.Context
4-
import android.security.KeyPairGeneratorSpec
5-
import java.math.BigInteger
4+
import android.security.keystore.KeyGenParameterSpec
5+
import android.security.keystore.KeyProperties
66
import java.security.KeyPair
77
import java.security.KeyPairGenerator
88
import java.security.PrivateKey
99
import java.security.PublicKey
1010
import java.security.spec.MGF1ParameterSpec
11-
import java.util.Calendar
1211
import javax.crypto.Cipher
1312
import javax.crypto.KeyGenerator
1413
import javax.crypto.SecretKey
1514
import javax.crypto.spec.OAEPParameterSpec
1615
import javax.crypto.spec.PSource
1716
import javax.crypto.spec.SecretKeySpec
18-
import javax.security.auth.x500.X500Principal
1917
import java.security.KeyStore as VendorKeyStore
2018

2119
internal class KeyStore(private val context: Context, private val propertyId: String) {
@@ -58,38 +56,50 @@ internal class KeyStore(private val context: Context, private val propertyId: St
5856
}
5957

6058
private fun createKeyPair(): KeyPair {
61-
val spec = buildKeyPairGeneratorSpec()
62-
val generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore")
63-
generator.initialize(spec)
59+
val spec = buildKeyGenParameterSpec()
60+
val generator = KeyPairGenerator.getInstance(
61+
KeyProperties.KEY_ALGORITHM_RSA,
62+
"AndroidKeyStore"
63+
)
64+
generator.initialize(spec as java.security.spec.AlgorithmParameterSpec)
6465

6566
return generator.generateKeyPair()
6667
}
6768

68-
private fun buildKeyPairGeneratorSpec(): KeyPairGeneratorSpec {
69-
val start = Calendar.getInstance()
70-
val end = Calendar.getInstance()
71-
end.add(Calendar.YEAR, 1)
72-
73-
return KeyPairGeneratorSpec.Builder(context)
74-
.setAlias(keyPairAlias)
75-
.setSubject(X500Principal("CN=Sample Name, O=Android Authority"))
76-
.setSerialNumber(BigInteger.ONE)
77-
.setStartDate(start.time)
78-
.setEndDate(end.time)
69+
private fun buildKeyGenParameterSpec(): KeyGenParameterSpec {
70+
return KeyGenParameterSpec.Builder(
71+
keyPairAlias,
72+
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
73+
)
74+
.setKeySize(2048)
75+
.setDigests(KeyProperties.DIGEST_SHA256)
76+
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
7977
.build()
8078
}
8179

8280
private fun retrieveKey(): SecretKey? {
83-
return sharedPreferences.getString(sharedPreferencesKey, null)?.let {
84-
val encrypted = it.decoded()
85-
return decryptKey(encrypted)
81+
return sharedPreferences.getString(sharedPreferencesKey, null)?.let { encryptedString ->
82+
try {
83+
val encrypted = encryptedString.decoded()
84+
decryptKey(encrypted)
85+
} catch (e: Exception) {
86+
// If decryption fails, the stored key might be corrupted
87+
// Return null to trigger key regeneration
88+
null
89+
}
8690
}
8791
}
8892

8993
private fun decryptKey(encryptedKey: ByteArray): SecretKey {
90-
cipher.init(Cipher.DECRYPT_MODE, privateKey, paddingSpec)
91-
val decrypted = cipher.doFinal(encryptedKey)
92-
return SecretKeySpec(decrypted, "AES")
94+
try {
95+
cipher.init(Cipher.DECRYPT_MODE, privateKey, paddingSpec)
96+
val decrypted = cipher.doFinal(encryptedKey)
97+
return SecretKeySpec(decrypted, "AES")
98+
} catch (e: javax.crypto.IllegalBlockSizeException) {
99+
// If decryption fails due to block size issues, try to regenerate the key
100+
// by deleting the corrupted entry and creating a new one
101+
throw IllegalStateException("Failed to decrypt stored key. Key may be corrupted.", e)
102+
}
93103
}
94104

95105
private fun createKey(): SecretKey {
@@ -110,8 +120,12 @@ internal class KeyStore(private val context: Context, private val propertyId: St
110120
}
111121

112122
private fun encryptKey(key: SecretKey): ByteArray {
113-
cipher.init(Cipher.ENCRYPT_MODE, publicKey, paddingSpec)
114-
return cipher.doFinal(key.encoded)
123+
try {
124+
cipher.init(Cipher.ENCRYPT_MODE, publicKey, paddingSpec)
125+
return cipher.doFinal(key.encoded)
126+
} catch (e: javax.crypto.IllegalBlockSizeException) {
127+
throw IllegalStateException("Failed to encrypt key. Key size may be incompatible.", e)
128+
}
115129
}
116130
}
117131

0 commit comments

Comments
 (0)