1

I have read that GCM is almost always more secure than CBC when implemented correctly.

However, in the documentation of NodeJS, CBC is being used as an example instead. The key-pair will be stored in the node environment.

Since the private key is being stored locally and CBC is an acceptable encryption for local files according to this answer, is it a secure enough implementation, or should GCM be used such as in this sample code?

isopach
  • 491
  • 1
  • 3
  • 14
  • That uses [`keyObject.export`](https://nodejs.org/api/crypto.html#crypto_keyobject_export_options) which is designed not only for local storage but **also interop**; it uses either PKCS8, whose (password-based) encryption was defined by PKCS5 which even at v2.0 in 2000 used only CBC, or for the specific formats (pkcs1 and sec1) by PEM encryption as defined by 1421 in 1993. GCM was proposed in 2004, which is later in time than 1993 and 2000. If you want _nodejs-only_ storage you have more flexibility; something newer like say JWK can use AES-GCM. – dave_thompson_085 Dec 04 '19 at 08:23

1 Answers1

2

The Cipher-Block-Chaining Mode becomes problematic if your threat model includes an attacker who actively manipulates the encrypted data. This allows an attacker to flip specific bits in the cipher to flip the same bits in the resulting plaintext - a property called malleability. If not paired with a MAC to ensure integrity, CBC is not very secure.

When encrypting a private key to be stored on a local device, the only requirement is confidentiality. An attacker could flip specific bits, but it is most likely that this will result in the private key becoming unusable instead. CBC is still good enough at providing confidentiality, and without the AES-NI extension, it's a lot faster than AES-GCM, as you can see in the following graphic:

Benchmark of AES-CBC and AES-GCM

Source: kazoo.ga

To give a succinct answer: Node.JS uses AES-CBC because for this case, the extra benefits offered by AES-GCM don't matter and AES-CBC is usually faster.


In the above graphic, the performance of AES-CBC without AES-NI is used as 100% performance. The relevant other category is AES-128-GCM w/o AES-NI. Of course, if NodeJS supports AES-NI, then AES-GCM is a better choice.

  • Thanks for explaining it in an easy-to-understand way! – isopach Dec 03 '19 at 09:27
  • Do these performance numbers account for the need to also do a MAC for CBC? – paj28 Dec 03 '19 at 09:59
  • 1
    @paj28 As you can see, the rightmost bar uses AES-128-CBC-HMAC-SHA1 with AES-NI. Sadly, there is no benchmark for AES-128-CBC-HMAC-SHA1 without AES-NI, but it would be consistently worse than plain AES-128-CBC w/o AES-NI. In this situation, HMAC is actually not required, as there is no requirement for integrity, only confidentiality. –  Dec 03 '19 at 10:19