Added clean implementation of ECDH for curve25519
This commit is contained in:
@@ -2,7 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -189,7 +188,7 @@ func Version() string {
|
||||
Patch,
|
||||
)
|
||||
path := filepath.Join(PathBase, "version.go")
|
||||
if e = ioutil.WriteFile(path, []byte(versionFileOut),
|
||||
if e = os.WriteFile(path, []byte(versionFileOut),
|
||||
0666); log.E.Chk(e) {
|
||||
fmt.Println(e)
|
||||
}
|
||||
|
||||
12
go.mod
12
go.mod
@@ -1,9 +1,10 @@
|
||||
module github.com/Indra-Labs/indranet
|
||||
module github.com/Indra-Labs/indra
|
||||
|
||||
go 1.18
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/cybriq/proc v0.1.33
|
||||
github.com/cybriq/proc v0.2.0
|
||||
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1
|
||||
)
|
||||
|
||||
@@ -18,9 +19,8 @@ require (
|
||||
github.com/src-d/gcfg v1.4.0 // indirect
|
||||
github.com/xanzy/ssh-agent v0.2.1 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 // indirect
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 // indirect
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 // indirect
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
)
|
||||
|
||||
16
go.sum
16
go.sum
@@ -5,8 +5,8 @@ github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYU
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/cybriq/proc v0.1.33 h1:sGEcCjrC7oJ2skIRyOwM6KHztTV1m3Q4fEfOJhIQmSc=
|
||||
github.com/cybriq/proc v0.1.33/go.mod h1:b6JDUUwfe8soxWzvAziWA/msrb73O2v6gZEQL+wHYx8=
|
||||
github.com/cybriq/proc v0.2.0 h1:oemzeS1eXBX0OZZk0U5MXe+BzSvF/pQyPZ8Rt3jIc/U=
|
||||
github.com/cybriq/proc v0.2.0/go.mod h1:b6JDUUwfe8soxWzvAziWA/msrb73O2v6gZEQL+wHYx8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -52,22 +52,26 @@ github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHg
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
|
||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b h1:huxqepDufQpLLIRXiVkTvnxrzJlpwmIWAObmcCcUFr0=
|
||||
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
82
pkg/ciph/gcm.go
Normal file
82
pkg/ciph/gcm.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package ciph
|
||||
|
||||
//
|
||||
// import (
|
||||
// "crypto/aes"
|
||||
// "crypto/cipher"
|
||||
// "crypto/rand"
|
||||
// "encoding/hex"
|
||||
// "errors"
|
||||
// "fmt"
|
||||
// "io"
|
||||
//
|
||||
// "golang.org/x/crypto/argon2"
|
||||
// )
|
||||
//
|
||||
// // Get returns a GCM cipher given a password string. Note that this cipher
|
||||
// // must be renewed every 4gb of encrypted data as it is GCM.
|
||||
// func Get(password []byte) (gcm cipher.AEAD, e error) {
|
||||
// bytes := make([]byte, len(password))
|
||||
// rb := make([]byte, len(password))
|
||||
// copy(bytes, password)
|
||||
// copy(rb, password)
|
||||
// var c cipher.Block
|
||||
// ark := argon2.IDKey(rb, bytes, 1, 64*1024, 4, 32)
|
||||
// if c, e = aes.NewCipher(ark); log.E.Chk(e) {
|
||||
// return
|
||||
// }
|
||||
// if gcm, e = cipher.NewGCM(c); log.E.Chk(e) {
|
||||
// }
|
||||
// for i := range bytes {
|
||||
// bytes[i] = 0
|
||||
// rb[i] = 0
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // DecryptMessage attempts to decode the received message
|
||||
// func DecryptMessage(creator string, ciph cipher.AEAD, data []byte) (
|
||||
// msg []byte,
|
||||
// e error,
|
||||
// ) {
|
||||
// nonceSize := ciph.NonceSize()
|
||||
// msg, e = ciph.Open(nil, data[:nonceSize], data[nonceSize:], nil)
|
||||
// if e != nil {
|
||||
// e = errors.New(fmt.Sprintf("%s %s", creator, e.Error()))
|
||||
// } else {
|
||||
// log.D.Ln("decrypted message", hex.EncodeToString(data[:nonceSize]))
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // EncryptMessage encrypts a message, if the nonce is given it uses that
|
||||
// // otherwise it generates a new one. If there is no cipher this just returns a
|
||||
// // message with the given magic prepended.
|
||||
// func EncryptMessage(
|
||||
// creator string,
|
||||
// ciph cipher.AEAD,
|
||||
// magic []byte,
|
||||
// nonce, data []byte,
|
||||
// ) (msg []byte, e error) {
|
||||
// if ciph != nil {
|
||||
// if nonce == nil {
|
||||
// nonce, e = GetNonce(ciph)
|
||||
// }
|
||||
// msg = append(
|
||||
// append(magic, nonce...),
|
||||
// ciph.Seal(nil, nonce, data, nil)...,
|
||||
// )
|
||||
// } else {
|
||||
// msg = append(magic, data...)
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // GetNonce reads from a cryptographically secure random number source
|
||||
// func GetNonce(ciph cipher.AEAD) (nonce []byte, e error) {
|
||||
// // get a nonce for the packet, it is both message ID and salt
|
||||
// nonce = make([]byte, ciph.NonceSize())
|
||||
// if _, e = io.ReadFull(rand.Reader, nonce); log.E.Chk(e) {
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
8
pkg/ciph/log.go
Normal file
8
pkg/ciph/log.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package ciph
|
||||
|
||||
import (
|
||||
"github.com/cybriq/proc"
|
||||
log2 "github.com/cybriq/proc/pkg/log"
|
||||
)
|
||||
|
||||
var log = log2.GetLogger(proc.PathBase)
|
||||
113
pkg/ecdh/ecdh.go
Normal file
113
pkg/ecdh/ecdh.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package ecdh
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/crypto/curve25519"
|
||||
)
|
||||
|
||||
// Keysize is the size of both Privkey and Pubkey for ECDH
|
||||
const Keysize = 32
|
||||
|
||||
// Privkey is a private key for use with ECDH
|
||||
type Privkey [Keysize]byte
|
||||
|
||||
// Pubkey is a public key generated via curve25519.ScalarBaseMult
|
||||
type Pubkey [Keysize]byte
|
||||
|
||||
// Keypair is pointers to a private and public key bundled into a struct
|
||||
type Keypair struct {
|
||||
*Privkey
|
||||
*Pubkey
|
||||
}
|
||||
|
||||
// KeySizeError indicates a provided slice of bytes is the wrong length
|
||||
var KeySizeError error = fmt.Errorf("key length must be precisely %d bytes",
|
||||
Keysize)
|
||||
|
||||
func GeneratePrivkey() (prv *Privkey, err error) {
|
||||
var pk [32]byte
|
||||
_, err = rand.Read(pk[:])
|
||||
if log.E.Chk(err) {
|
||||
return
|
||||
}
|
||||
pk[0] &= 248
|
||||
pk[31] &= 127
|
||||
pk[31] |= 64
|
||||
pr := Privkey(pk)
|
||||
prv = &pr
|
||||
return
|
||||
}
|
||||
|
||||
func (prv Privkey) GeneratePubkey() (pub *Pubkey) {
|
||||
var dst [32]byte
|
||||
curve25519.ScalarBaseMult(&dst, (*[32]byte)(&prv))
|
||||
pu := Pubkey(dst)
|
||||
pub = &pu
|
||||
return
|
||||
}
|
||||
|
||||
func (prv Privkey) ToBytes() (b []byte) {
|
||||
b = make([]byte, Keysize)
|
||||
copy(b, prv[:])
|
||||
return
|
||||
}
|
||||
|
||||
func (pub Pubkey) ToBytes() (b []byte) {
|
||||
b = make([]byte, Keysize)
|
||||
copy(b, pub[:])
|
||||
return
|
||||
}
|
||||
|
||||
func PrivkeyFromBytes(b []byte) (prv *Privkey, err error) {
|
||||
if len(b) != Keysize {
|
||||
err = KeySizeError
|
||||
return
|
||||
}
|
||||
var k [Keysize]byte
|
||||
copy(k[:], b)
|
||||
prv = (*Privkey)(&k)
|
||||
return
|
||||
}
|
||||
|
||||
func PubkeyFromBytes(b []byte) (pub *Pubkey, err error) {
|
||||
if len(b) != Keysize {
|
||||
err = KeySizeError
|
||||
return
|
||||
}
|
||||
var k [Keysize]byte
|
||||
copy(k[:], b)
|
||||
pub = (*Pubkey)(&k)
|
||||
return
|
||||
}
|
||||
|
||||
// GenerateKeypair generates a new curve25519 private/public key pair.
|
||||
func GenerateKeypair() (keypair Keypair, err error) {
|
||||
if keypair.Privkey, err = GeneratePrivkey(); log.E.Chk(err) {
|
||||
return
|
||||
}
|
||||
keypair.Pubkey = keypair.Privkey.GeneratePubkey()
|
||||
return
|
||||
}
|
||||
|
||||
// KeypairFromPrivkeyBytes generates a Keypair from raw bytes
|
||||
func KeypairFromPrivkeyBytes(b []byte) (keypair *Keypair, err error) {
|
||||
keypair = &Keypair{}
|
||||
if keypair.Privkey, err = PrivkeyFromBytes(b); log.E.Chk(err) {
|
||||
return
|
||||
}
|
||||
keypair.Pubkey = keypair.Privkey.GeneratePubkey()
|
||||
return
|
||||
}
|
||||
|
||||
// ComputeSecret uses a Keypair and a Pubkey to generate a secret to use in
|
||||
// encryption. This formula generates the same value from one private to another
|
||||
// public key as the public key of the first with the private key from the
|
||||
// second. Thus neither party must send a secret over the network.
|
||||
func (kp Privkey) ComputeSecret(p *Pubkey) (sec []byte, err error) {
|
||||
pub := [Keysize]byte(*p)
|
||||
if sec, err = curve25519.X25519(kp[:], pub[:]); log.E.Chk(err) {
|
||||
}
|
||||
return
|
||||
}
|
||||
27
pkg/ecdh/ecdh_test.go
Normal file
27
pkg/ecdh/ecdh_test.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package ecdh
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestComputeSecret(t *testing.T) {
|
||||
var err error
|
||||
var kp1, kp2 Keypair
|
||||
if kp1, err = GenerateKeypair(); log.E.Chk(err) {
|
||||
t.Error(err)
|
||||
}
|
||||
if kp2, err = GenerateKeypair(); log.E.Chk(err) {
|
||||
t.Error(err)
|
||||
}
|
||||
var sec1, sec2 []byte
|
||||
if sec1, err = kp1.ComputeSecret(kp2.Pubkey); log.E.Chk(err) {
|
||||
t.Error(err)
|
||||
}
|
||||
if sec2, err = kp2.ComputeSecret(kp1.Pubkey); log.E.Chk(err) {
|
||||
t.Error(err)
|
||||
}
|
||||
if bytes.Compare(sec1, sec2) != 0 {
|
||||
t.Error("secrets do not match")
|
||||
}
|
||||
}
|
||||
8
pkg/ecdh/log.go
Normal file
8
pkg/ecdh/log.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package ecdh
|
||||
|
||||
import (
|
||||
"github.com/cybriq/proc"
|
||||
log2 "github.com/cybriq/proc/pkg/log"
|
||||
)
|
||||
|
||||
var log = log2.GetLogger(proc.PathBase)
|
||||
15
pkg/message/encryption.go
Normal file
15
pkg/message/encryption.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package message
|
||||
|
||||
type Initial struct {
|
||||
PubKey []byte
|
||||
Nonce []byte
|
||||
Message []byte
|
||||
Signature []byte
|
||||
}
|
||||
|
||||
type Subsequent struct {
|
||||
Fingerprint []byte
|
||||
Nonce []byte
|
||||
Message []byte
|
||||
Signature []byte
|
||||
}
|
||||
8
pkg/router/log.go
Normal file
8
pkg/router/log.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/cybriq/proc"
|
||||
log2 "github.com/cybriq/proc/pkg/log"
|
||||
)
|
||||
|
||||
var log = log2.GetLogger(proc.PathBase)
|
||||
@@ -1,17 +0,0 @@
|
||||
package router
|
||||
|
||||
import "github.com/luke-park/ecdh25519"
|
||||
|
||||
type Router struct {
|
||||
priv *ecdh25519.PrivateKey
|
||||
*ecdh25519.PublicKey
|
||||
}
|
||||
|
||||
func New() (r *Router, err error) {
|
||||
priv, err := ecdh25519.GenerateKey()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r = &Router{priv: priv, PublicKey: priv.Public()}
|
||||
return
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package router
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
|
||||
}
|
||||
@@ -10,11 +10,11 @@ var (
|
||||
// GitRef is the gitref, as in refs/heads/branchname.
|
||||
GitRef = "refs/heads/main"
|
||||
// ParentGitCommit is the commit hash of the parent HEAD.
|
||||
ParentGitCommit = "58afc076f1599275e82e0eb9af24c0a603d442af"
|
||||
ParentGitCommit = "20fb60055de15a67fdf7ee18cde0306511f842af"
|
||||
// BuildTime stores the time when the current binary was built.
|
||||
BuildTime = "2022-09-29T20:50:01+02:00"
|
||||
BuildTime = "2022-10-05T12:43:02+02:00"
|
||||
// SemVer lists the (latest) git tag on the build.
|
||||
SemVer = "v0.0.38"
|
||||
SemVer = "v0.0.39"
|
||||
// PathBase is the path base returned from runtime caller.
|
||||
PathBase = "/home/loki/src/github.com/Indra-Labs/indra/"
|
||||
// Major is the major number from the tag.
|
||||
@@ -22,7 +22,7 @@ var (
|
||||
// Minor is the minor number from the tag.
|
||||
Minor = 0
|
||||
// Patch is the patch version number from the tag.
|
||||
Patch = 38
|
||||
Patch = 39
|
||||
)
|
||||
|
||||
// Version returns a pretty printed version information string.
|
||||
|
||||
Reference in New Issue
Block a user