repack icon indicating copy to clipboard operation
repack copied to clipboard

Support bundle verification with multiple public keys

Open baka3k opened this issue 10 months ago • 5 comments

Description

The situation we're facing is as follows: We have multiple independent MiniApp development teams, and we want each team to use their own unique private key.

This means that when verifying a bundle, we need to pass in the public key of the respective team (which is fetched from the server).

However, when examining the repack source code, we found that the 'verify' function is currently ONLY allowing for a single public key that is hardcoded into the source code, as shown below."

fun verifyBundle(context: Context, token: String?, fileContent: ByteArray?) {
            if (token == null) {
                throw Exception("The bundle verification failed because no token for the bundle was found.")
            }

            val stringPublicKey = getPublicKeyFromStringsIfExist(context)
                    ?: throw Exception("The bundle verification failed because PublicKey was not found in the bundle. Make sure you've added the PublicKey to the res/values/strings.xml under RepackPublicKey key.")

            val publicKey = parsePublicKey(stringPublicKey)
                    ?: throw Exception("The bundle verification failed because the PublicKey is invalid.")

            val claims: Map<String, Any?> = verifyAndDecodeToken(token, publicKey)

            val contentHash = claims["hash"] as String?
                    ?: throw Exception("The bundle verification failed because the token is invalid.")

            val fileHash = computeHash(fileContent)

            if (contentHash != fileHash) {
                throw Exception("The bundle verification failed because the bundle hash is invalid.")
            }
        }

 private fun getPublicKeyFromStringsIfExist(
                context: Context
        ): String? {
            val packageName: String = context.packageName
            val resId: Int =
                    context.resources.getIdentifier("RepackPublicKey", "string", packageName)
            if (resId != 0) {
                return context.getString(resId).ifEmpty {
                    null
                }
            }
            return null
        }

Suggested solution

It would be much better if the verify bundle function could accept an additional public key as a parameter, instead of hardcoding it as it is now, such as:

fun verifyBundle(context: Context, 
                         token: String?, 
                         fileContent: ByteArray?,
                         publicKeyAsByteArray: ByteArray? // add this parameter
) {
  val publicKey = publicKeyFromByteArray(publicKeyAsByteArray)
// 1. verify bundle by public key
// 2. check sum bundle

With this approach, we can have multiple mini-app development teams, each with their own private key for signing their mini-apps. We can authenticate development teams using their keys, allowing them to join the ecosystem or rejecting teams without relying on the main app's private key. Furthermore, if the main app's private key is lost or compromised, mini-apps created by various development teams can still operate. We have the flexibility to re-sign them whenever needed,(similar Google's Play App Signing approach)

Would you please consider this proposal

Thanks & BestRegard,

Additional context

No response

baka3k avatar Dec 13 '24 03:12 baka3k