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 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
package keygen
import (
"crypto"
"crypto/ecdsa"
"crypto/rand"
"encoding/binary"
"fmt"
"io"
"golang.org/x/crypto/curve25519"
"github.com/lestrrat-go/jwx/v2/internal/ecutil"
"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jwe/internal/concatkdf"
"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/lestrrat-go/jwx/v2/x25519"
)
// Bytes returns the byte from this ByteKey
func (k ByteKey) Bytes() []byte {
return []byte(k)
}
// NewRandom creates a new Generator that returns
// random bytes
func NewRandom(n int) Random {
return Random{keysize: n}
}
// Size returns the key size
func (g Random) Size() int {
return g.keysize
}
// Generate generates a random new key
func (g Random) Generate() (ByteSource, error) {
buf := make([]byte, g.keysize)
if _, err := io.ReadFull(rand.Reader, buf); err != nil {
return nil, fmt.Errorf(`failed to read from rand.Reader: %w`, err)
}
return ByteKey(buf), nil
}
// NewEcdhes creates a new key generator using ECDH-ES
func NewEcdhes(alg jwa.KeyEncryptionAlgorithm, enc jwa.ContentEncryptionAlgorithm, keysize int, pubkey *ecdsa.PublicKey, apu, apv []byte) (*Ecdhes, error) {
return &Ecdhes{
algorithm: alg,
enc: enc,
keysize: keysize,
pubkey: pubkey,
apu: apu,
apv: apv,
}, nil
}
// Size returns the key size associated with this generator
func (g Ecdhes) Size() int {
return g.keysize
}
// Generate generates new keys using ECDH-ES
func (g Ecdhes) Generate() (ByteSource, error) {
priv, err := ecdsa.GenerateKey(g.pubkey.Curve, rand.Reader)
if err != nil {
return nil, fmt.Errorf(`failed to generate key for ECDH-ES: %w`, err)
}
var algorithm string
if g.algorithm == jwa.ECDH_ES {
algorithm = g.enc.String()
} else {
algorithm = g.algorithm.String()
}
pubinfo := make([]byte, 4)
binary.BigEndian.PutUint32(pubinfo, uint32(g.keysize)*8)
if !priv.PublicKey.Curve.IsOnCurve(g.pubkey.X, g.pubkey.Y) {
return nil, fmt.Errorf(`public key used does not contain a point (X,Y) on the curve`)
}
z, _ := priv.PublicKey.Curve.ScalarMult(g.pubkey.X, g.pubkey.Y, priv.D.Bytes())
zBytes := ecutil.AllocECPointBuffer(z, priv.PublicKey.Curve)
defer ecutil.ReleaseECPointBuffer(zBytes)
kdf := concatkdf.New(crypto.SHA256, []byte(algorithm), zBytes, g.apu, g.apv, pubinfo, []byte{})
kek := make([]byte, g.keysize)
if _, err := kdf.Read(kek); err != nil {
return nil, fmt.Errorf(`failed to read kdf: %w`, err)
}
return ByteWithECPublicKey{
PublicKey: &priv.PublicKey,
ByteKey: ByteKey(kek),
}, nil
}
// NewX25519 creates a new key generator using ECDH-ES
func NewX25519(alg jwa.KeyEncryptionAlgorithm, enc jwa.ContentEncryptionAlgorithm, keysize int, pubkey x25519.PublicKey) (*X25519, error) {
return &X25519{
algorithm: alg,
enc: enc,
keysize: keysize,
pubkey: pubkey,
}, nil
}
// Size returns the key size associated with this generator
func (g X25519) Size() int {
return g.keysize
}
// Generate generates new keys using ECDH-ES
func (g X25519) Generate() (ByteSource, error) {
pub, priv, err := x25519.GenerateKey(rand.Reader)
if err != nil {
return nil, fmt.Errorf(`failed to generate key for X25519: %w`, err)
}
var algorithm string
if g.algorithm == jwa.ECDH_ES {
algorithm = g.enc.String()
} else {
algorithm = g.algorithm.String()
}
pubinfo := make([]byte, 4)
binary.BigEndian.PutUint32(pubinfo, uint32(g.keysize)*8)
zBytes, err := curve25519.X25519(priv.Seed(), g.pubkey)
if err != nil {
return nil, fmt.Errorf(`failed to compute Z: %w`, err)
}
kdf := concatkdf.New(crypto.SHA256, []byte(algorithm), zBytes, []byte{}, []byte{}, pubinfo, []byte{})
kek := make([]byte, g.keysize)
if _, err := kdf.Read(kek); err != nil {
return nil, fmt.Errorf(`failed to read kdf: %w`, err)
}
return ByteWithECPublicKey{
PublicKey: pub,
ByteKey: ByteKey(kek),
}, nil
}
// HeaderPopulate populates the header with the required EC-DSA public key
// information ('epk' key)
func (k ByteWithECPublicKey) Populate(h Setter) error {
key, err := jwk.FromRaw(k.PublicKey)
if err != nil {
return fmt.Errorf(`failed to create JWK: %w`, err)
}
if err := h.Set("epk", key); err != nil {
return fmt.Errorf(`failed to write header: %w`, err)
}
return nil
}
// HeaderPopulate populates the header with the required AES GCM
// parameters ('iv' and 'tag')
func (k ByteWithIVAndTag) Populate(h Setter) error {
if err := h.Set("iv", k.IV); err != nil {
return fmt.Errorf(`failed to write header: %w`, err)
}
if err := h.Set("tag", k.Tag); err != nil {
return fmt.Errorf(`failed to write header: %w`, err)
}
return nil
}
// HeaderPopulate populates the header with the required PBES2
// parameters ('p2s' and 'p2c')
func (k ByteWithSaltAndCount) Populate(h Setter) error {
if err := h.Set("p2c", k.Count); err != nil {
return fmt.Errorf(`failed to write header: %w`, err)
}
if err := h.Set("p2s", k.Salt); err != nil {
return fmt.Errorf(`failed to write header: %w`, err)
}
return nil
}
|