Skip to content

Commit

Permalink
Merge pull request #5 from klaxit/feature/prepare-release
Browse files Browse the repository at this point in the history
Prepare repository for public release
  • Loading branch information
ccyrille committed Sep 28, 2020
2 parents 03c57ad + 30e3f43 commit b0ace02
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 43 deletions.
18 changes: 18 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
language: java
install: skip

os: linux
dist: trusty
jdk: oraclejdk8

script:
- ./gradlew test --info --build-cache

before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/

cache:
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
30 changes: 14 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
# Gradle plugin to deeply hide secrets on Android
![travis ci status](https://travis-ci.com/klaxit/hidden-secrets-gradle-plugin.svg?branch=master)

This repository is the gradle plugin version of this POC : [HiddenSecrets](https://github.com/klaxit/HiddenSecrets)
# Gradle plugin to deeply hide secrets on Android

It is highly inspired from https://www.splinter.com.au/2014/09/16/storing-secret-keys/
This plugin allows any Android developer to deeply hide secrets in its project. It is an OSS equivalent of what [DexGuard](https://www.guardsquare.com/en/products/dexguard) can offer to prevent **credentials harvesting**.

It uses a combination of obfuscation techniques to do so :
- secret is obfuscated using the reversible XOR operator so it never appears in plain sight,
- obfuscated secret is stored in a NDK binary as an hexadecimal array, so it is really hard to spot / put together from a disassembly,
- the obfuscating string is not persisted in the binary to force runtime evaluation (ie : prevent the compiler from disclosing the secret by optimizing the de-obfuscation logic).
- the obfuscating string is not persisted in the binary to force runtime evaluation (ie : prevent the compiler from disclosing the secret by optimizing the de-obfuscation logic),
- optionnaly, anyone can provide it's own encoding / decoding algorithm when using the plugin to add an additional security layer.

This plugin is **used in production** at [Klaxit - Covoiturage quotidien](https://play.google.com/store/apps/details?id=com.wayzup.wayzupapp). Our engineering team at Klaxit will provide its best effort to maintain this project.

⚠️ Nothing on the client-side is unbreakable. So generally speaking, **keeping a secret in a mobile package is not a smart idea**. But when you absolutely need to, this is the best method we have found to hide it.

Expand All @@ -17,19 +20,12 @@ This project is also a demonstration on how to create a full Kotlin gradle plugi
## Compatibility
This gradle plugin can be used with any Android project in Java or Kotlin.

# 1 - Get the plugin

You can build the `.jar` file from the code as explained below, or directly get it from [releases](https://github.com/klaxit/hidden-secrets-gradle-plugin/releases).
# 1 - Install the plugin

## Build it
Checkout the code and run `gradle build` to create the `.jar` file in `/build/libs/`.
Get the latest version of the plugin from [releases](https://github.com/klaxit/hidden-secrets-gradle-plugin/releases).
Copy `HiddenSecretsPlugin-X.Y.Z.jar` to your Android project in `/app/libs/` folder.

## Copy the plugin
Copy `HiddenSecretsPlugin-1.0.0.jar` from the gradle plugin folder `/build/libs/` to your Android project in `/app/libs/`.

## Enable the plugin in your project

Add these line in your app level `build.gradle`:
Add these lines in your app level `build.gradle`:

```gradle
buildscript {
Expand All @@ -39,7 +35,7 @@ buildscript {
}
// Add dependency to HiddenSecretsPlugin
dependencies {
classpath("com.klaxit.hiddensecrets.gradle:HiddenSecretsPlugin:1.0.0")
classpath("com.klaxit.hiddensecrets.gradle:HiddenSecretsPlugin:X.Y.Z")
}
}
Expand Down Expand Up @@ -139,6 +135,8 @@ gradle obfuscate -Pkey=yourKeyToObfuscate [-Ppackage=com.your.package]

Pull Requests are very welcome!

To get started, checkout the code and run `gradle build` to create the `.jar` file in `/build/libs/`.

Please make sure that you have tested your code carefully before opening a PR, and make sure as well that you have no style issues.

## Authors
Expand Down
7 changes: 6 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ plugins {
}

group = "com.klaxit.hiddensecrets"
version = "1.0.0"
version = "0.1.0"

repositories {
mavenCentral()
Expand Down Expand Up @@ -32,6 +32,11 @@ gradlePlugin {
}
}

tasks.withType<Copy> {
//Required by Gradle 7.0
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}

tasks.withType<Test> {
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ open class HiddenSecretsPlugin : Plugin<Project> {
*/
@Input
fun getKeyParam(): String {
var key = ""
val key: String
if (project.hasProperty("key")) {
//From command line
key = project.property("key") as String
Expand All @@ -69,7 +69,7 @@ open class HiddenSecretsPlugin : Plugin<Project> {
@Input
fun getPackageNameParam(): String {
//From config
var packageName : String? = null
var packageName: String? = null
if (project.hasProperty("package")) {
//From command line
packageName = project.property("package") as String?
Expand Down Expand Up @@ -138,8 +138,7 @@ open class HiddenSecretsPlugin : Plugin<Project> {
/**
* Unzip plugin into tmp directory
*/
project.tasks.create(TASK_UNZIP_HIDDEN_SECRETS, Copy::
class.java,
project.tasks.create(TASK_UNZIP_HIDDEN_SECRETS, Copy::class.java,
object : Action<Copy?> {
@TaskAction
override fun execute(copy: Copy) {
Expand Down
8 changes: 4 additions & 4 deletions src/main/kotlin/com/klaxit/hiddensecrets/Utils.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.klaxit.hiddensecrets

import com.google.common.annotations.VisibleForTesting
import java.nio.charset.Charset
import java.security.MessageDigest
import kotlin.experimental.xor
Expand All @@ -26,7 +27,8 @@ class Utils {
/**
* Encode string to sha256
*/
private fun sha256(toHash: String): String {
@VisibleForTesting
fun sha256(toHash: String): String {
val bytes = toHash.toByteArray()
val md = MessageDigest.getInstance("SHA-256")
val digest = md.digest(bytes)
Expand All @@ -39,7 +41,6 @@ class Utils {
fun encodeSecret(key: String, packageName: String): String {
//Generate the obfuscator as the SHA256 of the app package name
val obfuscator = sha256(packageName)
//println("SHA 256 = " + obfuscator)
val obfuscatorBytes = obfuscator.toByteArray()

//Generate the obfuscated secret bytes array by applying a XOR between the secret and the obfuscator
Expand All @@ -55,13 +56,12 @@ class Utils {
val iterator: Iterator<Byte> = obfuscatedSecretBytes.iterator()
while (iterator.hasNext()) {
val item = iterator.next()
encoded += "0x" + Integer.toHexString(item.toInt())
encoded += "0x" + Integer.toHexString(item.toInt() and 0xff)
if (iterator.hasNext()) {
encoded += ", "
}
}
encoded += " }"

return encoded
}
}
Expand Down
17 changes: 0 additions & 17 deletions src/test/kotlin/HiddenSecretsTest.kt
Original file line number Diff line number Diff line change
@@ -1,22 +1,9 @@
import com.klaxit.hiddensecrets.HiddenSecretsPlugin
import io.kotlintest.shouldNotBe
import io.kotlintest.specs.WordSpec
import org.gradle.testfixtures.ProjectBuilder
import org.gradle.testkit.runner.GradleRunner
import org.junit.rules.TemporaryFolder

class HiddenSecretsTest : WordSpec({

"Using the Plugin ID" should {
"Apply the Plugin" {
val project = ProjectBuilder.builder().build()
project.pluginManager.apply("com.klaxit.HiddenSecrets")

val plugin = project.plugins.getPlugin(HiddenSecretsPlugin::class.java)
plugin shouldNotBe null
}
}

"Apply the plugin" should {
val testProjectDir = TemporaryFolder()
testProjectDir.create()
Expand All @@ -35,9 +22,5 @@ class HiddenSecretsTest : WordSpec({
val result = gradleRunner.withArguments("copyCpp").build()
println(result.output)
}
"Make command copyKotlin works" {
val result = gradleRunner.withArguments("copyCpp").build()
println(result.output)
}
}
})
14 changes: 13 additions & 1 deletion src/test/kotlin/UtilsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,23 @@ class UtilsTest : WordSpec({
}
}

"Using sha256()" should {
"encode String in sha256" {
val key = "youCanNotFindMySecret!"
Utils.sha256(key) shouldBe "7bdc2b5992ef7b4cce0e06295f564f4fad0c96e5f82a0bcf9cd8323d3a3bcfbd"
}
}

"Using encodeSecret()" should {
"encode String with a seed" {
val key = "keyToEncode"
val packageName = "com.klaxit.test"
Utils.encodeSecret(key,packageName) shouldBe "{ 0x5b, 0x6, 0x18, 0x31, 0xb, 0x72, 0x57, 0x5, 0x5d, 0x57, 0x3 }"
Utils.encodeSecret(key, packageName) shouldBe "{ 0x5b, 0x6, 0x18, 0x31, 0xb, 0x72, 0x57, 0x5, 0x5d, 0x57, 0x3 }"
}
"encode String with special characters" {
val key = "@&é(§èçà)-ù,;:=#°_*%£?./+"
val packageName = "com.klaxit.test"
Utils.encodeSecret(key, 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 }"
}
}
})

0 comments on commit b0ace02

Please sign in to comment.