Packages

Implementation of the mickey-128 crypto algorithm in elixir.

Current section

Files

Jump to
mickex lib key_stream.ex
Raw

lib/key_stream.ex

defmodule KeyStream do
use Bitwise
@r_mask 0x0000D2A8415A0AAC1D5363D5
@comp_0 0x00003FEA7942A8096AA97A30
@comp_1 0x00003DD7E3A21D63DD629E9A
@s_mask_0 0x00005802AF4A93819FFA7FAF
@s_mask_1 0x0000C52B4911B0634C8CB877
defstruct r: 0, s: 0
def generate_binary(key, iv, length) do
{key, _} = key |> Base.encode16() |> Integer.parse(16)
{iv, _} = iv |> Base.encode16() |> Integer.parse(16)
generate(key, iv, length)
end
def generate_hex(key, iv, length) do
{key, _} = key |> Integer.parse(16)
{iv, _} = iv |> Integer.parse(16)
generate(key, iv, length) |> Base.encode16() |> String.downcase()
end
defp generate(key, iv, length) do
ctx = setup(%KeyStream{}, key, iv)
{_ctx, bytes} =
Enum.reduce(1..length, {ctx, <<>>}, fn _, {ctx, bytes} ->
{ctx, byte} = keystream_byte(ctx)
{ctx, bytes <> <<byte>>}
end)
bytes
end
defp clock_r(r, input_bit_r, control_bit_r) do
feedback_bit = extract_bit(r, 79) ^^^ input_bit_r
r =
if control_bit_r == 1 do
r ^^^ (r <<< 1)
else
r <<< 1
end
if feedback_bit == 1, do: r ^^^ @r_mask, else: r
end
defp clock_s(s, input_bit_s, control_bit_s) do
feedback_bit = extract_bit(s, 79) ^^^ input_bit_s
s = (s <<< 1) ^^^ (s ^^^ @comp_0 &&& (s >>> 1) ^^^ @comp_1 &&& 0x7FFF_FFFF_FFFF_FFFF_FFFE)
if feedback_bit == 1 do
if control_bit_s == 1 do
s ^^^ @s_mask_1
else
s ^^^ @s_mask_0
end
else
s
end
end
defp clock_kg(ctx, mixing, input_bit) do
# &&& 1
control_bit_r = extract_bit(ctx.s, 27) ^^^ extract_bit(ctx.r, 53)
# &&& 1
control_bit_s = extract_bit(ctx.s, 53) ^^^ extract_bit(ctx.r, 26)
ctx =
if mixing == 1 do
%{ctx | r: clock_r(ctx.r, extract_bit(ctx.s, 40) ^^^ input_bit, control_bit_r)}
else
%{ctx | r: clock_r(ctx.r, input_bit, control_bit_r)}
end
%{ctx | s: clock_s(ctx.s, input_bit, control_bit_s)}
end
defp load(ctx, _binary, 0) do
ctx
end
defp load(ctx, binary, size) do
ctx = clock_kg(ctx, 1, binary &&& 1)
load(ctx, binary >>> 1, size - 1)
end
defp setup(ctx, key, iv) do
ctx = load(ctx, iv, 32)
ctx = load(ctx, key, 80)
pre_clock(ctx, 0, 80)
end
defp pre_clock(ctx, _binary, 0) do
ctx
end
defp pre_clock(ctx, binary, size) do
ctx = clock_kg(ctx, 1, binary &&& 1)
pre_clock(ctx, binary >>> 1, size - 1)
end
defp keystream_byte(ctx) do
Enum.reduce(0..7, {ctx, 0}, fn _, {ctx, byte} ->
byte = byte <<< 1
byte = byte ^^^ current_keystream_bit(ctx)
ctx = clock_kg(ctx, 0, 0)
{ctx, byte}
end)
end
defp current_keystream_bit(ctx), do: extract_bit(ctx.r, 0) ^^^ extract_bit(ctx.s, 0)
defp extract_bit(binary, pos) do
(binary &&& 1 <<< pos) >>> pos
end
end