@Override
  public void run() {
    encryptJobMetricsTracker.onJobProcessingStart();
    ByteBuffer encryptedUserMetadata = null;
    ByteBuffer encryptedKey = null;
    ByteBuf encryptedBlobContent = null;
    Exception exception = null;
    try {
      if (blobContentToEncrypt != null) {
        encryptedBlobContent = cryptoService.encrypt(blobContentToEncrypt, perBlobKey);
      }
      if (userMetadataToEncrypt != null) {
        encryptedUserMetadata = cryptoService.encrypt(userMetadataToEncrypt, perBlobKey);
      }
      Object containerKey =
          kms.getKey(putBlobOptions == null ? null : putBlobOptions.getRestRequest(), accountId, containerId);
      encryptedKey = cryptoService.encryptKey(perBlobKey, containerKey);
    } catch (Exception e) {
      exception = e;
      if (encryptedBlobContent != null) {
        encryptedBlobContent.release();
        encryptedBlobContent = null;
      }
    } finally {
      if (blobContentToEncrypt != null) {
        blobContentToEncrypt.release();
        blobContentToEncrypt = null;
      }
      encryptJobMetricsTracker.onJobProcessingComplete();
      callback.onCompletion(
          exception == null ? new EncryptJobResult(encryptedKey, encryptedUserMetadata, encryptedBlobContent) : null,
          exception);
    }
  }
Steps to be performed on encryption
1. Encrypt blob content using perBlobKey if not null
2. Encrypt user-metadata using perBlobKey if not null
2. Fetch ContainerKey from kms for the given blob
3. Encrypt perBlobKey using containerKey
4. Invoke callback with the encryptedKey and encryptedBlobContent
ambry-router/src/main/java/com/github/ambry/router/EncryptJob.java