Skip to content

Commit

Permalink
feat: Add Ed25519 algorithm for signing and verification
Browse files Browse the repository at this point in the history
- Add signing and verification support for ed25519 algorithm.
- Sign data and verify the signature using the ed25519 algorithm and SHA256 hash function.
- Sign data and verify signatures using ECDSA and RSA algorithms.
- Wrap error messages with the context to provide more information about the error.
- Use constants and variables to improve code readability.
  • Loading branch information
Laisky committed Jan 15, 2024
1 parent 9fc9907 commit f8747b2
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 10 deletions.
72 changes: 62 additions & 10 deletions crypto/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package crypto
import (
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
Expand Down Expand Up @@ -48,9 +49,9 @@ import (
// }

// SignByRSAWithSHA256 generate signature by rsa private key use sha256
func SignByRSAWithSHA256(priKey *rsa.PrivateKey, content []byte) ([]byte, error) {
func SignByRSAWithSHA256(prikey *rsa.PrivateKey, content []byte) ([]byte, error) {
hashed := sha256.Sum256(content)
return rsa.SignPKCS1v15(rand.Reader, priKey, crypto.SHA256, hashed[:])
return rsa.SignPKCS1v15(rand.Reader, prikey, crypto.SHA256, hashed[:])
}

// VerifyByRSAWithSHA256 verify signature by rsa public key use sha256
Expand All @@ -60,13 +61,13 @@ func VerifyByRSAWithSHA256(pubKey *rsa.PublicKey, content []byte, sig []byte) er
}

// SignReaderByRSAWithSHA256 generate signature by rsa private key use sha256
func SignReaderByRSAWithSHA256(priKey *rsa.PrivateKey, reader io.Reader) (sig []byte, err error) {
func SignReaderByRSAWithSHA256(prikey *rsa.PrivateKey, reader io.Reader) (sig []byte, err error) {
hasher := sha256.New()
if _, err = io.Copy(hasher, reader); err != nil {
return nil, errors.Wrap(err, "read content")
}

return rsa.SignPKCS1v15(rand.Reader, priKey, crypto.SHA256, hasher.Sum(nil))
return rsa.SignPKCS1v15(rand.Reader, prikey, crypto.SHA256, hasher.Sum(nil))
}

// VerifyReaderByRSAWithSHA256 verify signature by rsa public key use sha256
Expand All @@ -80,9 +81,9 @@ func VerifyReaderByRSAWithSHA256(pubKey *rsa.PublicKey, reader io.Reader, sig []
}

// SignByECDSAWithSHA256 generate signature by ecdsa private key use sha256
func SignByECDSAWithSHA256(priKey *ecdsa.PrivateKey, content []byte) (r, s *big.Int, err error) {
func SignByECDSAWithSHA256(prikey *ecdsa.PrivateKey, content []byte) (r, s *big.Int, err error) {
hash := sha256.Sum256(content)
return ecdsa.Sign(rand.Reader, priKey, hash[:])
return ecdsa.Sign(rand.Reader, prikey, hash[:])
}

// VerifyByECDSAWithSHA256 verify signature by ecdsa public key use sha256
Expand All @@ -92,9 +93,9 @@ func VerifyByECDSAWithSHA256(pubKey *ecdsa.PublicKey, content []byte, r, s *big.
}

// SignByECDSAWithSHA256AndBase64 generate signature by ecdsa private key use sha256
func SignByECDSAWithSHA256AndBase64(priKey *ecdsa.PrivateKey, content []byte) (signature string, err error) {
func SignByECDSAWithSHA256AndBase64(prikey *ecdsa.PrivateKey, content []byte) (signature string, err error) {
hash := sha256.Sum256(content)
r, s, err := ecdsa.Sign(rand.Reader, priKey, hash[:])
r, s, err := ecdsa.Sign(rand.Reader, prikey, hash[:])
if err != nil {
return "", errors.Wrap(err, "sign")
}
Expand All @@ -114,13 +115,13 @@ func VerifyByECDSAWithSHA256AndBase64(pubKey *ecdsa.PublicKey, content []byte, s
}

// SignReaderByECDSAWithSHA256 generate signature by ecdsa private key use sha256
func SignReaderByECDSAWithSHA256(priKey *ecdsa.PrivateKey, reader io.Reader) (r, s *big.Int, err error) {
func SignReaderByECDSAWithSHA256(prikey *ecdsa.PrivateKey, reader io.Reader) (r, s *big.Int, err error) {
hasher := sha256.New()
if _, err = io.Copy(hasher, reader); err != nil {
return nil, nil, errors.Wrap(err, "read content")
}

return ecdsa.Sign(rand.Reader, priKey, hasher.Sum(nil))
return ecdsa.Sign(rand.Reader, prikey, hasher.Sum(nil))
}

// VerifyReaderByECDSAWithSHA256 verify signature by ecdsa public key use sha256
Expand All @@ -133,6 +134,57 @@ func VerifyReaderByECDSAWithSHA256(pubKey *ecdsa.PublicKey, reader io.Reader, r,
return ecdsa.Verify(pubKey, hasher.Sum(nil), r, s), nil
}

const (
streamChunkSize = 4 * 1024 * 1024
)

// SignReaderByEd25519WithSHA256 generate signature by ecdsa private key use sha256
func SignReaderByEd25519WithSHA256(prikey ed25519.PrivateKey, reader io.Reader) (sig []byte, err error) {
hasher := sha256.New()
chunk := make([]byte, streamChunkSize)
for {
n, err := reader.Read(chunk)
if err != nil {
if errors.Is(err, io.EOF) {
break
}

return nil, errors.Wrap(err, "read chunk")
}

if _, err = hasher.Write(chunk[:n]); err != nil {
return nil, errors.Wrap(err, "write chunk")
}
}

return prikey.Sign(rand.Reader, hasher.Sum(nil), crypto.Hash(0))
}

// VerifyReaderByEd25519WithSHA256 verify signature by ecdsa public key use sha256
func VerifyReaderByEd25519WithSHA256(pubKey ed25519.PublicKey, reader io.Reader, sig []byte) error {
hasher := sha256.New()
chunk := make([]byte, streamChunkSize)
for {
n, err := reader.Read(chunk)
if err != nil {
if errors.Is(err, io.EOF) {
break
}

return errors.Wrap(err, "read chunk")
}

if _, err = hasher.Write(chunk[:n]); err != nil {
return errors.Wrap(err, "write chunk")
}
}

err := ed25519.VerifyWithOptions(pubKey, hasher.Sum(nil), sig, &ed25519.Options{
Hash: crypto.Hash(0),
})
return errors.Wrap(err, "verify")
}

const ecdsaSignDelimiter = "."

// EncodeES256SignByHex format ecdsa sign to stirng
Expand Down
35 changes: 35 additions & 0 deletions crypto/sign_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package crypto

import (
"bytes"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
Expand All @@ -11,6 +13,7 @@ import (
"testing"

"github.com/Laisky/zap"
"github.com/stretchr/testify/require"

"github.com/Laisky/go-utils/v4/log"
)
Expand Down Expand Up @@ -459,3 +462,35 @@ func TestECDSASignFormatAndParseByBase64(t *testing.T) {
// t.Fatalf("%+v", err)
// }
// }

func TestSignReaderByEd25519WithSHA256(t *testing.T) {
t.Parallel()

raw, err := Salt(100 * 1024 * 1024)
require.NoError(t, err)

prikey, err := NewEd25519Prikey()
require.NoError(t, err)

sig, err := SignReaderByEd25519WithSHA256(prikey, bytes.NewReader(raw))
require.NoError(t, err)

pubkey := Prikey2Pubkey(prikey).(ed25519.PublicKey)
err = VerifyReaderByEd25519WithSHA256(pubkey, bytes.NewReader(raw), sig)
require.NoError(t, err)

t.Run("false pubkey", func(t *testing.T) {
prikey, err := NewEd25519Prikey()
require.NoError(t, err)
pubkey := Prikey2Pubkey(prikey).(ed25519.PublicKey)

err = VerifyReaderByEd25519WithSHA256(pubkey, bytes.NewReader(raw), sig)
require.ErrorContains(t, err, "invalid signature")
})

t.Run("false sig", func(t *testing.T) {
falseSig := []byte("2l3fj238f83fu")
err := VerifyReaderByEd25519WithSHA256(pubkey, bytes.NewReader(raw), falseSig)
require.ErrorContains(t, err, "invalid signature")
})
}

0 comments on commit f8747b2

Please sign in to comment.