What is the Replacement for depreciated functions in the Erlang :crypto module?

Please can you provide or point to replacement code for:

crypto — crypto v5.5 (erlang.org)

from here: Deprecations — Erlang/OTP v27.0.1

It seems several functions have no equivalents.


Functions Deprecated in OTP 27
code:lib_dir/2 (this functionality will be removed in a future release)
crypto:private_decrypt/4 (do not use)
crypto:private_encrypt/4 (use public_key:sign/3 instead)
crypto:public_decrypt/4 (use public_key:verify/4 instead)
crypto:public_encrypt/4 (do not use)
mnesia_registry:create_table/_ (use mnesia:create_table/2 instead)
public_key:decrypt_private/2 (do not use)
public_key:decrypt_private/3 (do not use)
public_key:decrypt_public/2 (use public_key:verify/4 instead)
public_key:decrypt_public/3 (use public_key:verify/5 instead)
public_key:encrypt_private/2 (use public_key:sign/3 instead)
public_key:encrypt_private/3 (use public_key:sign 4 instead)
public_key:encrypt_public/2 (do not use)
public_key:encrypt_public/3 (do not use)
ssl:prf/5 (Use export_key_materials/4 instead. Note that in OTP 28 the 'testing' way of calling this function will no longer be supported.)

I have been trying to redo : raw.githubusercontent.com/WhatsApp/WhatsApp-Flows-Tools/refs/heads/main/examples/endpoint/nodejs/basic/src/encryption.js

For a project but the samples are all coming back with depreciated functions. (Even ChatGPT and Copilot return incorrect code)

here is my effort so far:

defmodule Flows do

  defmodule FlowEndpointException do
    defexception [:message, :status_code]

    @impl true
    def exception({status_code, message}) do
      %__MODULE__{message: message, status_code: status_code}
    end
  end

  def decrypt_request(body, private_pem, passphrase) do
    %{
      "encrypted_aes_key" => encrypted_aes_key,
      "encrypted_flow_data" => encrypted_flow_data,
      "initial_vector" => initial_vector
    } = body

    private_key = :public_key.pem_entry_decode({:RSAPrivateKey, private_pem, passphrase})

    try do
      decrypted_aes_key =
        encrypted_aes_key
        |> Base.decode64!()
        |> :crypto.decrypt(:rsa, private_key, [
          {:rsa_padding, :rsa_pkcs1_oaep_padding},
          {:rsa_oaep_md, :sha256}
        ])

      flow_data_buffer = Base.decode64!(encrypted_flow_data)
      initial_vector_buffer = Base.decode64!(initial_vector)

      tag_length = 16

      {encrypted_flow_data_body, encrypted_flow_data_tag} =
        :erlang.split_binary(flow_data_buffer, byte_size(flow_data_buffer) - tag_length)

      decrypted_json_string =
        :crypto.crypto_one_time_aead(
          :aes_128_gcm,
          decrypted_aes_key,
          initial_vector_buffer,
          encrypted_flow_data_body,
          "",
          encrypted_flow_data_tag,
          false
        )

      {
        :ok,
        %{
          decrypted_body: Jason.decode!(decrypted_json_string),
          aes_key_buffer: decrypted_aes_key,
          initial_vector_buffer: initial_vector_buffer
        }
      }
    rescue
      _ ->
        raise FlowEndpointException,
              {421, "Failed to decrypt the request. Please verify your private key."}
    end
  end

  def encrypt_response(response, aes_key_buffer, initial_vector_buffer) do
    flipped_iv = for <<byte <- initial_vector_buffer>>, do: Bitwise.bnot(byte)

    {cipher_text, cipher_tag} =
      :crypto.crypto_one_time_aead(
        :aes_128_gcm,
        aes_key_buffer,
        flipped_iv,
        Jason.encode!(response),
        "",
        16,
        true
      )

    Base.encode64(cipher_text <> cipher_tag)
  end
end

Working with crypto without any fundamental understanding is a recipe for disaster, even expert gets this wrong.

First you’ll need to understand why things have been deprecated, and what would be an alternative, if any.

1 Like

@Schultzer True, but I have a reference implementation in another language: NodeJS.

Porting it to Elixir was not too hard. but I end up with code that will not work in OPT-27, that’s the issue.

I don’t see a clear guide from Erlang documentation on how to replace depreciated functionality, that’s a problem.

Those deprecations have been reverted in OTP 27.1.

5 Likes