2 * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * This class implements the ECDSA signature algorithm. The static methods
32 * provide access to the algorithm primitives. The hash of the signed data
33 * must be provided externally.
35 * Signatures may be encoded in either "ASN.1" or "raw" formats; "ASN.1"
36 * is normally used (e.g. in SSL/TLS) but some protocols and API expect
37 * the raw format (e.g. PKCS#11 and OpenPGP). An ECDSA signature consists
38 * in two integers r and s, which are values modulo the subgroup order q.
39 * In ASN.1 format, the signature is the DER encoding of the ASN.1
42 * ECDSA-signature ::= SEQUENCE {
47 * In raw format, the two integers r and s are encoded with unsigned
48 * big-endian encoding (with the same encoding length) and concatenated.
50 * The Sign() and Verify() methods use the ASN.1 format. The SignRaw()
51 * and VerifyRaw() use the raw format. The SigRawToAsn1() and SigAsn1ToRaw()
52 * allow for converting between the two formats.
55 public class ECDSA : DSAUtils {
58 * Verify an ECDSA signature (ASN.1 format). Returned value is true
59 * on success. If the signature is invalid, then false is returned.
60 * Internal exceptions (due to an incorrect public key) are also
61 * converted to a returned value of false.
63 * There are four methods, depending on the source operands.
66 public static bool Verify(ECPublicKey pk,
67 byte[] hash, byte[] sig)
69 return Verify(pk, hash, 0, hash.Length, sig, 0, sig.Length);
72 public static bool Verify(ECPublicKey pk,
73 byte[] hash, int hashOff, int hashLen, byte[] sig)
75 return Verify(pk, hash, hashOff, hashLen, sig, 0, sig.Length);
78 public static bool Verify(ECPublicKey pk,
79 byte[] hash, byte[] sig, int sigOff, int sigLen)
81 return Verify(pk, hash, 0, hash.Length, sig, sigOff, sigLen);
84 public static bool Verify(ECPublicKey pk,
85 byte[] hash, int hashOff, int hashLen,
86 byte[] sig, int sigOff, int sigLen)
88 byte[] raw = SigAsn1ToRaw(sig, sigOff, sigLen);
93 hash, hashOff, hashLen, raw, 0, raw.Length);
97 * Verify an ECDSA signature (raw format). Returned value is true
98 * on success. If the signature is invalid, then false is returned.
99 * Internal exceptions (due to an incorrect public key) are also
100 * converted to a returned value of false.
102 * There are four methods, depending on the source operands.
105 public static bool VerifyRaw(ECPublicKey pk,
106 byte[] hash, byte[] sig)
109 hash, 0, hash.Length, sig, 0, sig.Length);
112 public static bool VerifyRaw(ECPublicKey pk,
113 byte[] hash, int hashOff, int hashLen, byte[] sig)
116 hash, hashOff, hashLen, sig, 0, sig.Length);
119 public static bool VerifyRaw(ECPublicKey pk,
120 byte[] hash, byte[] sig, int sigOff, int sigLen)
123 hash, 0, hash.Length, sig, sigOff, sigLen);
126 public static bool VerifyRaw(ECPublicKey pk,
127 byte[] hash, int hashOff, int hashLen,
128 byte[] sig, int sigOff, int sigLen)
134 ECCurve curve = pk.Curve;
137 * Get r and s from signature. This also verifies
138 * that they do not exceed the subgroup order.
140 if (sigLen == 0 || (sigLen & 1) != 0) {
143 int tlen = sigLen >> 1;
144 ModInt oneQ = new ModInt(curve.SubgroupOrder);
146 ModInt r = oneQ.Dup();
147 ModInt s = oneQ.Dup();
148 r.Decode(sig, sigOff, tlen);
149 s.Decode(sig, sigOff + tlen, tlen);
152 * If either r or s was too large, it got set to
153 * zero. We also don't want real zeros.
155 if (r.IsZero || s.IsZero) {
160 * Convert the hash value to an integer modulo q.
161 * As per FIPS 186-4, if the hash value is larger
162 * than q, then we keep the qlen leftmost bits of
165 int qBitLength = oneQ.ModBitLength;
166 int hBitLength = hashLen << 3;
168 if (hBitLength <= qBitLength) {
169 hv = new byte[hashLen];
170 Array.Copy(hash, hashOff, hv, 0, hashLen);
172 int qlen = (qBitLength + 7) >> 3;
174 Array.Copy(hash, hashOff, hv, 0, qlen);
175 int rs = (8 - (qBitLength & 7)) & 7;
176 BigInt.RShift(hv, rs);
178 ModInt z = oneQ.Dup();
182 * Apply the verification algorithm:
187 * test whether T.x mod q == r.
211 MutableECPoint T = curve.MakeGenerator();
212 uint good = T.MulSpecCT(u.Encode());
217 MutableECPoint M = pk.iPub.Dup();
218 good &= M.MulSpecCT(v.Encode());
221 * Compute T = u*G+v*iPub
223 uint nd = T.AddCT(M);
226 good &= ~T.IsInfinityCT;
229 * Get T.x, reduced modulo q.
230 * Signature is valid if and only if we get
231 * the same value as r (and we did not encounter
232 * an error previously).
235 return (good & r.EqCT(s)) != 0;
237 } catch (CryptoException) {
239 * Exceptions may occur if the key or signature
240 * have invalid values (non invertible, out of
241 * range...). Any such occurrence means that the
242 * signature is not valid.
249 * Compute an ECDSA signature (ASN.1 format). On error (e.g. due
250 * to an invalid private key), an exception is thrown.
252 * Internally, the process described in RFC 6979 is used to
253 * compute the per-signature random value 'k'. If 'rfc6979Hash'
254 * is not null, then a clone of that function is used for that
255 * process, and signatures are fully deterministic and should
256 * match RFC 6979 test vectors; if 'rfc6979Hash' is null, then
257 * the engine uses SHA-256 with additional randomness, resulting
258 * in randomized signatures. The systematic use of RFC 6979 in
259 * both cases ensures the safety of the private key even if the
260 * system RNG is predictible.
262 * There are four methods, depending on the source operands.
265 public static byte[] Sign(ECPrivateKey sk, IDigest rfc6979Hash,
268 return Sign(sk, rfc6979Hash, hash, 0, hash.Length);
271 public static byte[] Sign(ECPrivateKey sk, IDigest rfc6979Hash,
272 byte[] hash, int hashOff, int hashLen)
274 return SigRawToAsn1(SignRaw(sk, rfc6979Hash,
275 hash, hashOff, hashLen));
278 public static int Sign(ECPrivateKey sk, IDigest rfc6979Hash,
279 byte[] hash, byte[] outBuf, int outOff)
281 return Sign(sk, rfc6979Hash,
282 hash, 0, hash.Length, outBuf, outOff);
285 public static int Sign(ECPrivateKey sk, IDigest rfc6979Hash,
286 byte[] hash, int hashOff, int hashLen,
287 byte[] outBuf, int outOff)
289 byte[] sig = Sign(sk, rfc6979Hash, hash, hashOff, hashLen);
290 Array.Copy(sig, 0, outBuf, outOff, sig.Length);
295 * Compute an ECDSA signature (raw format). On error (e.g. due
296 * to an invalid private key), an exception is thrown.
298 * Internally, the process described in RFC 6979 is used to
299 * compute the per-signature random value 'k'. If 'rfc6979Hash'
300 * is not null, then a clone of that function is used for that
301 * process, and signatures are fully deterministic and should
302 * match RFC 6979 test vectors; if 'rfc6979Hash' is null, then
303 * the engine uses SHA-256 with additional randomness, resulting
304 * in randomized signatures. The systematic use of RFC 6979 in
305 * both cases ensures the safety of the private key even if the
306 * system RNG is predictible.
308 * The signature returned by these methods always has length
309 * exactly twice that of the encoded subgroup order (they are
310 * not minimalized). Use SigRawMinimalize() to reduce the
311 * signature size to its minimum length.
313 * There are four methods, depending on the source operands.
316 public static byte[] SignRaw(ECPrivateKey sk, IDigest rfc6979Hash,
319 return SignRaw(sk, rfc6979Hash, hash, 0, hash.Length);
322 public static int SignRaw(ECPrivateKey sk, IDigest rfc6979Hash,
323 byte[] hash, byte[] outBuf, int outOff)
325 return SignRaw(sk, rfc6979Hash,
326 hash, 0, hash.Length, outBuf, outOff);
329 public static int SignRaw(ECPrivateKey sk, IDigest rfc6979Hash,
330 byte[] hash, int hashOff, int hashLen,
331 byte[] outBuf, int outOff)
333 byte[] sig = SignRaw(sk, rfc6979Hash, hash, hashOff, hashLen);
334 Array.Copy(sig, 0, outBuf, outOff, sig.Length);
338 public static byte[] SignRaw(ECPrivateKey sk, IDigest rfc6979Hash,
339 byte[] hash, int hashOff, int hashLen)
341 ECCurve curve = sk.Curve;
342 byte[] q = curve.SubgroupOrder;
343 RFC6979 rf = new RFC6979(rfc6979Hash, q, sk.X,
344 hash, hashOff, hashLen, rfc6979Hash != null);
345 ModInt mh = rf.GetHashMod();
346 ModInt mx = mh.Dup();
350 * Compute DSA signature. We use a loop to enumerate
351 * candidates for k until a proper one is found (it
352 * is VERY improbable that we may have to loop).
354 ModInt mr = mh.Dup();
355 ModInt ms = mh.Dup();
356 ModInt mk = mh.Dup();
357 byte[] k = new byte[q.Length];
360 MutableECPoint G = curve.MakeGenerator();
361 if (G.MulSpecCT(k) == 0) {
363 * We may get an error here only if the
364 * curve is invalid (generator does not
365 * produce the expected subgroup).
367 throw new CryptoException(
368 "Invalid EC private key / curve");
370 mr.DecodeReduce(G.X);
383 byte[] sig = new byte[q.Length << 1];
384 mr.Encode(sig, 0, q.Length);
385 ms.Encode(sig, q.Length, q.Length);
391 * Generate a new EC key pair in the specified curve.
393 public static ECPrivateKey Generate(ECCurve curve)
395 return new ECPrivateKey(curve,
396 BigInt.RandIntNZ(curve.SubgroupOrder));