yggdrasil-go/src/crypto/crypto.go

188 lines
4.4 KiB
Go
Raw Normal View History

package crypto
2017-12-28 22:16:20 -06:00
/*
This part of the package wraps crypto operations needed elsewhere
In particular, it exposes key generation for ed25519 and nacl box
It also defines NodeID and TreeID as hashes of keys, and wraps hash functions
*/
2018-06-12 17:50:08 -05:00
import (
"crypto/rand"
"crypto/sha512"
"golang.org/x/crypto/ed25519"
"golang.org/x/crypto/nacl/box"
"github.com/yggdrasil-network/yggdrasil-go/src/util"
2018-06-12 17:50:08 -05:00
)
2017-12-28 22:16:20 -06:00
////////////////////////////////////////////////////////////////////////////////
// NodeID and TreeID
const NodeIDLen = sha512.Size
const TreeIDLen = sha512.Size
const handleLen = 8
type NodeID [NodeIDLen]byte
type TreeID [TreeIDLen]byte
type Handle [handleLen]byte
2017-12-28 22:16:20 -06:00
func GetNodeID(pub *BoxPubKey) *NodeID {
2018-01-04 22:37:51 +00:00
h := sha512.Sum512(pub[:])
return (*NodeID)(&h)
2017-12-28 22:16:20 -06:00
}
func GetTreeID(pub *SigPubKey) *TreeID {
2018-01-04 22:37:51 +00:00
h := sha512.Sum512(pub[:])
return (*TreeID)(&h)
2017-12-28 22:16:20 -06:00
}
func NewHandle() *Handle {
var h Handle
2018-01-04 22:37:51 +00:00
_, err := rand.Read(h[:])
if err != nil {
panic(err)
}
return &h
2017-12-28 22:16:20 -06:00
}
////////////////////////////////////////////////////////////////////////////////
// Signatures
const SigPubKeyLen = ed25519.PublicKeySize
const SigPrivKeyLen = ed25519.PrivateKeySize
const SigLen = ed25519.SignatureSize
2017-12-28 22:16:20 -06:00
type SigPubKey [SigPubKeyLen]byte
type SigPrivKey [SigPrivKeyLen]byte
type SigBytes [SigLen]byte
2017-12-28 22:16:20 -06:00
func NewSigKeys() (*SigPubKey, *SigPrivKey) {
var pub SigPubKey
var priv SigPrivKey
2018-01-04 22:37:51 +00:00
pubSlice, privSlice, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
copy(pub[:], pubSlice)
copy(priv[:], privSlice)
return &pub, &priv
2017-12-28 22:16:20 -06:00
}
func Sign(priv *SigPrivKey, msg []byte) *SigBytes {
var sig SigBytes
2018-01-04 22:37:51 +00:00
sigSlice := ed25519.Sign(priv[:], msg)
copy(sig[:], sigSlice)
return &sig
2017-12-28 22:16:20 -06:00
}
func Verify(pub *SigPubKey, msg []byte, sig *SigBytes) bool {
2018-01-04 22:37:51 +00:00
// Should sig be an array instead of a slice?...
// It's fixed size, but
return ed25519.Verify(pub[:], msg, sig[:])
2017-12-28 22:16:20 -06:00
}
////////////////////////////////////////////////////////////////////////////////
// NaCl-like crypto "box" (curve25519+xsalsa20+poly1305)
const BoxPubKeyLen = 32
const BoxPrivKeyLen = 32
const BoxSharedKeyLen = 32
const BoxNonceLen = 24
const BoxOverhead = box.Overhead
2017-12-28 22:16:20 -06:00
type BoxPubKey [BoxPubKeyLen]byte
type BoxPrivKey [BoxPrivKeyLen]byte
type BoxSharedKey [BoxSharedKeyLen]byte
type BoxNonce [BoxNonceLen]byte
2017-12-28 22:16:20 -06:00
func NewBoxKeys() (*BoxPubKey, *BoxPrivKey) {
2018-01-04 22:37:51 +00:00
pubBytes, privBytes, err := box.GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
pub := (*BoxPubKey)(pubBytes)
priv := (*BoxPrivKey)(privBytes)
2018-01-04 22:37:51 +00:00
return pub, priv
2017-12-28 22:16:20 -06:00
}
func GetSharedKey(myPrivKey *BoxPrivKey,
othersPubKey *BoxPubKey) *BoxSharedKey {
var shared [BoxSharedKeyLen]byte
priv := (*[BoxPrivKeyLen]byte)(myPrivKey)
pub := (*[BoxPubKeyLen]byte)(othersPubKey)
2018-01-04 22:37:51 +00:00
box.Precompute(&shared, pub, priv)
return (*BoxSharedKey)(&shared)
2017-12-28 22:16:20 -06:00
}
func BoxOpen(shared *BoxSharedKey,
2018-01-04 22:37:51 +00:00
boxed []byte,
nonce *BoxNonce) ([]byte, bool) {
out := util.GetBytes()
s := (*[BoxSharedKeyLen]byte)(shared)
n := (*[BoxNonceLen]byte)(nonce)
2018-01-04 22:37:51 +00:00
unboxed, success := box.OpenAfterPrecomputation(out, boxed, n, s)
return unboxed, success
2017-12-28 22:16:20 -06:00
}
func BoxSeal(shared *BoxSharedKey, unboxed []byte, nonce *BoxNonce) ([]byte, *BoxNonce) {
2018-01-04 22:37:51 +00:00
if nonce == nil {
nonce = NewBoxNonce()
2018-01-04 22:37:51 +00:00
}
nonce.Increment()
out := util.GetBytes()
s := (*[BoxSharedKeyLen]byte)(shared)
n := (*[BoxNonceLen]byte)(nonce)
2018-01-04 22:37:51 +00:00
boxed := box.SealAfterPrecomputation(out, unboxed, n, s)
return boxed, nonce
2017-12-28 22:16:20 -06:00
}
func NewBoxNonce() *BoxNonce {
var nonce BoxNonce
2018-01-04 22:37:51 +00:00
_, err := rand.Read(nonce[:])
for ; err == nil && nonce[0] == 0xff; _, err = rand.Read(nonce[:]) {
// Make sure nonce isn't too high
// This is just to make rollover unlikely to happen
// Rollover is fine, but it may kill the session and force it to reopen
}
if err != nil {
panic(err)
}
return &nonce
2017-12-28 22:16:20 -06:00
}
func (n *BoxNonce) Increment() {
2018-01-04 22:37:51 +00:00
oldNonce := *n
n[len(n)-1] += 2
for i := len(n) - 2; i >= 0; i-- {
if n[i+1] < oldNonce[i+1] {
n[i] += 1
}
}
2017-12-28 22:16:20 -06:00
}
// Used to subtract one nonce from another, staying in the range +- 64.
// This is used by the nonce progression machinery to advance the bitmask of recently received packets (indexed by nonce), or to check the appropriate bit of the bitmask.
// It's basically part of the machinery that prevents replays and duplicate packets.
func (n *BoxNonce) Minus(m *BoxNonce) int64 {
diff := int64(0)
for idx := range n {
diff *= 256
diff += int64(n[idx]) - int64(m[idx])
if diff > 64 {
diff = 64
}
if diff < -64 {
diff = -64
}
}
return diff
}