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 }