Skip to content

End To End Encryption

Petr Dvorak edited this page Mar 30, 2017 · 29 revisions

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.

Personalized vs. Non-Personalized Encryption

"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.

PA2.0 Non-Personalized Encryption (E2EE-NP)

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.

PA2.0 Personalized Encryption (E2EE-P)

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.

Encryption Categories

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.

Double Key Derivation Principle

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.

Encrypt-Then-MAC Principle

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 Encryption and Decryption

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)

Standard Request and Response Payloads

PowerAuth 2.0 Libraries use following standard payload format for encrypted requests and responses (values are Base64 encoded).

Non-Personalized Encryption

Request

{
    "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

Response

{
    "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.

Personalized Encryption

Request

{
    "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

Response

{
    "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.