postmoogle/vendor/maunium.net/go/mautrix/crypto/goolm/crypto/ed25519.go

180 lines
6.1 KiB
Go

package crypto
import (
"crypto/ed25519"
"encoding/base64"
"fmt"
"io"
"maunium.net/go/mautrix/crypto/goolm"
"maunium.net/go/mautrix/crypto/goolm/libolmpickle"
"maunium.net/go/mautrix/id"
)
const (
ED25519SignatureSize = ed25519.SignatureSize //The length of a signature
)
// Ed25519GenerateKey creates a new ed25519 key pair. If reader is nil, the random data is taken from crypto/rand.
func Ed25519GenerateKey(reader io.Reader) (Ed25519KeyPair, error) {
publicKey, privateKey, err := ed25519.GenerateKey(reader)
if err != nil {
return Ed25519KeyPair{}, err
}
return Ed25519KeyPair{
PrivateKey: Ed25519PrivateKey(privateKey),
PublicKey: Ed25519PublicKey(publicKey),
}, nil
}
// Ed25519GenerateFromPrivate creates a new ed25519 key pair with the private key given.
func Ed25519GenerateFromPrivate(privKey Ed25519PrivateKey) Ed25519KeyPair {
return Ed25519KeyPair{
PrivateKey: privKey,
PublicKey: privKey.PubKey(),
}
}
// Ed25519GenerateFromSeed creates a new ed25519 key pair with a given seed.
func Ed25519GenerateFromSeed(seed []byte) Ed25519KeyPair {
privKey := Ed25519PrivateKey(ed25519.NewKeyFromSeed(seed))
return Ed25519KeyPair{
PrivateKey: privKey,
PublicKey: privKey.PubKey(),
}
}
// Ed25519KeyPair stores both parts of a ed25519 key.
type Ed25519KeyPair struct {
PrivateKey Ed25519PrivateKey `json:"private,omitempty"`
PublicKey Ed25519PublicKey `json:"public,omitempty"`
}
// B64Encoded returns a base64 encoded string of the public key.
func (c Ed25519KeyPair) B64Encoded() id.Ed25519 {
return id.Ed25519(base64.RawStdEncoding.EncodeToString(c.PublicKey))
}
// Sign returns the signature for the message.
func (c Ed25519KeyPair) Sign(message []byte) []byte {
return c.PrivateKey.Sign(message)
}
// Verify checks the signature of the message against the givenSignature
func (c Ed25519KeyPair) Verify(message, givenSignature []byte) bool {
return c.PublicKey.Verify(message, givenSignature)
}
// PickleLibOlm encodes the key pair into target. target has to have a size of at least PickleLen() and is written to from index 0.
// It returns the number of bytes written.
func (c Ed25519KeyPair) PickleLibOlm(target []byte) (int, error) {
if len(target) < c.PickleLen() {
return 0, fmt.Errorf("pickle ed25519 key pair: %w", goolm.ErrValueTooShort)
}
written, err := c.PublicKey.PickleLibOlm(target)
if err != nil {
return 0, fmt.Errorf("pickle ed25519 key pair: %w", err)
}
if len(c.PrivateKey) != ed25519.PrivateKeySize {
written += libolmpickle.PickleBytes(make([]byte, ed25519.PrivateKeySize), target[written:])
} else {
written += libolmpickle.PickleBytes(c.PrivateKey, target[written:])
}
return written, nil
}
// UnpickleLibOlm decodes the unencryted value and populates the key pair accordingly. It returns the number of bytes read.
func (c *Ed25519KeyPair) UnpickleLibOlm(value []byte) (int, error) {
//unpickle PubKey
read, err := c.PublicKey.UnpickleLibOlm(value)
if err != nil {
return 0, err
}
//unpickle PrivateKey
privKey, readPriv, err := libolmpickle.UnpickleBytes(value[read:], ed25519.PrivateKeySize)
if err != nil {
return read, err
}
c.PrivateKey = privKey
return read + readPriv, nil
}
// PickleLen returns the number of bytes the pickled key pair will have.
func (c Ed25519KeyPair) PickleLen() int {
lenPublic := c.PublicKey.PickleLen()
var lenPrivate int
if len(c.PrivateKey) != ed25519.PrivateKeySize {
lenPrivate = libolmpickle.PickleBytesLen(make([]byte, ed25519.PrivateKeySize))
} else {
lenPrivate = libolmpickle.PickleBytesLen(c.PrivateKey)
}
return lenPublic + lenPrivate
}
// Curve25519PrivateKey represents the private key for ed25519 usage. This is just a wrapper.
type Ed25519PrivateKey ed25519.PrivateKey
// Equal compares the private key to the given private key.
func (c Ed25519PrivateKey) Equal(x Ed25519PrivateKey) bool {
return ed25519.PrivateKey(c).Equal(ed25519.PrivateKey(x))
}
// PubKey returns the public key derived from the private key.
func (c Ed25519PrivateKey) PubKey() Ed25519PublicKey {
publicKey := ed25519.PrivateKey(c).Public()
return Ed25519PublicKey(publicKey.(ed25519.PublicKey))
}
// Sign returns the signature for the message.
func (c Ed25519PrivateKey) Sign(message []byte) []byte {
return ed25519.Sign(ed25519.PrivateKey(c), message)
}
// Ed25519PublicKey represents the public key for ed25519 usage. This is just a wrapper.
type Ed25519PublicKey ed25519.PublicKey
// Equal compares the public key to the given public key.
func (c Ed25519PublicKey) Equal(x Ed25519PublicKey) bool {
return ed25519.PublicKey(c).Equal(ed25519.PublicKey(x))
}
// B64Encoded returns a base64 encoded string of the public key.
func (c Ed25519PublicKey) B64Encoded() id.Curve25519 {
return id.Curve25519(base64.RawStdEncoding.EncodeToString(c))
}
// Verify checks the signature of the message against the givenSignature
func (c Ed25519PublicKey) Verify(message, givenSignature []byte) bool {
return ed25519.Verify(ed25519.PublicKey(c), message, givenSignature)
}
// PickleLibOlm encodes the public key into target. target has to have a size of at least PickleLen() and is written to from index 0.
// It returns the number of bytes written.
func (c Ed25519PublicKey) PickleLibOlm(target []byte) (int, error) {
if len(target) < c.PickleLen() {
return 0, fmt.Errorf("pickle ed25519 public key: %w", goolm.ErrValueTooShort)
}
if len(c) != ed25519.PublicKeySize {
return libolmpickle.PickleBytes(make([]byte, ed25519.PublicKeySize), target), nil
}
return libolmpickle.PickleBytes(c, target), nil
}
// UnpickleLibOlm decodes the unencryted value and populates the public key accordingly. It returns the number of bytes read.
func (c *Ed25519PublicKey) UnpickleLibOlm(value []byte) (int, error) {
unpickled, readBytes, err := libolmpickle.UnpickleBytes(value, ed25519.PublicKeySize)
if err != nil {
return 0, err
}
*c = unpickled
return readBytes, nil
}
// PickleLen returns the number of bytes the pickled public key will have.
func (c Ed25519PublicKey) PickleLen() int {
if len(c) != ed25519.PublicKeySize {
return libolmpickle.PickleBytesLen(make([]byte, ed25519.PublicKeySize))
}
return libolmpickle.PickleBytesLen(c)
}