check.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. import collections
  2. import hashlib
  3. class VerificationFailed(Exception):
  4. pass
  5. EllipticCurve = collections.namedtuple('EllipticCurve', 'seed p a b')
  6. # All the following curves except the last one were taken from the OpenSSL
  7. # source code (crypto/ec/ec_curve.c). The last four are fake curves that should
  8. # not pass seed validation.
  9. curves = {
  10. 'prime192v1': EllipticCurve(
  11. seed=0x3045ae6fc8422f64ed579528d38120eae12196d5,
  12. p=0xfffffffffffffffffffffffffffffffeffffffffffffffff,
  13. a=0xfffffffffffffffffffffffffffffffefffffffffffffffc,
  14. b=0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1,
  15. ),
  16. 'secp224r1': EllipticCurve(
  17. seed=0xbd71344799d5c7fcdc45b59fa3b9ab8f6a948bc5,
  18. p=0xffffffffffffffffffffffffffffffff000000000000000000000001,
  19. a=0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe,
  20. b=0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4,
  21. ),
  22. 'secp384r1': EllipticCurve(
  23. seed=0xa335926aa319a27a1d00896a6773a4827acdac73,
  24. p=0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff,
  25. a=0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc,
  26. b=0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef,
  27. ),
  28. 'secp521r1': EllipticCurve(
  29. seed=0xd09e8800291cb85396cc6717393284aaa0da64ba,
  30. p=0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff,
  31. a=0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc,
  32. b=0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00,
  33. ),
  34. 'prime192v2': EllipticCurve(
  35. seed=0x31a92ee2029fd10d901b113e990710f0d21ac6b6,
  36. p=0xfffffffffffffffffffffffffffffffeffffffffffffffff,
  37. a=0xfffffffffffffffffffffffffffffffefffffffffffffffc,
  38. b=0xcc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953,
  39. ),
  40. 'prime192v3': EllipticCurve(
  41. seed=0xc469684435deb378c4b65ca9591e2a5763059a2e,
  42. p=0xfffffffffffffffffffffffffffffffeffffffffffffffff,
  43. a=0xfffffffffffffffffffffffffffffffefffffffffffffffc,
  44. b=0x22123dc2395a05caa7423daeccc94760a7d462256bd56916,
  45. ),
  46. 'prime239v1': EllipticCurve(
  47. seed=0xe43bb460f0b80cc0c0b075798e948060f8321b7d,
  48. p=0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff,
  49. a=0x7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc,
  50. b=0x6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a,
  51. ),
  52. 'prime239v2': EllipticCurve(
  53. seed=0xe8b4011604095303ca3b8099982be09fcb9ae616,
  54. p=0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff,
  55. a=0x7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc,
  56. b=0x617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c,
  57. ),
  58. 'prime239v3': EllipticCurve(
  59. seed=0x7d7374168ffe3471b60a857686a19475d3bfa2ff,
  60. p=0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff,
  61. a=0x7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc,
  62. b=0x255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e,
  63. ),
  64. 'prime256v1': EllipticCurve(
  65. seed=0xc49d360886e704936a6678e1139d26b7819f7e90,
  66. p=0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff,
  67. a=0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc,
  68. b=0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b,
  69. ),
  70. 'secp112r1': EllipticCurve(
  71. seed=0x00f50b028e4d696e676875615175290472783fb1,
  72. p=0xdb7c2abf62e35e668076bead208b,
  73. a=0xdb7c2abf62e35e668076bead2088,
  74. b=0x659ef8ba043916eede8911702b22,
  75. ),
  76. 'secp112r2': EllipticCurve(
  77. seed=0x002757a1114d696e6768756151755316c05e0bd4,
  78. p=0xdb7c2abf62e35e668076bead208b,
  79. a=0x6127c24c05f38a0aaaf65c0ef02c,
  80. b=0x51def1815db5ed74fcc34c85d709,
  81. ),
  82. 'secp128r1': EllipticCurve(
  83. seed=0x000e0d4d696e6768756151750cc03a4473d03679,
  84. p=0xfffffffdffffffffffffffffffffffff,
  85. a=0xfffffffdfffffffffffffffffffffffc,
  86. b=0xe87579c11079f43dd824993c2cee5ed3,
  87. ),
  88. 'secp128r2': EllipticCurve(
  89. seed=0x004d696e67687561517512d8f03431fce63b88f4,
  90. p=0xfffffffdffffffffffffffffffffffff,
  91. a=0xd6031998d1b3bbfebf59cc9bbff9aee1,
  92. b=0x5eeefca380d02919dc2c6558bb6d8a5d,
  93. ),
  94. 'secp160r1': EllipticCurve(
  95. seed=0x1053cde42c14d696e67687561517533bf3f83345,
  96. p=0x00ffffffffffffffffffffffffffffffff7fffffff,
  97. a=0x00ffffffffffffffffffffffffffffffff7ffffffc,
  98. b=0x001c97befc54bd7a8b65acf89f81d4d4adc565fa45,
  99. ),
  100. 'secp160r2': EllipticCurve(
  101. seed=0xb99b99b099b323e02709a4d696e6768756151751,
  102. p=0x00fffffffffffffffffffffffffffffffeffffac73,
  103. a=0x00fffffffffffffffffffffffffffffffeffffac70,
  104. b=0x00b4e134d3fb59eb8bab57274904664d5af50388ba,
  105. ),
  106. # This is prime192v1 with a wrong value for seed.
  107. 'wrong192v1': EllipticCurve(
  108. seed=0x123,
  109. p=0xfffffffffffffffffffffffffffffffeffffffffffffffff,
  110. a=0xfffffffffffffffffffffffffffffffefffffffffffffffc,
  111. b=0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1,
  112. ),
  113. # This is prime192v1 with a wrong value for p.
  114. 'wrong192v2': EllipticCurve(
  115. seed=0x3045ae6fc8422f64ed579528d38120eae12196d5,
  116. p=0x123,
  117. a=0xfffffffffffffffffffffffffffffffefffffffffffffffc,
  118. b=0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1,
  119. ),
  120. # This is prime192v1 with a wrong value for a.
  121. 'wrong192v3': EllipticCurve(
  122. seed=0x3045ae6fc8422f64ed579528d38120eae12196d5,
  123. p=0xfffffffffffffffffffffffffffffffeffffffffffffffff,
  124. a=0x123,
  125. b=0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1,
  126. ),
  127. # This is prime192v1 with a wrong value for b.
  128. 'wrong192v4': EllipticCurve(
  129. seed=0x3045ae6fc8422f64ed579528d38120eae12196d5,
  130. p=0xfffffffffffffffffffffffffffffffeffffffffffffffff,
  131. a=0xfffffffffffffffffffffffffffffffefffffffffffffffc,
  132. b=0x123,
  133. ),
  134. }
  135. def verify_curve(curve):
  136. """
  137. Проверяет, были ли сгенерированы параметры a и b данной кривой
  138. из семени.
  139. Вызывает исключение VerificationFailed в случае сбоя проверки.
  140. """
  141. # Далее следует реализация алгоритма проверки
  142. # описан в "Алгоритме цифровой подписи на эллиптических кривых (ECDSA)",
  143. # от Сертиком. Есть лишь несколько отличий от исходного алгоритма
  144. # и реализация:
  145. #
  146. # * несколько имен переменных изменены для ясности;
  147. # * документ от Certicom допускает произвольные начальные числа с битовой длиной
  148. # >= 160; здесь нас интересуют только семена длиной ровно 160 бит.
  149. if curve.seed.bit_length() > 160:
  150. raise VerificationFailed('seed too long')
  151. seed_bytes = curve.seed.to_bytes(length=160 // 8, byteorder='big')
  152. # Определите t, s и v, как указано в документе.
  153. t = curve.p.bit_length()
  154. s = (t - 1) // 160
  155. v = t - 160 * s
  156. # 1. Вычислите h = SHA-1(seed_bytes) и пусть c0 обозначает битовую строку
  157. # длина v битов, полученная путем взятия v крайних правых битов h.
  158. h = hashlib.sha1(seed_bytes).digest()
  159. h = int.from_bytes(h, byteorder='big')
  160. c0 = h & ((1 << v) - 1)
  161. print(h, c0)
  162. # 2. Пусть w[0] обозначает строку битов длины v бит, полученную установкой
  163. # крайний левый бит c0 в 0.
  164. #
  165. # Примечание: здесь мы используем 160 бит вместо v бит, как того требует документ.
  166. # Мы делаем это для того, чтобы сделать код проще и потому что он не делает никаких ошибок.
  167. # разница (см. шаг 6).
  168. w0 = c0 & ((1 << v - 1) - 1)
  169. w = [w0.to_bytes(length=160 // 8, byteorder='big')]
  170. # 3. Пусть z будет целым числом, двоичное представление которого задается 160-битной строкой
  171. # seed_bytes.
  172. z = curve.seed
  173. # 4. Для i от 1 до s делаем:
  174. for i in range(1, s + 1):
  175. # 4.1 Пусть s_i будет 160-битной строкой, которая представляет собой двоичное расширение
  176. # целое число (z+i)%(2**g).
  177. z_i = ((z + i) % (2 ** 160))
  178. s_i = z_i.to_bytes(length=160 // 8, byteorder='big')
  179. # 4.2 Вычисление w_i = SHA-1(s_i).
  180. w_i = hashlib.sha1(s_i).digest()
  181. w.append(w_i)
  182. # 5. Пусть w будет битовой строкой, полученной конкатенацией w_0,w_1,...,w_s.
  183. w = b''.join(w)
  184. # 6. Пусть c будет целым числом, целочисленное разложение которого задается w.
  185. #
  186. # На шаге 2 мы сказали, что использовали более длинную битовую длину для первого элемента
  187. # w. Это правильно, потому что результирующий c не меняется: используя 160
  188. # бит вместо v бит эквивалентно добавлению нескольких нулей слева от c.
  189. c = int.from_bytes(w, 'big')
  190. # Если b ** 2 * c == a ** 3 (mod p), то accept; в противном случае отклонить.
  191. if (curve.b * curve.b * c - curve.a * curve.a * curve.a) % curve.p != 0:
  192. raise VerificationFailed('curve verification failed')
  193. # Check all the curves defined above.
  194. # Should produce the following output:
  195. #
  196. # prime192v1: ok
  197. # prime192v2: ok
  198. # ...
  199. # secp384r1: ok
  200. # secp521r1: ok
  201. # wrong192v1: failed
  202. # wrong192v2: failed
  203. # wrong192v3: failed
  204. # wrong192v4: failed
  205. for name in sorted(curves):
  206. curve = curves[name]
  207. print(name, end=': ')
  208. try:
  209. verify_curve(curve)
  210. except VerificationFailed:
  211. print('failed')
  212. else:
  213. print('ok')