Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for ECIES with temporary keys #612

Merged
merged 14 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Related projects

If you need to upgrade PowerAuth Mobile SDK to a newer version, you can check following migration guides:

- [Migration from version `1.8.x` to `1.9.x`](docs/Migration-from-1.8-to-1.9.md)
- [Migration from version `1.7.x` to `1.8.x`](docs/Migration-from-1.7-to-1.8.md)
- [Migration from version `1.6.x` to `1.7.x`](docs/Migration-from-1.6-to-1.7.md)
- [Migration from version `1.5.x` to `1.6.x`](docs/Migration-from-1.5-to-1.6.md)
Expand All @@ -32,11 +33,12 @@ If you need to upgrade PowerAuth Mobile SDK to a newer version, you can check fo

| Mobile SDK | Protocol | PowerAuth Server | Support Status |
|------------|----------|---------------------|-----------------------------------|
| `1.8.x` | `V3.2` | `1.5+` | Fully supported |
| `1.7.x` | `V3.1` | `0.24+` | Security & Functionality bugfixes |
| `1.9.x` | `V3.3` | `1.9+` | Fully supported |
| `1.8.x` | `V3.2` | `1.5+` | Security & Functionality bugfixes |
| `1.7.x` | `V3.1` | `0.24+` | Security bugfixes |
| `1.6.x` | `V3.1` | `0.24+` | Security bugfixes |
| `1.5.x` | `V3.1` | `0.24+` | Security bugfixes |
| `1.4.x` | `V3.1` | `0.24+` | Security bugfixes |
| `1.4.x` | `V3.1` | `0.24+` | Not supported |
| `1.3.x` | `V3.1` | `0.23+` | Not supported |
| `1.2.x` | `V3.0` | `0.22+` | Not supported |
| `1.1.x` | `V3.0` | `0.21+` | Not supported |
Expand Down
84 changes: 84 additions & 0 deletions docs/Migration-from-1.8-to-1.9.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Migration from 1.8.x to 1.9.x

PowerAuth Mobile SDK in version `1.9.0` provides the following improvements:

