2 # PyGOST -- Pure Python GOST cryptographic functions library
3 # Copyright (C) 2015-2019 Sergey Matveev <stargrave@stargrave.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17 """ GOST R 34.10 public-key signature function.
19 This is implementation of GOST R 34.10-2001 (:rfc:`5832`), GOST R
20 34.10-2012 (:rfc:`7091`). The difference between 2001 and 2012 is the
21 key, digest and signature lengths.
24 from os import urandom
26 from pygost.utils import bytes2long
27 from pygost.utils import hexdec
28 from pygost.utils import long2bytes
29 from pygost.utils import modinvert
38 DEFAULT_CURVE = "id-GostR3410-2001-CryptoPro-A-ParamSet"
39 # Curve parameters are the following: p, q, a, b, x, y
41 "GostR3410_2001_ParamSet_cc": (
42 "C0000000000000000000000000000000000000000000000000000000000003C7",
43 "5fffffffffffffffffffffffffffffff606117a2f4bde428b7458a54b6e87b85",
44 "C0000000000000000000000000000000000000000000000000000000000003c4",
45 "2d06B4265ebc749ff7d0f1f1f88232e81632e9088fd44b7787d5e407e955080c",
46 "0000000000000000000000000000000000000000000000000000000000000002",
47 "a20e034bf8813ef5c18d01105e726a17eb248b264ae9706f440bedc8ccb6b22c",
49 "id-GostR3410-2001-TestParamSet": (
50 "8000000000000000000000000000000000000000000000000000000000000431",
51 "8000000000000000000000000000000150FE8A1892976154C59CFC193ACCF5B3",
52 "0000000000000000000000000000000000000000000000000000000000000007",
53 "5FBFF498AA938CE739B8E022FBAFEF40563F6E6A3472FC2A514C0CE9DAE23B7E",
54 "0000000000000000000000000000000000000000000000000000000000000002",
55 "08E2A8A0E65147D4BD6316030E16D19C85C97F0A9CA267122B96ABBCEA7E8FC8",
57 "id-GostR3410-2001-CryptoPro-A-ParamSet": (
58 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97",
59 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893",
60 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94",
61 "00000000000000000000000000000000000000000000000000000000000000a6",
62 "0000000000000000000000000000000000000000000000000000000000000001",
63 "8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14",
65 "id-GostR3410-2001-CryptoPro-B-ParamSet": (
66 "8000000000000000000000000000000000000000000000000000000000000C99",
67 "800000000000000000000000000000015F700CFFF1A624E5E497161BCC8A198F",
68 "8000000000000000000000000000000000000000000000000000000000000C96",
69 "3E1AF419A269A5F866A7D3C25C3DF80AE979259373FF2B182F49D4CE7E1BBC8B",
70 "0000000000000000000000000000000000000000000000000000000000000001",
71 "3FA8124359F96680B83D1C3EB2C070E5C545C9858D03ECFB744BF8D717717EFC",
73 "id-GostR3410-2001-CryptoPro-C-ParamSet": (
74 "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D759B",
75 "9B9F605F5A858107AB1EC85E6B41C8AA582CA3511EDDFB74F02F3A6598980BB9",
76 "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D7598",
77 "000000000000000000000000000000000000000000000000000000000000805a",
78 "0000000000000000000000000000000000000000000000000000000000000000",
79 "41ECE55743711A8C3CBF3783CD08C0EE4D4DC440D4641A8F366E550DFDB3BB67",
81 "id-GostR3410-2001-CryptoPro-XchA-ParamSet": (
82 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97",
83 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893",
84 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94",
85 "00000000000000000000000000000000000000000000000000000000000000a6",
86 "0000000000000000000000000000000000000000000000000000000000000001",
87 "8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14",
89 "id-GostR3410-2001-CryptoPro-XchB-ParamSet": (
90 "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D759B",
91 "9B9F605F5A858107AB1EC85E6B41C8AA582CA3511EDDFB74F02F3A6598980BB9",
92 "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D7598",
93 "000000000000000000000000000000000000000000000000000000000000805a",
94 "0000000000000000000000000000000000000000000000000000000000000000",
95 "41ECE55743711A8C3CBF3783CD08C0EE4D4DC440D4641A8F366E550DFDB3BB67",
97 "id-tc26-gost-3410-2012-256-paramSetA": (
98 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97",
99 "400000000000000000000000000000000FD8CDDFC87B6635C115AF556C360C67",
100 "C2173F1513981673AF4892C23035A27CE25E2013BF95AA33B22C656F277E7335",
101 "295F9BAE7428ED9CCC20E7C359A9D41A22FCCD9108E17BF7BA9337A6F8AE9513",
102 "91E38443A5E82C0D880923425712B2BB658B9196932E02C78B2582FE742DAA28",
103 "32879423AB1A0375895786C4BB46E9565FDE0B5344766740AF268ADB32322E5C",
105 "id-tc26-gost-3410-12-512-paramSetA": (
106 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7",
107 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27E69532F48D89116FF22B8D4E0560609B4B38ABFAD2B85DCACDB1411F10B275",
108 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4",
109 "E8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760",
110 "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003",
111 "7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4",
113 "id-tc26-gost-3410-12-512-paramSetB": (
114 "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006F",
115 "800000000000000000000000000000000000000000000000000000000000000149A1EC142565A545ACFDB77BD9D40CFA8B996712101BEA0EC6346C54374F25BD",
116 "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006C",
117 "687D1B459DC841457E3E06CF6F5E2517B97C7D614AF138BCBF85DC806C4B289F3E965D2DB1416D217F8B276FAD1AB69C50F78BEE1FA3106EFB8CCBC7C5140116",
118 "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002",
119 "1A8F7EDA389B094C2C071E3647A8940F3C123B697578C213BE6DD9E6C8EC7335DCB228FD1EDF4A39152CBCAAF8C0398828041055F94CEEEC7E21340780FE41BD"
121 "id-tc26-gost-3410-2012-512-paramSetC": (
122 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7",
123 "3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC98CDBA46506AB004C33A9FF5147502CC8EDA9E7A769A12694623CEF47F023ED",
124 "DC9203E514A721875485A529D2C722FB187BC8980EB866644DE41C68E143064546E861C0E2C9EDD92ADE71F46FCF50FF2AD97F951FDA9F2A2EB6546F39689BD3",
125 "B4C4EE28CEBC6C2C8AC12952CF37F16AC7EFB6A9F69F4B57FFDA2E4F0DE5ADE038CBC2FFF719D2C18DE0284B8BFEF3B52B8CC7A5F5BF0A3C8D2319A5312557E1",
126 "E2E31EDFC23DE7BDEBE241CE593EF5DE2295B7A9CBAEF021D385F7074CEA043AA27272A7AE602BF2A7B9033DB9ED3610C6FB85487EAE97AAC5BC7928C1950148",
127 "F5CE40D95B5EB899ABBCCFF5911CB8577939804D6527378B8C108C3D2090FF9BE18E2D33E3021ED2EF32D85822423B6304F726AA854BAE07D0396E9A9ADDC40F",
130 for c, params in CURVE_PARAMS.items():
131 CURVE_PARAMS[c] = [hexdec(param) for param in params]
134 class GOST3410Curve(object):
135 """ GOST 34.10 validated curve
137 >>> p, q, a, b, x, y = CURVE_PARAMS["id-GostR3410-2001-TestParamSet"]
138 >>> curve = GOST3410Curve(p, q, a, b, x, y)
139 >>> prv = prv_unmarshal(urandom(32))
140 >>> signature = sign(curve, prv, GOST341194(data).digest())
141 >>> pub = public_key(curve, prv)
142 >>> verify(curve, pub, GOST341194(data).digest(), signature)
145 def __init__(self, p, q, a, b, x, y):
146 self.p = bytes2long(p)
147 self.q = bytes2long(q)
148 self.a = bytes2long(a)
149 self.b = bytes2long(b)
150 self.x = bytes2long(x)
151 self.y = bytes2long(y)
152 r1 = self.y * self.y % self.p
153 r2 = ((self.x * self.x + self.a) * self.x + self.b) % self.p
157 raise ValueError("Invalid parameters")
164 def _add(self, p1x, p1y, p2x, p2y):
165 if p1x == p2x and p1y == p2y:
167 t = ((3 * p1x * p1x + self.a) * modinvert(2 * p1y, self.p)) % self.p
169 tx = self._pos(p2x - p1x) % self.p
170 ty = self._pos(p2y - p1y) % self.p
171 t = (ty * modinvert(tx, self.p)) % self.p
172 tx = self._pos(t * t - p1x - p2x) % self.p
173 ty = self._pos(t * (p1x - tx) - p1y) % self.p
176 def exp(self, degree, x=None, y=None):
182 raise ValueError("Bad degree value")
186 tx, ty = self._add(tx, ty, x, y)
188 x, y = self._add(x, y, x, y)
192 def public_key(curve, prv):
193 """ Generate public key from the private one
195 :param GOST3410Curve curve: curve to use
196 :param long prv: private key
197 :returns: public key's parts, X and Y
200 return curve.exp(prv)
203 def sign(curve, prv, digest, mode=2001):
204 """ Calculate signature for provided digest
206 :param GOST3410Curve curve: curve to use
207 :param long prv: private key
208 :param digest: digest for signing
209 :type digest: bytes, 32 or 64 bytes
211 :rtype: bytes, 64 or 128 bytes
213 size = MODE2SIZE[mode]
215 e = bytes2long(digest) % q
219 k = bytes2long(urandom(size)) % q
232 return long2bytes(s, size) + long2bytes(r, size)
235 def verify(curve, pub, digest, signature, mode=2001):
236 """ Verify provided digest with the signature
238 :param GOST3410Curve curve: curve to use
239 :type pub: (long, long)
240 :param digest: digest needed to check
241 :type digest: bytes, 32 or 64 bytes
242 :param signature: signature to verify with
243 :type signature: bytes, 64 or 128 bytes
246 size = MODE2SIZE[mode]
247 if len(signature) != size * 2:
248 raise ValueError("Invalid signature length")
251 s = bytes2long(signature[:size])
252 r = bytes2long(signature[size:])
253 if r <= 0 or r >= q or s <= 0 or s >= q:
255 e = bytes2long(digest) % curve.q
261 p1x, p1y = curve.exp(z1)
262 q1x, q1y = curve.exp(z2, pub[0], pub[1])
266 lm = modinvert(lm, p)
275 # This is not constant time comparison!
279 def prv_unmarshal(prv):
280 """Unmarshal private key
282 :param bytes prv: serialized private key
285 return bytes2long(prv[::-1])
288 def pub_marshal(pub, mode=2001):
289 """Marshal public key
291 :type pub: (long, long)
294 size = MODE2SIZE[mode]
295 return (long2bytes(pub[1], size) + long2bytes(pub[0], size))[::-1]
298 def pub_unmarshal(pub, mode=2001):
299 """Unmarshal public key
304 size = MODE2SIZE[mode]
306 return (bytes2long(pub[size:]), bytes2long(pub[:size]))