Webcrypto Polyfill package#23
Webcrypto Polyfill package#23jaredperreault-okta wants to merge 17 commits intojp-react-native-sdkfrom
Conversation
| return | ||
| } | ||
|
|
||
| val key = if (keyType == "public") keyPair.public else keyPair.private |
There was a problem hiding this comment.
I don't see where keyPair is defined. Not sure if this will compile or just crash when this method is called.
…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
There was a problem hiding this comment.
I think the structure is incorrect. It should be under "android/src/main/..." I only see android/main
FeiChen-okta
left a comment
There was a problem hiding this comment.
Left some comments for the android implementation.
| } | ||
|
|
||
| private fun base64URLEncode(data: ByteArray): String { | ||
| var base64 = Base64.encodeToString(data, Base64.NO_WRAP) |
There was a problem hiding this comment.
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.* |
There was a problem hiding this comment.
this is importing javas base64 class. this should be the android one
| private fun base64URLDecode(input: String): ByteArray { | ||
| var base64 = input.replace('-', '+').replace('_', '/') | ||
| // Add padding | ||
| when (base64.length % 4) { | ||
| 2 -> base64 += "==" | ||
| 3 -> base64 += "=" | ||
| } |
There was a problem hiding this comment.
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() |
|
|
||
| companion object { | ||
| const val NAME = "WebCryptoBridge" | ||
| private val keyStore = mutableMapOf<String, KeyPairEntry>() |
There was a problem hiding this comment.
I don't see any delete or anything to clear this?
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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, |
| fun importKey( | ||
| format: String, | ||
| keyDataJson: String, | ||
| algorithmJson: String, |
Initial Setup of
@okta/react-native-platformMVP Impl of
@okta/react-native-webcrypto-bridge