Skip to main content

Prox Generic Credential Formats

PROX_GENERIC credentials are 6 bytes (48 bits) encoded in Little Endian byte order. This format works simply and flexibly by assigning the raw byte stream the credential transmits to the Last Lock device. This allows a wide range of credential formats to be supported, with encoding and decoding logic left to the caller.

Header Table​

Not all PACS providers expose the header directly, so it is listed here for reference.

Bit LengthHeader (Binary)Header Bits
26-bit0000 0010 0000 0000 0118
27-bit0000 0010 0000 0000 117
28-bit0000 0010 0000 000116
29-bit0000 0010 0000 00115
30-bit0000 0010 0000 0114
31-bit0000 0010 0000 113
32-bit0000 0010 000112
33-bit0000 0010 00111
34-bit0000 0010 0110
35-bit0000 0010 19
36-bit0000 00118
37-bit0000 0007

PROX 10301 Example (26-bit)​

This is intended only as an example of how to encode a credential, following the header table provided above. Your mileage may vary depending on the specific credential format you are using. Refer to the documentation provided by the issuer of your credentials for the correct byte structure.

This specific PROX 10301 is 26 bits: [even_parity:1][facility:8][card_number:16][odd_parity:1]

Example: Facility=123, Card=45678

Step 1: Card data (26 bits)
Parity | Facility (123) | Card Number (45678) | Parity
1 | 01111011 | 1011001001101110 | 1
= 10111101110110010011011101

Even parity: count 1s in (facility + top 4 bits of card) = 9 → parity = 1
Odd parity: count 1s in (bottom 12 bits of card) = 6 → parity = 1

Step 2: Add 18-bit header (for 26-bit format)
Header (18 bits) | Card Data (26 bits)
000000100000000001 | 10111101110110010011011101
= 00000010000000000110111101110110010011011101 (44 bits)

Step 3: Pad to 48 bits (add 4 zero bits at MSB)
0000 00000010000000000110111101110110010011011101
= 0x002006F764DD (big endian)

Step 4: Convert to Little Endian bytes
Big Endian: 00 20 06 F7 64 DD
Little Endian: DD 64 F7 06 20 00

Final credential data: DD64F7062000
def encode_h10301(facility_code: int, card_number: int) -> bytes:
"""Encode PROX 10301 as PROX_GENERIC (6 bytes, Little Endian)."""
data_24 = (facility_code << 16) | card_number

# Calculate parity
upper_12 = (facility_code << 4) | (card_number >> 12)
even_parity = bin(upper_12).count('1') % 2
lower_12 = card_number & 0xFFF
odd_parity = 1 - (bin(lower_12).count('1') % 2)

# Assemble 26-bit card data
card_26 = (even_parity << 25) | (data_24 << 1) | odd_parity

# Add 18-bit header (26-bit format), giving 44 bits total
header_26bit = (1 << 11) | 1 # 0b000000100000000001 = 2049
value_44 = (header_26bit << 26) | card_26

return value_44.to_bytes(6, byteorder='little')

# Example: facility=123, card=45678 -> DD64F7062000
credential_data = encode_h10301(123, 45678)

Assign to a device:

credential = org_pb2.Credential(
credential_type=org_pb2.PROX_GENERIC,
data=encode_h10301(123, 45678) # DD64F7062000
)
org.Assign(org_pb2.AssignmentsRequest(
assignments={14: org_pb2.Credentials(credentials=[credential])}
))