2018-12-14 20:49:18 -06:00
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"
2018-12-14 20:49:18 -06:00
"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
2018-12-14 20:49:18 -06:00
type Handle [ handleLen ] byte
2017-12-28 22:16:20 -06:00
2018-12-14 20:49:18 -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
}
2018-12-14 20:49:18 -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
}
2018-12-14 20:49:18 -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
2018-12-14 20:49:18 -06:00
const SigPubKeyLen = ed25519 . PublicKeySize
const SigPrivKeyLen = ed25519 . PrivateKeySize
const SigLen = ed25519 . SignatureSize
2017-12-28 22:16:20 -06:00
2018-12-14 20:49:18 -06:00
type SigPubKey [ SigPubKeyLen ] byte
type SigPrivKey [ SigPrivKeyLen ] byte
type SigBytes [ SigLen ] byte
2017-12-28 22:16:20 -06:00
2018-12-14 20:49:18 -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
}
2018-12-14 20:49:18 -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
}
2018-12-14 20:49:18 -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)
2018-12-14 20:49:18 -06:00
const BoxPubKeyLen = 32
const BoxPrivKeyLen = 32
const BoxSharedKeyLen = 32
const BoxNonceLen = 24
const BoxOverhead = box . Overhead
2017-12-28 22:16:20 -06:00
2018-12-14 20:49:18 -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
2018-12-14 20:49:18 -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 )
}
2018-12-14 20:49:18 -06:00
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
}
2018-12-14 20:49:18 -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 )
2018-12-14 20:49:18 -06:00
return ( * BoxSharedKey ) ( & shared )
2017-12-28 22:16:20 -06:00
}
2018-12-14 20:49:18 -06:00
func BoxOpen ( shared * BoxSharedKey ,
2018-01-04 22:37:51 +00:00
boxed [ ] byte ,
2018-12-14 20:49:18 -06:00
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
}
2018-12-14 20:49:18 -06:00
func BoxSeal ( shared * BoxSharedKey , unboxed [ ] byte , nonce * BoxNonce ) ( [ ] byte , * BoxNonce ) {
2018-01-04 22:37:51 +00:00
if nonce == nil {
2018-12-14 20:49:18 -06:00
nonce = NewBoxNonce ( )
2018-01-04 22:37:51 +00:00
}
2018-12-14 20:49:18 -06: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
}
2018-12-14 20:49:18 -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
}
2018-12-14 20:49:18 -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
}
2018-12-14 20:49:18 -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
}