/src/libgcrypt/cipher/ecc-gost.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* ecc-gots.c - Elliptic Curve GOST signatures |
2 | | * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc. |
3 | | * Copyright (C) 2013 Dmitry Eremin-Solenikov |
4 | | * |
5 | | * This file is part of Libgcrypt. |
6 | | * |
7 | | * Libgcrypt is free software; you can redistribute it and/or modify |
8 | | * it under the terms of the GNU Lesser General Public License as |
9 | | * published by the Free Software Foundation; either version 2.1 of |
10 | | * the License, or (at your option) any later version. |
11 | | * |
12 | | * Libgcrypt is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with this program; if not, see <http://www.gnu.org/licenses/>. |
19 | | */ |
20 | | |
21 | | #include <config.h> |
22 | | #include <stdio.h> |
23 | | #include <stdlib.h> |
24 | | #include <string.h> |
25 | | #include <errno.h> |
26 | | |
27 | | #include "g10lib.h" |
28 | | #include "mpi.h" |
29 | | #include "cipher.h" |
30 | | #include "context.h" |
31 | | #include "ec-context.h" |
32 | | #include "ecc-common.h" |
33 | | #include "pubkey-internal.h" |
34 | | |
35 | | |
36 | | /* Compute an GOST R 34.10-01/-12 signature. |
37 | | * Return the signature struct (r,s) from the message hash. The caller |
38 | | * must have allocated R and S. |
39 | | */ |
40 | | gpg_err_code_t |
41 | | _gcry_ecc_gost_sign (gcry_mpi_t input, mpi_ec_t ec, |
42 | | gcry_mpi_t r, gcry_mpi_t s) |
43 | 0 | { |
44 | 0 | gpg_err_code_t rc = 0; |
45 | 0 | gcry_mpi_t k, dr, sum, ke, x, e; |
46 | 0 | mpi_point_struct I; |
47 | 0 | gcry_mpi_t hash; |
48 | 0 | unsigned int qbits; |
49 | |
|
50 | 0 | if (DBG_CIPHER) |
51 | 0 | log_mpidump ("gost sign hash ", input ); |
52 | |
|
53 | 0 | qbits = mpi_get_nbits (ec->n); |
54 | | |
55 | | /* Convert the INPUT into an MPI if needed. */ |
56 | 0 | rc = _gcry_dsa_normalize_hash (input, &hash, qbits); |
57 | 0 | if (rc) |
58 | 0 | return rc; |
59 | | |
60 | 0 | k = NULL; |
61 | 0 | dr = mpi_alloc (0); |
62 | 0 | sum = mpi_alloc (0); |
63 | 0 | ke = mpi_alloc (0); |
64 | 0 | e = mpi_alloc (0); |
65 | 0 | x = mpi_alloc (0); |
66 | 0 | point_init (&I); |
67 | |
|
68 | 0 | mpi_mod (e, input, ec->n); /* e = hash mod n */ |
69 | |
|
70 | 0 | if (!mpi_cmp_ui (e, 0)) |
71 | 0 | mpi_set_ui (e, 1); |
72 | | |
73 | | /* Two loops to avoid R or S are zero. This is more of a joke than |
74 | | a real demand because the probability of them being zero is less |
75 | | than any hardware failure. Some specs however require it. */ |
76 | 0 | do |
77 | 0 | { |
78 | 0 | do |
79 | 0 | { |
80 | 0 | mpi_free (k); |
81 | 0 | k = _gcry_dsa_gen_k (ec->n, GCRY_STRONG_RANDOM); |
82 | |
|
83 | 0 | _gcry_dsa_modify_k (k, ec->n, qbits); |
84 | |
|
85 | 0 | _gcry_mpi_ec_mul_point (&I, k, ec->G, ec); |
86 | 0 | if (_gcry_mpi_ec_get_affine (x, NULL, &I, ec)) |
87 | 0 | { |
88 | 0 | if (DBG_CIPHER) |
89 | 0 | log_debug ("ecc sign: Failed to get affine coordinates\n"); |
90 | 0 | rc = GPG_ERR_BAD_SIGNATURE; |
91 | 0 | goto leave; |
92 | 0 | } |
93 | 0 | mpi_mod (r, x, ec->n); /* r = x mod n */ |
94 | 0 | } |
95 | 0 | while (!mpi_cmp_ui (r, 0)); |
96 | 0 | mpi_mulm (dr, ec->d, r, ec->n); /* dr = d*r mod n */ |
97 | 0 | mpi_mulm (ke, k, e, ec->n); /* ke = k*e mod n */ |
98 | 0 | mpi_addm (s, ke, dr, ec->n); /* sum = (k*e+ d*r) mod n */ |
99 | 0 | } |
100 | 0 | while (!mpi_cmp_ui (s, 0)); |
101 | | |
102 | 0 | if (DBG_CIPHER) |
103 | 0 | { |
104 | 0 | log_mpidump ("gost sign result r ", r); |
105 | 0 | log_mpidump ("gost sign result s ", s); |
106 | 0 | } |
107 | |
|
108 | 0 | leave: |
109 | 0 | point_free (&I); |
110 | 0 | mpi_free (x); |
111 | 0 | mpi_free (e); |
112 | 0 | mpi_free (ke); |
113 | 0 | mpi_free (sum); |
114 | 0 | mpi_free (dr); |
115 | 0 | mpi_free (k); |
116 | |
|
117 | 0 | if (hash != input) |
118 | 0 | mpi_free (hash); |
119 | |
|
120 | 0 | return rc; |
121 | 0 | } |
122 | | |
123 | | |
124 | | /* Verify a GOST R 34.10-01/-12 signature. |
125 | | * Check if R and S verifies INPUT. |
126 | | */ |
127 | | gpg_err_code_t |
128 | | _gcry_ecc_gost_verify (gcry_mpi_t input, mpi_ec_t ec, |
129 | | gcry_mpi_t r, gcry_mpi_t s) |
130 | 0 | { |
131 | 0 | gpg_err_code_t err = 0; |
132 | 0 | gcry_mpi_t e, x, z1, z2, v, rv, zero; |
133 | 0 | mpi_point_struct Q, Q1, Q2; |
134 | |
|
135 | 0 | if (!_gcry_mpi_ec_curve_point (ec->Q, ec)) |
136 | 0 | return GPG_ERR_BROKEN_PUBKEY; |
137 | | |
138 | 0 | if( !(mpi_cmp_ui (r, 0) > 0 && mpi_cmp (r, ec->n) < 0) ) |
139 | 0 | return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */ |
140 | 0 | if( !(mpi_cmp_ui (s, 0) > 0 && mpi_cmp (s, ec->n) < 0) ) |
141 | 0 | return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */ |
142 | | |
143 | 0 | x = mpi_alloc (0); |
144 | 0 | e = mpi_alloc (0); |
145 | 0 | z1 = mpi_alloc (0); |
146 | 0 | z2 = mpi_alloc (0); |
147 | 0 | v = mpi_alloc (0); |
148 | 0 | rv = mpi_alloc (0); |
149 | 0 | zero = mpi_alloc (0); |
150 | |
|
151 | 0 | point_init (&Q); |
152 | 0 | point_init (&Q1); |
153 | 0 | point_init (&Q2); |
154 | |
|
155 | 0 | mpi_mod (e, input, ec->n); /* e = hash mod n */ |
156 | 0 | if (!mpi_cmp_ui (e, 0)) |
157 | 0 | mpi_set_ui (e, 1); |
158 | 0 | mpi_invm (v, e, ec->n); /* v = e^(-1) (mod n) */ |
159 | 0 | mpi_mulm (z1, s, v, ec->n); /* z1 = s*v (mod n) */ |
160 | 0 | mpi_mulm (rv, r, v, ec->n); /* rv = r*v (mod n) */ |
161 | 0 | mpi_subm (z2, zero, rv, ec->n); /* z2 = -r*v (mod n) */ |
162 | |
|
163 | 0 | _gcry_mpi_ec_mul_point (&Q1, z1, ec->G, ec); |
164 | | /* log_mpidump ("Q1.x", Q1.x); */ |
165 | | /* log_mpidump ("Q1.y", Q1.y); */ |
166 | | /* log_mpidump ("Q1.z", Q1.z); */ |
167 | 0 | _gcry_mpi_ec_mul_point (&Q2, z2, ec->Q, ec); |
168 | | /* log_mpidump ("Q2.x", Q2.x); */ |
169 | | /* log_mpidump ("Q2.y", Q2.y); */ |
170 | | /* log_mpidump ("Q2.z", Q2.z); */ |
171 | 0 | _gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ec); |
172 | | /* log_mpidump (" Q.x", Q.x); */ |
173 | | /* log_mpidump (" Q.y", Q.y); */ |
174 | | /* log_mpidump (" Q.z", Q.z); */ |
175 | |
|
176 | 0 | if (!mpi_cmp_ui (Q.z, 0)) |
177 | 0 | { |
178 | 0 | if (DBG_CIPHER) |
179 | 0 | log_debug ("ecc verify: Rejected\n"); |
180 | 0 | err = GPG_ERR_BAD_SIGNATURE; |
181 | 0 | goto leave; |
182 | 0 | } |
183 | 0 | if (_gcry_mpi_ec_get_affine (x, NULL, &Q, ec)) |
184 | 0 | { |
185 | 0 | if (DBG_CIPHER) |
186 | 0 | log_debug ("ecc verify: Failed to get affine coordinates\n"); |
187 | 0 | err = GPG_ERR_BAD_SIGNATURE; |
188 | 0 | goto leave; |
189 | 0 | } |
190 | 0 | mpi_mod (x, x, ec->n); /* x = x mod E_n */ |
191 | 0 | if (mpi_cmp (x, r)) /* x != r */ |
192 | 0 | { |
193 | 0 | if (DBG_CIPHER) |
194 | 0 | { |
195 | 0 | log_mpidump (" x", x); |
196 | 0 | log_mpidump (" r", r); |
197 | 0 | log_mpidump (" s", s); |
198 | 0 | log_debug ("ecc verify: Not verified\n"); |
199 | 0 | } |
200 | 0 | err = GPG_ERR_BAD_SIGNATURE; |
201 | 0 | goto leave; |
202 | 0 | } |
203 | 0 | if (DBG_CIPHER) |
204 | 0 | log_debug ("ecc verify: Accepted\n"); |
205 | |
|
206 | 0 | leave: |
207 | 0 | point_free (&Q2); |
208 | 0 | point_free (&Q1); |
209 | 0 | point_free (&Q); |
210 | 0 | mpi_free (zero); |
211 | 0 | mpi_free (rv); |
212 | 0 | mpi_free (v); |
213 | 0 | mpi_free (z2); |
214 | 0 | mpi_free (z1); |
215 | 0 | mpi_free (x); |
216 | 0 | mpi_free (e); |
217 | 0 | return err; |
218 | 0 | } |