diff options
Diffstat (limited to 'vendor/go.mau.fi/libsignal/ecc')
-rw-r--r-- | vendor/go.mau.fi/libsignal/ecc/Curve.go | 109 | ||||
-rw-r--r-- | vendor/go.mau.fi/libsignal/ecc/DjbECPublicKey.go | 29 | ||||
-rw-r--r-- | vendor/go.mau.fi/libsignal/ecc/DkbECPrivateKey.go | 29 | ||||
-rw-r--r-- | vendor/go.mau.fi/libsignal/ecc/Doc.go | 3 | ||||
-rw-r--r-- | vendor/go.mau.fi/libsignal/ecc/ECKeyPair.go | 27 | ||||
-rw-r--r-- | vendor/go.mau.fi/libsignal/ecc/ECPrivateKey.go | 7 | ||||
-rw-r--r-- | vendor/go.mau.fi/libsignal/ecc/ECPublicKey.go | 11 | ||||
-rw-r--r-- | vendor/go.mau.fi/libsignal/ecc/SignCurve25519.go | 97 |
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[:]) +} |