Skip to content

Commit

Permalink
Added default configurations for rooting and antipiracy modules, …
Browse files Browse the repository at this point in the history
…and pre-packaged DSLs. Now every Kevlar entry point requires a DSL: removed dfu config (so that users can intentionally choose which one to use). Documentation updates w.r.t. the configuration of libraries (wip). Cleaned up example code & website configuration. Polishing here&there.
  • Loading branch information
cioccarellia committed Jan 18, 2024
1 parent 9a8b808 commit 632b2f4
Show file tree
Hide file tree
Showing 19 changed files with 375 additions and 140 deletions.
1 change: 1 addition & 0 deletions .idea/codeStyles/Project.xml
100755 → 100644

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/kotlinc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import java.util.concurrent.atomic.AtomicInteger
* Main class for `:antipiracy` package.
* */
public class KevlarAntipiracy(
block: AntipiracySettingsBuilder.() -> Unit = DefaultAntipiracySettings
block: AntipiracySettingsBuilder.() -> Unit
) {
private val settings: AntipiracySettings = AntipiracySettingsBuilder().apply(block).build()

Expand All @@ -47,12 +47,60 @@ public class KevlarAntipiracy(
* */
public fun blankAttestation(index: Int = 0): AntipiracyAttestation = AntipiracyAttestation.Blank(index)
}
}

