Skip to content

Commit

Permalink
Merge pull request #145 from stytchauth/jordan/SDK-1585-fix-pkce-random
Browse files Browse the repository at this point in the history
SDK-1585 Use SecureRandom instead of Random for PKCE code challenges
  • Loading branch information
jhaven-stytch authored Apr 12, 2024
2 parents b10e1d0 + 19c7ec7 commit 091ae50
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 35 deletions.
2 changes: 1 addition & 1 deletion sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ plugins {

ext {
PUBLISH_GROUP_ID = 'com.stytch.sdk'
PUBLISH_VERSION = '0.20.4'
PUBLISH_VERSION = '0.20.5'
PUBLISH_ARTIFACT_ID = 'sdk'
}

Expand Down
78 changes: 44 additions & 34 deletions sdk/src/main/java/com/stytch/sdk/common/EncryptionManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import com.stytch.sdk.common.extensions.toHexString
import java.security.InvalidKeyException
import java.security.MessageDigest
import java.security.SecureRandom
import kotlin.random.Random
import org.bouncycastle.crypto.Signer
import org.bouncycastle.crypto.generators.Ed25519KeyPairGenerator
import org.bouncycastle.crypto.params.Ed25519KeyGenerationParameters
Expand All @@ -28,7 +27,6 @@ import org.bouncycastle.crypto.signers.Ed25519Signer

@Suppress("TooManyFunctions")
internal object EncryptionManager {

private const val PREF_FILE_NAME = "stytch_secured_pref"
private const val MASTER_KEY_URI = "android-keystore://stytch_master_key"
private var keysetManager: AndroidKeysetManager? = null
Expand All @@ -39,7 +37,10 @@ internal object EncryptionManager {
SignatureConfig.register()
}

private fun getOrGenerateNewAES256KeysetManager(context: Context, keyAlias: String): AndroidKeysetManager {
private fun getOrGenerateNewAES256KeysetManager(
context: Context,
keyAlias: String,
): AndroidKeysetManager {
return try {
AndroidKeysetManager.Builder()
.withSharedPref(context, keyAlias, PREF_FILE_NAME)
Expand Down Expand Up @@ -93,15 +94,18 @@ internal object EncryptionManager {
/**
* @throws Exception - if failed to generate keys
*/
fun createNewKeys(context: Context, rsaKeyAlias: String) {
fun createNewKeys(
context: Context,
rsaKeyAlias: String,
) {
val ksm = getOrGenerateNewAES256KeysetManager(context, rsaKeyAlias)
keysetManager = ksm
aead = ksm.keysetHandle.getPrimitive(Aead::class.java)
}

fun generateCodeChallenge(): String {
val randomGenerator = Random(System.currentTimeMillis())
val randomBytes: ByteArray = randomGenerator.nextBytes(Constants.CODE_CHALLENGE_BYTE_COUNT)
val randomBytes = ByteArray(Constants.CODE_CHALLENGE_BYTE_COUNT)
SecureRandom().nextBytes(randomBytes)
return randomBytes.toHexString()
}

Expand All @@ -128,34 +132,40 @@ internal object EncryptionManager {

fun isKeysetUsingKeystore(): Boolean = keysetManager?.isUsingKeystore == true

fun generateEd25519KeyPair(): Pair<String, String> = try {
val gen = Ed25519KeyPairGenerator()
gen.init(Ed25519KeyGenerationParameters(SecureRandom()))
val keyPair = gen.generateKeyPair()
val publicKey = keyPair.public as Ed25519PublicKeyParameters
val privateKey = keyPair.private as Ed25519PrivateKeyParameters
Pair(publicKey.encoded.toBase64EncodedString(), privateKey.encoded.toBase64EncodedString())
} catch (e: Exception) {
throw StytchMissingPublicKeyError(e)
}
fun generateEd25519KeyPair(): Pair<String, String> =
try {
val gen = Ed25519KeyPairGenerator()
gen.init(Ed25519KeyGenerationParameters(SecureRandom()))
val keyPair = gen.generateKeyPair()
val publicKey = keyPair.public as Ed25519PublicKeyParameters
val privateKey = keyPair.private as Ed25519PrivateKeyParameters
Pair(publicKey.encoded.toBase64EncodedString(), privateKey.encoded.toBase64EncodedString())
} catch (e: Exception) {
throw StytchMissingPublicKeyError(e)
}

fun signEd25519Challenge(challengeString: String, privateKeyString: String): String = try {
val signer: Signer = Ed25519Signer()
val challenge = challengeString.toBase64DecodedByteArray()
val privateKey = Ed25519PrivateKeyParameters(privateKeyString.toBase64DecodedByteArray())
signer.init(true, privateKey)
signer.update(challenge, 0, challenge.size)
val signature: ByteArray = signer.generateSignature()
signature.toBase64EncodedString()
} catch (e: Exception) {
throw StytchChallengeSigningFailed(e)
}
fun signEd25519Challenge(
challengeString: String,
privateKeyString: String,
): String =
try {
val signer: Signer = Ed25519Signer()
val challenge = challengeString.toBase64DecodedByteArray()
val privateKey = Ed25519PrivateKeyParameters(privateKeyString.toBase64DecodedByteArray())
signer.init(true, privateKey)
signer.update(challenge, 0, challenge.size)
val signature: ByteArray = signer.generateSignature()
signature.toBase64EncodedString()
} catch (e: Exception) {
throw StytchChallengeSigningFailed(e)
}

fun deriveEd25519PublicKeyFromPrivateKeyBytes(privateKeyBytes: ByteArray): String = try {
val privateKeyRebuild = Ed25519PrivateKeyParameters(privateKeyBytes, 0)
val publicKeyRebuild = privateKeyRebuild.generatePublicKey()
publicKeyRebuild.encoded.toBase64EncodedString()
} catch (e: Exception) {
throw StytchMissingPublicKeyError(e)
}
fun deriveEd25519PublicKeyFromPrivateKeyBytes(privateKeyBytes: ByteArray): String =
try {
val privateKeyRebuild = Ed25519PrivateKeyParameters(privateKeyBytes, 0)
val publicKeyRebuild = privateKeyRebuild.generatePublicKey()
publicKeyRebuild.encoded.toBase64EncodedString()
} catch (e: Exception) {
throw StytchMissingPublicKeyError(e)
}
}

0 comments on commit 091ae50

Please sign in to comment.