Skip to content

Webcrypto Polyfill package#23

Open
jaredperreault-okta wants to merge 17 commits intojp-react-native-sdkfrom
jp-rn-webcrypto
Open

Webcrypto Polyfill package#23
jaredperreault-okta wants to merge 17 commits intojp-react-native-sdkfrom
jp-rn-webcrypto

Conversation

@jaredperreault-okta
Copy link
Copy Markdown
Contributor

@jaredperreault-okta jaredperreault-okta commented Mar 21, 2026

Initial Setup of @okta/react-native-platform
MVP Impl of @okta/react-native-webcrypto-bridge

@jaredperreault-okta jaredperreault-okta marked this pull request as ready for review March 26, 2026 20:25
return
}

val key = if (keyType == "public") keyPair.public else keyPair.private
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I don't see where keyPair is defined. Not sure if this will compile or just crash when this method is called.

AlexNachbaur and others added 2 commits April 2, 2026 11:41
…rectness, and architecture improvements

Critical fixes:
- Fix Android exportKey compilation error (undefined keyPair variable)
- Fix Android importKey type mismatch (KeyPair vs KeyPairEntry)
- Fix iOS silent failure in getRandomValues (now calls fatalError on CSPRNG failure)
- Fix iOS importKey key size calculation (derive from modulus, not DER blob)
- Fix iOS ASN.1 DER parsing with proper length decoding (replaces hardcoded offsets)
- Fix iOS hardcoded exponent with parsed value from key data

Security & safety:
- Eliminate all force-unwrap (as!) casts in iOS via typed KeyEntry struct
- Add synchronized blocks to all Android keyStore accesses for thread safety
- Add key usage validation in JS verify() to match WebCrypto spec
- JS getRandomValues validates returned length matches requested length

Architecture:
- Migrate bridge serialization from number[]/[NSNumber]/ReadableArray to Base64 strings
  across all layers (iOS, Android, TypeScript spec, JS polyfill), reducing serialization
  overhead from ~400% to ~33%
- Extract iOS RSA DER parsing/construction into standalone RSAKeyUtils.swift for testability
- Replace Android hand-rolled X.509 DER construction (~60 lines) with platform RSAPublicKeySpec
- Remove dead code (getCryptoAlg), fix typos, clean up unused parameters

Infrastructure:
- Fix Jest config (testMatch pattern, setupFiles path, test import paths)
- Add unit tests for digest, getRandomValues, importKey, verify, and polyfill installation
- Update mocks to match Base64 bridge interface
- Remove private:true flag, remove nonexistent ./cpp from files array
- Update Android SDK defaults to 35
Harden native crypto bridge with security, correctness, and architecture improvements
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I think the structure is incorrect. It should be under "android/src/main/..." I only see android/main

Copy link
Copy Markdown

@FeiChen-okta FeiChen-okta left a comment

Choose a reason for hiding this comment

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

Left some comments for the android implementation.

}

private fun base64URLEncode(data: ByteArray): String {
var base64 = Base64.encodeToString(data, Base64.NO_WRAP)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

this can be simplified to:

return Base64.getUrlEncoder().encodeToString(data)

or

return   Base64.encodeToString(data, Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING)                                                                                                                                                

This is getting mixed up the Java Base64 class with the Android's Base64 class.

or callers just call

Base64.encodeToString(data, Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING)

import java.math.BigInteger
import java.security.*
import java.security.spec.RSAPublicKeySpec
import java.util.*
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

this is importing javas base64 class. this should be the android one

Comment on lines +48 to +54
private fun base64URLDecode(input: String): ByteArray {
var base64 = input.replace('-', '+').replace('_', '/')
// Add padding
when (base64.length % 4) {
2 -> base64 += "=="
3 -> base64 += "="
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

same here. can just use Base64.decode(base64, Base64.NO_WRAP)
no need to do the string replacements.


@ReactMethod(isBlockingSynchronousMethod = true)
fun randomUUID(): String {
return UUID.randomUUID().toString()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

use SecureRandom. and 16 bytes


companion object {
const val NAME = "WebCryptoBridge"
private val keyStore = mutableMapOf<String, KeyPairEntry>()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I don't see any delete or anything to clear this?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Looking at this again. I don't think you want this. This is just a in memory map. If the app closes, you lose all your keys. You want to use the android keystore.

// MARK: - Synchronous Methods

@ReactMethod(isBlockingSynchronousMethod = true)
fun getRandomValues(length: Double): String {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Need some input validate in the length. I would say min 16.
Also whats the usage between this and randomUUID? I don't see this being called anywhere.

fun generateKey(
algorithmJson: String,
extractable: Boolean,
keyUsages: ReadableArray,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

this is not being used. I suppose it is to be used to create a key for signing/verifying or both. I think you can leave this out and assume that all generated keys can be used to sign/verify.


@ReactMethod
fun sign(
algorithmJson: String,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

this is not being used. This is hardcoded to RSA. I think it is fine to remove this. Note that android suppose EC keys too.


@ReactMethod
fun verify(
algorithmJson: String,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

same as sign method

fun importKey(
format: String,
keyDataJson: String,
algorithmJson: String,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

not used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants