public ByteBuf encrypt(ByteBuf toEncrypt, SecretKeySpec key, byte[] iv) throws GeneralSecurityException {
    ByteBuf encryptedContent = null;
    ByteBuf temp = null;
    try {
      Cipher encrypter = Cipher.getInstance(GCM_CRYPTO_INSTANCE, "BC");
      if (iv == null) {
        iv = new byte[ivValSize];
        random.nextBytes(iv);
      }
      encrypter.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
      int outputSize = encrypter.getOutputSize(toEncrypt.readableBytes());

      encryptedContent = PooledByteBufAllocator.DEFAULT.ioBuffer(IVRecord_Format_V1.getIVRecordSize(iv) + outputSize);
      IVRecord_Format_V1.serializeIVRecord(encryptedContent, iv);

      ByteBuffer toEncryptBuffer;
      if (toEncrypt.nioBufferCount() != 1) {
        temp = PooledByteBufAllocator.DEFAULT.ioBuffer(toEncrypt.readableBytes());
        temp.writeBytes(toEncrypt);
        toEncryptBuffer = temp.nioBuffer();
      } else {
        toEncryptBuffer = toEncrypt.nioBuffer();
      }
      ByteBuffer encryptedContentBuffer = encryptedContent.nioBuffer(encryptedContent.writerIndex(),
          encryptedContent.capacity() - encryptedContent.writerIndex());
      int n = encrypter.doFinal(toEncryptBuffer, encryptedContentBuffer);
      encryptedContent.writerIndex(encryptedContent.writerIndex() + n);
      toEncrypt.skipBytes(toEncrypt.readableBytes());
      return encryptedContent;
    } catch (Exception e) {
      if (encryptedContent != null) {
        encryptedContent.release();
      }
      throw new GeneralSecurityException("Exception thrown while encrypting data", e);
    } finally {
      if (temp != null) {
        temp.release();
      }
    }
  }
Helper function to encrypt ByteBuf with the given key. When useFixedIv is true, don't use a random iv byte
array, using a all zero byte array instead. Only set it to be true in test.
@param toEncrypt {@link ByteBuf} that needs to be encrypted
@param key the secret key (of type T) to use to encrypt
@param iv If null, will create a random byte array serve as iv bytes.
@return the {@link ByteBuf} containing the encrypted content. Ensure the result has all
the information like the IV along with the encrypted content, in order to decrypt the content with a given key
@throws {@link GeneralSecurityException} on any exception with encryption
ambry-router/src/main/java/com/github/ambry/router/GCMCryptoService.java