Skip to content

Commit

Permalink
JWT: Add a signature generator for Ed25519
Browse files Browse the repository at this point in the history
Ed25519 is arguably safer than ECDSA, because it doesn't depend on
randomly generated nonce values.
  • Loading branch information
EdSchouten committed Jun 19, 2024
1 parent 118cb9c commit 4d8e1ea
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 0 deletions.
2 changes: 2 additions & 0 deletions pkg/jwt/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ go_library(
"demultiplexing_signature_validator.go",
"ecdsa_sha_signature_generator.go",
"ecdsa_sha_signature_validator.go",
"ed25519_signature_generator.go",
"ed25519_signature_validator.go",
"forwarding_signature_validator.go",
"generate_authorization_header.go",
Expand Down Expand Up @@ -40,6 +41,7 @@ go_test(
"authorization_header_parser_test.go",
"ecdsa_sha_signature_generator_test.go",
"ecdsa_sha_signature_validator_test.go",
"ed25519_signature_generator_test.go",
"ed25519_signature_validator_test.go",
"generate_authorization_header_test.go",
"hmac_sha_signature_validator_test.go",
Expand Down
31 changes: 31 additions & 0 deletions pkg/jwt/ed25519_signature_generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package jwt

import (
"crypto/ed25519"
)

type ed25519SignatureGenerator struct {
privateKey ed25519.PrivateKey
}

// NewEd25519SignatureGenerator creates a SignatureGenerator that can
// sign a JWT using the Edwards-curve Digital Signature Algorithm
// (EdDSA), using Curve25519 as its elliptic curve and SHA-512 as a
// hashing algorithm.
//
// EdDSA uses asymmetrical cryptography, meaning that signing is
// performed using a private key, while verification only relies on a
// public key.
func NewEd25519SignatureGenerator(privateKey ed25519.PrivateKey) SignatureGenerator {
return ed25519SignatureGenerator{
privateKey: privateKey,
}
}

func (sc ed25519SignatureGenerator) GetAlgorithm() string {
return "EdDSA"
}

func (sc ed25519SignatureGenerator) GenerateSignature(headerAndPayload string) ([]byte, error) {
return ed25519.Sign(sc.privateKey, []byte(headerAndPayload)), nil
}
34 changes: 34 additions & 0 deletions pkg/jwt/ed25519_signature_generator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package jwt_test

import (
"crypto/ed25519"
"crypto/x509"
"encoding/pem"
"testing"

"github.com/buildbarn/bb-storage/pkg/jwt"
"github.com/stretchr/testify/require"
)

func TestEd25519SignatureGenerator(t *testing.T) {
// Create a signature generator.
block, _ := pem.Decode([]byte(`-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIJFl+ugysbBc60+O+IIFLSJL0TYtV1iW9W9YQ9t2l4MN
-----END PRIVATE KEY-----`))
require.NotNil(t, block)
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
require.NoError(t, err)
privateKey := key.(ed25519.PrivateKey)
signatureGenerator := jwt.NewEd25519SignatureGenerator(privateKey)
require.Equal(t, "EdDSA", signatureGenerator.GetAlgorithm())

// Sign a token.
headerAndPayload := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ"
signature, err := signatureGenerator.GenerateSignature(headerAndPayload)
require.NoError(t, err)

// Ensure that the generated signature is valid.
signatureValidator := jwt.NewEd25519SignatureValidator(privateKey.Public().(ed25519.PublicKey))
require.NoError(t, err)
require.True(t, signatureValidator.ValidateSignature("EdDSA", nil, headerAndPayload, signature))
}

0 comments on commit 4d8e1ea

Please sign in to comment.