public val DefaultAntipiracySettings: AntipiracySettingsBuilder.() -> Unit = {
this.run {
scan {
pirate()
/**
* Contains relevant pre-packaged configurations for automatically configuring [KevlarAntipiracy].
* */
@Suppress("FunctionName")
public object Defaults {
public fun Full(): KevlarAntipiracy = KevlarAntipiracy(fullAntipiracySettingsDsl)
public fun JustPirateApps(): KevlarAntipiracy = KevlarAntipiracy(pirateOnlyAntipiracySettingsDsl)
public fun JustStores(): KevlarAntipiracy = KevlarAntipiracy(storeOnlyAntipiracySettingsDsl)
public fun PirateAndStore(): KevlarAntipiracy = KevlarAntipiracy(pirateAndStoreAntipiracySettingsDsl)
public fun Empty(): KevlarAntipiracy = KevlarAntipiracy(emptyAntipiracySettingsDsl)


private val fullAntipiracySettingsDsl: AntipiracySettingsBuilder.() -> Unit = {
this.run {
scan {
pirate()
store()
collateral()
}
}
}

private val pirateOnlyAntipiracySettingsDsl: AntipiracySettingsBuilder.() -> Unit = {
this.run {
scan {
pirate()
}
}
}

private val storeOnlyAntipiracySettingsDsl: AntipiracySettingsBuilder.() -> Unit = {
this.run {
scan {
store()
}
}
}

private val pirateAndStoreAntipiracySettingsDsl: AntipiracySettingsBuilder.() -> Unit = {
this.run {
scan {
pirate()
store()
}
}
}

private val emptyAntipiracySettingsDsl: AntipiracySettingsBuilder.() -> Unit = {
this.run {
scan {
// No scan parameters
}
}
}
}
}
65 changes: 41 additions & 24 deletions docs/pages/modules/antipiracy/antipiracy.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,32 +30,12 @@ Each attestation request will cause Kevlar to grab the package list, run the app

The settings you provide influence what will be included in the attestation.

??? note "Empty & default settings"
The settings on `antipiracy` are additive. If you leave a blank DSL, nothing will be detected, because no checks will be run, because the settings are empty.

If you do not pass a DSL at all, the default settings will be used (they only scan for pirate apps, not stores nor collateral).

```kotlin title="Custom"
private val antipiracy = KevlarAntipiracy {
scan {
pirate()
store()
collateral()
}
}
```

```kotlin title="Empty"
private val antipiracy = KevlarAntipiracy {
scan {

}
}
```

```kotlin title="Default"
private val antipiracy = KevlarAntipiracy()
```





## Attestation process overview
Expand Down Expand Up @@ -87,4 +67,41 @@ Scan settings are taken into account intelligently to analyze and run the batter

The full attestation process takes from start to finish ≈ 75-200ms for my devices and emulators (assuming the full app list is returned, which it won't for Android 11+ [which is actually good news for performance, since the time taken for computing the whole attestation is linearly proportional to the number of applications returned by `PackageManager`]). It is mainly influenced by the processing power of the device, the number of apps installed, and your scan configuration.

It is decently fast, given that it will be run in the background before business-critical transactions (e.g. when the user clicks "purchase", we first check that the device is clean and then actually contact Google Play to initiate the transaction).
It is decently fast, given that it is intended to be run quickly in the background before business-critical transactions (e.g. when the user clicks "purchase", we first check that the device is clean and then actually contact Google Play to initiate the high-value transaction).








# Configuring `KevlarAntipiracy`
The antipiracy module is easy to configure, since it works automatically: you just have to choose which search criteria is used.

You may choose to configure the antipiracy module manually (using the dedicated DSL, more flexibility), or just using one of the default configurations.


```kotlin title="Default Configurations"
private val antipiracy = KevlarAntipiracy.Defaults.Full()
```

```kotlin title="Manual DSL"
private val antipiracy = KevlarAntipiracy {
scan {
pirate()
collateral()
}
}
```

You can find more information about each individual item in the [reference](reference.md) page.


The settings are additive. If you leave a blank DSL, nothing will be detected, because no checks will be run, because the settings are empty.

```kotlin title="Empty"
private val antipiracy = KevlarAntipiracy {
scan {}
}
```
79 changes: 47 additions & 32 deletions docs/pages/modules/integrity/integrity.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,41 +36,9 @@ It is capable of detecting:
To [implement](implementation.md) this, you initialize `KevlarIntegrity` and provide your desired settings (which influence what is to be checked and what not). Then you can submit attestation requests (which will be executed according to your settings).


??? note "Empty & default settings"
The settings on `integrity` are additive. If you leave a blank DSL, nothing will be detected, because no checks will be run, because the settings are empty.

By default, only `debug` and `installer` checks are enbabled, since you need to provide additional arguments to enable `signature` and `packageName`

If you do not pass a DSL at all, the default settings will be used (they scan for signature, package name, and debug).

```kotlin title="Custom (simplified)"
private val integrity = KevlarIntegrity {
checks {
packageName() {
// Allowed package name
hardcodedPackageName("com.kevlar.showcase")
}
signature() {
// Allowed signature
hardcodedSignatures("J+nqXLfuIO8B2AmhkMYHGE4jDyw=")
}
debug()
installer()
}
}
```

```kotlin title="Empty"
private val integrity = KevlarIntegrity {
checks {

}
}
```

```kotlin title="Default"
private val integrity = KevlarIntegrity()
```


## Attestation process overview
Expand All @@ -90,5 +58,52 @@ The attestation is returned in `IntegrityAttestation` (it is a sealed class), wh
!!! warning
`Blank` is completely different from `Clear` (or `Failed`). It means that the software is initialized but that nothing has been done yet. Do not mix them up.







## Configuring `KevlarIntegrity`
The integrity module requires attentive and detailed configuration (since kevlar needs the "real" data that will be compared at against the runtime values when your app executes).
You can find details on the process of configuring and retrieving the necessary data in the [implementation](implementation.md) page.

Thus there are no default configuration: you have to manually specify each item through the DSL.

```kotlin title="Manual configuration (simplified)"
private val integrity = KevlarIntegrity {
checks {
packageName() {
// Allowed package name
hardcodedPackageName("com.kevlar.showcase")
}
signature() {
// Allowed signature
hardcodedSignatures("J+nqXLfuIO8B2AmhkMYHGE4jDyw=")
}
debug()
installer()
}
}
```

You can find more information about each individual item in the [reference](reference.md) page.

The settings are additive. If you leave a blank DSL, nothing will be detected, because no checks will be run, because the settings are empty.

```kotlin title="Empty"
private val integrity = KevlarIntegrity {
checks {}
}
```









## Use cases
This is a pretty typical scenario for any application where it is critical to preserve self-integrity and run unmodified code.
1 change: 0 additions & 1 deletion docs/pages/modules/rooting/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ private val rooting = KevlarRooting {
root()
magisk()
busybox()
toybox()
xposed()
}

Expand Down
42 changes: 42 additions & 0 deletions docs/pages/modules/rooting/reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Reference

The complete rooting configuration is as follows.

```kotlin title="Complete Rooting settings"
private val rooting = KevlarRooting {
targets {
root()
magisk()
busybox()
xposed()
}

status {
testKeys()
emulator()
selinux {
flagPermissive()
}
}

allowExplicitRootCheck()
}
```


!!! warning
Bear in mind, this kind of configuration is exhaustive and should be used just in a few cases where you *really* need to detect all of those conditions.
Only including what your application's security environment requires is a key step in properly configuring the library.


Unlike other Kevlar modules, here you can actually require two different types of attestation: you have `attestateTargets` and `attestateRooting`.
Once you require the attestation through any of those two methods, any discrepancies between your expected configuration (w.r.t. the invoked attestation type) and the actual device status will be reported back to you.

```kotlin
withContext(externalDispatcher) {
val targetAttestation = rooting.attestateTargets(context)
val statusAttestation = rooting.attestateStatus()
}
```


Loading

0 comments on commit 632b2f4

Please sign in to comment.