/**
  * Returns a JSONObject representation of the instruction object.
  *
  * @deprecated no longer used and will be removed in the future
  */
 @Deprecated
 private static JSONObject convertInstructionToJSONObject(EncryptionInstruction instruction) {
   JSONObject instructionJSON = new JSONObject();
   try {
     JSONObject materialsDescriptionJSON = new JSONObject(instruction.getMaterialsDescription());
     instructionJSON.put(Headers.MATERIALS_DESCRIPTION, materialsDescriptionJSON.toString());
     instructionJSON.put(
         Headers.CRYPTO_KEY, Base64.encodeAsString(instruction.getEncryptedSymmetricKey()));
     byte[] iv = instruction.getSymmetricCipher().getIV();
     instructionJSON.put(Headers.CRYPTO_IV, Base64.encodeAsString(iv));
   } catch (JSONException e) {
   } // Keys are never null, so JSONException will never be thrown.
   return instructionJSON;
 }
  /**
   * Update the request's ObjectMetadata with the necessary information for decrypting the object
   *
   * @param request Non-null PUT request encrypted using the given instruction
   * @param instruction Non-null instruction used to encrypt the data in this PUT request.
   * @deprecated no longer used and will be removed in the future
   */
  @Deprecated
  public static void updateMetadataWithEncryptionInstruction(
      PutObjectRequest request, EncryptionInstruction instruction) {
    byte[] keyBytesToStoreInMetadata = instruction.getEncryptedSymmetricKey();
    Cipher symmetricCipher = instruction.getSymmetricCipher();
    Map<String, String> materialsDescription = instruction.getMaterialsDescription();

    ObjectMetadata metadata = request.getMetadata();
    if (metadata == null) metadata = new ObjectMetadata();

    if (request.getFile() != null) {
      Mimetypes mimetypes = Mimetypes.getInstance();
      metadata.setContentType(mimetypes.getMimetype(request.getFile()));
    }

    updateMetadata(metadata, keyBytesToStoreInMetadata, symmetricCipher, materialsDescription);
    request.setMetadata(metadata);
  }
  /**
   * Returns an updated object where the object content input stream contains the decrypted
   * contents.
   *
   * @param object The object whose contents are to be decrypted.
   * @param instruction The instruction that will be used to decrypt the object data.
   * @return The updated object where the object content input stream contains the decrypted
   *     contents.
   * @deprecated no longer used and will be removed in the future
   */
  @Deprecated
  public static S3Object decryptObjectUsingInstruction(
      S3Object object, EncryptionInstruction instruction) {
    S3ObjectInputStream objectContent = object.getObjectContent();

    InputStream decryptedInputStream =
        new RepeatableCipherInputStream(objectContent, instruction.getCipherFactory());
    object.setObjectContent(
        new S3ObjectInputStream(decryptedInputStream, objectContent.getHttpRequest()));
    return object;
  }
  /**
   * Returns an updated request where the input stream contains the encrypted object contents. The
   * specified instruction will be used to encrypt data.
   *
   * @param request The request whose contents are to be encrypted.
   * @param instruction The instruction that will be used to encrypt the object data.
   * @return The updated request where the input stream contains the encrypted contents.
   * @deprecated no longer used and will be removed in the future
   */
  @Deprecated
  public static PutObjectRequest encryptRequestUsingInstruction(
      PutObjectRequest request, EncryptionInstruction instruction) {
    // Create a new metadata object if there is no metadata already.
    ObjectMetadata metadata = request.getMetadata();
    if (metadata == null) {
      metadata = new ObjectMetadata();
    }

    // Record the original Content MD5, if present, for the unencrypted data
    if (metadata.getContentMD5() != null) {
      metadata.addUserMetadata(Headers.UNENCRYPTED_CONTENT_MD5, metadata.getContentMD5());
    }

    // Removes the original content MD5 if present from the meta data.
    metadata.setContentMD5(null);

    // Record the original, unencrypted content-length so it can be accessed later
    final long plaintextLength = getUnencryptedContentLength(request, metadata);
    if (plaintextLength >= 0) {
      metadata.addUserMetadata(Headers.UNENCRYPTED_CONTENT_LENGTH, Long.toString(plaintextLength));
    }

    // Put the calculated length of the encrypted contents in the metadata
    long cryptoContentLength =
        calculateCryptoContentLength(instruction.getSymmetricCipher(), request, metadata);
    if (cryptoContentLength >= 0) {
      metadata.setContentLength(cryptoContentLength);
    }

    request.setMetadata(metadata);

    // Create encrypted input stream
    request.setInputStream(
        getEncryptedInputStream(request, instruction.getCipherFactory(), plaintextLength));

    // Treat all encryption requests as input stream upload requests, not as file upload requests.
    request.setFile(null);

    return request;
  }