OmemoAesCipher.java

  1. /**
  2.  *
  3.  * Copyright 2017 Paul Schaub, 2019-2023 Florian Schmaus
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.jivesoftware.smackx.omemo.internal;

  18. import java.nio.charset.StandardCharsets;
  19. import java.security.InvalidAlgorithmParameterException;
  20. import java.security.InvalidKeyException;
  21. import java.security.NoSuchAlgorithmException;

  22. import javax.crypto.BadPaddingException;
  23. import javax.crypto.Cipher;
  24. import javax.crypto.IllegalBlockSizeException;
  25. import javax.crypto.NoSuchPaddingException;
  26. import javax.crypto.SecretKey;
  27. import javax.crypto.spec.IvParameterSpec;
  28. import javax.crypto.spec.SecretKeySpec;

  29. import org.jivesoftware.smack.util.RandomUtil;
  30. import org.jivesoftware.smackx.omemo.util.OmemoConstants;
  31. import org.jivesoftware.smackx.omemo.util.OmemoMessageBuilder;

  32. public class OmemoAesCipher {

  33.     static {
  34.         byte[] iv = OmemoMessageBuilder.generateIv();
  35.         byte[] key = new byte[16];
  36.         RandomUtil.fillWithSecureRandom(key);

  37.         try {
  38.             encryptAesGcmNoPadding("This is just a test", key, iv);
  39.         } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException
  40.                         | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
  41.             String message = "Unable to perform " + OmemoConstants.Crypto.CIPHERMODE
  42.                             + " operation requires by OMEMO. Ensure that a suitable crypto provider for is available."
  43.                             + " For example Bouncycastle on Android (BouncyCastleProvider)";
  44.             throw new AssertionError(message, e);
  45.         }
  46.     }

  47.     private enum CipherOpmode {
  48.         encrypt(Cipher.ENCRYPT_MODE),
  49.         decrypt(Cipher.DECRYPT_MODE),
  50.         ;

  51.         public final int opmodeInt;

  52.         CipherOpmode(int opmodeInt) {
  53.             this.opmodeInt = opmodeInt;
  54.         }
  55.     }

  56.     private static byte[] performCipherOperation(CipherOpmode opmode, byte[] input, byte[] key,
  57.                     byte[] initializationVector)
  58.                     throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException,
  59.                     NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
  60.         SecretKey secretKey = new SecretKeySpec(key, OmemoConstants.Crypto.KEYTYPE);
  61.         IvParameterSpec ivSpec = new IvParameterSpec(initializationVector);

  62.         Cipher cipher = Cipher.getInstance(OmemoConstants.Crypto.CIPHERMODE);
  63.         cipher.init(opmode.opmodeInt, secretKey, ivSpec);

  64.         byte[] ciphertext = cipher.doFinal(input);

  65.         return ciphertext;
  66.     }

  67.     public static byte[] decryptAesGcmNoPadding(byte[] ciphertext, byte[] key, byte[] initializationVector)
  68.                     throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException,
  69.                     NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
  70.         return performCipherOperation(CipherOpmode.decrypt, ciphertext, key, initializationVector);
  71.     }

  72.     public static byte[] encryptAesGcmNoPadding(byte[] plaintext, byte[] key, byte[] initializationVector)
  73.                     throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
  74.                     InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
  75.         return performCipherOperation(CipherOpmode.encrypt, plaintext, key, initializationVector);
  76.     }

  77.     public static byte[] encryptAesGcmNoPadding(String plaintext, byte[] key, byte[] initializationVector)
  78.                     throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
  79.                     InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
  80.         byte[] plaintextBytes = plaintext.getBytes(StandardCharsets.UTF_8);
  81.         return encryptAesGcmNoPadding(plaintextBytes, key, initializationVector);
  82.     }
  83. }