1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
"""
utility functions for Yubico modules
"""
# Copyright (c) 2010, Yubico AB
# See the file COPYING for licence statement.
__all__ = [
# constants
# functions
'crc16',
'validate_crc16',
'hexdump',
'modhex_decode',
'hotp_truncate',
# classes
]
import sys
import string
from .yubico_version import __version__
from . import yubikey_defs
from . import yubico_exception
_CRC_OK_RESIDUAL = 0xf0b8
def ord_byte(byte):
"""Convert a byte to its integer value"""
if sys.version_info < (3, 0):
return ord(byte)
else:
# In Python 3, single bytes are represented as integers
return int(byte)
def chr_byte(number):
"""Convert an integer value to a length-1 bytestring"""
if sys.version_info < (3, 0):
return chr(number)
else:
return bytes([number])
def crc16(data):
"""
Calculate an ISO13239 CRC checksum of the input buffer (bytestring).
"""
m_crc = 0xffff
for this in data:
m_crc ^= ord_byte(this)
for _ in range(8):
j = m_crc & 1
m_crc >>= 1
if j:
m_crc ^= 0x8408
return m_crc
def validate_crc16(data):
"""
Validate that the CRC of the contents of buffer is the residual OK value.
The input is a bytestring.
"""
return crc16(data) == _CRC_OK_RESIDUAL
class DumpColors:
""" Class holding ANSI colors for colorization of hexdump output """
def __init__(self):
self.colors = {'BLUE': '\033[94m',
'GREEN': '\033[92m',
'RESET': '\033[0m',
}
self.enabled = True
return None
def get(self, what):
"""
Get the ANSI code for 'what'
Returns an empty string if disabled/not found
"""
if self.enabled:
if what in self.colors:
return self.colors[what]
return ''
def enable(self):
""" Enable colorization """
self.enabled = True
def disable(self):
""" Disable colorization """
self.enabled = False
def hexdump(src, length=8, colorize=False):
""" Produce a string hexdump of src, for debug output.
Input: bytestring; output: text string
"""
if not src:
return str(src)
if type(src) is not bytes:
raise yubico_exception.InputError('Hexdump \'src\' must be bytestring (got %s)' % type(src))
offset = 0
result = ''
for this in group(src, length):
if colorize:
last, this = this[-1], this[:-1]
colors = DumpColors()
color = colors.get('RESET')
if ord_byte(last) & yubikey_defs.RESP_PENDING_FLAG:
# write to key
color = colors.get('BLUE')
elif ord_byte(last) & yubikey_defs.SLOT_WRITE_FLAG:
color = colors.get('GREEN')
hex_s = color + ' '.join(["%02x" % ord_byte(x) for x in this]) + colors.get('RESET')
hex_s += " %02x" % ord_byte(last)
else:
hex_s = ' '.join(["%02x" % ord_byte(x) for x in this])
result += "%04X %s\n" % (offset, hex_s)
offset += length
return result
def group(data, num):
""" Split data into chunks of num chars each """
return [data[i:i+num] for i in range(0, len(data), num)]
def modhex_decode(data):
""" Convert a modhex bytestring to ordinary hex. """
try:
maketrans = string.maketrans
except AttributeError:
# Python 3
maketrans = bytes.maketrans
t_map = maketrans(b"cbdefghijklnrtuv", b"0123456789abcdef")
return data.translate(t_map)
def hotp_truncate(hmac_result, length=6):
""" Perform the HOTP Algorithm truncating.
Input is a bytestring.
"""
if len(hmac_result) != 20:
raise yubico_exception.YubicoError("HMAC-SHA-1 not 20 bytes long")
offset = ord_byte(hmac_result[19]) & 0xf
bin_code = (ord_byte(hmac_result[offset]) & 0x7f) << 24 \
| (ord_byte(hmac_result[offset+1]) & 0xff) << 16 \
| (ord_byte(hmac_result[offset+2]) & 0xff) << 8 \
| (ord_byte(hmac_result[offset+3]) & 0xff)
return bin_code % (10 ** length)
def tlv_parse(data):
""" Parses a bytestring of TLV values into a dict with the tags as keys."""
parsed = {}
while data:
t, l, data = ord_byte(data[0]), ord_byte(data[1]), data[2:]
parsed[t], data = data[:l], data[l:]
return parsed
|