github.com/lestrrat-go/jwx/v2@v2.0.21/x25519/x25519.go (about) 1 package x25519 2 3 import ( 4 "bytes" 5 "crypto" 6 cryptorand "crypto/rand" 7 "fmt" 8 "io" 9 10 "golang.org/x/crypto/curve25519" 11 ) 12 13 // This mirrors ed25519's structure for private/public "keys". jwx 14 // requires dedicated types for these as they drive 15 // serialization/deserialization logic, as well as encryption types. 16 // 17 // Note that with the x25519 scheme, the private key is a sequence of 18 // 32 bytes, while the public key is the result of X25519(private, 19 // basepoint). 20 // 21 // Portions of this file are from Go's ed25519.go, which is 22 // Copyright 2016 The Go Authors. All rights reserved. 23 24 const ( 25 // PublicKeySize is the size, in bytes, of public keys as used in this package. 26 PublicKeySize = 32 27 // PrivateKeySize is the size, in bytes, of private keys as used in this package. 28 PrivateKeySize = 64 29 // SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032. 30 SeedSize = 32 31 ) 32 33 // PublicKey is the type of X25519 public keys 34 type PublicKey []byte 35 36 // Any methods implemented on PublicKey might need to also be implemented on 37 // PrivateKey, as the latter embeds the former and will expose its methods. 38 39 // Equal reports whether pub and x have the same value. 40 func (pub PublicKey) Equal(x crypto.PublicKey) bool { 41 xx, ok := x.(PublicKey) 42 if !ok { 43 return false 44 } 45 return bytes.Equal(pub, xx) 46 } 47 48 // PrivateKey is the type of X25519 private key 49 type PrivateKey []byte 50 51 // Public returns the PublicKey corresponding to priv. 52 func (priv PrivateKey) Public() crypto.PublicKey { 53 publicKey := make([]byte, PublicKeySize) 54 copy(publicKey, priv[SeedSize:]) 55 return PublicKey(publicKey) 56 } 57 58 // Equal reports whether priv and x have the same value. 59 func (priv PrivateKey) Equal(x crypto.PrivateKey) bool { 60 xx, ok := x.(PrivateKey) 61 if !ok { 62 return false 63 } 64 return bytes.Equal(priv, xx) 65 } 66 67 // Seed returns the private key seed corresponding to priv. It is provided for 68 // interoperability with RFC 7748. RFC 7748's private keys correspond to seeds 69 // in this package. 70 func (priv PrivateKey) Seed() []byte { 71 seed := make([]byte, SeedSize) 72 copy(seed, priv[:SeedSize]) 73 return seed 74 } 75 76 // NewKeyFromSeed calculates a private key from a seed. It will return 77 // an error if len(seed) is not SeedSize. This function is provided 78 // for interoperability with RFC 7748. RFC 7748's private keys 79 // correspond to seeds in this package. 80 func NewKeyFromSeed(seed []byte) (PrivateKey, error) { 81 privateKey := make([]byte, PrivateKeySize) 82 if len(seed) != SeedSize { 83 return nil, fmt.Errorf("unexpected seed size: %d", len(seed)) 84 } 85 copy(privateKey, seed) 86 public, err := curve25519.X25519(seed, curve25519.Basepoint) 87 if err != nil { 88 return nil, fmt.Errorf(`failed to compute public key: %w`, err) 89 } 90 copy(privateKey[SeedSize:], public) 91 92 return privateKey, nil 93 } 94 95 // GenerateKey generates a public/private key pair using entropy from rand. 96 // If rand is nil, crypto/rand.Reader will be used. 97 func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { 98 if rand == nil { 99 rand = cryptorand.Reader 100 } 101 102 seed := make([]byte, SeedSize) 103 if _, err := io.ReadFull(rand, seed); err != nil { 104 return nil, nil, err 105 } 106 107 privateKey, err := NewKeyFromSeed(seed) 108 if err != nil { 109 return nil, nil, err 110 } 111 publicKey := make([]byte, PublicKeySize) 112 copy(publicKey, privateKey[SeedSize:]) 113 114 return publicKey, privateKey, nil 115 }