- Added support for PowerAuth protocol version 3.3, including the following improvements:
- The PowerAuth protocol is no longer use EC key-pairs for encryption and signature calculation (dual use problem.)
- The End-To-End encryption is now using a temporary keys to improve the forward secrecy of our ECIES scheme.
- Simplified construction of encrypted request and response. Check updated [Android](PowerAuth-SDK-for-Android.md#end-to-end-encryption) or [iOS](PowerAuth-SDK-for-iOS.md#end-to-end-encryption) documentation for more details.

### Compatibility with PowerAuth Server

- This release is fully compatible with PowerAuth Server version `1.9.0` and newer.

## Android

### API changes

- The following methods are now deprecated in the `PowerAuthSDK` class:
- Synchronous method `getEciesEncryptorForApplicationScope()` is replaced with asynchronous variant that guarantees the temporary encryption key is prepared.
- Synchronous method `getEciesEncryptorForActivationScope()` is replaced with asynchronous variant that guarantees the temporary encryption key is prepared.

- Removed all interfaces deprecated in release `1.8.x`

### Other changes

#### End-To-End Encryption

Encrypted request now contains a new property `temporaryKeyId` with type `String`, please update your model objects. For example:

```json
{
"temporaryKeyId" : "UUID",
"ephemeralPublicKey" : "BASE64-DATA-BLOB",
"encryptedData": "BASE64-DATA-BLOB",
"mac" : "BASE64-DATA-BLOB",
"nonce" : "BASE64-NONCE",
"timestamp" : 1694172789256
}
```

You can use new `EciesCryptogram.toEncryptedRequest()` method to convert cryptogram into easily serializable request object. It's also no longer necessary to synchronize the time with the server, because as the new asynchronous `getEciesEncryptorFor{*}Scope()` methods do that automatically.

## iOS & tvOS

### API changes

- The following methods in `PowerAuthSDK` are now deprecated:
- Synchronous function `eciesEncryptorForApplicationScope()` is replaced with asynchronous variant that guarantees the temporary encryption key is prepared.
- Synchronous function `eciesEncryptorForActivationScope()` is replaced with asynchronous variant that guarantees the temporary encryption key is prepared.

- Removed all interfaces deprecated in release `1.8.x`

### Other changes

#### End-To-End Encryption

Encrypted request now contains a new property `temporaryKeyId` with type `String`, please update your model objects. For example:

```json
{
"temporaryKeyId" : "UUID",
"ephemeralPublicKey" : "BASE64-DATA-BLOB",
"encryptedData": "BASE64-DATA-BLOB",
"mac" : "BASE64-DATA-BLOB",
"nonce" : "BASE64-NONCE",
"timestamp" : 1694172789256
}
```

You can use the new `PowerAuthCoreEciesCryptogram.requestPayload()` function to prepare a dictionary containing all request parameters. It's also no longer necessary to synchronize the time with the server, because as the new asynchronous `eciesEncryptorFor{*}Scope()` functions do that automatically.

## iOS & tvOS App Extensions

- Removed all interfaces deprecated in release `1.8.x`

## Known Bugs

The PowerAuth SDKs for iOS and tvOS App Extensions, as well as for watchOS, do not use time synchronized with the server for token-based authentication. To avoid any compatibility issues with the server, the authentication headers generated in your App Extension or on watchOS still use the older protocol version 3.1. This issue will be fixed in a future SDK update.

You can watch the following related issues:

- [wultra/powerauth-mobile-sdk#551](https://github.com/wultra/powerauth-mobile-sdk/issues/551)
- [wultra/powerauth-mobile-watch-sdk#7](https://github.com/wultra/powerauth-mobile-watch-sdk/issues/7)
- [wultra/powerauth-mobile-extensions-sdk#7](https://github.com/wultra/powerauth-mobile-extensions-sdk/issues/7)
60 changes: 31 additions & 29 deletions docs/PowerAuth-SDK-for-Android.md
Original file line number Diff line number Diff line change
Expand Up @@ -2091,29 +2091,29 @@ The following steps are typically required for a full E2EE request and response
1. Acquire the right encryptor from the `PowerAuthSDK` instance. For example:
```kotlin
// Encryptor for "application" scope.
val encryptor = powerAuthSDK.eciesEncryptorForApplicationScope
val cancelable = powerAuthSDK.eciesEncryptorForApplicationScope(object : IGetEciesEncryptorListener {
override fun onGetEciesEncryptorSuccess(encryptor: EciesEncryptor) {
// Success
}

override fun onGetEciesEncryptorFailed(t: Throwable) {
// Failure
}
})
// ...or similar, for an "activation" scope.
val encryptor = powerAuthSDK.getEciesEncryptorForActivationScope(context)
val cancelable = powerAuthSDK.getEciesEncryptorForActivationScope(context, object : IGetEciesEncryptorListener {
override fun onGetEciesEncryptorSuccess(encryptor: EciesEncryptor) {
// Success
}

override fun onGetEciesEncryptorFailed(t: Throwable) {
// Failure
}
})
```

1. Serialize your request payload, if needed, into a sequence of bytes. This step typically means that you need to serialize your model object into a JSON-formatted sequence of bytes.

1. Make sure that the PowerAuth SDK instance has [time synchronized with the server](#synchronized-time):
```kotlin
val timeService = powerAuthSDK.timeSynchronizationService
if (!timeService.isTimeSynchronized) {
timeService.synchronizeTime(object : ITimeSynchronizationListener {
override fun onTimeSynchronizationSucceeded() {
// Success
}

override fun onTimeSynchronizationFailed(t: Throwable) {
// Failure
}
})
}
```

1. Encrypt your payload:
```kotlin
val cryptogram = encryptor.encryptRequest(payloadData)
Expand All @@ -2122,16 +2122,15 @@ The following steps are typically required for a full E2EE request and response
}
```

1. Construct a JSON from the provided cryptogram object. The dictionary with the following keys is expected:
- `ephemeralPublicKey` property fill with `cryptogram.getKeyBase64()`
- `encryptedData` property fill with `cryptogram.getBodyBase64()`
- `mac` property fill with `cryptogram.getMacBase64()`
- `nonce` property fill with `cryptogram.getNonceBase64()`
- `timestamp` property fill with `cryptogram.getTimestamp()`

1. Construct a JSON from the provided cryptogram object:
```kotlin
val requestObject = cryptogram.toEncryptedRequest()
val requestJson = Gson().toJson(requestObject)
```
So, the final request JSON should look like this:
```json
{
"temporaryKeyId" : "UUID",
"ephemeralPublicKey" : "BASE64-DATA-BLOB",
"encryptedData" : "BASE64-DATA-BLOB",
"mac" : "BASE64-DATA-BLOB",
Expand All @@ -2152,7 +2151,7 @@ The following steps are typically required for a full E2EE request and response
1. Fire your HTTP request and wait for a response
- In case that non-200 HTTP status code is received, then the error processing is identical to a standard RESTful response defined in our protocol. So, you can expect a JSON object with `"error"` and `"message"` properties in the response.

1. Decrypt the response. The received JSON typically looks like this:
1. Decrypt the response. The received JSON response typically looks like this:
```json
{
"encryptedData" : "BASE64-DATA-BLOB",
Expand All @@ -2161,10 +2160,13 @@ The following steps are typically required for a full E2EE request and response
"timestamp" : 1694172789256
}
```

So, you need to create yet another "cryptogram" object, but with only two properties set:
So, you need to create yet another "cryptogram" object:
```kotlin
val responseCryptogram = EciesCryptogram(response.encryptedData, response.mac)
val responseObject = Gson().fromJson(responseData, EciesEncryptedResponse::class.java)
val responseCryptogram = EciesCryptogram.fromEncryptedResponse(responseObject)
if (responseCryptogram == null) {
// failure
}
val responseData = encryptor.decryptResponse(responseCryptogram)
if (responseData == null) {
// failed to decrypt response data
Expand Down
52 changes: 23 additions & 29 deletions docs/PowerAuth-SDK-for-iOS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1255,20 +1255,20 @@ The following steps are typically required for a full E2EE request and response
import PowerAuthCore

// Encryptor for "application" scope.
guard let encryptor = powerAuthSDK.eciesEncryptorForApplicationScope() else { ...failure... }
sdk.eciesEncryptorForApplicationScope { encryptor, error in
if let encryptor {
// success
} else {
// failure
}
}
// ...or similar, for an "activation" scope.
guard let encryptor = powerAuthSDK.eciesEncryptorForActivationScope() else { ...failure... }
```

1. Make sure that the PowerAuth SDK instance has [time synchronized with the server](#synchronized-time):
```swift
let timeService = powerAuthSDK.timeSynchronizationService
if !timeService.isTimeSynchronized {
timeService.synchronizeTime(callback: { error in
if error != nil {
// failure
}
}, callbackQueue: .main)
sdk.eciesEncryptorForActivationScope { encryptor, error in
if let encryptor {
// success
} else {
// failure
}
}
```

Expand All @@ -1279,18 +1279,16 @@ The following steps are typically required for a full E2EE request and response
guard let cryptogram = encryptor.encryptRequest(payloadData) else { ...failure... }
```

1. Construct a JSON from the provided cryptogram object. The dictionary with the following keys is expected:
- `ephemeralPublicKey` property fill with `cryptogram.keyBase64`
- `encryptedData` property fill with `cryptogram.bodyBase64`
- `mac` property fill with `cryptogram.macBase64`
- `nonce` property fill with `cryptogram.nonceBase64`
- `timestamp` property fill with `cryptogram.timestamp`

1. Construct a JSON from the provided cryptogram object:
```swift
guard let requestBody = try? JSONSerialization.data(withJSONObject: cryptogram.requestPayload()) else { ...failure... }
```
So, the final request JSON should look like this:
```json
{
"temporaryKeyId" : "UUID",
"ephemeralPublicKey" : "BASE64-DATA-BLOB",
"encryptedData": "BASE64-DATA-BLOB",
"encryptedData" : "BASE64-DATA-BLOB",
"mac" : "BASE64-DATA-BLOB",
"nonce" : "BASE64-NONCE",
"timestamp" : 1694172789256
Expand All @@ -1309,7 +1307,7 @@ The following steps are typically required for a full E2EE request and response
1. Fire your HTTP request and wait for a response
- In case that non-200 HTTP status code is received, then the error processing is identical to a standard RESTful response defined in our protocol. So, you can expect a JSON object with `"error"` and `"message"` properties in the response.

1. Decrypt the response. The received JSON typically looks like this:
1. Decrypt the response. The received JSON response typically looks like this:
```json
{
"encryptedData": "BASE64-DATA-BLOB",
Expand All @@ -1318,14 +1316,10 @@ The following steps are typically required for a full E2EE request and response
"timestamp": 1694172789256
}
```
So, you need to create yet another "cryptogram" object, but with only two properties set:
So, you need to create yet another "cryptogram" object:
```swift
let responseCryptogram = PowerAuthCoreEciesCryptogram()
responseCryptogram.bodyBase64 = response.getEncryptedData()
responseCryptogram.macBase64 = response.getMac()
responseCryptogram.nonceBase64 = response.getNonce()
responseCryptogram.timestamp = response.getTimestamp()

guard let response = try? JSONSerialization.jsonObject(with: responseBody) else { ...failure... }
guard let responseCryptogram = PowerAuthCoreEciesCryptogram(responsePayload: response) else { ...not a dictionary... }
guard let responseData = encryptor.decryptResponse(responseCryptogram) else { ... failed to decrypt data ... }
```

Expand Down
8 changes: 5 additions & 3 deletions docs/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Related projects

If you need to upgrade PowerAuth Mobile SDK to a newer version, you can check the following migration guides:

- [Migration from version `1.8.x` to `1.9.x`](Migration-from-1.8-to-1.9.md)
- [Migration from version `1.7.x` to `1.8.x`](Migration-from-1.7-to-1.8.md)
- [Migration from version `1.6.x` to `1.7.x`](Migration-from-1.6-to-1.7.md)
- [Migration from version `1.5.x` to `1.6.x`](Migration-from-1.5-to-1.6.md)
Expand All @@ -32,11 +33,12 @@ If you need to upgrade PowerAuth Mobile SDK to a newer version, you can check th

| Mobile SDK | Protocol | PowerAuth Server | Support Status |
|------------|----------|---------------------|-----------------------------------|
| `1.8.x` | `V3.2` | `1.5+` | Fully supported |
| `1.7.x` | `V3.1` | `0.24+` | Security & Functionality bugfixes |
| `1.9.x` | `V3.3` | `1.9+` | Fully supported |
| `1.8.x` | `V3.2` | `1.5+` | Security & Functionality bugfixes |
| `1.7.x` | `V3.1` | `0.24+` | Security bugfixes |
| `1.6.x` | `V3.1` | `0.24+` | Security bugfixes |
| `1.5.x` | `V3.1` | `0.24+` | Security bugfixes |
| `1.4.x` | `V3.1` | `0.24+` | Security bugfixes |
| `1.4.x` | `V3.1` | `0.24+` | Not supported |
| `1.3.x` | `V3.1` | `0.23+` | Not supported |
| `1.2.x` | `V3.0` | `0.22+` | Not supported |
| `1.1.x` | `V3.0` | `0.21+` | Not supported |
Expand Down
2 changes: 1 addition & 1 deletion include/PowerAuth/ECIES.h
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ namespace powerAuth
public:
/// Build associated data from provided parameters. If activationId is not available (e.g. for ECIES in application scope)
/// then you can provide an empty string.
static cc7::ByteArray buildAssociatedData(const std::string & applicationKey, const std::string & activationId);
static cc7::ByteArray buildAssociatedData(const std::string & applicationKey, const std::string & temporaryKeyId, const std::string & activationId);
};


Expand Down
Loading
Loading