Packages
grizzly
0.4.2
9.1.4
9.1.2
9.1.1
9.1.0
9.0.0
8.15.3
8.15.2
8.15.1
8.15.0
8.14.0
8.13.0
8.12.0
8.11.3
8.11.2
8.11.1
8.11.0
8.10.0
8.9.0
8.8.1
8.8.0
8.7.1
8.7.0
8.6.12
8.6.11
8.6.10
8.6.9
8.6.8
8.6.7
retired
8.6.6
8.6.5
8.6.4
8.6.3
8.6.2
8.6.1
8.6.0
8.5.3
8.5.2
8.5.1
8.5.0
8.4.0
8.3.0
8.2.3
8.2.2
8.2.1
8.2.0
8.1.0
8.0.1
8.0.0
7.4.3
7.4.2
7.4.1
7.4.0
7.3.0
7.2.0
7.1.4
7.1.3
7.1.2
7.1.1
7.1.0
7.0.4
7.0.3
7.0.2
7.0.1
7.0.0
6.8.8
6.8.7
6.8.6
6.8.5
6.8.4
6.8.3
6.8.2
6.8.1
6.8.0
6.7.1
6.7.0
6.6.1
6.6.0
6.5.1
6.5.0
6.4.0
6.3.0
6.2.0
6.1.1
6.1.0
6.0.1
6.0.0
5.4.1
5.4.0
5.3.0
5.2.8
5.2.7
5.2.6
5.2.5
5.2.4
5.2.3
5.2.2
5.2.1
5.2.0
5.1.2
5.1.1
5.1.0
5.0.2
5.0.1
5.0.0
4.0.1
4.0.0
3.0.0
2.1.0
2.0.0
1.0.1
1.0.0
0.22.7
0.22.6
0.22.5
0.22.4
0.22.3
0.22.2
0.22.1
0.22.0
0.21.1
0.21.0
0.20.2
0.20.1
0.20.0
0.19.1
0.19.0
0.18.3
0.18.2
0.18.1
0.18.0
0.17.7
0.17.6
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.2
0.16.1
0.16.0
0.15.11
0.15.10
0.15.9
0.15.8
0.15.7
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.8
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.0
0.12.3
0.12.2
0.12.1
0.12.0
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.0
0.9.0-rc.4
0.9.0-rc.3
0.9.0-rc.2
0.9.0-rc.1
0.9.0-rc.0
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.0
0.4.3
0.4.2
Elixir Z-Wave library
Current section
Files
Jump to
Current section
Files
lib/grizzly/security.ex
defmodule Grizzly.Security do
@moduledoc """
Helpers for security
"""
import Bitwise
@type key :: :s2_unauthenticated | :s2_authenticated | :s2_access_control | :s0
@type key_byte :: 0x01 | 0x02 | 0x04 | 0x80
@typedoc """
Possible key exchange failures
- `:none` - Bootstrapping was successful
- `:key` - No match between requested and granted keys
- `:scheme` - no scheme is supported by the controller or joining node
- `:decrypt` - joining node failed to decrypt the input pin from the value. Wrong input value/DSK from user
- `:cancel` - user has canceled the S2 bootstrapping
- `:auth` - the echo kex change frame does not match the earlier exchanged frame
- `:get` - the joining node requested a key that was not granted by the controller at an earlier stage
- `:verify` - the joining node cannot verify and decrypt the exchanged key
- `:report` - the including node transmitted a frame containing a different key than what was currently being exchanged
"""
@type key_exchange_fail_type ::
:none | :key | :scheme | :curves | :decrypt | :cancel | :auth | :get | :verify | :report
@spec byte_to_keys(byte) :: [key]
def byte_to_keys(granted_keys_byte) do
<<s0::size(1), _::size(4), ac::size(1), auth::size(1), unauth::size(1)>> =
<<granted_keys_byte>>
keys = [s0: s0, ac: ac, auth: auth, unauth: unauth]
Enum.reduce(keys, [], fn
{:s0, 1}, acc -> acc ++ [:s0]
{:ac, 1}, acc -> acc ++ [:s2_access_control]
{:auth, 1}, acc -> acc ++ [:s2_authenticated]
{:unauth, 1}, acc -> acc ++ [:s2_unauthenticated]
{_, 0}, acc -> acc
end)
end
@spec keys_to_byte([key]) :: byte
def keys_to_byte(keys) do
Enum.reduce(keys, 0, fn key, byte -> byte ||| key_byte(key) end)
end
@doc """
Validate the user input pin length, should be a 16 bit number
"""
@spec validate_user_input_pin_length(non_neg_integer()) :: :valid | :invalid
def validate_user_input_pin_length(n) when n >= 0 and n <= 65535, do: :valid
def validate_user_input_pin_length(_), do: :invalid
@doc """
Decode a byte repersentation of the key exchanged failed type
"""
@spec failed_type_from_byte(byte()) :: key_exchange_fail_type() | :unk
def failed_type_from_byte(0x00), do: :none
def failed_type_from_byte(0x01), do: :key
def failed_type_from_byte(0x02), do: :scheme
def failed_type_from_byte(0x03), do: :curves
def failed_type_from_byte(0x05), do: :decrypt
def failed_type_from_byte(0x06), do: :cancel
def failed_type_from_byte(0x07), do: :auth
def failed_type_from_byte(0x08), do: :get
def failed_type_from_byte(0x09), do: :verify
def failed_type_from_byte(0x0A), do: :report
def failed_type_from_byte(_), do: :unk
@doc """
Get the byte repersentation of a key.
The key `:none` is an invalid key to encode to,
so this function does not support encoding to that
key.
"""
@spec key_byte(key) :: key_byte()
def key_byte(:s0), do: 0x80
def key_byte(:s2_access_control), do: 0x04
def key_byte(:s2_authenticated), do: 0x02
def key_byte(:s2_unauthenticated), do: 0x01
@doc """
Gets the highest security level key from a key list
Since Z-Wave will work at the highest S2 security group
available on a node, if multiple groups are in a list of keys
it will assume that highest level is the security level of the node
who provided this list.
If the node S0 security Z-Wave will response with granted keys
with the lone key being S0.
"""
@spec get_highest_level([key]) :: key | :none
def get_highest_level([]), do: :none
def get_highest_level([:s0]), do: :s0
def get_highest_level(keys) do
Enum.reduce(keys, fn
:s2_access_control, _ ->
:s2_access_control
:s2_authenticated, last_highest when last_highest != :s2_access_control ->
:s2_authenticated
:s2_unauthenticated, last_highest
when last_highest not in [:s2_authenticated, :s2_access_control] ->
:s2_unauthenticated
:s2_unauthenticated, :s2_authenticated ->
:s2_authenticated
:s2_unauthenticated, :s2_access_control ->
:s2_access_control
_, last_highest ->
last_highest
end)
end
end