Skip to content

[CAL-2901] Symmetric encryption keys are weaker than they should be #10805

@nicktrn

Description

@nicktrn

Issue Summary

cal.com/.env.example

Lines 88 to 91 in 7c23773

# Application Key for symmetric encryption and decryption
# must be 32 bytes for AES256 encryption algorithm
# You can use: `openssl rand -base64 24` to generate one
CALENDSO_ENCRYPTION_KEY=

Currently, 24 random bytes are expanded via base64-encoding to match the required AES-256 key length of 32 bytes.

This is effectively AES-192 security (with two additional rounds).

Recommendations

diff --git a/.env.example b/.env.example
index 20bef8f8a..209740148 100644
--- a/.env.example
+++ b/.env.example
@@ -87,7 +87,7 @@ CRON_ENABLE_APP_SYNC=false
 
 # Application Key for symmetric encryption and decryption
 # must be 32 bytes for AES256 encryption algorithm
-# You can use: `openssl rand -base64 24` to generate one
+# You can use: `openssl rand -base64 32` to generate one
 CALENDSO_ENCRYPTION_KEY=
 
 # Intercom Config
diff --git a/packages/lib/crypto.ts b/packages/lib/crypto.ts
index d33f0c8f4..f662f22cc 100644
--- a/packages/lib/crypto.ts
+++ b/packages/lib/crypto.ts
@@ -13,7 +13,7 @@ const IV_LENGTH = 16; // AES blocksize
  * @returns Encrypted value using key
  */
 export const symmetricEncrypt = function (text: string, key: string) {
-  const _key = Buffer.from(key, "latin1");
+  const _key = Buffer.from(key, "base64");
   const iv = crypto.randomBytes(IV_LENGTH);
 
   const cipher = crypto.createCipheriv(ALGORITHM, _key, iv);
@@ -30,7 +30,7 @@ export const symmetricEncrypt = function (text: string, key: string) {
  * @param key Key used to decrypt value must be 32 bytes for AES256 encryption algorithm
  */
 export const symmetricDecrypt = function (text: string, key: string) {
-  const _key = Buffer.from(key, "latin1");
+  const _key = Buffer.from(key, "base64");
 
   const components = text.split(":");
   const iv_from_ciphertext = Buffer.from(components.shift() || "", OUTPUT_ENCODING);

The key encoding could also be chosen dynamically based on its length and an additional env var OLD_ENCRYPTION_KEY provided to migrate old secrets on-demand.

As part of the migration, I would recommend switching over to aes-256-gcm. Using non-authenticated AES in CBC mode is not recommended when GCM is available.

Could also take care of this at the same time:

From SyncLinear.com | CAL-2901

Metadata

Metadata

Assignees

Labels

Low priorityCreated by Linear-GitHub Syncauthenticationarea: authentication, auth, google sign in, password, SAML, password reset, can't log infoundationlinearSync Github Issue from community members to Linear.appsecurity🐛 bugSomething isn't working

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions