summaryrefslogtreecommitdiffstats
path: root/vendor/go.mau.fi/libsignal/ecc
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/go.mau.fi/libsignal/ecc')
-rw-r--r--vendor/go.mau.fi/libsignal/ecc/Curve.go109
-rw-r--r--vendor/go.mau.fi/libsignal/ecc/DjbECPublicKey.go29
-rw-r--r--vendor/go.mau.fi/libsignal/ecc/DkbECPrivateKey.go29
-rw-r--r--vendor/go.mau.fi/libsignal/ecc/Doc.go3
-rw-r--r--vendor/go.mau.fi/libsignal/ecc/ECKeyPair.go27
-rw-r--r--vendor/go.mau.fi/libsignal/ecc/ECPrivateKey.go7
-rw-r--r--vendor/go.mau.fi/libsignal/ecc/ECPublicKey.go11
-rw-r--r--vendor/go.mau.fi/libsignal/ecc/SignCurve25519.go97
8 files changed, 312 insertions, 0 deletions
diff --git a/vendor/go.mau.fi/libsignal/ecc/Curve.go b/vendor/go.mau.fi/libsignal/ecc/Curve.go
new file mode 100644
index 00000000..f93cc39a
--- /dev/null
+++ b/vendor/go.mau.fi/libsignal/ecc/Curve.go
@@ -0,0 +1,109 @@
+package ecc
+
+import (
+ "crypto/rand"
+ "errors"
+ "fmt"
+ "io"
+
+ "golang.org/x/crypto/curve25519"
+
+ "go.mau.fi/libsignal/logger"
+)
+
+// DjbType is the Diffie-Hellman curve type (curve25519) created by D. J. Bernstein.
+const DjbType = 0x05
+
+var ErrBadKeyType = errors.New("bad key type")
+
+// DecodePoint will take the given bytes and offset and return an ECPublicKeyable object.
+// This is used to check the byte at the given offset in the byte array for a special
+// "type" byte that will determine the key type. Currently only DJB EC keys are supported.
+func DecodePoint(bytes []byte, offset int) (ECPublicKeyable, error) {
+ keyType := bytes[offset] & 0xFF
+
+ switch keyType {
+ case DjbType:
+ keyBytes := [32]byte{}
+ copy(keyBytes[:], bytes[offset+1:])
+ return NewDjbECPublicKey(keyBytes), nil
+ default:
+ return nil, fmt.Errorf("%w %d", ErrBadKeyType, keyType)
+ }
+}
+
+func CreateKeyPair(privateKey []byte) *ECKeyPair {
+ var private, public [32]byte
+ copy(private[:], privateKey)
+
+ private[0] &= 248
+ private[31] &= 127
+ private[31] |= 64
+
+ curve25519.ScalarBaseMult(&public, &private)
+
+ // Put data into our keypair struct
+ djbECPub := NewDjbECPublicKey(public)
+ djbECPriv := NewDjbECPrivateKey(private)
+ keypair := NewECKeyPair(djbECPub, djbECPriv)
+
+ logger.Debug("Returning keypair: ", keypair)
+ return keypair
+}
+
+// GenerateKeyPair returns an EC Key Pair.
+func GenerateKeyPair() (*ECKeyPair, error) {
+ // logger.Debug("Generating EC Key Pair...")
+ // Get cryptographically secure random numbers.
+ random := rand.Reader
+
+ // Create a byte array for our public and private keys.
+ var private, public [32]byte
+
+ // Generate some random data
+ _, err := io.ReadFull(random, private[:])
+ if err != nil {
+ return nil, err
+ }
+
+ // Documented at: http://cr.yp.to/ecdh.html
+ private[0] &= 248
+ private[31] &= 127
+ private[31] |= 64
+
+ curve25519.ScalarBaseMult(&public, &private)
+
+ // Put data into our keypair struct
+ djbECPub := NewDjbECPublicKey(public)
+ djbECPriv := NewDjbECPrivateKey(private)
+ keypair := NewECKeyPair(djbECPub, djbECPriv)
+
+ // logger.Debug("Returning keypair: ", keypair)
+
+ return keypair, nil
+}
+
+// VerifySignature verifies that the message was signed with the given key.
+func VerifySignature(signingKey ECPublicKeyable, message []byte, signature [64]byte) bool {
+ logger.Debug("Verifying signature of bytes: ", message)
+ publicKey := signingKey.PublicKey()
+ valid := verify(publicKey, message, &signature)
+ logger.Debug("Signature valid: ", valid)
+ return valid
+}
+
+// CalculateSignature signs a message with the given private key.
+func CalculateSignature(signingKey ECPrivateKeyable, message []byte) [64]byte {
+ logger.Debug("Signing bytes with signing key")
+ // Get cryptographically secure random numbers.
+ var random [64]byte
+ r := rand.Reader
+ io.ReadFull(r, random[:])
+
+ // Get the private key.
+ privateKey := signingKey.Serialize()
+
+ // Sign the message.
+ signature := sign(&privateKey, message, random)
+ return *signature
+}
diff --git a/vendor/go.mau.fi/libsignal/ecc/DjbECPublicKey.go b/vendor/go.mau.fi/libsignal/ecc/DjbECPublicKey.go
new file mode 100644
index 00000000..11757fb4
--- /dev/null
+++ b/vendor/go.mau.fi/libsignal/ecc/DjbECPublicKey.go
@@ -0,0 +1,29 @@
+package ecc
+
+// NewDjbECPublicKey creates a new Curve25519 public key with the given bytes.
+func NewDjbECPublicKey(publicKey [32]byte) *DjbECPublicKey {
+ key := DjbECPublicKey{
+ publicKey: publicKey,
+ }
+ return &key
+}
+
+// DjbECPublicKey implements the ECPublicKey interface and uses Curve25519.
+type DjbECPublicKey struct {
+ publicKey [32]byte
+}
+
+// PublicKey returns the EC public key as a byte array.
+func (d *DjbECPublicKey) PublicKey() [32]byte {
+ return d.publicKey
+}
+
+// Serialize returns the public key prepended by the DjbType value.
+func (d *DjbECPublicKey) Serialize() []byte {
+ return append([]byte{DjbType}, d.publicKey[:]...)
+}
+
+// Type returns the DjbType value.
+func (d *DjbECPublicKey) Type() int {
+ return DjbType
+}
diff --git a/vendor/go.mau.fi/libsignal/ecc/DkbECPrivateKey.go b/vendor/go.mau.fi/libsignal/ecc/DkbECPrivateKey.go
new file mode 100644
index 00000000..055692ca
--- /dev/null
+++ b/vendor/go.mau.fi/libsignal/ecc/DkbECPrivateKey.go
@@ -0,0 +1,29 @@
+package ecc
+
+// NewDjbECPrivateKey returns a new EC private key with the given bytes.
+func NewDjbECPrivateKey(key [32]byte) *DjbECPrivateKey {
+ private := DjbECPrivateKey{
+ privateKey: key,
+ }
+ return &private
+}
+
+// DjbECPrivateKey implements the ECPrivateKey interface and uses Curve25519.
+type DjbECPrivateKey struct {
+ privateKey [32]byte
+}
+
+// PrivateKey returns the private key as a byte-array.
+func (d *DjbECPrivateKey) PrivateKey() [32]byte {
+ return d.privateKey
+}
+
+// Serialize returns the private key as a byte-array.
+func (d *DjbECPrivateKey) Serialize() [32]byte {
+ return d.privateKey
+}
+
+// Type returns the EC type value.
+func (d *DjbECPrivateKey) Type() int {
+ return DjbType
+}
diff --git a/vendor/go.mau.fi/libsignal/ecc/Doc.go b/vendor/go.mau.fi/libsignal/ecc/Doc.go
new file mode 100644
index 00000000..06e2cac7
--- /dev/null
+++ b/vendor/go.mau.fi/libsignal/ecc/Doc.go
@@ -0,0 +1,3 @@
+// Package ecc provides a way to generate, sign, and use Elliptic-Curve
+// X25519 Cryptography keys.
+package ecc
diff --git a/vendor/go.mau.fi/libsignal/ecc/ECKeyPair.go b/vendor/go.mau.fi/libsignal/ecc/ECKeyPair.go
new file mode 100644
index 00000000..11103447
--- /dev/null
+++ b/vendor/go.mau.fi/libsignal/ecc/ECKeyPair.go
@@ -0,0 +1,27 @@
+package ecc
+
+// NewECKeyPair returns a new elliptic curve keypair given the specified public and private keys.
+func NewECKeyPair(publicKey ECPublicKeyable, privateKey ECPrivateKeyable) *ECKeyPair {
+ keypair := ECKeyPair{
+ publicKey: publicKey,
+ privateKey: privateKey,
+ }
+
+ return &keypair
+}
+
+// ECKeyPair is a combination of both public and private elliptic curve keys.
+type ECKeyPair struct {
+ publicKey ECPublicKeyable
+ privateKey ECPrivateKeyable
+}
+
+// PublicKey returns the public key from the key pair.
+func (e *ECKeyPair) PublicKey() ECPublicKeyable {
+ return e.publicKey
+}
+
+// PrivateKey returns the private key from the key pair.
+func (e *ECKeyPair) PrivateKey() ECPrivateKeyable {
+ return e.privateKey
+}
diff --git a/vendor/go.mau.fi/libsignal/ecc/ECPrivateKey.go b/vendor/go.mau.fi/libsignal/ecc/ECPrivateKey.go
new file mode 100644
index 00000000..be3ddae5
--- /dev/null
+++ b/vendor/go.mau.fi/libsignal/ecc/ECPrivateKey.go
@@ -0,0 +1,7 @@
+package ecc
+
+// ECPrivateKeyable is an interface for all elliptic curve private keys.
+type ECPrivateKeyable interface {
+ Serialize() [32]byte
+ Type() int
+}
diff --git a/vendor/go.mau.fi/libsignal/ecc/ECPublicKey.go b/vendor/go.mau.fi/libsignal/ecc/ECPublicKey.go
new file mode 100644
index 00000000..9b71f050
--- /dev/null
+++ b/vendor/go.mau.fi/libsignal/ecc/ECPublicKey.go
@@ -0,0 +1,11 @@
+package ecc
+
+// KeySize is the size of EC keys (32) with the EC type byte prepended to it.
+const KeySize int = 33
+
+// ECPublicKeyable is an interface for all elliptic curve public keys.
+type ECPublicKeyable interface {
+ Serialize() []byte
+ Type() int
+ PublicKey() [32]byte
+}
diff --git a/vendor/go.mau.fi/libsignal/ecc/SignCurve25519.go b/vendor/go.mau.fi/libsignal/ecc/SignCurve25519.go
new file mode 100644
index 00000000..a9bd7b48
--- /dev/null
+++ b/vendor/go.mau.fi/libsignal/ecc/SignCurve25519.go
@@ -0,0 +1,97 @@
+package ecc
+
+// Package curve25519sign implements a signature scheme based on Curve25519 keys.
+// See https://moderncrypto.org/mail-archive/curves/2014/000205.html for details.
+
+import (
+ "crypto/ed25519"
+ "crypto/sha512"
+
+ "filippo.io/edwards25519"
+ "filippo.io/edwards25519/field"
+)
+
+// sign signs the message with privateKey and returns a signature as a byte slice.
+func sign(privateKey *[32]byte, message []byte, random [64]byte) *[64]byte {
+
+ // Calculate Ed25519 public key from Curve25519 private key
+ var A edwards25519.Point
+ privateKeyScalar, _ := edwards25519.NewScalar().SetBytesWithClamping(privateKey[:])
+ A.ScalarBaseMult(privateKeyScalar)
+ publicKey := *(*[32]byte)(A.Bytes())
+
+ // Calculate r
+ diversifier := [32]byte{
+ 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
+
+ var r [64]byte
+ hash := sha512.New()
+ hash.Write(diversifier[:])
+ hash.Write(privateKey[:])
+ hash.Write(message)
+ hash.Write(random[:])
+ hash.Sum(r[:0])
+
+ // Calculate R
+ var rReduced *edwards25519.Scalar
+ rReduced, _ = edwards25519.NewScalar().SetUniformBytes(r[:])
+ var R edwards25519.Point
+ R.ScalarBaseMult(rReduced)
+
+ var encodedR [32]byte
+ encodedR = *(*[32]byte)(R.Bytes())
+
+ // Calculate S = r + SHA2-512(R || A_ed || msg) * a (mod L)
+ var hramDigest [64]byte
+ hash.Reset()
+ hash.Write(encodedR[:])
+ hash.Write(publicKey[:])
+ hash.Write(message)
+ hash.Sum(hramDigest[:0])
+ hramDigestReduced, _ := edwards25519.NewScalar().SetUniformBytes(hramDigest[:])
+
+ sScalar := edwards25519.NewScalar().MultiplyAdd(hramDigestReduced, privateKeyScalar, rReduced)
+ s := *(*[32]byte)(sScalar.Bytes())
+
+ signature := new([64]byte)
+ copy(signature[:], encodedR[:])
+ copy(signature[32:], s[:])
+ signature[63] |= publicKey[31] & 0x80
+
+ return signature
+}
+
+// verify checks whether the message has a valid signature.
+func verify(publicKey [32]byte, message []byte, signature *[64]byte) bool {
+
+ publicKey[31] &= 0x7F
+
+ /* Convert the Curve25519 public key into an Ed25519 public key. In
+ particular, convert Curve25519's "montgomery" x-coordinate into an
+ Ed25519 "edwards" y-coordinate:
+
+ ed_y = (mont_x - 1) / (mont_x + 1)
+
+ NOTE: mont_x=-1 is converted to ed_y=0 since fe_invert is mod-exp
+
+ Then move the sign bit into the pubkey from the signature.
+ */
+
+ var edY, one, montX, montXMinusOne, montXPlusOne field.Element
+ _, _ = montX.SetBytes(publicKey[:])
+ _ = one.One()
+ montXMinusOne.Subtract(&montX, &one)
+ montXPlusOne.Add(&montX, &one)
+ montXPlusOne.Invert(&montXPlusOne)
+ edY.Multiply(&montXMinusOne, &montXPlusOne)
+
+ A_ed := *(*[32]byte)(edY.Bytes())
+
+ A_ed[31] |= signature[63] & 0x80
+ signature[63] &= 0x7F
+
+ return ed25519.Verify(A_ed[:], message, signature[:])
+}