Repository navigation
crypto: API changes needed for AES Counter with CBC-MAC (CCM) support #2383
Description
Overview
I've started work on adding AES CCM support to node. This is part of a larger goal of getting full DTLS support into node. Specifically I need AES_128_CCM_8 support. Until then, I'm working on a native module for the crypto support and helping @Rantanen improve his DTLS protocol module.
OpenSSL already supports this cipher, so I thought it was a matter of adding the necessary calls. I've since run into a complication with the order of calls required by OpenSSL and how the CipherBase class is structured.
I'm looking for some discussion and/or guidance on how to proceed with implementation.
CCM Requirements
CCM requires specifying 2 or 3 additional lengths for proper operation.
- Length of the IV. This is already available as an argument and does not present any issues.
- Length of the authentication tag
- Length of the plaintext / ciphertext (only required if also specifying AAD)
Authentication Tag Length
The authentication tag length must be specified before calling EVP_CipherInit_ex with the key and iv parameters (source). If specified afterwards, OpenSSL returns a buffer full of zeroes.
Plaintext / Ciphertext length
The total plaintext or ciphertext length must be specified before setting the AAD (via EVP_CipherUpdate in cipher.setAAD) and before adding any plaintext (via EVP_CipherUpdate in cipher.update). If not specified before, cipher.setAAD will fail.
Proposed API Changes
In order to provide the 1 or 2 lengths required, some API changes will be needed. This is where some input would be greatly appreciated.
The requirement for the authentication tag length is needed before the final OpenSSL call of CipherBase::initiv. This means crypto.createCipheriv and crypto.createDecipheriv need additional optional parameters.
- Add an optional
authTagLengthproperty to theoptionsparameter ofcrypto.createCipherivandcrypto.createDecipheriv
The requirement for the plaintext / ciphertext length depends on using AAD, thus perhaps it makes sense to add an optional parameter to cipher.setAAD?
- Change the signature of
cipher.setAADtocipher.setAAD(buffer, [length]). The confusing part here is thatlengthis not the length of the AAD, but the plaintext / ciphertext length.
I'm open to any and all suggestions regarding API signature changes, or even new methods.
What does everyone think?
Activity
bnoordhuis commentedon Aug 15, 2015
/cc @nodejs/crypto
indutny commentedon Aug 15, 2015
I'm -1 for adding yet another argument to
createCipheriv. I think it would be better to just pick it up from the options object that we accept as the last argument. And while we are here, I suggest to pickivfrom it as well.brycekahle commentedon Aug 22, 2015
@indutny Updated proposal for
authTagLength. Thoughts on thesetAADchange?indutny commentedon Sep 9, 2015
May I ask you to educate me a little bit about the length of cipher-/plain- text? Why is it required to specify, could it be different for the same cipher?
brycekahle commentedon Sep 10, 2015
It is a requirement of OpenSSL. See https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Encryption_using_CCM_mode
indutny commentedon Sep 10, 2015
I think this sounds like a good idea to put it in
setAAD, it is a part of the authenticated data, right?shigeki commentedon Sep 10, 2015
I also had the same question as fedor, the reason why the clear/cipher-text length is needed before
setAADand looked the openssl code and found that it is included in the first block sequence of CBC-MAC for authentication.And I found one more requirement for CCM that
EVP_Encrypt/DecryptUpdateof clear/cipher-text can be invoked only once. It is different from the case of GCM.So we can have an another idea of api that
setAADjust stores the data and the clear/cipher-text length and data of aad can be registered at the firstcipher.updateonly in CCM case so that we need not to pass the clear/cipher-text length tosetAADand it is consistent with GCM. And we need to prohibit to executecipher.updatemore than once in CCM.stemail23 commentedon Sep 30, 2015
Does this explain why if I try to use aes-128-ccm algorithm, I get
Trying to add data in unsupported stateexception thrown?shigeki commentedon Sep 30, 2015
Yes, Node currently supports only GCM mode for AEAD. You cannot use CCM now.
calvinmetcalf commentedon Jan 5, 2016
another option would be something along the lines of #941 to create a non-streaming api for encrypting/decrypting. this would also avoid the footgun in gcm of decrypting before authenticating.
Strickly speaking we don't really need the authtag length, we get by in GCM by only allowing a single size.
Partha-Mukherjee-G2H commentedon Jan 6, 2016
Hello Bryce (and others). I was checking to see if AES_128_CCM_8 is supported by Node.js crypto lib, and ran into this thread. Since it was initiated in August, Since I would like to use this cipher suite for a project I am working on, I am wondering if this work has been completed yet? Or if there is a date it is expected to be done? Thanks!
brycekahle commentedon Jan 7, 2016
@Partha-Mukherjee-G2H it is not supported yet by the core crypto API. You can use my module node-aes-ccm in the meantime.
Partha-Mukherjee-G2H commentedon Jan 7, 2016
@brycekahle - I greatly appreciate the fast reply! I have not worked with native C++ modules in node.js before so I will take a good look at that.
I more really quick question for you:
In your notes you mention: "node-aes-ccm requires io.js >= 3.0 because we need OpenSSL 1.0.2d or later for AES CCM support.",
but the io.js website states that it (as of 3.3.31) has merged with node.js.
Do I still need to io.js installed to run the node-aes-ccm module?
Or is the latest stable version of node.js enough?
thanks!!
brycekahle commentedon Jan 7, 2016
I haven't tested with later versions of node, but it should work. If not, raise an issue on that repo and I can fix it.
Trott commentedon Jul 7, 2017
Is it the case right now that there's agreement that the feature makes sense, but no one planning to implement and submit a pull request?
Is someone willing to mentor a moderately crypto-savvy person who wanted to do this? (That's not me and I don't have anyone specific in mind. I'm just trying to figure out a way to move this forward.)
tniessen commentedon Dec 14, 2017
I am planning to implement this after landing #17566.
eduardbme commentedon Mar 27, 2018
Any update on this ?
This code still returns "Trying to add data in unsupported state".
Is it possible to use a 'ccm' methods in node ?
tniessen commentedon Mar 27, 2018
@eduardbcom #18138 is awaiting TSC approval and will add full support for
aes-128-ccm,aes-192-ccmandaes-256-ccmin non-FIPS mode.eduardbme commentedon Mar 27, 2018
@tniessen got it, thanks!
crypto: add support for AES-CCM