authorgravatar for 33079554+naoki9911@users.noreply.github.comNaoki MATSUMOTO <33079554+naoki9911@users.noreply.github.com> 2022-10-26 20:18:06+09:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-10-26 13:18:06+02:00
logcd4865d88c368095e131d2d95d3cce637db0ff5a
treebacfeebb1515a9454818786b180c5e188009012a
parent22b71b1376eaa75aa141022404d6ddf40495c886
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

std.crypto.sign.ecdsa: accepts unusual parameters like EcdsaP384Sha256 (#13302)

This commit accepts unusual parameters like EcdsaP384Sha256. Some certifictes(below certs are in /etc/ssl/certs/ca-certificates.crt on Ubuntu 22.04) use EcdsaP384Sha256 to sign itself. - Subject: C=GR, L=Athens, O=Hellenic Academic and Research Institutions Cert. Authority, CN=Hellenic Academic and Research Institutions ECC RootCA 2015 - Subject: C=US, ST=Texas, L=Houston, O=SSL Corporation, CN=SSL.com EV Root Certification Authority ECC - Subject: C=US, ST=Texas, L=Houston, O=SSL Corporation, CN=SSL.com Root Certification Authority ECC In verify(), hash array `h` is allocated to be larger than the scalar.encoded_length. The array is regarded as big-endian. Hash values are filled in the back of the array and the rest bytes in front are filled with zero. In sign(), the hash array is allocated and filled as same as verify(). In deterministicScalar(), hash bytes are insufficient to generate `k` To generate `k` without narrowing its value range, this commit uses algorithm stage h. in "Section 3.2 Generation of k" in RFC6979.

1 files changed, 67 insertions(+), 9 deletions(-)

lib/std/crypto/ecdsa.zig+67-9
...@@ -92,10 +92,11 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {...@@ -92,10 +92,11 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {
92 const s = try Curve.scalar.Scalar.fromBytes(self.s, .Big);92 const s = try Curve.scalar.Scalar.fromBytes(self.s, .Big);
93 if (r.isZero() or s.isZero()) return error.IdentityElement;93 if (r.isZero() or s.isZero()) return error.IdentityElement;
9494
95 var h: [Hash.digest_length]u8 = undefined;
96 Hash.hash(msg, &h, .{});
97
98 const ht = Curve.scalar.encoded_length;95 const ht = Curve.scalar.encoded_length;
96 const h_len = @max(Hash.digest_length, ht);
97 var h: [h_len]u8 = [_]u8{0} ** h_len;
98 Hash.hash(msg, h[h_len - Hash.digest_length .. h_len], .{});
99
99 const z = reduceToScalar(ht, h[0..ht].*);100 const z = reduceToScalar(ht, h[0..ht].*);
100 if (z.isZero()) {101 if (z.isZero()) {
101 return error.SignatureVerificationFailed;102 return error.SignatureVerificationFailed;
...@@ -228,14 +229,16 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {...@@ -228,14 +229,16 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {
228 pub fn sign(key_pair: KeyPair, msg: []const u8, noise: ?[noise_length]u8) (IdentityElementError || NonCanonicalError)!Signature {229 pub fn sign(key_pair: KeyPair, msg: []const u8, noise: ?[noise_length]u8) (IdentityElementError || NonCanonicalError)!Signature {
229 const secret_key = key_pair.secret_key;230 const secret_key = key_pair.secret_key;
230231
231 var h: [Hash.digest_length]u8 = undefined;
232 Hash.hash(msg, &h, .{});
233
234 const scalar_encoded_length = Curve.scalar.encoded_length;232 const scalar_encoded_length = Curve.scalar.encoded_length;
233 const h_len = @max(Hash.digest_length, scalar_encoded_length);
234 var h: [h_len]u8 = [_]u8{0} ** h_len;
235 var h_slice = h[h_len - Hash.digest_length .. h_len];
236 Hash.hash(msg, h_slice, .{});
237
235 std.debug.assert(h.len >= scalar_encoded_length);238 std.debug.assert(h.len >= scalar_encoded_length);
236 const z = reduceToScalar(scalar_encoded_length, h[0..scalar_encoded_length].*);239 const z = reduceToScalar(scalar_encoded_length, h[0..scalar_encoded_length].*);
237240
238 const k = deterministicScalar(h, secret_key.bytes, noise);241 const k = deterministicScalar(h_slice.*, secret_key.bytes, noise);
239242
240 const p = try Curve.basePoint.mul(k.toBytes(.Big), .Big);243 const p = try Curve.basePoint.mul(k.toBytes(.Big), .Big);
241 const xs = p.affineCoordinates().x.toBytes(.Big);244 const xs = p.affineCoordinates().x.toBytes(.Big);
...@@ -268,6 +271,7 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {...@@ -268,6 +271,7 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {
268 fn deterministicScalar(h: [Hash.digest_length]u8, secret_key: Curve.scalar.CompressedScalar, noise: ?[noise_length]u8) Curve.scalar.Scalar {271 fn deterministicScalar(h: [Hash.digest_length]u8, secret_key: Curve.scalar.CompressedScalar, noise: ?[noise_length]u8) Curve.scalar.Scalar {
269 var k = [_]u8{0x00} ** h.len;272 var k = [_]u8{0x00} ** h.len;
270 var m = [_]u8{0x00} ** (h.len + 1 + noise_length + secret_key.len + h.len);273 var m = [_]u8{0x00} ** (h.len + 1 + noise_length + secret_key.len + h.len);
274 var t = [_]u8{0x00} ** Curve.scalar.encoded_length;
271 const m_v = m[0..h.len];275 const m_v = m[0..h.len];
272 const m_i = &m[m_v.len];276 const m_i = &m[m_v.len];
273 const m_z = m[m_v.len + 1 ..][0..noise_length];277 const m_z = m[m_v.len + 1 ..][0..noise_length];
...@@ -286,8 +290,13 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {...@@ -286,8 +290,13 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {
286 Hmac.create(&k, &m, &k);290 Hmac.create(&k, &m, &k);
287 Hmac.create(m_v, m_v, &k);291 Hmac.create(m_v, m_v, &k);
288 while (true) {292 while (true) {
289 Hmac.create(m_v, m_v, &k);293 var t_off: usize = 0;
290 if (Curve.scalar.Scalar.fromBytes(m_v[0..Curve.scalar.encoded_length].*, .Big)) |s| return s else |_| {}294 while (t_off < t.len) : (t_off += m_v.len) {
295 const t_end = @min(t_off + m_v.len, t.len);
296 Hmac.create(m_v, m_v, &k);
297 std.mem.copy(u8, t[t_off..t_end], m_v[0 .. t_end - t_off]);
298 }
299 if (Curve.scalar.Scalar.fromBytes(t, .Big)) |s| return s else |_| {}
291 mem.copy(u8, m_v, m_v);300 mem.copy(u8, m_v, m_v);
292 m_i.* = 0x00;301 m_i.* = 0x00;
293 Hmac.create(&k, m[0 .. m_v.len + 1], &k);302 Hmac.create(&k, m[0 .. m_v.len + 1], &k);
...@@ -325,6 +334,55 @@ test "ECDSA - Basic operations over Secp256k1" {...@@ -325,6 +334,55 @@ test "ECDSA - Basic operations over Secp256k1" {
325 try sig2.verify(msg, kp.public_key);334 try sig2.verify(msg, kp.public_key);
326}335}
327336
337test "ECDSA - Basic operations over EcdsaP384Sha256" {
338 const Scheme = Ecdsa(crypto.ecc.P384, crypto.hash.sha2.Sha256);
339 const kp = try Scheme.KeyPair.create(null);
340 const msg = "test";
341
342 var noise: [Scheme.noise_length]u8 = undefined;
343 crypto.random.bytes(&noise);
344 const sig = try kp.sign(msg, noise);
345 try sig.verify(msg, kp.public_key);
346
347 const sig2 = try kp.sign(msg, null);
348 try sig2.verify(msg, kp.public_key);
349}
350
351test "ECDSA - Verifying a existing signature with EcdsaP384Sha256" {
352 const Scheme = Ecdsa(crypto.ecc.P384, crypto.hash.sha2.Sha256);
353 // zig fmt: off
354 const sk_bytes = [_]u8{
355 0x6a, 0x53, 0x9c, 0x83, 0x0f, 0x06, 0x86, 0xd9, 0xef, 0xf1, 0xe7, 0x5c, 0xae,
356 0x93, 0xd9, 0x5b, 0x16, 0x1e, 0x96, 0x7c, 0xb0, 0x86, 0x35, 0xc9, 0xea, 0x20,
357 0xdc, 0x2b, 0x02, 0x37, 0x6d, 0xd2, 0x89, 0x72, 0x0a, 0x37, 0xf6, 0x5d, 0x4f,
358 0x4d, 0xf7, 0x97, 0xcb, 0x8b, 0x03, 0x63, 0xc3, 0x2d
359 };
360 const msg = [_]u8{
361 0x64, 0x61, 0x74, 0x61, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x67, 0x6e,
362 0x69, 0x6e, 0x67, 0x0a
363 };
364 const sig_ans_bytes = [_]u8{
365 0x30, 0x64, 0x02, 0x30, 0x7a, 0x31, 0xd8, 0xe0, 0xf8, 0x40, 0x7d, 0x6a, 0xf3,
366 0x1a, 0x5d, 0x02, 0xe5, 0xcb, 0x24, 0x29, 0x1a, 0xac, 0x15, 0x94, 0xd1, 0x5b,
367 0xcd, 0x75, 0x2f, 0x45, 0x79, 0x98, 0xf7, 0x60, 0x9a, 0xd5, 0xca, 0x80, 0x15,
368 0x87, 0x9b, 0x0c, 0x27, 0xe3, 0x01, 0x8b, 0x73, 0x4e, 0x57, 0xa3, 0xd2, 0x9a,
369 0x02, 0x30, 0x33, 0xe0, 0x04, 0x5e, 0x76, 0x1f, 0xc8, 0xcf, 0xda, 0xbe, 0x64,
370 0x95, 0x0a, 0xd4, 0x85, 0x34, 0x33, 0x08, 0x7a, 0x81, 0xf2, 0xf6, 0xb6, 0x94,
371 0x68, 0xc3, 0x8c, 0x5f, 0x88, 0x92, 0x27, 0x5e, 0x4e, 0x84, 0x96, 0x48, 0x42,
372 0x84, 0x28, 0xac, 0x37, 0x93, 0x07, 0xd3, 0x50, 0x32, 0x71, 0xb0
373 };
374 // zig fmt: on
375
376 const sk = try Scheme.SecretKey.fromBytes(sk_bytes);
377 const kp = try Scheme.KeyPair.fromSecretKey(sk);
378
379 const sig_ans = try Scheme.Signature.fromDer(&sig_ans_bytes);
380 try sig_ans.verify(&msg, kp.public_key);
381
382 const sig = try kp.sign(&msg, null);
383 try sig.verify(&msg, kp.public_key);
384}
385
328const TestVector = struct {386const TestVector = struct {
329 key: []const u8,387 key: []const u8,
330 msg: []const u8,388 msg: []const u8,