Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update encryption algorithms for crypto4 #680

Closed
romanstrobl opened this issue Jan 9, 2025 · 0 comments
Closed

Update encryption algorithms for crypto4 #680

romanstrobl opened this issue Jan 9, 2025 · 0 comments
Assignees

Comments

@romanstrobl
Copy link
Member

romanstrobl commented Jan 9, 2025

Description

Add new encryption algorithms for crypto4:

  • AES is now using always 256bit keys in CTR or GCM mode
    • CTR mode for AEAD, key encryption
    • GCM mode for local vault

Cover the new encryption algorithms by tests.

Acceptance criteria

AEAD implemented as specified and covered by unit tests.

Technical specification

Let's define a new primitive that provides authenticated encryption with associated data:

  • Common constants:

    • NONCE_LENGTH = 12 - The purpose of nonce is to provide initial IV value to AES/CTR.
    • TAG_LENGTH = 32 - The tag length specifies how
    • LABEL - The kmac256 label: String LABEL = "PA4MAC-AEAD"
  • byte[] AEAD.seal(SecretKey key, byte[] keyContext, byte[] nonce, byte[] associatedData, byte[] plaintext)

    • Function encrypts plaintext. Parameters:
      • key - secret symmetric key.
      • keyContext - a context related to the secret key.
      • nonce - nonce a part of IV for underlying cipher.
      • associatedData - data that is not encrypted but included into MAC calculation.
      • plaintext - data to be encrypted.
    • Returns:
      • byte array with encrypted data
    • Implementation:
      // Prepare or validate nonce
      if (nonce == null) {
          // Create a new fresh nonce if no nonce provided.
          nonce = Generator.randomBytes(NONCE_LENGTH)
      } else if (nonce.length != NONCE_LENGTH) {
          throw new Exception();
      }
      // Derive encryption and authentication key
      byte[] KEY_ENC = KDF.derive(key, 20_001, keyContext);
      byte[] KEY_MAC = KDF.derive(key, 20_002, keyContext);
      // Prepare IV. Append 4 zero bytes to make IV 16 bytes long. So, the counter in CTR mode always starts at 0.
      // We expect that only 32 least significant bits in nonce is used as a counter, so the maximum length of plaintext is 2^32.
      byte[] IV = ByteUtils.concat(nonce, ByteUtils.zeroBytes(4));
      // Encrypt
      byte[] ENCRYPTED = AES.encrypt(plaintext, IV, KEY_ENC, "AES/CTR/NoPadding");
      // Calculate MAC
      byte[] MAC = Mac.kmac256(KEY_MAC, ByteUtils.concat(nonce, associatedData, ENCRYPTED), LABEL);
      // Prepare final ciphertext
      return ByteUtils.concat(nonce, MAC, ENCRYPTED);
  • byte[] AEAD.open(SecretKey key, byte[] keyContext, byte[] associatedData, byte[] ciphertext)

    • Function decrypts ciphertext. Parameters:
      • key - secret symmetric key.
      • keyContext - a context related to the secret key.
      • associatedData - data that is included into MAC calculation.
      • ciphertext - data to be decrypted.
    • Returns:
      • byte array with decrypted data.
    • Implementation:
      if (ciphertext.length < NONCE_LENGTH + TAG_LENGTH) {
          throw Exception();
      }
      // Extract components from ciphertext
      byte[] NONCE = ByteUtils.subarray(ciphertext, 0, NONCE_LENGTH);
      byte[] TAG = ByteUtils.subarray(ciphertext, NONCE_LENGTH, TAG_LENGTH);
      byte[] ENCRYPTED = ByteUtils.subarray(ciphertext, NONCE_LENGTH + TAG_LENGTH, ciphertext.length - NONCE_LENGTH - TAG_LENGTH);
      // Derive encryption and authentication key
      byte[] KEY_ENC = KDF.derive(key, 20_001, keyContext);
      byte[] KEY_MAC = KDF.derive(key, 20_002, keyContext);
      // Calculate mac
      byte[] MAC = Mac.kmac256(KEY_MAC, ByteUtils.concat(NONCE, associatedData, ENCRYPTED), LABEL);
      if (MAC != TAG) {
          throw new Exception();
      }
      // Prepare IV
      byte[] IV = ByteUtils.concat(NONCE, ByteUtils.zeroBytes(4));
      // Decrypt
      byte[] PLAINTEXT = AES.decrypt(ENCRYPTED, IV, KEY_ENC, "AES/CTR/NoPadding");
      // Success
      return PLAINTEXT;
  • byte[] AEAD.extractNonce(byte[] ciphertext)

    • Extract nonce from the ciphertext.
    • Implementation:
      if (ciphertext.length < NONCE_LENGTH + TAG_LENGTH) {
          throw Exception();
      }
      return ByteUtils.subarray(ciphertext, 0, NONCE_LENGTH);
    • This function is useful on the server, when the server needs to validate in advance whether the nonce is unique.

QA specification

Functionality is covered by unit tests.

@romanstrobl romanstrobl changed the title [Feature]: Update Encryption Algorithms for Crypto4 [Feature]: Update encryption algorithms for crypto4 Jan 9, 2025
@romanstrobl romanstrobl changed the title [Feature]: Update encryption algorithms for crypto4 Update encryption algorithms for crypto4 Jan 9, 2025
@romanstrobl romanstrobl self-assigned this Jan 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant