Add chat session
This commit is contained in:
74
yggdrasil/user/pubkey.go
Normal file
74
yggdrasil/user/pubkey.go
Normal file
@ -0,0 +1,74 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
pk "github.com/Tnze/go-mc/net/packet"
|
||||
)
|
||||
|
||||
type PublicKey struct {
|
||||
ExpiresAt time.Time
|
||||
PubKey *rsa.PublicKey
|
||||
Signature []byte
|
||||
}
|
||||
|
||||
func (p PublicKey) WriteTo(w io.Writer) (n int64, err error) {
|
||||
pubKeyEncoded, err := x509.MarshalPKIXPublicKey(p.PubKey)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return pk.Tuple{
|
||||
pk.Long(p.ExpiresAt.UnixMilli()),
|
||||
pk.ByteArray(pubKeyEncoded),
|
||||
pk.ByteArray(p.Signature),
|
||||
}.WriteTo(w)
|
||||
}
|
||||
|
||||
func (p *PublicKey) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
var (
|
||||
ExpiresAt pk.Long
|
||||
PubKey pk.ByteArray
|
||||
Signature pk.ByteArray
|
||||
)
|
||||
n, err = pk.Tuple{
|
||||
&ExpiresAt,
|
||||
&PubKey,
|
||||
&Signature,
|
||||
}.ReadFrom(r)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
p.ExpiresAt = time.UnixMilli(int64(ExpiresAt))
|
||||
pubKey, err := x509.ParsePKIXPublicKey(PubKey)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
if key, ok := pubKey.(*rsa.PublicKey); !ok {
|
||||
return n, errors.New("expect RSA public key")
|
||||
} else {
|
||||
p.PubKey = key
|
||||
}
|
||||
|
||||
p.Signature = Signature
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (p *PublicKey) Verify() bool {
|
||||
if p.ExpiresAt.Before(time.Now()) {
|
||||
return false
|
||||
}
|
||||
encoded, err := x509.MarshalPKIXPublicKey(p.PubKey)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return VerifySignature(encoded, p.Signature)
|
||||
}
|
||||
|
||||
func (p *PublicKey) VerifyMessage(hash, signature []byte) error {
|
||||
return rsa.VerifyPKCS1v15(p.PubKey, crypto.SHA256, hash, signature)
|
||||
}
|
92
yggdrasil/user/validator.go
Normal file
92
yggdrasil/user/validator.go
Normal file
@ -0,0 +1,92 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
_ "embed"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
)
|
||||
|
||||
//go:embed yggdrasil_session_pubkey.der
|
||||
var pubKeyBytes []byte
|
||||
var pubKey = unwrap(x509.ParsePKIXPublicKey(pubKeyBytes)).(*rsa.PublicKey)
|
||||
|
||||
// VerifySignature has the same functional as
|
||||
// net.minecraft.world.entity.player.ProfilePublicKey.Data#validateSignature
|
||||
func VerifySignature(profilePubKey, signature []byte) bool {
|
||||
hash := sha256.New()
|
||||
unwrap(hash.Write([]byte("-----BEGIN RSA PRIVATE KEY-----\n")))
|
||||
breaker := lineBreaker{out: hash}
|
||||
enc := base64.NewEncoder(base64.StdEncoding, &breaker)
|
||||
unwrap(enc.Write(profilePubKey))
|
||||
must(enc.Close())
|
||||
must(breaker.Close())
|
||||
unwrap(hash.Write([]byte("\n-----END RSA PRIVATE KEY-----\n")))
|
||||
return rsa.VerifyPKCS1v15(pubKey, crypto.SHA256, hash.Sum(nil), signature) != nil
|
||||
}
|
||||
|
||||
const pemLineLength = 76
|
||||
|
||||
var nl = []byte{'\n'}
|
||||
|
||||
type lineBreaker struct {
|
||||
line [pemLineLength]byte
|
||||
used int
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
func (l *lineBreaker) Write(b []byte) (n int, err error) {
|
||||
if l.used+len(b) < pemLineLength {
|
||||
copy(l.line[l.used:], b)
|
||||
l.used += len(b)
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
n, err = l.out.Write(l.line[0:l.used])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
excess := pemLineLength - l.used
|
||||
l.used = 0
|
||||
|
||||
n1, err := l.out.Write(b[0:excess])
|
||||
if err != nil {
|
||||
return n + n1, err
|
||||
}
|
||||
|
||||
n2, err := l.out.Write(nl)
|
||||
if err != nil {
|
||||
return n + n1 + n2, err
|
||||
}
|
||||
|
||||
n3, err := l.Write(b[excess:])
|
||||
return n1 + n2 + n3, err
|
||||
}
|
||||
|
||||
func (l *lineBreaker) Close() (err error) {
|
||||
if l.used > 0 {
|
||||
_, err = l.out.Write(l.line[0:l.used])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = l.out.Write(nl)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func must(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func unwrap[T any](v T, err error) T {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return v
|
||||
}
|
BIN
yggdrasil/user/yggdrasil_session_pubkey.der
Normal file
BIN
yggdrasil/user/yggdrasil_session_pubkey.der
Normal file
Binary file not shown.
Reference in New Issue
Block a user