Module refinery.lib.maru

Maru hash implementation; it matches the C implementation found in Donut.

Expand source code Browse git
"""
Maru hash implementation; it matches the C implementation found in Donut.
"""
from __future__ import annotations

from ctypes import (
    Array,
    Union,
    c_uint8,
    c_uint32,
)

from refinery.lib.speck import (
    Speck64128KeySchedule,
    speck_encrypt32,
)

MARU_MAX_STR = 64
MARU_BLK_LEN = 16
MARU_HASH_LEN = 8


class uint8_array(Array):
    _type_ = c_uint8
    _length_ = MARU_BLK_LEN


class uint32_array(Array):
    _type_ = c_uint32
    _length_ = MARU_BLK_LEN // 4


class m_type(Union):
    _fields_ = ("b", uint8_array), ("w", uint32_array)


def swap_dwords(value: int) -> int:
    return (value & 0xFFFFFFFF) << 32 | (value & 0xFFFFFFFF00000000) >> 32


def speck_operation(v: bytearray, m: bytearray) -> int:
    rk = Speck64128KeySchedule(m)
    h_bytes = speck_encrypt32(v, rk, 27)
    h_int = int.from_bytes(h_bytes, "little")
    h_swapped = swap_dwords(h_int)
    return h_swapped


def maru32(value: bytes, seed: int) -> int:
    m = m_type()
    h = seed
    input_length = len(value)
    idx = 0
    length = 0
    end = False
    while not end:
        if length == input_length or length == MARU_MAX_STR:
            m.b[idx:] = (0,) * (MARU_BLK_LEN - idx)
            m.b[idx] = 0x80
            if idx >= MARU_BLK_LEN - 4:
                h_swapped = swap_dwords(h)
                h_bytes = h_swapped.to_bytes(8, "little")
                h ^= speck_operation(h_bytes, bytes(m.b))
                m.b[:] = (0,) * MARU_BLK_LEN
            m.w[(MARU_BLK_LEN // 4) - 1] = length * 8
            idx = MARU_BLK_LEN
            end = True
        else:
            m.b[idx] = value[length]
            length += 1
            idx += 1
        if idx == MARU_BLK_LEN:
            h_swapped = swap_dwords(h)
            h_bytes = h_swapped.to_bytes(8, "little")
            h ^= speck_operation(h_bytes, bytes(m.b))
            idx = 0
    return h


def maru32digest(value: bytes, seed: int) -> bytes:
    return maru32(value, seed).to_bytes(8, 'big')

Functions

def swap_dwords(value)
Expand source code Browse git
def swap_dwords(value: int) -> int:
    return (value & 0xFFFFFFFF) << 32 | (value & 0xFFFFFFFF00000000) >> 32
def speck_operation(v, m)
Expand source code Browse git
def speck_operation(v: bytearray, m: bytearray) -> int:
    rk = Speck64128KeySchedule(m)
    h_bytes = speck_encrypt32(v, rk, 27)
    h_int = int.from_bytes(h_bytes, "little")
    h_swapped = swap_dwords(h_int)
    return h_swapped
def maru32(value, seed)
Expand source code Browse git
def maru32(value: bytes, seed: int) -> int:
    m = m_type()
    h = seed
    input_length = len(value)
    idx = 0
    length = 0
    end = False
    while not end:
        if length == input_length or length == MARU_MAX_STR:
            m.b[idx:] = (0,) * (MARU_BLK_LEN - idx)
            m.b[idx] = 0x80
            if idx >= MARU_BLK_LEN - 4:
                h_swapped = swap_dwords(h)
                h_bytes = h_swapped.to_bytes(8, "little")
                h ^= speck_operation(h_bytes, bytes(m.b))
                m.b[:] = (0,) * MARU_BLK_LEN
            m.w[(MARU_BLK_LEN // 4) - 1] = length * 8
            idx = MARU_BLK_LEN
            end = True
        else:
            m.b[idx] = value[length]
            length += 1
            idx += 1
        if idx == MARU_BLK_LEN:
            h_swapped = swap_dwords(h)
            h_bytes = h_swapped.to_bytes(8, "little")
            h ^= speck_operation(h_bytes, bytes(m.b))
            idx = 0
    return h
def maru32digest(value, seed)
Expand source code Browse git
def maru32digest(value: bytes, seed: int) -> bytes:
    return maru32(value, seed).to_bytes(8, 'big')

Classes

class uint8_array (*args, **kwargs)

Abstract base class for arrays.

The recommended way to create concrete array types is by multiplying any ctypes data type with a non-negative integer. Alternatively, you can subclass this type and define length and type class variables. Array elements can be read and written using standard subscript and slice accesses for slice reads, the resulting object is not itself an Array.

Expand source code Browse git
class uint8_array(Array):
    _type_ = c_uint8
    _length_ = MARU_BLK_LEN

Ancestors

  • _ctypes.Array
  • _ctypes._CData
class uint32_array (*args, **kwargs)

Abstract base class for arrays.

The recommended way to create concrete array types is by multiplying any ctypes data type with a non-negative integer. Alternatively, you can subclass this type and define length and type class variables. Array elements can be read and written using standard subscript and slice accesses for slice reads, the resulting object is not itself an Array.

Expand source code Browse git
class uint32_array(Array):
    _type_ = c_uint32
    _length_ = MARU_BLK_LEN // 4

Ancestors

  • _ctypes.Array
  • _ctypes._CData
class m_type (*args, **kwargs)

Union base class

Expand source code Browse git
class m_type(Union):
    _fields_ = ("b", uint8_array), ("w", uint32_array)

Ancestors

  • _ctypes.Union
  • _ctypes._CData

Instance variables

var b

Structure/Union member

var w

Structure/Union member