Initial commit.
[BoarSSL] / Crypto / RFC6979.cs
1 /*
2 * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
3 *
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:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
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
22 * SOFTWARE.
23 */
24
25 using System;
26
27 namespace Crypto {
28
29 /*
30 * This class implements the computation of the transient secret value
31 * "k" for DSA and ECDSA, using the method described in RFC 6979. It
32 * can perform the deterministic computation, and optionally inject
33 * extra random bytes when randomized signatures are needed.
34 */
35
36 class RFC6979 {
37
38 HMAC_DRBG drbg;
39 byte[] q;
40 int qlen;
41 ModInt mh;
42
43 internal RFC6979(IDigest h, byte[] q, byte[] x,
44 byte[] hv, bool deterministic)
45 : this(h, q, x, hv, 0, hv.Length, deterministic)
46 {
47 }
48
49 internal RFC6979(IDigest h, byte[] q, byte[] x,
50 byte[] hv, int hvOff, int hvLen, bool deterministic)
51 {
52 if (h == null) {
53 h = new SHA256();
54 } else {
55 h = h.Dup();
56 h.Reset();
57 }
58 drbg = new HMAC_DRBG(h);
59 mh = new ModInt(q);
60 qlen = mh.ModBitLength;
61 int qolen = (qlen + 7) >> 3;
62 this.q = new byte[qolen];
63 Array.Copy(q, q.Length - qolen, this.q, 0, qolen);
64 int hlen = hvLen << 3;
65 if (hlen > qlen) {
66 byte[] htmp = new byte[hvLen];
67 Array.Copy(hv, hvOff, htmp, 0, hv.Length);
68 BigInt.RShift(htmp, hlen - qlen);
69 hv = htmp;
70 hvOff = 0;
71 }
72 mh.DecodeReduce(hv, hvOff, hvLen);
73 ModInt mx = mh.Dup();
74 mx.Decode(x);
75
76 byte[] seed = new byte[(qolen << 1) + (deterministic ? 0 : 32)];
77 mx.Encode(seed, 0, qolen);
78 mh.Encode(seed, qolen, qolen);
79 if (!deterministic) {
80 RNG.GetBytes(seed, qolen << 1,
81 seed.Length - (qolen << 1));
82 }
83 drbg.SetSeed(seed);
84 }
85
86 internal ModInt GetHashMod()
87 {
88 return mh.Dup();
89 }
90
91 internal void NextK(byte[] k)
92 {
93 for (;;) {
94 drbg.GetBytes(k);
95 BigInt.RShift(k, (k.Length << 3) - qlen);
96 if (!BigInt.IsZero(k) && BigInt.CompareCT(k, q) < 0) {
97 return;
98 }
99 }
100 }
101 }
102
103 }