-
Notifications
You must be signed in to change notification settings - Fork 22
End To End Encryption
PowerAuth 2.0 supports end-to-end encryption mechanism based on a shared symmetric key. This chapter explains the principles of this end-to-end encryption mechanism.
"HTTPS" is an example of a "non-personalized encryption" mechanism. Data that are transferred over the HTTPS can be encrypted without any identity being provided beforehand, since ad-hoc keys are established for the purpose of data encryption. While the need to protect resources that are available to anyone anytime can be a subject of discussion, HTTPS has proven to be a great technology for common web, and provides value in cases where people fill sensitive data in before they are authenticated.
PowerAuth 2.0 supports its own non-personalized encryption as well. But it also supports a personalized encryption using a key established during the activation process. In personalized encryption, data encryption keys are specific for particular parties - a message can be decrypted only on a correct device, for example.
PowerAuth 2.0 supports non-personalized encryption using a symmetric transport key derived from KEY_SERVER_MASTER_PUBLIC
and ephemeral private key. This key is then used as a "transport key", in the same way as with personalized encryption.
PowerAuth 2.0 supports "personalized encryption" using a master transport key KEY_TRANSPORT
established during the PowerAuth 2.0 Client activation. In this mode of opperation, data are encrypted using a key specific for given activation (activated user device, in most cases) and therefore are readable only on the correct device.
There are 5 categories of service resources from the security perspective. Each of them can be protected with different combination of encryption mechanisms.
Resource type | Description | HTTPS | E2EE-NP | E2EE-P |
---|---|---|---|---|
Public | Any resources that are available before login. For banking application, examples could be the currency exchange rates, contacts, or nearby ATMs or branches. These data are generally available and do not require any level of protection besides HTTPS. | YES | NO | NO |
Registration | Any resources that are related to the user registration. In case of PowerAuth 2.0 protected banking application, these are resources related to PowerAuth 2.0 Standard RESTful API. These resources must be available for non-authenticated users and after the activation is complete, the identity is established and can be later authenticated. | YES | YES | NO |
Authentication | Any resources related to the user authentication. Example could be a /login endpoint. These endpoints are interesting, because on the request side, the identity is not yet established and if the authentication is successful, response is authenticated. |
YES | YES | Response only |
Authenticated | Any resources that are available after the login. Example could be the list of accounts, transaction history, list of cards, etc. | YES | YES | YES |
Authenticated & Signed | Any resources that are available after the login and require additional authentication as a proof of execution. Example could be submitting a new payment, signing a contract, etc. | YES | YES | YES |
As you can see, you should use HTTPS for all your resources, including PowerAuth 2.0 protected services, simply because it is a good practice.
PowerAuth 2.0 Server is able to reconstruct the KEY_TRANSPORT
any time. However, using this key for end-to-end encryption directly would be a bad practice, or too computationally intensive. To describe the issue in detail, KEY_TRANSPORT
must not be used directly, because either:
- The PowerAuth 2.0 Server would have to handle all encryption / decryption itself so that other server applications that integrate with it do not have to hold the
KEY_TRANSPORT
key. This, however, would create a lot of extra traffic on the PowerAuth 2.0 Server, which is undesired. ... or - Other server applications that integrate with PowerAuth 2.0 Server would have to obtain and store the
KEY_TRANSPORT
key value, so that they can use the key for encryption / decryption themselves. This would create possible key management issues.
In order to design a better mechanism, the key used for data encryption uses the "double key derivation principle". A key is derived using following two indexes:
-
SESSION_INDEX
- 16B long random byte index that is associated with a given "session". In this context, the "session" is any period of time for which the given index may be valid. It can be either an HTTP session established during the login, or a period between multiple device registrations to the push server, etc. In any case, client can use only a session index that is already established on the server. -
AD_HOC_INDEX
- 16B long random byte index that is generated for a given message, different and pseudo-unique for given data.
The resulting key is therefore derived using following algorithm:
SESSION_INDEX = Generator.randomBytes(16)
AD_HOC_INDEX = Generator.randomBytes(16)
KEY_TRANSPORT_PARTIAL = KDF_INTERNAL(`KEY_TRANSPORT`, `SESSION_INDEX`)
KEY_TRANSPORT_ENCRYPTION = KDF_INTERNAL(KEY_TRANSPORT_PARTIAL, AD_HOC_INDEX)
The nice thing about this approach is that PowerAuth 2.0 Server is able to provide the KEY_TRANSPORT_PARTIAL
and SESSION_INDEX
to server application that integrates with it without exposing the underlying KEY_TRANSPORT
master key. The server application can then generate ad-hoc transport key with random AD_HOC_INDEX
and use it for data encryption, as shown on the following image:
As a result of the double key derivation principle, encryption is available only after the session is established. For example: After the user authenticates with PowerAuth, login response data and any data after the login can be encrypted using PowerAuth 2.0 end-to-end encryption. For the data that are available before login, the encryption key cannot be obtained on the server side, since there is no information on how to look the correct encryption key up.
Note: It must be proactively checked that MAC_INDEX, SESSION_INDEX and AD_HOC_INDEX are of a different value.
As a part of the encryption, MAC of the encrypted data is computed and sent alongside the encrypted data. We use "Encrypt-then-MAC" principle. We use following algorithm to compute a MAC:
MAC_INDEX = Generator.randomBytes(16)
KEY_TRANSPORT_MAC = KDF_INTERNAL.derive(KEY_TRANSPORT_PARTIAL, MAC_INDEX)
MAC = Mac.hmacSha256(KEY_TRANSPORT_MAC, ENCRYPTED_DATA)
Note: It must be proactively checked that MAC_INDEX, SESSION_INDEX and AD_HOC_INDEX are of a different value.
Data are encrypted using AES algorithm:
ENCRYPTED_DATA = AES.encrypt(DATA, NONCE, KEY_TRANSPORT_ENCRYPTION)
In order to allow other party to decrypt the data, following information must be sent alongside with encrypted data:
ENCRYPTED_DATA
SESSION_INDEX
AD_HOC_INDEX
NONCE
For the purpose of data authentication, MAC information must be sent as well:
MAC
MAC_INDEX
Client must first compute the KEY_TRANSPORT_MAC
and then verify the MAC signature of the data, stopping on failure.
Decryption algorithm then goes as follows:
// KEY_TRANSPORT was fetched from the device storage.
// See [[key derivation chapter|Key-Derivation]] for details.
KEY_TRANSPORT_PARTIAL = KDF_INTERNAL(KEY_TRANSPORT, SESSION_INDEX)
KEY_TRANSPORT_ENCRYPTION = KDF_INTERNAL(KEY_TRANSPORT_PARTIAL, AD_HOC_INDEX)
DATA = AES.decrypt(ENCRYPTED_DATA, NONCE, KEY_TRANSPORT_ENCRYPTION)
PowerAuth 2.0 Libraries use following standard payload format for encrypted requests and responses (values are Base64 encoded).
{
"encryption": "nonpersonalized",
"requestObject": {
"applicationKey": "UNfS0VZX3JhbmRvbQ==",
"sessionIndex": "MTIzNDU2Nzg5MDEyMzQ1Ng==",
"adHocIndex": "MTIzNDU2Nzg5MGFiY2RlZg==",
"macIndex": "Nzg5MGMTIzNDU2FiY2RlZg==",
"nonce": "YWJjZGVmYWJjZGVmYWJjZA==",
"ephemeralPublicKey": "mYWJjZGVmYWJjZAYWJjZGVmYWJjZGVmYWJjZA==",
"mac": "IGVuY3J5cHRlZCBkYXRhVGhlc2UgYXJl",
"encryptedData": "VGhlc2UgYXJlIGVuY3J5cHRlZCBkYXRh"
}
}
Field | Description |
---|---|
type |
Type of the field, nonpersonalized in case of non-personalized encryption |
applicationKey |
Identifier of the application version |
encryptedData |
Data encrypted with a transport key derived using the double derivation principle |
mac |
Encrypted data signature |
sessionIndex |
Key index specific for given session, used in the KDF for AES encryption |
adHocIndex |
Key index specific for given request, used in the KDF for AES encryption |
macIndex |
Key index used for given request, used in the KDF for MAC signature compitation |
nonce |
A nonce value, used as IV for the AES encryption |
ephemeralPublicKey |
A key used for deriving temporary secret in case of nonpersonalized encryption type |
{
"status": "OK",
"encryption": "nonpersonalized",
"responseObject": {
"applicationKey": "UNfS0VZX3JhbmRvbQ==",
"sessionIndex": "MTIzNDU2Nzg5MDEyMzQ1Ng==",
"adHocIndex": "MTIzNDU2Nzg5MGFiY2RlZg==",
"macIndex": "Nzg5MGMTIzNDU2FiY2RlZg==",
"nonce": "YWJjZGVmYWJjZGVmYWJjZA==",
"ephemeralPublicKey": "mYWJjZGVmYWJjZAYWJjZGVmYWJjZGVmYWJjZA==",
"mac": "IGVuY3J5cHRlZCBkYXRhVGhlc2UgYXJl",
"encryptedData": "VGhlc2UgYXJlIGVuY3J5cHRlZCBkYXRh"
}
}
Fields have the same meaning as in the request, see above.
{
"encryption": "personalized",
"requestObject": {
"activationId": "c564e700-7e86-4a87-b6c8-a5a0cc89683f",
"sessionIndex": "MTIzNDU2Nzg5MDEyMzQ1Ng==",
"adHocIndex": "MTIzNDU2Nzg5MGFiY2RlZg==",
"macIndex": "Nzg5MGMTIzNDU2FiY2RlZg==",
"nonce": "YWJjZGVmYWJjZGVmYWJjZA==",
"mac": "IGVuY3J5cHRlZCBkYXRhVGhlc2UgYXJl",
"encryptedData": "VGhlc2UgYXJlIGVuY3J5cHRlZCBkYXRh"
}
}
Field | Description |
---|---|
type |
Type of the field, personalized in case of personalized encryption |
activationId |
Identifier of the activation |
encryptedData |
Data encrypted with a transport key derived using the double derivation principle |
mac |
Encrypted data signature |
sessionIndex |
Key index specific for given session, used in the KDF for AES encryption |
adHocIndex |
Key index specific for given request, used in the KDF for AES encryption |
macIndex |
Key index used for given request, used in the KDF for MAC signature compitation |
nonce |
A nonce value, used as IV for the AES encryption |
{
"status": "OK",
"encryption": "personalized",
"responseObject": {
"activationId": "c564e700-7e86-4a87-b6c8-a5a0cc89683f",
"sessionIndex": "MTIzNDU2Nzg5MDEyMzQ1Ng==",
"adHocIndex": "MTIzNDU2Nzg5MGFiY2RlZg==",
"macIndex": "Nzg5MGMTIzNDU2FiY2RlZg==",
"nonce": "YWJjZGVmYWJjZGVmYWJjZA==",
"mac": "IGVuY3J5cHRlZCBkYXRhVGhlc2UgYXJl",
"encryptedData": "VGhlc2UgYXJlIGVuY3J5cHRlZCBkYXRh"
}
}
Fields have the same meaning as in the request, see above.
If you need any assistance, do not hesitate to drop us a line at [email protected].
PowerAuth 2.0 Specification
- Overview
- Basic Definitions
- Activation
- Key Derivation
- Checking Status
- Signatures
- MAC Token Based Authentication
- End-To-End Encryption
- Standard REST API
- Implementation Details
- List of Used Keys
Deployment
Applications
- PowerAuth Server
- PowerAuth Admin
- PowerAuth Push Server
- PowerAuth CMD Tool
- PowerAuth Mobile SDK
- SDK for RESTful APIs
- PowerAuth Web Flow
Development
Releases