From f5fbb7fb370057fc7636b8e5de47f9cda4bff75e Mon Sep 17 00:00:00 2001 From: dylan-kwon Date: Wed, 28 Aug 2024 12:24:20 +0900 Subject: [PATCH 1/5] Update obfuscator generation logic Generate the 'obfuscator' using a combination of the Package Name and Keystore Hash --- .../com/klaxit/hiddensecrets/CodeGenerator.kt | 1 + .../hiddensecrets/HiddenSecretsPlugin.kt | 38 +++++- .../kotlin/com/klaxit/hiddensecrets/Utils.kt | 18 ++- src/main/resources/cpp/secrets.cpp | 6 +- src/main/resources/cpp/signature.cpp | 118 ++++++++++++++++++ src/main/resources/cpp/signature.hpp | 5 + src/test/kotlin/HiddenSecretsTest.kt | 5 +- src/test/kotlin/IntegrationTest.kt | 20 ++- src/test/kotlin/UtilsTest.kt | 7 +- 9 files changed, 199 insertions(+), 19 deletions(-) create mode 100644 src/main/resources/cpp/signature.cpp create mode 100644 src/main/resources/cpp/signature.hpp diff --git a/src/main/kotlin/com/klaxit/hiddensecrets/CodeGenerator.kt b/src/main/kotlin/com/klaxit/hiddensecrets/CodeGenerator.kt index eb36ae7..7b9c8ed 100644 --- a/src/main/kotlin/com/klaxit/hiddensecrets/CodeGenerator.kt +++ b/src/main/kotlin/com/klaxit/hiddensecrets/CodeGenerator.kt @@ -16,6 +16,7 @@ object CodeGenerator { " JNIEnv* pEnv,\n" + " jobject pThis,\n" + " jstring packageName) {\n" + + " jstring obfuscatingJStr = getSignature(pEnv, packageName);\n" + " char obfuscatedSecret[] = $obfuscatedKey;\n" + " return getOriginalKey(obfuscatedSecret, sizeof(obfuscatedSecret), packageName, pEnv);\n" + "}\n" diff --git a/src/main/kotlin/com/klaxit/hiddensecrets/HiddenSecretsPlugin.kt b/src/main/kotlin/com/klaxit/hiddensecrets/HiddenSecretsPlugin.kt index fe2ab3b..ae07751 100644 --- a/src/main/kotlin/com/klaxit/hiddensecrets/HiddenSecretsPlugin.kt +++ b/src/main/kotlin/com/klaxit/hiddensecrets/HiddenSecretsPlugin.kt @@ -21,6 +21,7 @@ open class HiddenSecretsPlugin : Plugin { private const val APP_MAIN_FOLDER = "src/main/" private const val DEFAULT_KEY_NAME_LENGTH = 8 private const val KEY_PLACEHOLDER = "YOUR_KEY_GOES_HERE" + private const val KEY_NAME_PLACEHOLDER = "YOUR_KEY_NAME_GOES_HERE" private const val PACKAGE_PLACEHOLDER = "YOUR_PACKAGE_GOES_HERE" private const val KOTLIN_FILE_NAME = "Secrets.kt" @@ -40,10 +41,12 @@ open class HiddenSecretsPlugin : Plugin { private const val PROP_KEY_NAME = "keyName" private const val PROP_PACKAGE = "package" private const val PROP_FILE_NAME = "propertiesFileName" + private const val PROP_KEY_HASH = "keyHash" // Errors private const val ERROR_EMPTY_KEY = "No key provided, use argument '-Pkey=yourKey'" private const val ERROR_EMPTY_PACKAGE = "Empty package name, use argument '-Ppackage=your.package.name'" + private const val ERROR_EMPTY_KEY_HASH = "Empty keyHash, use argument '-PkeyHash=yourKeystoreHash'" // Sample usage private const val SAMPLE_FROM_PROPS = "-P${PROP_FILE_NAME}=credentials.properties" @@ -160,6 +163,21 @@ open class HiddenSecretsPlugin : Plugin { return keyName } + /** + * Get key hash param from command line + */ + @Input + fun getKeyHash(): String { + val key: String + if (project.hasProperty(PROP_KEY_HASH)) { + // From command line + key = project.property(PROP_KEY_HASH) as String + } else { + throw InvalidUserDataException(ERROR_EMPTY_KEY_HASH) + } + return key + } + /** * Generate en encoded key from command line params */ @@ -167,10 +185,13 @@ open class HiddenSecretsPlugin : Plugin { val key = getKeyParam() println("### SECRET ###\n$key\n") + val keyHash = getKeyHash() + println("### KEY HASH ###\n$keyHash\n") + val packageName = getPackageNameParam() println("### PACKAGE NAME ###\n$packageName\n") - val encodedKey = Utils.encodeSecret(key, packageName) + val encodedKey = Utils.encodeSecret(key, keyHash, packageName) println("### OBFUSCATED SECRET ###\n$encodedKey") return encodedKey } @@ -261,7 +282,8 @@ open class HiddenSecretsPlugin : Plugin { fun hideSecret( keyName: String, packageName: String, - obfuscatedKey: String + obfuscatedKey: String, + keyHash: String, ) { // Add method in Kotlin code var secretsKotlin = getKotlinFile() @@ -302,7 +324,7 @@ open class HiddenSecretsPlugin : Plugin { // Replace package name text = text.replace(PACKAGE_PLACEHOLDER, Utils.getCppName(kotlinPackage)) // Replace key name - text = text.replace("YOUR_KEY_NAME_GOES_HERE", cppKeyName) + text = text.replace(KEY_NAME_PLACEHOLDER, cppKeyName) // Replace demo key text = text.replace(KEY_PLACEHOLDER, obfuscatedKey) secretsCpp.writeText(text) @@ -389,8 +411,9 @@ open class HiddenSecretsPlugin : Plugin { val keyName = getKeyNameParam() val packageName = getPackageNameParam() val obfuscatedKey = getObfuscatedKey() + val keyHash = getKeyHash() - hideSecret(keyName, packageName, obfuscatedKey) + hideSecret(keyName, packageName, obfuscatedKey, keyHash) } } @@ -408,14 +431,17 @@ open class HiddenSecretsPlugin : Plugin { copyCppFiles(true) copyKotlinFile(true) + val keyHash = getKeyHash() val packageName = getPackageNameParam() val propsFile = getPropertiesFile() val props = getPropertiesFromFile(propsFile = propsFile) println("Generating secrets from props: ${propsFile.path}") props.entries.forEach { entry -> val keyName = entry.key as String - val obfuscatedKey = Utils.encodeSecret(entry.value as String, packageName) - hideSecret(keyName, packageName, obfuscatedKey) + val obfuscatedKey = Utils.encodeSecret( + entry.value as String, keyHash, packageName + ) + hideSecret(keyName, packageName, obfuscatedKey, keyHash) } } } diff --git a/src/main/kotlin/com/klaxit/hiddensecrets/Utils.kt b/src/main/kotlin/com/klaxit/hiddensecrets/Utils.kt index 1c5fdb5..47dcc05 100644 --- a/src/main/kotlin/com/klaxit/hiddensecrets/Utils.kt +++ b/src/main/kotlin/com/klaxit/hiddensecrets/Utils.kt @@ -33,12 +33,26 @@ object Utils { return digest.fold("") { str, it -> str + "%02x".format(it) } } + /** + * Obfuscator is created using SHA-256 of (keyHash + package) + */ + fun createObfuscator( + keyHash: String, + packageName: String + ): String { + return sha256(keyHash + packageName) + } + /** * Encode a string key to and hex array using package name */ - fun encodeSecret(key: String, packageName: String): String { + fun encodeSecret( + key: String, + keyHash: String, + packageName: String + ): String { // Generate the obfuscator as the SHA256 of the app package name - val obfuscator = sha256(packageName) + val obfuscator = createObfuscator(keyHash, packageName) val obfuscatorBytes = obfuscator.toByteArray() // Generate the obfuscated secret bytes array by applying a XOR between the secret and the obfuscator diff --git a/src/main/resources/cpp/secrets.cpp b/src/main/resources/cpp/secrets.cpp index a881813..317a2d9 100644 --- a/src/main/resources/cpp/secrets.cpp +++ b/src/main/resources/cpp/secrets.cpp @@ -5,6 +5,9 @@ #include "sha256.hpp" #include "sha256.cpp" +#include "signature.hpp" +#include "signature.cpp" + /* Copyright (c) 2020-present Klaxit SAS * * Permission is hereby granted, free of charge, to any person @@ -69,6 +72,7 @@ Java_YOUR_PACKAGE_GOES_HERE_Secrets_getYOUR_KEY_NAME_GOES_HERE( JNIEnv *pEnv, jobject pThis, jstring packageName) { + jstring obfuscatingJStr = getSignature(pEnv, packageName); char obfuscatedSecret[] = YOUR_KEY_GOES_HERE; - return getOriginalKey(obfuscatedSecret, sizeof(obfuscatedSecret), packageName, pEnv); + return getOriginalKey(obfuscatedSecret, sizeof(obfuscatedSecret), obfuscatingJStr, pEnv); } \ No newline at end of file diff --git a/src/main/resources/cpp/signature.cpp b/src/main/resources/cpp/signature.cpp new file mode 100644 index 0000000..99bed8f --- /dev/null +++ b/src/main/resources/cpp/signature.cpp @@ -0,0 +1,118 @@ +#include +#include "sha256.hpp" + +/* Copyright (c) 2024-present Dylan Kwon +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +jobject getApplication(JNIEnv *pEnv) { + jclass appGlobalsClass = pEnv->FindClass("android/app/AppGlobals"); + jmethodID jGetInitialApplication = pEnv->GetStaticMethodID(appGlobalsClass,"getInitialApplication","()Landroid/app/Application;"); + return pEnv->CallStaticObjectMethod(appGlobalsClass, jGetInitialApplication); +} + +jstring getPackageName(JNIEnv *pEnv) { + jobject applicationObject = getApplication(pEnv); + jclass contextClass = pEnv->FindClass("android/content/Context"); + jmethodID getPackageNameMethodId = pEnv->GetMethodID(contextClass, "getPackageName", "()Ljava/lang/String;"); + return static_cast(pEnv->CallObjectMethod(applicationObject, getPackageNameMethodId)); +} + +jstring getKeyHash(JNIEnv *pEnv) { + // Application + jobject applicationObject = getApplication(pEnv); + + // PackageName + jstring packageNameString = getPackageName(pEnv); + + // Context + jclass contextClass = pEnv->FindClass("android/content/Context"); + + // PackageManager + jmethodID getPackageManagerMethodId = pEnv->GetMethodID(contextClass, "getPackageManager", "()Landroid/content/pm/PackageManager;"); + jobject packageManagerObject = pEnv->CallObjectMethod(applicationObject, getPackageManagerMethodId); + jclass packageManagerClass = pEnv->GetObjectClass(packageManagerObject); + + // PackageInfo + jmethodID getPackageInfoMethodId = pEnv->GetMethodID(packageManagerClass, "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;"); + jobject packageInfoObject = pEnv->CallObjectMethod(packageManagerObject, getPackageInfoMethodId, packageNameString, 0x08000000); + jclass packageInfoClass = pEnv->GetObjectClass(packageInfoObject); + + // SigningInfo + jfieldID signingInfoFieldId = pEnv->GetFieldID(packageInfoClass, "signingInfo", "Landroid/content/pm/SigningInfo;"); + jobject signingInfoObject = pEnv->GetObjectField(packageInfoObject, signingInfoFieldId); + jclass signingInfoClass = pEnv->GetObjectClass(signingInfoObject); + + // SigningInfo.hasMultipleSignersBoolean + jmethodID hasMultipleSignersMethodId = pEnv->GetMethodID(signingInfoClass, "hasMultipleSigners", "()Z"); + jboolean hasMultipleSignersBoolean = pEnv->CallBooleanMethod(signingInfoObject, hasMultipleSignersMethodId); + + // Signatures + jobjectArray signatures; + + if (hasMultipleSignersBoolean) { + jmethodID getApkContentsSignersMethodId = pEnv->GetMethodID(signingInfoClass, "getApkContentsSigners", "()[Landroid/content/pm/Signature;"); + signatures = reinterpret_cast(pEnv->CallObjectMethod(signingInfoObject, getApkContentsSignersMethodId)); + } else { + jmethodID getSigningCertificateHistoryMethodId = pEnv->GetMethodID(signingInfoClass, "getSigningCertificateHistory", "()[Landroid/content/pm/Signature;"); + signatures = reinterpret_cast(pEnv->CallObjectMethod(signingInfoObject, getSigningCertificateHistoryMethodId)); + } + + // First Signature + jobject signatureObject = pEnv->GetObjectArrayElement(signatures, 0); + jclass signatureClass = pEnv->GetObjectClass(signatureObject); + + // First Signature ByteArray + jmethodID toByteArrayMethodId = pEnv->GetMethodID(signatureClass, "toByteArray", "()[B"); + jbyteArray signatureByteArray = reinterpret_cast(pEnv->CallObjectMethod(signatureObject, toByteArrayMethodId)); + + // MessageDigest + jclass messageDigestClass = pEnv->FindClass("java/security/MessageDigest"); + jmethodID getInstanceMethodId = pEnv->GetStaticMethodID(messageDigestClass,"getInstance","(Ljava/lang/String;)Ljava/security/MessageDigest;"); + jobject messageDigestObject = pEnv->CallStaticObjectMethod(messageDigestClass,getInstanceMethodId, pEnv->NewStringUTF("SHA")); + + // MessageDigest Update + jmethodID updateMethodId = pEnv->GetMethodID(messageDigestClass,"update","([B)V"); + pEnv->CallVoidMethod(messageDigestObject, updateMethodId, signatureByteArray); + + // MessageDigest Digest + jmethodID digestMethodId = pEnv->GetMethodID(messageDigestClass,"digest","()[B"); + jbyteArray digestByteArray = reinterpret_cast(pEnv->CallObjectMethod(messageDigestObject, digestMethodId)); + + // Base64 + jclass base64Class = pEnv->FindClass("android/util/Base64"); + jmethodID encodeMethodId = pEnv->GetStaticMethodID(base64Class,"encodeToString","([BI)Ljava/lang/String;"); + jstring base64String = static_cast(pEnv->CallStaticObjectMethod(base64Class, encodeMethodId, digestByteArray, 2)); + + return base64String; +} + +jstring getSignature(JNIEnv* pEnv, jstring packageName) { + jstring keyHash = getKeyHash(pEnv); + + jclass signatureClass = pEnv->GetObjectClass(keyHash); + jmethodID concatMethodId = pEnv->GetMethodID(signatureClass, "concat", "(Ljava/lang/String;)Ljava/lang/String;"); + jstring concat = reinterpret_cast(pEnv->CallObjectMethod(keyHash, concatMethodId, packageName)); + + return concat; +} \ No newline at end of file diff --git a/src/main/resources/cpp/signature.hpp b/src/main/resources/cpp/signature.hpp new file mode 100644 index 0000000..45268c5 --- /dev/null +++ b/src/main/resources/cpp/signature.hpp @@ -0,0 +1,5 @@ +#ifndef SIGNATURE_H +#define SIGNATURE_H + + +#endif // SIGNATURE_H \ No newline at end of file diff --git a/src/test/kotlin/HiddenSecretsTest.kt b/src/test/kotlin/HiddenSecretsTest.kt index b5eecac..2c5a565 100644 --- a/src/test/kotlin/HiddenSecretsTest.kt +++ b/src/test/kotlin/HiddenSecretsTest.kt @@ -30,6 +30,7 @@ class HiddenSecretsTest : WordSpec({ // Properties val key = "thisIsATestKey" val packageName = "com.package.test" + val keyHash = "5ptCUaVG+0JGgprlT1yKuyJrUI4=" "Make command ${HiddenSecretsPlugin.TASK_COPY_CPP} succeed" { val result = gradleRunner.withArguments(HiddenSecretsPlugin.TASK_COPY_CPP).build() @@ -42,10 +43,10 @@ class HiddenSecretsTest : WordSpec({ } "Make command ${HiddenSecretsPlugin.TASK_OBFUSCATE} succeed" { - val result = gradleRunner.withArguments(HiddenSecretsPlugin.TASK_OBFUSCATE, "-Pkey=$key", "-Ppackage=$packageName").build() + val result = gradleRunner.withArguments(HiddenSecretsPlugin.TASK_OBFUSCATE, "-Pkey=$key", "-Ppackage=$packageName", "-PkeyHash=$keyHash").build() println(result.output) // Should contain obfuscated key - result.output shouldContain "{ 0x15, 0x58, 0xb, 0x43, 0x78, 0x4a, 0x23, 0x6d, 0x1, 0x4b, 0x46, 0x7c, 0x57, 0x41 }" + result.output shouldContain "{ 0x45, 0xd, 0x5e, 0x42, 0x7d, 0x10, 0x76, 0x36, 0x6, 0x15, 0x16, 0x73, 0x51, 0x18 }" } "Make command ${HiddenSecretsPlugin.TASK_PACKAGE_NAME} succeed" { diff --git a/src/test/kotlin/IntegrationTest.kt b/src/test/kotlin/IntegrationTest.kt index fabf808..e26b316 100644 --- a/src/test/kotlin/IntegrationTest.kt +++ b/src/test/kotlin/IntegrationTest.kt @@ -1,6 +1,6 @@ import com.klaxit.hiddensecrets.HiddenSecretsPlugin import io.kotest.core.spec.style.WordSpec -import io.kotest.data.Row4 +import io.kotest.data.Row5 import io.kotest.datatest.withData import io.kotest.matchers.shouldBe import org.gradle.testkit.runner.GradleRunner @@ -39,14 +39,21 @@ class IntegrationTest : WordSpec({ val test = this "Make command ${HiddenSecretsPlugin.TASK_HIDE_SECRET} succeed" { test.withData( - Row4("thisIsATestKey", "thisIsATestKeyName", "thisIsATestKeyName", "com.package.test"), - Row4( + Row5( + "thisIsATestKey", + "thisIsATestKeyName", + "thisIsATestKeyName", + "com.package.test", + "5ptCUaVG+0JGgprlT1yKuyJrUI4=", + ), + Row5( "this_is_a_test_key", "this_is_a_test_key_name", "this_1is_1a_1test_1key_1name", - "com.package.test" + "com.package.test", + "7IoCUPVG0IrfEB381+KSyn2kUa0=", ), - ) { (key, keyName, cppKeyName, packageName) -> + ) { (key, keyName, cppKeyName, packageName, keyHash) -> testProjectDir.run { val packagePath = packageName.replace('.', '/') val packageDirJava = newFolder("src/main/java/$packagePath") @@ -73,7 +80,8 @@ class IntegrationTest : WordSpec({ HiddenSecretsPlugin.TASK_HIDE_SECRET, "-Pkey=$key", "-PkeyName=$keyName", - "-Ppackage=$packageName" + "-Ppackage=$packageName", + "-PkeyHash=$keyHash", ) .build() println(result.output) diff --git a/src/test/kotlin/UtilsTest.kt b/src/test/kotlin/UtilsTest.kt index b96d293..d1ab482 100644 --- a/src/test/kotlin/UtilsTest.kt +++ b/src/test/kotlin/UtilsTest.kt @@ -8,6 +8,7 @@ import java.io.File */ class UtilsTest : WordSpec({ + val keyHash = "5ptCUaVG+0JGgprlT1yKuyJrUI4=" val packageName = "com.klaxit.test" "Using getCppName()" should { @@ -34,15 +35,17 @@ class UtilsTest : WordSpec({ val key = "keyToEncode" Utils.encodeSecret( key, + keyHash, packageName - ) shouldBe "{ 0x5b, 0x6, 0x18, 0x31, 0xb, 0x72, 0x57, 0x5, 0x5d, 0x57, 0x3 }" + ) shouldBe "{ 0x52, 0x1, 0x18, 0x6d, 0x5f, 0x21, 0xb, 0x55, 0x59, 0x57, 0x5d }" } "encode String with special characters" { val key = "@&é(§èçà)-ù,;:=#°_*%£?./+" Utils.encodeSecret( key, + keyHash, packageName - ) shouldBe "{ 0x70, 0x45, 0xa2, 0xcc, 0x4c, 0xf5, 0x9e, 0xa5, 0x9a, 0xf0, 0xc1, 0xa6, 0x92, 0x4a, 0x4e, 0xa6, 0x8a, 0x1a, 0xc, 0x5e, 0x5, 0x14, 0xf7, 0x86, 0x6b, 0x13, 0x40, 0xf5, 0x9a, 0xc, 0x16, 0x16, 0x19 }" + ) shouldBe "{ 0x79, 0x42, 0xa2, 0x90, 0x18, 0xa6, 0xc2, 0xf5, 0x9e, 0xf0, 0x9f, 0xa0, 0x90, 0x1f, 0x1d, 0xa6, 0x80, 0x1e, 0x58, 0x58, 0xe, 0x15, 0xa1, 0x88, 0x6a, 0x13, 0x14, 0xf3, 0xc5, 0x9, 0x4b, 0x1f, 0x4f }" } } From 215361e6122da202fcb44ff25f50af0b4f349358 Mon Sep 17 00:00:00 2001 From: dylan-kwon Date: Wed, 28 Aug 2024 12:30:47 +0900 Subject: [PATCH 2/5] Update README.md Add -PkeyHash --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 758b891..5c10bb3 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ For more details about the installation check the [plugin's page](https://plugin Obfuscate and hide your key in your project : ```shell -./gradlew hideSecret -Pkey=yourKeyToObfuscate [-PkeyName=YourSecretKeyName] [-Ppackage=com.your.package] +./gradlew hideSecret -PkeyHash=YourKeystoreHash -Pkey=yourKeyToObfuscate [-PkeyName=YourSecretKeyName] [-Ppackage=com.your.package] ``` The parameter `keyName` is optional, by default the key name is randomly generated. The parameter `package` is optional, by default the `applicationId` of your project will be used. @@ -92,7 +92,7 @@ As an example, we will use a [rot13 algorithm](https://en.wikipedia.org/wiki/ROT After a rot13 encoding your key `yourKeyToObfuscate` becomes `lbheXrlGbBoshfpngr`. Add it in your app : ```shell -./gradlew hideSecret -Pkey=lbheXrlGbBoshfpngr -PkeyName=YourSecretKeyName +./gradlew hideSecret -Pkey=lbheXrlGbBoshfpngr -PkeyName=YourSecretKeyName -PkeyHash=YourKeystoreHash ``` Then in `secrets.cpp` you need to add your own decoding code in `customDecode` method: @@ -145,7 +145,7 @@ keyName2=yourKeyToObfuscate2 3. Run ``` shell -./gradlew hideSecretFromPropertiesFile -PpropertiesFileName=credentials.properties +./gradlew hideSecretFromPropertiesFile -PpropertiesFileName=credentials.properties -PkeyHash=YourKeystoreHash ``` It will regenerate all secret files in the project and update all secrets from the properties file. From 7c02922df19da650291cd150d65812f3e6513d45 Mon Sep 17 00:00:00 2001 From: dylan-kwon Date: Thu, 29 Aug 2024 00:37:48 +0900 Subject: [PATCH 3/5] Remove unused codes --- .../kotlin/com/klaxit/hiddensecrets/HiddenSecretsPlugin.kt | 6 ++---- src/main/resources/cpp/signature.cpp | 5 +++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/com/klaxit/hiddensecrets/HiddenSecretsPlugin.kt b/src/main/kotlin/com/klaxit/hiddensecrets/HiddenSecretsPlugin.kt index ae07751..0bb2209 100644 --- a/src/main/kotlin/com/klaxit/hiddensecrets/HiddenSecretsPlugin.kt +++ b/src/main/kotlin/com/klaxit/hiddensecrets/HiddenSecretsPlugin.kt @@ -283,7 +283,6 @@ open class HiddenSecretsPlugin : Plugin { keyName: String, packageName: String, obfuscatedKey: String, - keyHash: String, ) { // Add method in Kotlin code var secretsKotlin = getKotlinFile() @@ -411,9 +410,8 @@ open class HiddenSecretsPlugin : Plugin { val keyName = getKeyNameParam() val packageName = getPackageNameParam() val obfuscatedKey = getObfuscatedKey() - val keyHash = getKeyHash() - hideSecret(keyName, packageName, obfuscatedKey, keyHash) + hideSecret(keyName, packageName, obfuscatedKey) } } @@ -441,7 +439,7 @@ open class HiddenSecretsPlugin : Plugin { val obfuscatedKey = Utils.encodeSecret( entry.value as String, keyHash, packageName ) - hideSecret(keyName, packageName, obfuscatedKey, keyHash) + hideSecret(keyName, packageName, obfuscatedKey) } } } diff --git a/src/main/resources/cpp/signature.cpp b/src/main/resources/cpp/signature.cpp index 99bed8f..ad4b194 100644 --- a/src/main/resources/cpp/signature.cpp +++ b/src/main/resources/cpp/signature.cpp @@ -1,5 +1,6 @@ -#include -#include "sha256.hpp" +#include "secrets.hpp" + +#include /* Copyright (c) 2024-present Dylan Kwon * From 813d354fd17b190a8fbd4a29497802b9ab542736 Mon Sep 17 00:00:00 2001 From: dylan-kwon Date: Thu, 29 Aug 2024 03:33:32 +0900 Subject: [PATCH 4/5] Fix CodeGenerator --- src/main/kotlin/com/klaxit/hiddensecrets/CodeGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/klaxit/hiddensecrets/CodeGenerator.kt b/src/main/kotlin/com/klaxit/hiddensecrets/CodeGenerator.kt index 7b9c8ed..14ff1cc 100644 --- a/src/main/kotlin/com/klaxit/hiddensecrets/CodeGenerator.kt +++ b/src/main/kotlin/com/klaxit/hiddensecrets/CodeGenerator.kt @@ -18,7 +18,7 @@ object CodeGenerator { " jstring packageName) {\n" + " jstring obfuscatingJStr = getSignature(pEnv, packageName);\n" + " char obfuscatedSecret[] = $obfuscatedKey;\n" + - " return getOriginalKey(obfuscatedSecret, sizeof(obfuscatedSecret), packageName, pEnv);\n" + + " return getOriginalKey(obfuscatedSecret, sizeof(obfuscatedSecret), obfuscatingJStr, pEnv);\n" + "}\n" } From f5ab45c61e884f2cbe60f9f891a7017c31fe3c57 Mon Sep 17 00:00:00 2001 From: dylan-kwon Date: Thu, 29 Aug 2024 03:35:02 +0900 Subject: [PATCH 5/5] Processing getKeyHash by Android version --- src/main/resources/cpp/signature.cpp | 36 ++++++++++++++++++---------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/main/resources/cpp/signature.cpp b/src/main/resources/cpp/signature.cpp index ad4b194..930959c 100644 --- a/src/main/resources/cpp/signature.cpp +++ b/src/main/resources/cpp/signature.cpp @@ -59,24 +59,34 @@ jstring getKeyHash(JNIEnv *pEnv) { jobject packageInfoObject = pEnv->CallObjectMethod(packageManagerObject, getPackageInfoMethodId, packageNameString, 0x08000000); jclass packageInfoClass = pEnv->GetObjectClass(packageInfoObject); - // SigningInfo - jfieldID signingInfoFieldId = pEnv->GetFieldID(packageInfoClass, "signingInfo", "Landroid/content/pm/SigningInfo;"); - jobject signingInfoObject = pEnv->GetObjectField(packageInfoObject, signingInfoFieldId); - jclass signingInfoClass = pEnv->GetObjectClass(signingInfoObject); - - // SigningInfo.hasMultipleSignersBoolean - jmethodID hasMultipleSignersMethodId = pEnv->GetMethodID(signingInfoClass, "hasMultipleSigners", "()Z"); - jboolean hasMultipleSignersBoolean = pEnv->CallBooleanMethod(signingInfoObject, hasMultipleSignersMethodId); + // SDK Version + jclass buildClass = pEnv->FindClass("android/os/Build$VERSION"); + jfieldID versionCodeFieldId = pEnv->GetStaticFieldID(buildClass, "SDK_INT", "I"); + jint versionCode = pEnv->GetStaticIntField(buildClass, versionCodeFieldId); // Signatures jobjectArray signatures; - if (hasMultipleSignersBoolean) { - jmethodID getApkContentsSignersMethodId = pEnv->GetMethodID(signingInfoClass, "getApkContentsSigners", "()[Landroid/content/pm/Signature;"); - signatures = reinterpret_cast(pEnv->CallObjectMethod(signingInfoObject, getApkContentsSignersMethodId)); + if (versionCode >= 28) { + // SigningInfo + jfieldID signingInfoFieldId = pEnv->GetFieldID(packageInfoClass, "signingInfo", "Landroid/content/pm/SigningInfo;"); + jobject signingInfoObject = pEnv->GetObjectField(packageInfoObject, signingInfoFieldId); + jclass signingInfoClass = pEnv->GetObjectClass(signingInfoObject); + + // SigningInfo.hasMultipleSignersBoolean + jmethodID hasMultipleSignersMethodId = pEnv->GetMethodID(signingInfoClass, "hasMultipleSigners", "()Z"); + jboolean hasMultipleSignersBoolean = pEnv->CallBooleanMethod(signingInfoObject, hasMultipleSignersMethodId); + + if (hasMultipleSignersBoolean) { + jmethodID getApkContentsSignersMethodId = pEnv->GetMethodID(signingInfoClass, "getApkContentsSigners", "()[Landroid/content/pm/Signature;"); + signatures = reinterpret_cast(pEnv->CallObjectMethod(signingInfoObject, getApkContentsSignersMethodId)); + } else { + jmethodID getSigningCertificateHistoryMethodId = pEnv->GetMethodID(signingInfoClass, "getSigningCertificateHistory", "()[Landroid/content/pm/Signature;"); + signatures = reinterpret_cast(pEnv->CallObjectMethod(signingInfoObject, getSigningCertificateHistoryMethodId)); + } } else { - jmethodID getSigningCertificateHistoryMethodId = pEnv->GetMethodID(signingInfoClass, "getSigningCertificateHistory", "()[Landroid/content/pm/Signature;"); - signatures = reinterpret_cast(pEnv->CallObjectMethod(signingInfoObject, getSigningCertificateHistoryMethodId)); + jfieldID signaturesFieldId = pEnv->GetFieldID(packageInfoClass, "signatures", "[Landroid/content/pm/Signature;"); + signatures = reinterpret_cast(pEnv->GetObjectField(packageInfoObject, signaturesFieldId)); } // First Signature