Module refinery.lib.maru

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

Expand source code Browse git
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Maru hash implementation; it matches the C implementation found in Donut.
"""
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)

XXX to be provided

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)

XXX to be provided

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