Packages

Elixir implementation of the SLIP-0039 : Shamir's Secret-Sharing for Mnemonic Codes.

Current section

Files

Jump to
slip39 lib slip39 cypher.ex
Raw

lib/slip39/cypher.ex

defmodule Slip39.Cypher do
alias Slip39.Constants
import Bitwise
def encrypt(master_secret, passphrase, iteration_exponent, identifier) do
if bit_size(master_secret) |> rem(2) != 0 do
raise("The length of the master secret in bytes must be an even number.")
end
encrypt_decrypt_common(
0..(Constants.get!(:ROUND_COUNT) - 1),
master_secret,
passphrase,
iteration_exponent,
identifier
)
end
def decrypt(encrypted_master_secret, passphrase, iteration_exponent, identifier) do
if bit_size(encrypted_master_secret) |> rem(2) != 0 do
raise("The length of the encrypted master secret in bytes must be an even number.")
end
encrypt_decrypt_common(
(Constants.get!(:ROUND_COUNT) - 1)..0,
encrypted_master_secret,
passphrase,
iteration_exponent,
identifier
)
end
defp encrypt_decrypt_common(range, secret, passphrase, iteration_exponent, identifier) do
chunk_length = bit_size(secret) |> div(2)
<<left::size(chunk_length), right::size(chunk_length)>> =
secret
left = <<left::size(chunk_length)>>
right = <<right::size(chunk_length)>>
salt = get_salt(identifier)
{left, right} =
range
|> Enum.reduce({left, right}, fn i, {left, right} ->
f = round_function(i, passphrase, iteration_exponent, salt, right)
{right, :crypto.exor(left, f)}
end)
right <> left
end
defp round_function(i, passphrase, e, salt, r) do
Plug.Crypto.KeyGenerator.generate(
<<i::8, passphrase::bitstring>>,
salt <> r,
iterations:
Constants.get!(:BASE_ITERATION_COUNT) <<< e
|> Integer.floor_div(Constants.get!(:ROUND_COUNT)),
length: byte_size(r)
)
end
defp get_salt(identifier) do
# We calculate the byte length needed to store identifier
id_byte_length = <<identifier::size(Constants.get!(:ID_LENGTH_BITS))>> |> byte_size()
<<Constants.get!(:SALT_STRING)::binary, identifier::size(8 * id_byte_length)>>
end
end