# Android

_Encrypt data client-side, collect card details & perform 3D Secure authentication._

The [Evervault](https://evervault.com/) Android SDK is a library for encrypting data and collecting credit cards data on Android Devices. It's simple to integrate, easy to use and it supports a wide range of data types.

## Features

- Core encryption capabilities for various data types.
- A secure and customizable PaymentCard Compose view.
- Built-in data type recognition and appropriate encryption handling.

## Supported Platforms

- Android (API Version 26-33)

## Quickstart

### Install SDK

Our Android SDK distributed via [maven](https://central.sonatype.com/search?q=com.evervault.sdk), and can be installed using your preferred build tool.

If you are installing `evervault-inputs` from version `2.0.0` and onwards you will also need to add the JitPack repository to your build file:

```kotlin
dependencyResolutionManagement {
  repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
  repositories {
    mavenCentral()
    maven { url = uri("https://jitpack.io") }
  }
}
```

#### Gradle DSL

```kotlin
implementation("com.evervault.sdk:evervault-core:1.2")
implementation("com.evervault.sdk:evervault-inputs:2.0.0")
implementation("com.evervault.sdk:evervault-enclaves:2.0.0")
```

#### Maven

```xml
<dependency>
  <groupId>com.evervault.sdk</groupId>
  <artifactId>evervault-core</artifactId>
  <version>1.2</version>
  </dependency>
<dependency>
  <groupId>com.evervault.sdk</groupId>
  <artifactId>evervault-inputs</artifactId>
  <version>2.0.0</version>
  </dependency>
<dependency>
  <groupId>com.evervault.sdk</groupId>
  <artifactId>evervault-enclaves</artifactId>
  <version>2.0.0</version>
  </dependency>
```

#### Initialize SDK

Before using the Evervault Android SDK, you need to configure it with your Evervault Team ID and App ID. This step is essential for establishing a connection with the Evervault encryption service.

```kotlin
Evervault.shared.configure("<TEAM_ID>", "<APP_ID>")
```

Make sure to replace `<TEAM_ID>` and `<APP_ID>` with your actual Evervault Team ID and App ID which can be found in the [Evervault Dashboard](https://app.evervault.com)

### Encrypting Data

Once the SDK is configured, you can use the `encrypt` method to encrypt sensitive data. The `encrypt` method accepts Java's primitive data types and an optional [role](/developers/data-policies)

Here's an example of encrypting a social security number:

```kotlin
val encryptedPassword = Evervault.shared.encrypt("123-12-1234")
```

A role defines an encryption policy to be applied to the return ciphertext. The `encrypt` function takes as an optional parameter `role` which is the `id` of the role created in your [Evervault App](https://app.evervault.com)

```kotlin
val encryptedPassword = Evervault.shared.encrypt("123-12-1234", 'role-id')
```

The `encrypt` method returns an `Any` type, so you will need to safely cast the result based on the data type you provided. For Boolean, Numerics, and Strings, the encrypted data is returned as a String. For Arrays, Lists and Maps, the encrypted data maintains the same structure but is encrypted (except that Arrays become Lists). For ByteArray, the encrypted data is returned as encrypted ByteArray, which can be useful for encrypting files.

### Decrypting Data

Decrypts data previously encrypted with the `encrypt()` function or through Relay.
The `decrypt()` function allows you to decrypt previously encrypted data using a token.

The token is a time bound token for decrypting data. The token can be generated using our [backend SDKs](/sdks) or through our [REST API](/api).
The payload must be the same payload that was used to create the token and expires 10 minutes after creation.
The payload must be a map and the response is `Any` which can, and should be, cast to `Map<String, Any>`

```kotlin
val encrypted = Evervault.shared.encrypt("Super Secret Password")

val decrypted = Evervault.shared.decrypt(token, mapOf("data" to encrypted)) as Map<String, Any>
println(decrypted["data"]) // Output: "Super Secret Password"
```

## Inputs

The Evervault Android SDK also provides a Compose view called `PaymentCard`. This view is designed for capturing credit card information and automatically encrypts the credit card number and CVC without exposing the unencrypted data. The `PaymentCard` view can be customized to fit your application's design.

Here's an example of using the `PaymentCard` composable:

```kotlin
UserParentLayout {
    val onDataChange: (PaymentCardData) -> Unit = {} // Handle card data
    // ...
    PaymentCard(onDataChange = onDataChange) {
        // User custom payment card layout using the [PaymentCardInputScope] components with a combination of user own components and modifiers
    }
}
```

The encrypted credit card number and CVC are captured in the `PaymentCardData`, as well as the expiry month and year and validation fields.

### Styling

The `PaymentCard` and its components can be customized to fit your application's design. The view excepts a number of parameters that enable you to customize the modifier, text and placeholder styles. The `content` parameter accepts a `@Composable PaymentCardInputScope.()` function, which can be used to customize the view's layout. The `PaymentCardInputScope` components can be customized with a modifier (`Modifier`), label (`String` or `@Composable`), placeholder (`String` or `@Composable`), text style (`TextStyle`), and input field colors (`TextFieldColors`).

Two build-in layouts are provided:

#### Inline

- `InlinePaymentCard` (the default layout) - This layout displays the card number, expiry and CVC fields inline.

![Screenshot of the Android PaymentCard with Inline styling]()

```kotlin
@Composable
fun InlinePaymentCard(
    modifier: Modifier = Modifier,
    textStyle: TextStyle = TextStyle.Default,
    placeholderTexts: PlaceholderTexts = PlaceholderDefaults.texts(),
    placeholderTextStyle: TextStyle = textStyle.copy(color = MaterialTheme.colorScheme.secondary),
    onDataChange: (PaymentCardData) -> Unit = {}
)
```

#### Rows

`RowsPaymentCard` - Displays the credit card number on a single row. Below it, places the expiry and cvc fields next to each other.

![Screenshot of the Android PaymentCard with Rows styling]()

```kotlin
@Composable
fun RowsPaymentCard(
    modifier: Modifier = Modifier,
    textStyle: TextStyle = TextStyle.Default,
    placeholderTexts: PlaceholderTexts = PlaceholderDefaults.texts(),
    placeholderTextStyle: TextStyle = textStyle.copy(color = MaterialTheme.colorScheme.secondary),
    onDataChange: (PaymentCardData) -> Unit = {}
)
```

You can also customize these layout through theming and modifiers:

```kotlin
UserCustomTheme {
    // ...
    val modifier: Modifier = Modifier
    val onDataChange: (PaymentCardData) -> Unit = {} // Handle card data
    // ...
    InlinePaymentCard(modifier = modifier, onDataChange = onDataChange)
}
```

#### Custom Layout

If these two layouts do not fit your application's design, you can create your own layout by passing a `@Composable` function to the `content` parameter. The `@Composable` function will receive a `PaymentCardInputScope` (together with the `PaymentCard` `Modifier`) object, which contains the `CardImage`, `CardNumberField`, `ExpiryField` and `CVCField` fields. You can use these fields to create your own layout:

```kotlin
UserParentLayout {
    val onDataChange: (PaymentCardData) -> Unit = {} // Handle card data
    // ...
    PaymentCard(onDataChange = onDataChange) { modifier ->
        Column(
            modifier = modifier
                .border(BorderStroke(1.dp, Color.LightGray), RoundedCornerShape(8.dp))
                .padding(16.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.spacedBy(8.dp),
        ) {
            CardImage()

            CardNumberField(
                modifier = Modifier.fillMaxWidth(),
                label = {
                    Text(
                        text = LabelTextsDefaults.CreditCardText,
                        color = Color.Blue
                    )
                },
                placeholder = {
                    Text(
                        text = PlaceholderTextsDefaults.CreditCardText,
                        color = Color(0x75757575),
                        fontSize = 12.sp
                    )
                },
                textStyle = MaterialTheme.typography.titleLarge,
                textFieldColors = customTextFieldColors()
            )

            ExpiryField(
                modifier = Modifier.fillMaxWidth(),
                label = {
                    Text(
                        text = LabelTextsDefaults.ExpirationDateText,
                        color = Color.Blue
                    )
                },
                placeholder = {
                    Text(
                        text = PlaceholderTextsDefaults.ExpirationDateText,
                        color = Color(0x9E9E9E9E),
                        fontSize = 10.sp
                    )
                },
                textStyle = MaterialTheme.typography.titleMedium,
                textFieldColors = customTextFieldColors()
            )

            CVCField(
                modifier = Modifier.fillMaxWidth(),
                label = {
                    Text(
                        text = LabelTextsDefaults.CvcText,
                        color = Color.Blue
                    )
                },
                placeholder = {
                    Text(
                        text = PlaceholderTextsDefaults.CvcText,
                        color = Color(0xBDBDBDBD),
                        fontSize = 8.sp
                    )
                },
                textStyle = MaterialTheme.typography.bodyMedium,
                textFieldColors = customTextFieldColors()
            )
        }
    }
}

@Composable
private fun customTextFieldColors(): TextFieldColors = TextFieldDefaults.colors(
    focusedIndicatorColor = Color.Transparent,
    unfocusedIndicatorColor = Color.Transparent,
    disabledIndicatorColor = Color.Transparent,
    focusedContainerColor = Color.Transparent,
    unfocusedContainerColor = Color.Transparent,
    disabledContainerColor = Color.Transparent,
)
```

#### Optional Rendering

Fields can be optionally displayed by passing in a list of CardFields. For example if you with to only render the Card Number field use the following code.

```kotlin
import com.evervault.sdk.input.model.CardFields

UserCustomTheme {
    // ...
    val modifier: Modifier = Modifier
    val onDataChange: (PaymentCardData) -> Unit = {} //
    PaymentCardView { onDataChange ->
        PaymentCard(onDataChange = onDataChange, enabledFields = listOf(CardFields.CARD_NUMBER)) { modifier ->
            Column(
                modifier = modifier
                    .border(BorderStroke(1.dp, Color.LightGray), RoundedCornerShape(8.dp))
                    .padding(16.dp),
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.spacedBy(8.dp),
            ) {
                CardImage()

                CardNumberField(
                    modifier = Modifier.fillMaxWidth(),
                    label = null,
                    placeholder = {
                        Text(
                            text = PlaceholderTextsDefaults.CreditCardText,
                            color = Color(0x75757575),
                            fontSize = 12.sp
                        )
                    },
                    textStyle = MaterialTheme.typography.titleLarge,
                    textFieldColors = customTextFieldColors()
                )
            }
        }
    }
}
```

## Enclaves

The Evervault Enclaves SDK provides an accessible solution for developers to deploy Docker containers within a Secure Enclave. It enables you to interact with your Enclaves endpoints via standard HTTPS requests directly from your Android applications. A key feature that enables this is the attestation verification performed before completing the TLS handshake. For a deeper understanding of this process, you can explore our [TLS Attestation documentation](/enclaves#attestation-in-tls).

The attestation verification is executed using a custom Trust Manager on a `OkHttpClient.Builder`. This Trust Manager needs initialization with an `AttestationData` object:

```kotlin
data class AttestationData(
    val enclaveName: String,
    val pcrs: List<PCRs>
) {
    constructor(enclaveName: String, vararg pcrs: PCRs)
}

data class PCRs(
    val pcr0: String? = null,
    val pcr1: String? = null,
    val pcr2: String? = null,
    val pcr8: String? = null
)
```

It is crucial to ensure that the supplied PCRs align with the PCRs of the respective Enclave.

Then you configure the HTTP Client with the attestations:

```kotlin

val client = OkHttpClient.Builder()
    .trustManager(AttestationData(
        enclaveName = enclaveName,
        // Replace with legitimate PCR strings when not in debug mode
        PCRs(
            pcr0 = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            pcr1 = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            pcr2 = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            pcr8 = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
        )
    ))
    .build()
```

Only use this client for requests to your Enclave. For all other requests, use a separate client.

### Enclave PCR Manager

If the PCRs of your Enclave change, the attestation connection will fail from all clients that are not updated with the new PCRs. The `EnclaveTrustManager` is a service that can optionally be used to cache a list of PCRs that are returned from an API under your control. The `EnclaveTrustManager` can be used by passing a `PcrCallback` and the `enclaveName` as a parameter to `AttestationData` that is used to build the `OkHttpClient`. The `EnclaveTrustManager` will cache the response PCRs from the `PcrCallback` and refresh them at a default interval of 5 minutes. This refresh can be configured by passing the `callbackInterval` parameter.

This example below show how to call an endpoint that returns a list of PCRs as the callback function.

```kotlin
val pcrRequest = Request.Builder()
    .url(BuildConfig.PCR_CALLBACK_URL)
    .build()

val pcrCallback: PcrCallback = {
    val pcrResponse = pcrClient.newCall(pcrRequest).execute()
    val type = object : TypeToken<List<PCRs>>() {}.type
    val responseMap: List<PCRs> = Gson().fromJson(pcrResponse.body!!.string(), type)
    responseMap
}

val client = OkHttpClient.Builder()
    .enclavesTrustManager(
        AttestationData(
            enclaveName = enclaveName,
            pcrCallback
        ),
        appUuid
    )
    .build()
```

The endpoint returning the PCRs must return the PCRs in the format

```json
[
  {
    "pcr0": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
    "pcr1": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
    "pcr2": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
    "pcr8": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
  }
]
```

#### Using the Evervault API as a PCR Provider

The Evervault API exposes an endpoint to retrieve the PCRs for all active versions of your Enclave which you can use to keep your clients in sync with your Enclave across deployments.

```kotlin
// Data type to deserialize the Evervault API's response
data class PCRContainer(
    val data: List<PCRs>
)

fun invokeEnclaveWithEvervaultPCRProvider(enclaveName: String, appId: String, url: String) {
  val pcrClient = OkHttpClient.Builder().build()
  val pcrRequest = Request.Builder()
      .url("https://api.evervault.com/enclaves/$enclaveName/attestation")
      .header("x-evervault-app-id", appId)
      .build()

  try {
    val pcrCallback: PcrCallback = {
      val pcrResponse = pcrClient.newCall(pcrRequest).execute()
      val type = object : TypeToken<PCRContainer>() {}.type
      val responseMap: PCRContainer = Gson().fromJson(pcrResponse.body!!.string(), type)
      responseMap.data
    }

    val jsonPayload = JSONObject()
    jsonPayload.put("a", 1)
    jsonPayload.put("b", 2)

    val request = Request.Builder()
      .url(url)
      .header("content-type", "application/json")
      .post(requestBody)
      .build()

    val enclaveClient = OkHttpClient.Builder()
      .enclavesTrustManager(
          AttestationData(
              enclaveName = enclaveName,
              pcrCallback
          ),
          appUuid
      )
      .build()

    val response = client.newCall(request).execute()
  } catch (e: Exception) {
      when(e) {
          is IOException, is PCRCallbackError -> {
              e.printStackTrace()
              return "Error: ${e.message}"
          }
          else -> throw e
      }
  }
}
```

#### Considerations

- It's crucial to note that the PCR values associated with an Enclave change with each new deployment. Consequently, older versions of your app with hardcoded PCRs may stop functioning. To alleviate this, you can accommodate previous deployments by providing multiple `PCRs` objects or use the `EnclaveTrustManager`:

```kotlin
AttestationData(
    enclaveName = enclaveName,
    listOf(
        PCRs(
            pcr0 = "fd4b",
            pcr1 = "bc3f",
            pcr2 = "2c10",
            pcr8 = "dfb3"
        ),
        PCRs(
            pcr0 = "c779",
            pcr1 = "bc3f",
            pcr2 = "4cbf",
            pcr8 = "dfb3"
        )
    )
)
```

Using the `EnclaveTrustManager` by passing a `PcrCallback` to the `AttestationData` allows you do update your PCRs remotely via an endpoint you control. When an Enclave is deployed and the PCRs change the list of PCRs returned from the endpoint should expand to hold the new PCRs e.g

```json
[
  {
    "pcr0": "fd4b", // Old PCRs
    "pcr1": "bc3f",
    "pcr2": "2c10",
    "pcr8": "dfb3"
  },
  {
    "pcr0": "c779", // New PCRs
    "pcr1": "bc3f",
    "pcr2": "4cbf",
    "pcr8": "dfb3"
  }
]
```

The `EnclaveTrustManager` will cache the new PCRs and old PCRs. Over time you can then remove the old PCRs from your endpoints response leaving just the new PCRs.

```json
[
  {
    "pcr0": "c779", // New PCRs
    "pcr1": "bc3f",
    "pcr2": "4cbf",
    "pcr8": "dfb3"
  }
]
```

This allows for the updating of an Enclave without having to re-publish your client with new PCRs.

- Please be aware that the Android SDK is compatible only with Enclaves that have the API Key Authentication set to `false` in your enclave.toml file:

```
api_key_auth = false
```

- Only use the `OkHttpClient` configured with the `AttestationData` for requests to your Enclave. For all other requests, use a separate client. If you have multiple Enclaves, you will need to configure a separate `OkHttpClient` for each Enclave.

- When calling an endpoint of your Enclave, use make sure you do not have any underscore `_` in the request url. Replace any underscore, such as the one in your App ID, with hyphens `-`.

These considerations are essential to remember for a seamless integration and operation of the Evervault Enclaves SDK in your Android applications.

## Google Pay

The Evervault SDK provides a Google Pay component that allows your customers to make payments in your app using credit and debit cards saved to their Google Account. Read the [Google Pay](/cards/google-pay?client=android) guide for more information.

## Proguard Rules

If you are using code shrinking with ProGuard you will need to specify exclusion rules for evervault-core dependencies. To do this add the following lines to your `proguard-rules.pro`

```
## Keep the BouncyCastle provider classes
-keep class org.bouncycastle.jce.provider.** { *; }

## Keep all classes from the org.bouncycastle package
-keep class org.bouncycastle.** { *; }

## Keep all classes that implement javax.crypto interfaces
-keep class * extends javax.crypto.** { *; }
```

## Sample App

The Evervault Android SDK Package includes a sample app, located in the `sampleapplication` directory. The sample app demonstrates various use cases of the SDK, including string encryption, file (image) encryption, the usage of the `PaymentCard` view with customized styling and how to contruct an attested Enclave client.

## License

The sample app is released under the MIT License. See the [LICENSE](https://github.com/evervault/evervault-multiplatform/blob/main/LICENSE) file for more information.

Feel free to experiment with the sample app to understand the capabilities of the Evervault Android SDK and explore different integration options for your own projects.

## Contributing

Bug reports and pull requests are welcome on [GitHub](https://github.com/evervault/evervault-android).

## Feedback

Questions or feedback? [Let us know](mailto:support@evervault.com).

