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

Merge develop to master #650

Merged
merged 35 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ce62ff1
Fix #623: Set develop version to 1.9.0-SNAPSHOT
banterCZ Jul 26, 2024
7e0de5c
Merge pull request #631 from wultra/issues/623-version-1.9.0-SNAPSHOT
banterCZ Jul 26, 2024
ed57cd0
Bump slf4j.version from 2.0.13 to 2.0.16
dependabot[bot] Aug 12, 2024
b811032
Merge pull request #634 from wultra/dependabot/maven/slf4j.version-2.…
dependabot[bot] Aug 19, 2024
b7d38f2
Bump org.apache.maven.plugins:maven-surefire-plugin from 3.3.1 to 3.4.0
dependabot[bot] Aug 19, 2024
72991c1
Bump junit.version from 5.10.3 to 5.11.0
dependabot[bot] Aug 19, 2024
766881f
Merge pull request #635 from wultra/dependabot/maven/junit.version-5.…
dependabot[bot] Aug 19, 2024
0b9592f
Merge pull request #636 from wultra/dependabot/maven/org.apache.maven…
dependabot[bot] Aug 19, 2024
fffca2c
Bump org.apache.maven.plugins:maven-deploy-plugin from 3.1.2 to 3.1.3…
dependabot[bot] Aug 27, 2024
7532ada
Implement support for temporary keys (#632)
petrdvorak Aug 27, 2024
e840a5c
Bump org.apache.maven.plugins:maven-surefire-plugin from 3.4.0 to 3.5.0
dependabot[bot] Sep 2, 2024
aca5e79
Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.8.0 to 3.10.0
dependabot[bot] Sep 2, 2024
97f3737
Merge pull request #639 from wultra/dependabot/maven/org.apache.maven…
dependabot[bot] Sep 2, 2024
c227a0e
Merge pull request #638 from wultra/dependabot/maven/org.apache.maven…
dependabot[bot] Sep 2, 2024
6843a39
Fix #640: Add documentation for temporary keys (#641)
petrdvorak Sep 11, 2024
fe71d6b
Fix #642: Add exact list of used cryptographic standards (#643)
petrdvorak Sep 17, 2024
5130390
Bump junit.version from 5.11.0 to 5.11.1
dependabot[bot] Sep 30, 2024
24ec9ca
Bump com.fasterxml.jackson.core:jackson-databind from 2.17.2 to 2.18.0
dependabot[bot] Sep 30, 2024
0ff5f3f
Merge pull request #644 from wultra/dependabot/maven/junit.version-5.…
dependabot[bot] Sep 30, 2024
f68f18e
Merge pull request #645 from wultra/dependabot/maven/com.fasterxml.ja…
dependabot[bot] Sep 30, 2024
338eafd
Fix #651: Create PowerAuth-2024.10 page
romanstrobl Oct 2, 2024
1ac8f2f
Merge pull request #652 from wultra/issues/651-release-page
romanstrobl Oct 2, 2024
03c958a
Fix #654: Add temporary keys into the list of keys
romanstrobl Oct 3, 2024
367f854
Merge pull request #655 from wultra/issues/654-add-temporary-keys-int…
romanstrobl Oct 3, 2024
6b0b8a3
Fix #646: Update documentation for OTP validation and commit phase pa…
romanstrobl Oct 4, 2024
a31a98c
Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.10.0 to 3.10.1
dependabot[bot] Oct 7, 2024
2846c06
Bump junit.version from 5.11.1 to 5.11.2
dependabot[bot] Oct 7, 2024
f2fb074
Bump org.apache.maven.plugins:maven-surefire-plugin from 3.5.0 to 3.5.1
dependabot[bot] Oct 7, 2024
a89bf80
Merge pull request #658 from wultra/dependabot/maven/org.apache.maven…
dependabot[bot] Oct 7, 2024
a761df2
Merge pull request #657 from wultra/dependabot/maven/junit.version-5.…
dependabot[bot] Oct 7, 2024
83de379
Merge pull request #656 from wultra/dependabot/maven/org.apache.maven…
dependabot[bot] Oct 7, 2024
6cdf6a9
Fix invalid links in the documentation
banterCZ Oct 7, 2024
cbd42df
Merge pull request #659 from wultra/issues/646-fix-doc-links
banterCZ Oct 7, 2024
9038799
Fix #660: Fix documentation for iat and iat_ms in temporary keys (#661)
romanstrobl Oct 7, 2024
e52f5dc
Fix #647: Set release version to 1.9.0 (#649)
banterCZ Oct 10, 2024
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
54 changes: 29 additions & 25 deletions docs/End-To-End-Encryption.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ Assume we have the following constants and variables defined in our scheme:
- `KEY_EPH_PUB` - Public part of `EPH_KEYPAIR`.
- `SHARED_INFO_2` - Input parameter to MAC calculation.

### Temporary Encryption Keys

To provide required cryptographic features, such as forward secrecy, encryption uses [temporary encryption keys](./Temporary-Encryption-Keys.md) since protocol version `3.3`.

### Encryption Scope

Expand All @@ -37,17 +40,17 @@ PowerAuth protocol defines two basic usage scopes for ECIES encryption:

#### Application Scope

ECIES in application scope has following configuration of parameters:
ECIES in application scope has the following configuration of parameters:

- `KEY_ENC_PUB` is `KEY_SERVER_MASTER_PUBLIC`
- `KEY_ENC_PUB` is a [temporary key](./Temporary-Encryption-Keys.md) with given `TEMP_KEY_ID` identifier fetched from the server associated with a specific application version and signed with `KEY_SERVER_MASTER_PRIVATE` (to prove it was intended for the application scope).
- `SHARED_INFO_1` is a pre-shared constant and is different for each endpoint (see [Pre-shared constants](#pre-shared-constants))
- `SHARED_INFO_2_BASE` is calculated from `APPLICATION_SECRET`:
```java
byte[] SHARED_INFO_2_BASE = Hash.sha256(APPLICATION_SECRET);
```
- `ASSOCIATED_DATA` is calculated as:
```java
byte[] ASSOCIATED_DATA = ByteUtils.concatWithSizes(VERSION, APPLICATION_KEY);
byte[] ASSOCIATED_DATA = ByteUtils.concatWithSizes(VERSION, APPLICATION_KEY, TEMP_KEY_ID);
```

<!-- begin box warning -->
Expand All @@ -56,17 +59,17 @@ Note that the `APPLICATION_SECRET` constant is in Base64 form, so we need to rei

#### Activation Scope

ECIES in activation scope has following configuration of parameters:
ECIES in activation scope has the following configuration of parameters:

- `KEY_ENC_PUB` is `KEY_SERVER_PUBLIC` (e.g. key which is unique for each activation)
- `KEY_ENC_PUB` is a [temporary key](./Temporary-Encryption-Keys.md) with given `TEMP_KEY_ID` identifier fetched from the server associated with a specific application version and activation, and signed with `KEY_SERVER_PRIVATE` (the key which is unique for each activation, to prove it was intended for the activations cope).
- `SHARED_INFO_1` is a pre-shared constant and is different for each endpoint (see [Pre-shared constants](#pre-shared-constants))
- `SHARED_INFO_2_BASE` is calculated from `APPLICATION_SECRET` and `KEY_TRANSPORT`:
```java
byte[] SHARED_INFO_2_BASE = Mac.hmacSha256(KEY_TRANSPORT, APPLICATION_SECRET);
```
- `ASSOCIATED_DATA` is calculated as:
```java
byte[] ASSOCIATED_DATA = ByteUtils.concatWithSizes(VERSION, APPLICATION_KEY, ACTIVATION_ID);
byte[] ASSOCIATED_DATA = ByteUtils.concatWithSizes(VERSION, APPLICATION_KEY, ACTIVATION_ID, TEMP_KEY_ID);
```

<!-- begin box warning -->
Expand All @@ -75,7 +78,7 @@ Note that the `APPLICATION_SECRET` constant is in Base64 form, so we need to rei

### ECIES Encryption

Assume we have a public key `KEY_ENC_PUB`, data `PLAINTEXT` to be encrypted, `ASSOCIATED_DATA` to be included in mac calculation and a `SHARED_INFO_1` and `SHARED_INFO_2_BASE` constants (`byte[]`) as encryption parameters. ECIES encryption works in a following way:
Assume we have a public key `KEY_ENC_PUB`, data `PLAINTEXT` to be encrypted, `ASSOCIATED_DATA` to be included in MAC calculation and a `SHARED_INFO_1` and `SHARED_INFO_2_BASE` constants (`byte[]`) as encryption parameters. ECIES encryption works in the following way:

1. Generate an ephemeral key pair:
```java
Expand Down Expand Up @@ -111,16 +114,16 @@ Assume we have a public key `KEY_ENC_PUB`, data `PLAINTEXT` to be encrypted, `AS
1. Derive `IV` from `NONCE` and encrypt ata using AES.
```java
byte[] IV = KDF_INTERNAL.derive(KEY_IV, NONCE);
byte[] DATA_ENCRYPTED = AES.encrypt(PLAINTEXT, IV, KEY_ENC)
byte[] DATA_ENCRYPTED = AES.encrypt(PLAINTEXT, IV, KEY_ENC);
```
1. Compute the MAC of encrypted data, include `SHARED_INFO_2`.
```java
byte[] DATA = Bytes.concat(DATA_ENCRYPTED, SHARED_INFO_2);
byte[] MAC = Mac.hmacSha256(KEY_MAC, DATA)
byte[] MAC = Mac.hmacSha256(KEY_MAC, DATA);
```
1. Prepare ECIES payload.
```java
EciesPayload payload = (DATA_ENCRYPTED, MAC, KEY_EPH_PUB, NONCE, TIMESTAMP)
EciesPayload payload = (DATA_ENCRYPTED, MAC, KEY_EPH_PUB, NONCE, TIMESTAMP);
```

If this is a response encryption, then we omit `KEY_EPH_PUB` and set it to `null` in steps 3. and 9. to make the response shorter. For example, `SHARED_INFO_2` is then calculated as:
Expand All @@ -140,13 +143,13 @@ Assume we have a private key `KEY_ENC_PRIV`, encrypted data as an instance of th
```
1. Derive base secret key from the private key and ephemeral public key from the ECIES payload (in this step, we do not trim the key to 16b only, we keep all 32b).
```java
SecretKey KEY_BASE = ECDH.phase(KEY_ENC_PRIV, KEY_EPH_PUB)
SecretKey KEY_BASE = ECDH.phase(KEY_ENC_PRIV, KEY_EPH_PUB);
```
1. Derive a secret key using X9.63 KDF function (using SHA256 internally). When calling the KDF, we use `VERSION`, `SHARED_INFO_1` together with `KEY_EPH_PUB` value (as raw `byte[]`) as an `info` parameter.
```java
byte[] VERSION_BYTES = ByteUtils.encode(VERSION);
byte[] INFO = Bytes.concat(VERSION_BYTES, SHARED_INFO_1, KEY_EPH_PUB);
SecretKey KEY_SECRET = KDF_X9_63_SHA256.derive(KEY_BASE, INFO, 48)
SecretKey KEY_SECRET = KDF_X9_63_SHA256.derive(KEY_BASE, INFO, 48);
```
1. Split the 48 bytes long `KEY_SECRET` to three 16B keys. The first part is used as an encryption key `KEY_ENC`. The second part is used as MAC key `KEY_MAC`. The final part is a key for IV derivation `KEY_IV`.
```java
Expand All @@ -166,7 +169,7 @@ Assume we have a private key `KEY_ENC_PRIV`, encrypted data as an instance of th
1. Decrypt the data using AES, with `IV` value derived from `NONCE`.
```java
byte[] IV = KDF_INTERNAL.derive(KEY_IV, NONCE);
byte[] PLAINTEXT = AES.decrypt(DATA_ENCRYPTED, IV, KEY_ENC)
byte[] PLAINTEXT = AES.decrypt(DATA_ENCRYPTED, IV, KEY_ENC);
```

If this is a response decryption, then we omit `KEY_EPH_PUB` and set it to `null` in step 1.
Expand All @@ -175,9 +178,9 @@ If this is a response decryption, then we omit `KEY_EPH_PUB` and set it to `null

Practical implementation of ECIES encryption in PowerAuth accounts for a typical request-response cycle, since encrypting RESTful API requests and responses is the most common use-case.

Client implementation creates an encryptor object that allows encrypting the request and decrypting the response. When encrypting the request, encryptor object accepts a `byte[]` and a public key (for example, `MASTER_SERVER_PUBLIC_KEY`) and produces an instance of `EciesPayload` class. After it receives an encrypted response from the server, which is essentially another instance of `EciesPayload`, it is able to use the original encryption context (the shared encryption keys) to decrypt the response.
Client implementation creates an encryptor object that allows encrypting the request and decrypting the response. When encrypting the request, encryptor object accepts a `byte[]` and a [temporary public key](./Temporary-Encryption-Keys.md) . Then, it produces an instance of `EciesPayload` class. After it receives an encrypted response from the server, which is essentially another instance of `EciesPayload`, it is able to use the original encryption context (the shared encryption keys) to decrypt the response.

Server implementation creates a decryptor object that allows decrypting the original request data and encrypting the response. When server receives an encrypted request, essentially as an `EciesPayload` instance again, it uses a private key (for example, `MASTER_SERVER_PRIVATE_KEY`) to decrypt the original bytes and uses the encryption context to encrypt a response to the client.
Server implementation creates a decryptor object that allows decrypting the original request data and encrypting the response. When server receives an encrypted request, essentially as an `EciesPayload` instance again, it uses a [temporary private key](./Temporary-Encryption-Keys.md) (looked up based on the temporary key ID) to decrypt the original bytes and uses the encryption context to encrypt a response to the client.

Since the client and server use the same encryption context, the ephemeral public key needs to be only sent with the request from the client. Response may only contain encrypted data and MAC value.

Expand All @@ -202,6 +205,7 @@ The typical JSON encoded request is following:

```json
{
"temporaryKeyId": "dc497e8a-8faa-44bc-a52a-20d8393005d2",
"ephemeralPublicKey" : "A97NlW0JPLJfpG0AUvaRHRGSHh+quZu+u0c+yxsK7Xji",
"encryptedData" : "qYLONkDWFpXefTKPbaKTA/PWdRYH5pk9uvGjUqSYbeK7Q0aOohK2MknTyviyNuSp",
"mac" : "DNlZdsM1wgH8v2mAROjj3vmQu4DI4ZJnuTBzQMrHsew=",
Expand Down Expand Up @@ -246,18 +250,18 @@ The response doesn't use HTTP headers.

PowerAuth protocol defines following `SHARED_INFO_1` (also called as `sh1` or `sharedInfo1`) constants for its own internal purposes:

| RESTful endpoint | ECIES scope | `SHARED_INFO_1` value |
| ------------------------------------- | ------------ | --------------------- |
| RESTful endpoint | ECIES scope | `SHARED_INFO_1` value |
| ------------------------------------- | ------------ |---------------------------|
| `/pa/v3/activation/create` (level 1) | application | `/pa/generic/application` |
| `/pa/v3/activation/create` (level 2) | application | `/pa/activation` |
| `/pa/v3/upgrade` | activation | `/pa/upgrade` |
| `/pa/v3/vault/unlock` | activation | `/pa/vault/unlock` |
| `/pa/v3/token/create` | activation | `/pa/token/create` |
| `/pa/v3/recovery/confirm` | activation | `/pa/recovery/confirm` |
| `/pa/v3/activation/create` (level 2) | application | `/pa/activation` |
| `/pa/v3/upgrade` | activation | `/pa/upgrade` |
| `/pa/v3/vault/unlock` | activation | `/pa/vault/unlock` |
| `/pa/v3/token/create` | activation | `/pa/token/create` |
| `/pa/v3/recovery/confirm` | activation | `/pa/recovery/confirm` |

On top of that, following constants can be used for application-specific purposes:

| Purpose | ECIES scope | `SHARED_INFO_1` value |
| ---------------------------------------- | ------------ | --------------------- |
| Purpose | ECIES scope | `SHARED_INFO_1` value |
| ---------------------------------------- | ------------ |---------------------------|
| Generic encryptor for application scope | application | `/pa/generic/application` |
| Generic encryptor for activation scope | activation | `/pa/generic/activation` |
| Generic encryptor for activation scope | activation | `/pa/generic/activation` |
28 changes: 28 additions & 0 deletions docs/List-of-Used-Algorithms.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# List of Used Algorithms

The following algorithms are used in the PowerAuth cryptography scheme.

## PowerAuth 3 Protocol

- Current protocol version: `3.3`

### Cryptographic Primitives

| Algorithm | Impacts | Note |
|---------------|----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `AES-128` | mobile, server | Symmetric encryption with 128 bit keys. Used in `AES/CBC/PKCS7Padding` or `AES/CBC/NoPadding`, depending on use-case. |
| `Argon2` | server | Iterative hash used for storing recovery PUK values associated with recovery codes (`argon2i`). |
| `CRC-16` | mobile, server | Checksum algorithm, used to add a validation to the activation code (2 bytes out of 12 are allocated for checksum). |
| `ECDH` | mobile, server | Key agreement algorithm for ECC-based Diffie-Hellman, uses `secp256r1` curve. |
| `ECDSA` | mobile, server | Asymmetric signatures based on ECC, with `secp256r1` curve and `SHA256` hash function (`SHA256withECDSA`). |
| `ECIES` | mobile, server | Asymmetric encryption scheme based on ECC, with `secp256r1` and `X9.63` (`SHA256`) KDF function. |
| `HMAC-SHA256` | mobile, server | MAC algorithm with `SHA256` as underlying has function. Used in various situations across the protocol. |
| `HMAC-SHA512` | server | MAC algorithm with `SHA256` as underlying has function. Currently only used when validating TOTP in proximity OTP feature. |
| `PBKDF2` | mobile | Derivation function, used with `HMAC-SHA1` algorithm (`PBKDF2WithHmacSHA1`) and 10 000 iterations. _Note: Used exclusively for deriving a symmetric encryption key from PIN code on a mobile device, and hence strength of the algorithm is unimportant._ |
| `SHA256` | mobile, server | Hash function. Used in various situations across the protocol. |
| `X9.63` | mobile, server | Key derivation function with `SHA256`. Used for deriving keys with random index. |

### Algorithm Providers

- Server-Side: [Bouncy Castle](https://www.bouncycastle.org/)
- Client-Side: [OpenSSL](https://openssl-library.org/) (libCrypto)
84 changes: 84 additions & 0 deletions docs/Standard-RESTful-API.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ The following endpoints are published in PowerAuth Standard RESTful API (protoco
- [`/pa/v3/upgrade/start`](#upgrade-start) - Start a protocol upgrade (requires encryption).
- [`/pa/v3/upgrade/commit`](#upgrade-commit) - Commits a protocol upgrade (requires authentication).
- [`/pa/v3/recovery/confirm`](#confirm-recovery) - Confirm a recovery code (requires authentication and encryption).
- [`/pa/v3/keystore/create`](#create-new-key-pair) - Create a new temporary key pair for ECIES encryption.
<!-- end -->

## Security Features
Expand Down Expand Up @@ -720,3 +721,86 @@ The JSON response after the decryption:
}
```
<!-- end -->

## Temporary Keys API

<!-- begin api POST /pa/v3/keystore/create -->
### Create New Key Pair

Create a new temporary key pair with either application or activation scope, and obtain the temporary public for subsequent ECIES encryption.

<!-- begin remove -->
| Request parameter | Value |
| ----------------- |------------------------------------------|
| Method | `POST` |
| Resource URI | `/pa/v3/keystore/create` |
<!-- end -->

#### Request

##### Body

The JSON request contains an encoded JWT payload (signed with `HS256`) in a standard request envelope:

```json
{
"requestObject": {
"jwt": "..."
}
}
```

The decoded content of the JWT payload is:

```json
{
"applicationKey" : "...",
"activationId" : "...",
"challenge" : "..."
}
```

If the `activationId` is present (and represents an existing activation), the payload represents request for **activation scoped** temporary public key. Otherwise, the payload represents request for **application scoped** temporary public key. The scope determines how the JWT is signed. In both cases, the JWT is signed with standard `HS256` algorithm, with the following secret key:

- Application scope: Secret key is application secret `APP_SECRET` (decoded to raw bytes).
- Activation scope: Secret key is derived as `KDF_INTERNAL.derive(KEY_TRANSPORT, APP_SECRET)`.

#### Response 200

The JSON response contains an encoded JWT payload (signed with `ES256`) in a standard request envelope:

```json
{
"requestObject": {
"jwt": "..."
}
}
```

The decoded content of the JWT payload is:

```json
{
"sub": "...",
"applicationKey" : "...",
"activationId" : "...",
"challenge" : "...",
"publicKey": "...",
"iat": "...",
"exp": "...",
"iat_ms": "...",
"exp_ms": "..."
}
```

- The `sub` claim represents temporary key ID.
- The `applicationKey`, `activationId` and `challenge` claims are the same as in the request, so that the client can validate the response from the server not only for correct signature, but also to ensure the response is related to the issued request.
- The `publicKey` claim represents Base64 encoded temporary public key.
- The `iat` and `exp` attributes are standard claims representing timestamp of JWT issue and expiration timestamp. To provide a millisecond precision, they are augmented with `iat_ms` and `exp_ms` claims.

The issued public key can be related to either application or activation scope, based on the presence of `activationId` (see the request description for the details). In both cases, the JWT with the public key is signed using `ES256` algorithm, and the scope determines what key is used:

- Application scope: Private key is the application-specific master server private key `KEY_SERVER_MASTER_PRIVATE`.
- Activation scope: Private key is the activation-specific server private key `KEY_SERVER_PRIVATE`.

<!-- end -->
Loading
Loading