2 # PyGOST -- Pure Python GOST cryptographic functions library
3 # Copyright (C) 2015-2016 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
40 DEFAULT_CURVE = "GostR3410_2001_CryptoPro_A_ParamSet"
41 # Curve parameters are the following: p, q, a, b, x, y
43 "GostR3410_2001_ParamSet_cc": (
44 "C0000000000000000000000000000000000000000000000000000000000003C7",
45 "5fffffffffffffffffffffffffffffff606117a2f4bde428b7458a54b6e87b85",
46 "C0000000000000000000000000000000000000000000000000000000000003c4",
47 "2d06B4265ebc749ff7d0f1f1f88232e81632e9088fd44b7787d5e407e955080c",
48 "0000000000000000000000000000000000000000000000000000000000000002",
49 "a20e034bf8813ef5c18d01105e726a17eb248b264ae9706f440bedc8ccb6b22c",
51 "GostR3410_2001_TestParamSet": (
52 "8000000000000000000000000000000000000000000000000000000000000431",
53 "8000000000000000000000000000000150FE8A1892976154C59CFC193ACCF5B3",
54 "0000000000000000000000000000000000000000000000000000000000000007",
55 "5FBFF498AA938CE739B8E022FBAFEF40563F6E6A3472FC2A514C0CE9DAE23B7E",
56 "0000000000000000000000000000000000000000000000000000000000000002",
57 "08E2A8A0E65147D4BD6316030E16D19C85C97F0A9CA267122B96ABBCEA7E8FC8",
59 "GostR3410_2001_CryptoPro_A_ParamSet": (
60 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97",
61 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893",
62 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94",
63 "00000000000000000000000000000000000000000000000000000000000000a6",
64 "0000000000000000000000000000000000000000000000000000000000000001",
65 "8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14",
67 "GostR3410_2001_CryptoPro_B_ParamSet": (
68 "8000000000000000000000000000000000000000000000000000000000000C99",
69 "800000000000000000000000000000015F700CFFF1A624E5E497161BCC8A198F",
70 "8000000000000000000000000000000000000000000000000000000000000C96",
71 "3E1AF419A269A5F866A7D3C25C3DF80AE979259373FF2B182F49D4CE7E1BBC8B",
72 "0000000000000000000000000000000000000000000000000000000000000001",
73 "3FA8124359F96680B83D1C3EB2C070E5C545C9858D03ECFB744BF8D717717EFC",
75 "GostR3410_2001_CryptoPro_C_ParamSet": (
76 "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D759B",
77 "9B9F605F5A858107AB1EC85E6B41C8AA582CA3511EDDFB74F02F3A6598980BB9",
78 "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D7598",
79 "000000000000000000000000000000000000000000000000000000000000805a",
80 "0000000000000000000000000000000000000000000000000000000000000000",
81 "41ECE55743711A8C3CBF3783CD08C0EE4D4DC440D4641A8F366E550DFDB3BB67",
83 "GostR3410_2001_CryptoPro_XchA_ParamSet": (
84 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97",
85 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893",
86 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94",
87 "00000000000000000000000000000000000000000000000000000000000000a6",
88 "0000000000000000000000000000000000000000000000000000000000000001",
89 "8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14",
91 "GostR3410_2001_CryptoPro_XchB_ParamSet": (
92 "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D759B",
93 "9B9F605F5A858107AB1EC85E6B41C8AA582CA3511EDDFB74F02F3A6598980BB9",
94 "9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D7598",
95 "000000000000000000000000000000000000000000000000000000000000805a",
96 "0000000000000000000000000000000000000000000000000000000000000000",
97 "41ECE55743711A8C3CBF3783CD08C0EE4D4DC440D4641A8F366E550DFDB3BB67",
99 "GostR3410_2012_TC26_ParamSetA": (
100 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7",
101 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27E69532F48D89116FF22B8D4E0560609B4B38ABFAD2B85DCACDB1411F10B275",
102 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4",
103 "E8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760",
104 "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003",
105 "7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4",
107 "GostR3410_2012_TC26_ParamSetB": (
108 "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006F",
109 "800000000000000000000000000000000000000000000000000000000000000149A1EC142565A545ACFDB77BD9D40CFA8B996712101BEA0EC6346C54374F25BD",
110 "8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006C",
111 "687D1B459DC841457E3E06CF6F5E2517B97C7D614AF138BCBF85DC806C4B289F3E965D2DB1416D217F8B276FAD1AB69C50F78BEE1FA3106EFB8CCBC7C5140116",
112 "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002",
113 "1A8F7EDA389B094C2C071E3647A8940F3C123B697578C213BE6DD9E6C8EC7335DCB228FD1EDF4A39152CBCAAF8C0398828041055F94CEEEC7E21340780FE41BD"
116 for c, params in CURVE_PARAMS.items():
117 CURVE_PARAMS[c] = [hexdec(param) for param in params]
120 class GOST3410Curve(object):
121 """ GOST 34.10 validated curve
123 >>> p, q, a, b, x, y = CURVE_PARAMS["GostR3410_2001_TestParamSet"]
124 >>> curve = GOST3410Curve(p, q, a, b, x, y)
125 >>> priv = bytes2long(urandom(32))
126 >>> signature = sign(curve, priv, GOST341194(data).digest())
127 >>> pubX, pubY = public_key(curve, priv)
128 >>> verify(curve, pubX, pubY, GOST341194(data).digest(), signature)
131 def __init__(self, p, q, a, b, x, y):
132 self.p = bytes2long(p)
133 self.q = bytes2long(q)
134 self.a = bytes2long(a)
135 self.b = bytes2long(b)
136 self.x = bytes2long(x)
137 self.y = bytes2long(y)
138 r1 = self.y * self.y % self.p
139 r2 = ((self.x * self.x + self.a) * self.x + self.b) % self.p
143 raise ValueError("Invalid parameters")
150 def _add(self, p1x, p1y, p2x, p2y):
151 if p1x == p2x and p1y == p2y:
153 t = ((3 * p1x * p1x + self.a) * modinvert(2 * p1y, self.p)) % self.p
155 tx = self._pos(p2x - p1x) % self.p
156 ty = self._pos(p2y - p1y) % self.p
157 t = (ty * modinvert(tx, self.p)) % self.p
158 tx = self._pos(t * t - p1x - p2x) % self.p
159 ty = self._pos(t * (p1x - tx) - p1y) % self.p
162 def exp(self, degree, x=None, y=None):
169 raise ValueError("Bad degree value")
172 tx, ty = self._add(tx, ty, x, y)
174 x, y = self._add(x, y, x, y)
178 def public_key(curve, private_key):
179 """ Generate public key from the private one
181 :param GOST3410Curve curve: curve to use
182 :param long private_key: private key
183 :return: public key's parts, X and Y
186 return curve.exp(private_key)
189 def sign(curve, private_key, digest, size=SIZE_3410_2001):
190 """ Calculate signature for provided digest
192 :param GOST3410Curve curve: curve to use
193 :param long private_key: private key
194 :param digest: digest for signing
195 :type digest: bytes, 32 or 64 bytes
196 :param size: signature size
197 :type size: 32 (for 34.10-2001) or 64 (for 34.10-2012)
199 :rtype: bytes, 64 or 128 bytes
201 if len(digest) != size:
202 raise ValueError("Invalid digest length")
204 e = bytes2long(digest) % q
208 k = bytes2long(urandom(size)) % q
221 return long2bytes(s, size) + long2bytes(r, size)
224 def verify(curve, pubkeyX, pubkeyY, digest, signature, size=SIZE_3410_2001):
225 """ Verify provided digest with the signature
227 :param GOST3410Curve curve: curve to use
228 :param long pubkeyX: public key's X
229 :param long pubkeyY: public key's Y
230 :param digest: digest needed to check
231 :type digest: bytes, 32 or 64 bytes
232 :param signature: signature to verify with
233 :type signature: bytes, 64 or 128 bytes
234 :param size: signature size
235 :type size: 32 (for 34.10-2001) or 64 (for 34.10-2012)
238 if len(digest) != size:
239 raise ValueError("Invalid digest length")
240 if len(signature) != size * 2:
241 raise ValueError("Invalid signature length")
244 s = bytes2long(signature[:size])
245 r = bytes2long(signature[size:])
246 if r <= 0 or r >= q or s <= 0 or s >= q:
248 e = bytes2long(digest) % curve.q
254 p1x, p1y = curve.exp(z1)
255 q1x, q1y = curve.exp(z2, pubkeyX, pubkeyY)
259 lm = modinvert(lm, p)
268 # This is not constant time comparison!
272 def prv_unmarshal(private_key):
273 """Unmarshal private key
275 :param bytes private_key: serialized private key
278 return bytes2long(private_key[::-1])
281 def pub_marshal(pub, mode=2001):
282 """Marshal public key
284 :type pub: (long, long)
287 size = MODE2SIZE[mode]
288 return (long2bytes(pub[1], size) + long2bytes(pub[0], size))[::-1]
291 def pub_unmarshal(pub, mode=2001):
292 """Unmarshal public key
298 size = MODE2SIZE[mode]
299 return (bytes2long(pub[size:]), bytes2long(pub[:size]))