github.com/zntrio/harp/v2@v2.0.9/pkg/sdk/value/signature/raw/transformer.go (about)

     1  // Licensed to Elasticsearch B.V. under one or more contributor
     2  // license agreements. See the NOTICE file distributed with
     3  // this work for additional information regarding copyright
     4  // ownership. Elasticsearch B.V. licenses this file to you under
     5  // the Apache License, Version 2.0 (the "License"); you may
     6  // not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  //     http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing,
    12  // software distributed under the License is distributed on an
    13  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    14  // KIND, either express or implied.  See the License for the
    15  // specific language governing permissions and limitations
    16  // under the License.
    17  
    18  package raw
    19  
    20  import (
    21  	"context"
    22  	"crypto/ecdsa"
    23  	"crypto/ed25519"
    24  	"crypto/elliptic"
    25  	"crypto/rand"
    26  	"crypto/sha256"
    27  	"crypto/sha512"
    28  	"errors"
    29  	"fmt"
    30  	"hash"
    31  	"math/big"
    32  
    33  	"github.com/zntrio/harp/v2/pkg/sdk/security/crypto/rfc6979"
    34  	"github.com/zntrio/harp/v2/pkg/sdk/types"
    35  	"github.com/zntrio/harp/v2/pkg/sdk/value/signature"
    36  )
    37  
    38  type rawTransformer struct {
    39  	key interface{}
    40  }
    41  
    42  // -----------------------------------------------------------------------------
    43  
    44  func (d *rawTransformer) To(ctx context.Context, input []byte) ([]byte, error) {
    45  	if types.IsNil(d.key) {
    46  		return nil, fmt.Errorf("paseto: signer key must not be nil")
    47  	}
    48  
    49  	var (
    50  		sig []byte
    51  		err error
    52  	)
    53  
    54  	switch sk := d.key.(type) {
    55  	case ed25519.PrivateKey:
    56  		// Ed25519 doesn't support pre-hash as input to prevent collision.
    57  		sig = ed25519.Sign(sk, input)
    58  
    59  	case *ecdsa.PrivateKey:
    60  		var digest []byte
    61  
    62  		// Get hash function for curve
    63  		hf, errHash := d.hashFromCurve(sk.Curve)
    64  		if errHash != nil {
    65  			return nil, fmt.Errorf("raw: unable to retrieve hash function for curve: %w", errHash)
    66  		}
    67  
    68  		// Build a hash function instance
    69  		h := hf()
    70  
    71  		// Input is already a hash?
    72  		if signature.IsInputPreHashed(ctx) {
    73  			digest = input
    74  			if len(digest) != h.Size() {
    75  				return nil, fmt.Errorf("raw: invalid pre-hash length, expected %d bytes, got %d", h.Size(), len(input))
    76  			}
    77  		} else {
    78  			// Hash the decoded content
    79  			h.Write(input)
    80  
    81  			// Set hash value
    82  			digest = h.Sum(nil)
    83  		}
    84  
    85  		var (
    86  			errSig error
    87  			r, s   *big.Int
    88  		)
    89  		if signature.IsDeterministic(ctx) {
    90  			// Deterministic signature
    91  			r, s = rfc6979.SignECDSA(sk, digest, hf)
    92  			if r == nil {
    93  				errSig = errors.New("unable to apply determistic signature")
    94  			}
    95  		} else {
    96  			// Sign
    97  			r, s, errSig = ecdsa.Sign(rand.Reader, sk, digest)
    98  		}
    99  		if errSig != nil {
   100  			return nil, fmt.Errorf("raw: unable to sign the content: %w", errSig)
   101  		}
   102  
   103  		// Calculate optimized buffer size
   104  		curveBits := sk.Curve.Params().BitSize
   105  		keyBytes := curveBits / 8
   106  		if curveBits%8 > 0 {
   107  			keyBytes++
   108  		}
   109  
   110  		// We serialize the outputs (r and s) into big-endian byte arrays and pad
   111  		// them with zeros on the left to make sure the sizes work out. Both arrays
   112  		// must be keyBytes long, and the output must be 2*keyBytes long.
   113  		rBytes := r.Bytes()
   114  		rBytesPadded := make([]byte, keyBytes)
   115  		copy(rBytesPadded[keyBytes-len(rBytes):], rBytes)
   116  
   117  		sBytes := s.Bytes()
   118  		sBytesPadded := make([]byte, keyBytes)
   119  		copy(sBytesPadded[keyBytes-len(sBytes):], sBytes)
   120  
   121  		// Assemble the signature
   122  		sig = rBytesPadded
   123  		sig = append(sig, sBytesPadded...)
   124  	default:
   125  		return nil, errors.New("raw: key is not supported")
   126  	}
   127  	if err != nil {
   128  		return nil, fmt.Errorf("raw: unable to sign input: %w", err)
   129  	}
   130  
   131  	// Detached signature requested?
   132  	if signature.IsDetached(ctx) {
   133  		return sig, nil
   134  	}
   135  
   136  	// No error
   137  	return append(sig, input...), nil
   138  }
   139  
   140  func (d *rawTransformer) From(ctx context.Context, input []byte) ([]byte, error) {
   141  	switch sk := d.key.(type) {
   142  	case ed25519.PublicKey:
   143  		// Ed25519 doesn't support pre-hash as input to prevent collision.
   144  		if ed25519.Verify(sk, input[ed25519.SignatureSize:], input[:ed25519.SignatureSize]) {
   145  			return input[ed25519.SignatureSize:], nil
   146  		}
   147  
   148  	case *ecdsa.PublicKey:
   149  		// Extract signature
   150  		pkLen, err := d.privateKeySizeFromCurve(sk.Curve)
   151  		if err != nil {
   152  			return nil, fmt.Errorf("raw: unable to retrieve private key length: %w", err)
   153  		}
   154  
   155  		// Check minimal input length
   156  		if len(input) < 2*pkLen {
   157  			return nil, errors.New("raw: too short signature")
   158  		}
   159  
   160  		// Get hash function for curve
   161  		hf, err := d.hashFromCurve(sk.Curve)
   162  		if err != nil {
   163  			return nil, fmt.Errorf("raw: unable to retrieve hash function for curve: %w", err)
   164  		}
   165  
   166  		// Build a hash function instance
   167  		h := hf()
   168  
   169  		var digest []byte
   170  
   171  		// Input is already a hash?
   172  		if signature.IsInputPreHashed(ctx) {
   173  			digest = input[2*pkLen:]
   174  			if len(digest) != h.Size() {
   175  				return nil, fmt.Errorf("invalid pre-hash length, expected %d bytes, got %d bytes", h.Size(), len(digest))
   176  			}
   177  		} else {
   178  			// Hash the decoded content
   179  			h.Write(input[2*pkLen:])
   180  
   181  			// Set hash value
   182  			digest = h.Sum(nil)
   183  		}
   184  
   185  		// Extract sig
   186  		sig := input[:2*pkLen]
   187  
   188  		// Unpack signature
   189  		var (
   190  			r = new(big.Int).SetBytes(sig[:pkLen])
   191  			s = new(big.Int).SetBytes(sig[pkLen:])
   192  		)
   193  
   194  		// Validate signature
   195  		if ecdsa.Verify(sk, digest, r, s) {
   196  			return input[2*pkLen:], nil
   197  		}
   198  	default:
   199  		return nil, errors.New("raw: key is not supported")
   200  	}
   201  
   202  	// Default to error
   203  	return nil, errors.New("raw: unable to validate input signature")
   204  }
   205  
   206  // -----------------------------------------------------------------------------
   207  
   208  func (d *rawTransformer) hashFromCurve(curve elliptic.Curve) (func() hash.Hash, error) {
   209  	switch curve {
   210  	case elliptic.P256():
   211  		return sha256.New, nil
   212  	case elliptic.P384():
   213  		return sha512.New384, nil
   214  	case elliptic.P521():
   215  		return sha512.New, nil
   216  	default:
   217  	}
   218  
   219  	// Default to error
   220  	return nil, errors.New("current curve is not supported")
   221  }
   222  
   223  func (d *rawTransformer) privateKeySizeFromCurve(curve elliptic.Curve) (int, error) {
   224  	switch curve {
   225  	case elliptic.P256():
   226  		return 32, nil
   227  	case elliptic.P384():
   228  		return 48, nil
   229  	case elliptic.P521():
   230  		return 66, nil
   231  	default:
   232  	}
   233  
   234  	return 0, errors.New("current curve is not supported")
   235  }