You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

utils.py 2.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import base64
  2. import binascii
  3. import struct
  4. from .compat import binary_type, bytes_from_int, text_type
  5. try:
  6. from cryptography.hazmat.primitives.asymmetric.utils import (
  7. decode_dss_signature, encode_dss_signature
  8. )
  9. except ImportError:
  10. pass
  11. def force_unicode(value):
  12. if isinstance(value, binary_type):
  13. return value.decode('utf-8')
  14. elif isinstance(value, text_type):
  15. return value
  16. else:
  17. raise TypeError('Expected a string value')
  18. def force_bytes(value):
  19. if isinstance(value, text_type):
  20. return value.encode('utf-8')
  21. elif isinstance(value, binary_type):
  22. return value
  23. else:
  24. raise TypeError('Expected a string value')
  25. def base64url_decode(input):
  26. if isinstance(input, text_type):
  27. input = input.encode('ascii')
  28. rem = len(input) % 4
  29. if rem > 0:
  30. input += b'=' * (4 - rem)
  31. return base64.urlsafe_b64decode(input)
  32. def base64url_encode(input):
  33. return base64.urlsafe_b64encode(input).replace(b'=', b'')
  34. def to_base64url_uint(val):
  35. if val < 0:
  36. raise ValueError('Must be a positive integer')
  37. int_bytes = bytes_from_int(val)
  38. if len(int_bytes) == 0:
  39. int_bytes = b'\x00'
  40. return base64url_encode(int_bytes)
  41. def from_base64url_uint(val):
  42. if isinstance(val, text_type):
  43. val = val.encode('ascii')
  44. data = base64url_decode(val)
  45. buf = struct.unpack('%sB' % len(data), data)
  46. return int(''.join(["%02x" % byte for byte in buf]), 16)
  47. def merge_dict(original, updates):
  48. if not updates:
  49. return original
  50. try:
  51. merged_options = original.copy()
  52. merged_options.update(updates)
  53. except (AttributeError, ValueError) as e:
  54. raise TypeError('original and updates must be a dictionary: %s' % e)
  55. return merged_options
  56. def number_to_bytes(num, num_bytes):
  57. padded_hex = '%0*x' % (2 * num_bytes, num)
  58. big_endian = binascii.a2b_hex(padded_hex.encode('ascii'))
  59. return big_endian
  60. def bytes_to_number(string):
  61. return int(binascii.b2a_hex(string), 16)
  62. def der_to_raw_signature(der_sig, curve):
  63. num_bits = curve.key_size
  64. num_bytes = (num_bits + 7) // 8
  65. r, s = decode_dss_signature(der_sig)
  66. return number_to_bytes(r, num_bytes) + number_to_bytes(s, num_bytes)
  67. def raw_to_der_signature(raw_sig, curve):
  68. num_bits = curve.key_size
  69. num_bytes = (num_bits + 7) // 8
  70. if len(raw_sig) != 2 * num_bytes:
  71. raise ValueError('Invalid signature')
  72. r = bytes_to_number(raw_sig[:num_bytes])
  73. s = bytes_to_number(raw_sig[num_bytes:])
  74. return encode_dss_signature(r, s)