0001 Spark Auth Protocol and AES Encryption Support
0002 ==============================================
0003
0004 This file describes an auth protocol used by Spark as a more secure alternative to DIGEST-MD5. This
0005 protocol is built on symmetric key encryption, based on the assumption that the two endpoints being
0006 authenticated share a common secret, which is how Spark authentication currently works. The protocol
0007 provides mutual authentication, meaning that after the negotiation both parties know that the remote
0008 side knows the shared secret. The protocol is influenced by the ISO/IEC 9798 protocol, although it's
0009 not an implementation of it.
0010
0011 This protocol could be replaced with TLS PSK, except no PSK ciphers are available in the currently
0012 released JREs.
0013
0014 The protocol aims at solving the following shortcomings in Spark's current usage of DIGEST-MD5:
0015
0016 - MD5 is an aging hash algorithm with known weaknesses, and a more secure alternative is desired.
0017 - DIGEST-MD5 has a pre-defined set of ciphers for which it can generate keys. The only
0018 viable, supported cipher these days is 3DES, and a more modern alternative is desired.
0019 - Encrypting AES session keys with 3DES doesn't solve the issue, since the weakest link
0020 in the negotiation would still be MD5 and 3DES.
0021
0022 The protocol assumes that the shared secret is generated and distributed in a secure manner.
0023
0024 The protocol always negotiates encryption keys. If encryption is not desired, the existing
0025 SASL-based authentication, or no authentication at all, can be chosen instead.
0026
0027 When messages are described below, it's expected that the implementation should support
0028 arbitrary sizes for fields that don't have a fixed size.
0029
0030 Client Challenge
0031 ----------------
0032
0033 The auth negotiation is started by the client. The client starts by generating an encryption
0034 key based on the application's shared secret, and a nonce.
0035
0036 KEY = KDF(SECRET, SALT, KEY_LENGTH)
0037
0038 Where:
0039 - KDF(): a key derivation function that takes a secret, a salt, a configurable number of
0040 iterations, and a configurable key length.
0041 - SALT: a byte sequence used to salt the key derivation function.
0042 - KEY_LENGTH: length of the encryption key to generate.
0043
0044
0045 The client generates a message with the following content:
0046
0047 CLIENT_CHALLENGE = (
0048 APP_ID,
0049 KDF,
0050 ITERATIONS,
0051 CIPHER,
0052 KEY_LENGTH,
0053 ANONCE,
0054 ENC(APP_ID || ANONCE || CHALLENGE))
0055
0056 Where:
0057
0058 - APP_ID: the application ID which the server uses to identify the shared secret.
0059 - KDF: the key derivation function described above.
0060 - ITERATIONS: number of iterations to run the KDF when generating keys.
0061 - CIPHER: the cipher used to encrypt data.
0062 - KEY_LENGTH: length of the encryption keys to generate, in bits.
0063 - ANONCE: the nonce used as the salt when generating the auth key.
0064 - ENC(): an encryption function that uses the cipher and the generated key. This function
0065 will also be used in the definition of other messages below.
0066 - CHALLENGE: a byte sequence used as a challenge to the server.
0067 - ||: concatenation operator.
0068
0069 When strings are used where byte arrays are expected, the UTF-8 representation of the string
0070 is assumed.
0071
0072 To respond to the challenge, the server should consider the byte array as representing an
0073 arbitrary-length integer, and respond with the value of the integer plus one.
0074
0075
0076 Server Response And Challenge
0077 -----------------------------
0078
0079 Once the client challenge is received, the server will generate the same auth key by
0080 using the same algorithm the client has used. It will then verify the client challenge:
0081 if the APP_ID and ANONCE fields match, the server knows that the client has the shared
0082 secret. The server then creates a response to the client challenge, to prove that it also
0083 has the secret key, and provides parameters to be used when creating the session key.
0084
0085 The following describes the response from the server:
0086
0087 SERVER_CHALLENGE = (
0088 ENC(APP_ID || ANONCE || RESPONSE),
0089 ENC(SNONCE),
0090 ENC(INIV),
0091 ENC(OUTIV))
0092
0093 Where:
0094
0095 - RESPONSE: the server's response to the client challenge.
0096 - SNONCE: a nonce to be used as salt when generating the session key.
0097 - INIV: initialization vector used to initialize the input channel of the client.
0098 - OUTIV: initialization vector used to initialize the output channel of the client.
0099
0100 At this point the server considers the client to be authenticated, and will try to
0101 decrypt any data further sent by the client using the session key.
0102
0103
0104 Default Algorithms
0105 ------------------
0106
0107 Configuration options are available for the KDF and cipher algorithms to use.
0108
0109 The default KDF is "PBKDF2WithHmacSHA1". Users should be able to select any algorithm
0110 from those supported by the `javax.crypto.SecretKeyFactory` class, as long as they support
0111 PBEKeySpec when generating keys. The default number of iterations was chosen to take a
0112 reasonable amount of time on modern CPUs. See the documentation in TransportConf for more
0113 details.
0114
0115 The default cipher algorithm is "AES/CTR/NoPadding". Users should be able to select any
0116 algorithm supported by the commons-crypto library. It should allow the cipher to operate
0117 in stream mode.
0118
0119 The default key length is 128 (bits).
0120
0121
0122 Implementation Details
0123 ----------------------
0124
0125 The commons-crypto library currently only supports AES ciphers, and requires an initialization
0126 vector (IV). This first version of the protocol does not explicitly include the IV in the client
0127 challenge message. Instead, the IV should be derived from the nonce, including the needed bytes, and
0128 padding the IV with zeroes in case the nonce is not long enough.
0129
0130 Future versions of the protocol might add support for new ciphers and explicitly include needed
0131 configuration parameters in the messages.
0132
0133
0134 Threat Assessment
0135 -----------------
0136
0137 The protocol is secure against different forms of attack:
0138
0139 * Eavesdropping: the protocol is built on the assumption that it's computationally infeasible
0140 to calculate the original secret from the encrypted messages. Neither the secret nor any
0141 encryption keys are transmitted on the wire, encrypted or not.
0142
0143 * Man-in-the-middle: because the protocol performs mutual authentication, both ends need to
0144 know the shared secret to be able to decrypt session data. Even if an attacker is able to insert a
0145 malicious "proxy" between endpoints, the attacker won't be able to read any of the data exchanged
0146 between client and server, nor insert arbitrary commands for the server to execute.
0147
0148 * Replay attacks: the use of nonces when generating keys prevents an attacker from being able to
0149 just replay messages sniffed from the communication channel.
0150
0151 An attacker may replay the client challenge and successfully "prove" to a server that it "knows" the
0152 shared secret. But the attacker won't be able to decrypt the server's response, and thus won't be
0153 able to generate a session key, which will make it hard to craft a valid, encrypted message that the
0154 server will be able to understand. This will cause the server to close the connection as soon as the
0155 attacker tries to send any command to the server. The attacker can just hold the channel open for
0156 some time, which will be closed when the server times out the channel. These issues could be
0157 separately mitigated by adding a shorter timeout for the first message after authentication, and
0158 potentially by adding host blacklists if a possible attack is detected from a particular host.