File: ecutil.go

package info (click to toggle)
golang-github-lestrrat-go-jwx 2.1.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,872 kB
  • sloc: sh: 222; makefile: 86; perl: 62
file content (114 lines) | stat: -rw-r--r-- 2,882 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Package ecutil defines tools that help with elliptic curve related
// computation
package ecutil

import (
	"crypto/elliptic"
	"math/big"
	"sync"

	"github.com/lestrrat-go/jwx/v2/jwa"
)

// data for available curves. Some algorithms may be compiled in/out
var curveToAlg = map[elliptic.Curve]jwa.EllipticCurveAlgorithm{}
var algToCurve = map[jwa.EllipticCurveAlgorithm]elliptic.Curve{}
var availableAlgs []jwa.EllipticCurveAlgorithm
var availableCrvs []elliptic.Curve

func RegisterCurve(crv elliptic.Curve, alg jwa.EllipticCurveAlgorithm) {
	curveToAlg[crv] = alg
	algToCurve[alg] = crv
	availableAlgs = append(availableAlgs, alg)
	availableCrvs = append(availableCrvs, crv)
}

func IsAvailable(alg jwa.EllipticCurveAlgorithm) bool {
	_, ok := algToCurve[alg]
	return ok
}

func AvailableAlgorithms() []jwa.EllipticCurveAlgorithm {
	return availableAlgs
}

func AvailableCurves() []elliptic.Curve {
	return availableCrvs
}

func AlgorithmForCurve(crv elliptic.Curve) (jwa.EllipticCurveAlgorithm, bool) {
	v, ok := curveToAlg[crv]
	return v, ok
}

func CurveForAlgorithm(alg jwa.EllipticCurveAlgorithm) (elliptic.Curve, bool) {
	v, ok := algToCurve[alg]
	return v, ok
}

const (
	// size of buffer that needs to be allocated for EC521 curve
	ec521BufferSize = 66 // (521 / 8) + 1
)

var ecpointBufferPool = sync.Pool{
	New: func() interface{} {
		// In most cases the curve bit size will be less than this length
		// so allocate the maximum, and keep reusing
		buf := make([]byte, 0, ec521BufferSize)
		return &buf
	},
}

func getCrvFixedBuffer(size int) []byte {
	//nolint:forcetypeassert
	buf := *(ecpointBufferPool.Get().(*[]byte))
	if size > ec521BufferSize && cap(buf) < size {
		buf = append(buf, make([]byte, size-cap(buf))...)
	}
	return buf[:size]
}

// ReleaseECPointBuffer releases the []byte buffer allocated.
func ReleaseECPointBuffer(buf []byte) {
	buf = buf[:cap(buf)]
	buf[0] = 0x0
	for i := 1; i < len(buf); i *= 2 {
		copy(buf[i:], buf[:i])
	}
	buf = buf[:0]
	ecpointBufferPool.Put(&buf)
}

func CalculateKeySize(crv elliptic.Curve) int {
	// We need to create a buffer that fits the entire curve.
	// If the curve size is 66, that fits in 9 bytes. If the curve
	// size is 64, it fits in 8 bytes.
	bits := crv.Params().BitSize

	// For most common cases we know before hand what the byte length
	// is going to be. optimize
	var inBytes int
	switch bits {
	case 224, 256, 384: // TODO: use constant?
		inBytes = bits / 8
	case 521:
		inBytes = ec521BufferSize
	default:
		inBytes = bits / 8
		if (bits % 8) != 0 {
			inBytes++
		}
	}

	return inBytes
}

// AllocECPointBuffer allocates a buffer for the given point in the given
// curve. This buffer should be released using the ReleaseECPointBuffer
// function.
func AllocECPointBuffer(v *big.Int, crv elliptic.Curve) []byte {
	buf := getCrvFixedBuffer(CalculateKeySize(crv))
	v.FillBytes(buf)
	return buf
}