-1

NOTE: This question originally conflated a "digital signature" and a "MAC", which I've since learned are not the same thing. Any references (in the answer or any comments) to a "signature" should be read as a "MAC".

I'm experimenting with auth tokens and I'm trying to wrap my mind around the best method.

Goals

  1. Upon successful login, a token is created containing the users accountID, a nonce, and an expiry. The token is then passed back to the client to be used for the next request.
  2. The client passes the token back to the server with each request to identify the origin (accountID) of any given request.
  3. The token contains a nonce that's changed with each request.
  4. A MAC is created from the plaintext value to ensure it's not been tampered with.
  5. The plaintext value of the token (including the MAC) is then encrypted to ensure it's securely obscured.
  6. The client is never privy to the macKey or the encryptionKey. The client is not intended to ever have access to the plaintext contents of the token.

Current Method

///process.env.TOKEN_ENCRYPTION_PASSWORD = '13sd4089f-268c-483d-9e82-jk3c1b47c77a';
///process.env.TOKEN_MAC_KEY = '1fde05f4-268c-483d-9e82-85fc1b42321';

/// Successful login by user ...

var token = {
    nonce : 'SOME-UUID-GOES-HERE',
    accountID : 'account-12345',
    expires : 1234567890
};

token.mac = crypto.createHmac('sha512', TOKEN_MAC_KEY)
                  .update(JSON.stringify(token))
                  .digest('base64');

var encryptedToken = cryptoJS.AES.encrypt(JSON.stringify(token), TOKEN_ENCRYPTION_PASSWORD).toString();

response.send({
    message : 'Created, MAC'd, and encrypted an auth token.',
    authToken : encryptedToken
});

Questions

  1. Is it secure, in this case, to employ a MAC-then-encrypt method? I've read several opinions on this and walked away more confused than when I started.
  2. I've read that cbc-mode should be used when employing a MAC-then-encrypt method. Is this the default mode for CryptoJS.AES.encrypt()?
  3. CryptoJS.AES seems pretty generic. Is this defaulting to AES256? Or is that something that I need to explicitly declare in my code?
  4. When passing a string to CryptoJS.AES.encrypt() I've read that it automagically generates a key and and iv 'behind the scenes'. Would it be more secure to generate my own key and iv, or should I just let CryptoJS handle that?
  5. Is there more security to be had by employing a MAC-encrypt-MAC method, or is that just adding complexity to my app logic?
1
  1. Mac-then-Encrypt is perfectly fine. There is a theoretical attack in which a Mac-then-Encrypt scheme using a malleable mode (Like CBC) may be posible for an attacker to tamper the ciphertext to get a plaintext with the same Mac, but it's just theoric
  2. You're not limited to cbc mode, just as an example TLS uses Mac-then-Encrypt and CTR mode is used too. Also what CryptoJS does by default is implementation defined, read the documentation, but I think that CryptoJS.AES.encrypt() will default to a single block encryption or ECB which is not secure
  3. Documentation again
  4. Documentation is your friend
  5. There is no extra security, just increases the size of your message with no reason. Both methods Mac-then-Encrypt and Encrypt-then-Mac are equally secure as far as we know. Even with the theoretical attack mentioned before

The only thing I don't understand in your scheme is why the nonce? It's used for your business? Is for some kind of supposed "cryptographic security"? It's used as CSRF token?

| improve this answer | |

Not the answer you're looking for? Browse other questions tagged or ask your own question.