gost3410/private.go | 33 +++++++++++++++++++++------------ gost3410/private_test.go | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++--- gost3410/public.go | 42 +++++++++++++++++++++++++++++++++++++++++- news.texi | 3 +++ diff --git a/gost3410/private.go b/gost3410/private.go index 02b06621507d74cbe15f3eb90b4001469e2649e0c3527ba64807eca9f6a9c5ee..0f8944fb9122d9b0e36a14d5927b33a5e50828c07a4e3a7bf2de77b28150751b 100644 --- a/gost3410/private.go +++ b/gost3410/private.go @@ -139,8 +139,11 @@ pad(r.Bytes(), pointSize)..., ), nil } -// Sign the digest. opts argument is unused. -func (prv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { +// Sign the digest. opts argument is unused. That is identical to SignDigest, +// but kept to be friendly to crypto.Signer. +func (prv *PrivateKey) Sign( + rand io.Reader, digest []byte, opts crypto.SignerOpts, +) ([]byte, error) { return prv.SignDigest(digest, rand) } @@ -160,11 +163,14 @@ func (prv *PrivateKeyReverseDigest) Public() crypto.PublicKey { return prv.Prv.Public() } -func (prv *PrivateKeyReverseDigest) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { - d := make([]byte, len(digest)) - copy(d, digest) - reverse(d) - return prv.Prv.Sign(rand, d, opts) +func (prv *PrivateKeyReverseDigest) Sign( + rand io.Reader, digest []byte, opts crypto.SignerOpts, +) ([]byte, error) { + dgst := make([]byte, len(digest)) + for i := 0; i < len(digest); i++ { + dgst[i] = digest[len(digest)-i-1] + } + return prv.Prv.Sign(rand, dgst, opts) } type PrivateKeyReverseDigestAndSignature struct { @@ -175,11 +181,14 @@ func (prv *PrivateKeyReverseDigestAndSignature) Public() crypto.PublicKey { return prv.Prv.Public() } -func (prv *PrivateKeyReverseDigestAndSignature) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) { - d := make([]byte, len(digest)) - copy(d, digest) - reverse(d) - sign, err := prv.Prv.Sign(rand, d, opts) +func (prv *PrivateKeyReverseDigestAndSignature) Sign( + rand io.Reader, digest []byte, opts crypto.SignerOpts, +) ([]byte, error) { + dgst := make([]byte, len(digest)) + for i := 0; i < len(digest); i++ { + dgst[i] = digest[len(digest)-i-1] + } + sign, err := prv.Prv.Sign(rand, dgst, opts) if err != nil { return sign, err } diff --git a/gost3410/private_test.go b/gost3410/private_test.go index 24e981cc2e7ab16e1fa593ef0ae6d820f71fe0b102a6341cd8066358bd90d1b1..2e37efe5fa35ecf9c452e7617ed88d356f53a8a31bbe8aaa586d0e113d283fd0 100644 --- a/gost3410/private_test.go +++ b/gost3410/private_test.go @@ -18,15 +18,75 @@ import ( "crypto" "crypto/rand" + "io" "testing" ) func TestSignerInterface(t *testing.T) { - prvRaw := make([]byte, 32) - rand.Read(prvRaw) - prv, err := NewPrivateKey(CurveIdGostR34102001TestParamSet(), prvRaw) + c := CurveIdGostR34102001TestParamSet() + prvRaw := make([]byte, c.PointSize()) + _, err := io.ReadFull(rand.Reader, prvRaw) + if err != nil { + t.Fatal(err) + } + prv, err := NewPrivateKey(c, prvRaw) if err != nil { t.Fatal(err) } var _ crypto.Signer = prv + var _ crypto.Signer = &PrivateKeyReverseDigest{prv} + var _ crypto.Signer = &PrivateKeyReverseDigestAndSignature{prv} +} + +func TestSignerReverseDigest(t *testing.T) { + dgst := make([]byte, 32) + _, err := io.ReadFull(rand.Reader, dgst) + if err != nil { + t.Fatal(err) + } + prv0, err := GenPrivateKey(CurveIdGostR34102001TestParamSet(), rand.Reader) + if err != nil { + t.Fatal(err) + } + pub0 := prv0.Public().(*PublicKey) + sign, err := prv0.Sign(rand.Reader, dgst, nil) + if err != nil { + t.Fatal(err) + } + valid, err := pub0.VerifyDigest(dgst, sign) + if err != nil { + t.Fatal(err) + } + if !valid { + t.FailNow() + } + var _ crypto.PublicKey = pub0 + + prv1 := PrivateKeyReverseDigest{prv0} + pub1 := PublicKeyReverseDigest{prv1.Public().(*PublicKey)} + sign, err = prv1.Sign(rand.Reader, dgst, nil) + if err != nil { + t.Fatal(err) + } + valid, err = pub1.VerifyDigest(dgst, sign) + if err != nil { + t.Fatal(err) + } + if !valid { + t.FailNow() + } + + prv2 := PrivateKeyReverseDigestAndSignature{prv0} + pub2 := PublicKeyReverseDigestAndSignature{prv2.Public().(*PublicKey)} + sign, err = prv2.Sign(rand.Reader, dgst, nil) + if err != nil { + t.Fatal(err) + } + valid, err = pub2.VerifyDigest(dgst, sign) + if err != nil { + t.Fatal(err) + } + if !valid { + t.FailNow() + } } diff --git a/gost3410/public.go b/gost3410/public.go index 8aa09604ee6c9ee5bfc3356d3a409453074122698e061e46b5b171084f2e7825..4917553cda1522e16d8b72bd94e0a11917c88a8df184c665e37b972684bff46c 100644 --- a/gost3410/public.go +++ b/gost3410/public.go @@ -22,7 +22,7 @@ "math/big" ) type PublicKey struct { - C *Curve + C *Curve X, Y *big.Int } @@ -149,3 +149,43 @@ return false } return our.X.Cmp(their.X) == 0 && our.Y.Cmp(their.Y) == 0 && our.C.Equal(their.C) } + +type PublicKeyReverseDigest struct { + Pub *PublicKey +} + +func (pub PublicKeyReverseDigest) VerifyDigest( + digest, signature []byte, +) (bool, error) { + dgst := make([]byte, len(digest)) + for i := 0; i < len(digest); i++ { + dgst[i] = digest[len(digest)-i-1] + } + return pub.Pub.VerifyDigest(dgst, signature) +} + +func (pub PublicKeyReverseDigest) Equal(theirKey crypto.PublicKey) bool { + return pub.Pub.Equal(theirKey) +} + +type PublicKeyReverseDigestAndSignature struct { + Pub *PublicKey +} + +func (pub PublicKeyReverseDigestAndSignature) VerifyDigest( + digest, signature []byte, +) (bool, error) { + dgst := make([]byte, len(digest)) + for i := 0; i < len(digest); i++ { + dgst[i] = digest[len(digest)-i-1] + } + sign := make([]byte, len(signature)) + for i := 0; i < len(signature); i++ { + sign[i] = signature[len(signature)-i-1] + } + return pub.Pub.VerifyDigest(dgst, sign) +} + +func (pub PublicKeyReverseDigestAndSignature) Equal(theirKey crypto.PublicKey) bool { + return pub.Pub.Equal(theirKey) +} diff --git a/news.texi b/news.texi index e6f85e1122b91b366342164d13161d726803fd9f2c76d0acb6c905f6892f4b39..d52bf2459cd25805aad7b2cfb94e0f6099e691a2b667d01677c8ca2cb7438ce8 100644 --- a/news.texi +++ b/news.texi @@ -13,6 +13,9 @@ @code{gost3410.NewPrivateKeyLE}, @code{gost3410.PrivateKey.RawLE}, @code{gost3410.NewPrivateKeyBE}, @code{gost3410.PrivateKey.RawBE}, functions appeared, to simplify dealing with different endianness keys serialisation + @item + @code{gost3410.PublicKeyReverseDigest} and + @code{gost3410.PublicKeyReverseDigestAndSignature} wrappers appeared @end itemize @anchor{Release 5.12.0}