Skip to content

Commit

Permalink
feat: handshake crypto part + tests
Browse files Browse the repository at this point in the history
rebase: regen go.sum and gen.sum
  • Loading branch information
glouvigny committed Oct 14, 2019
1 parent cb6b22c commit 755d805
Show file tree
Hide file tree
Showing 16 changed files with 2,468 additions and 2 deletions.
13 changes: 13 additions & 0 deletions api/internal/crypto_sigchain.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
syntax = "proto3";

package sigchain;

option go_package = "berty.tech/go/internal/cryptosigchain";

import "internal/crypto_sigchain_entry.proto";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";

message SigChain {
bytes id = 1 [(gogoproto.customname) = "ID"];
repeated SigChainEntry entries = 2;
}
19 changes: 19 additions & 0 deletions api/internal/crypto_sigchain_entry.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
syntax = "proto3";

package sigchain;

option go_package = "berty.tech/go/internal/cryptosigchain";

import "google/protobuf/timestamp.proto";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";

message SigChainEntry {
bytes entry_hash = 1;
uint32 entry_type_code = 2;
bytes parent_entry_hash = 3;
google.protobuf.Timestamp created_at = 4 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
google.protobuf.Timestamp expiring_at = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
bytes signer_public_key_bytes = 6;
bytes subject_public_key_bytes = 7;
bytes signature = 8;
}
2 changes: 2 additions & 0 deletions docs/gen.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions go/gen.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions go/go.mod

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

82 changes: 82 additions & 0 deletions go/go.sum

Large diffs are not rendered by default.

96 changes: 96 additions & 0 deletions go/internal/crypto/crypto.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package crypto

import (
"context"
"errors"

"berty.tech/go/pkg/iface"
sign "github.com/libp2p/go-libp2p-core/crypto"
)

type crypto struct {
privKey sign.PrivKey
sigChain iface.SigChain
store interface{}
}

func (c *crypto) GetSigChainForAccount(accountID []byte) (iface.SigChain, error) {
// TODO:
panic("implement me")
}

func (c *crypto) GetDevicePublicKey() sign.PubKey {
return c.privKey.GetPublic()
}

func (c *crypto) GetAccountPublicKey() (sign.PubKey, error) {
initialEntry := c.sigChain.GetInitialEntry()

if initialEntry.GetEntryType() != iface.SigChainEntryType_INIT_CHAIN {
return nil, errors.New("first sig chain node is invalid")
}

pubKey, err := initialEntry.GetSubject()
if err != nil {
return nil, err
}

return pubKey, nil
}

func (c *crypto) GetPublicRendezvousSeed(ctx context.Context) ([]byte, error) {
// TODO:
panic("implement me")
}

func (c *crypto) GetSigChain() iface.SigChain {
return c.sigChain
}

func (c *crypto) Sign(data []byte) ([]byte, error) {
return c.privKey.Sign(data)
}

func (c *crypto) AddDeviceToOwnSigChain(ctx context.Context, key sign.PubKey) error {
_, err := c.sigChain.AddEntry(c.privKey, key)
return err
}

func (c *crypto) SaveContactSigChain(ctx context.Context, chain iface.SigChain) error {
// TODO:
panic("implement me")
}

func (c *crypto) ResetPublicRendezvousSeed(ctx context.Context) ([]byte, error) {
// TODO:
panic("implement me")
}

func (c *crypto) SetDerivationStatusForGroupMember(ctx context.Context, member iface.CryptoGroupMember, key []byte, counter uint64) error {
// TODO
panic("implement me")
}

func (c *crypto) RegisterEventHandler(ctx context.Context) (chan<- iface.CryptoEvent, error) {
// TODO:
panic("implement me")
}

func (c *crypto) Close() error {
return nil
}

func NewCrypto(store interface{}, privKey sign.PrivKey, sigChain iface.SigChain) iface.Crypto {
c := &crypto{
privKey: privKey,
sigChain: sigChain,
store: store,
}

// TODO:
// c.groups = group.NewGroupsModule(c)

return c
}

var _ iface.Crypto = (*crypto)(nil)
102 changes: 102 additions & 0 deletions go/internal/crypto/crypto_module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package crypto

import (
"context"
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"encoding/binary"
"errors"
"time"

sigchain "berty.tech/go/internal/cryptosigchain"
"berty.tech/go/pkg/iface"
sign "github.com/libp2p/go-libp2p-core/crypto"
)

func InitNewIdentity(ctx context.Context, store interface{}) (iface.Crypto, sign.PrivKey, error) {
if store == nil {
return nil, nil, errors.New("no datastore defined")
}

privKey, err := GeneratePrivateKey()
if err != nil {
return nil, nil, err
}

sigChain, err := InitSigChain(privKey)

return NewCrypto(store, privKey, sigChain), privKey, nil
}

func InitFromOtherDeviceIdentity(ctx context.Context, store interface{} /* other params */) (iface.Crypto, sign.PrivKey, error) {
// TODO:
panic("implement me")
}

func OpenIdentity(ctx context.Context, store interface{}, key sign.PrivKey, chain iface.SigChain) (iface.Crypto, error) {
return NewCrypto(store, key, chain), nil
}

func InitSigChain(key sign.PrivKey) (iface.SigChain, error) {
accountKey, err := GeneratePrivateKey()
if err != nil {
return nil, err
}

sigChain := sigchain.NewSigChain()

_, err = sigChain.Init(accountKey)
if err != nil {
return nil, err
}

_, err = sigChain.AddEntry(accountKey, key.GetPublic())
if err != nil {
return nil, err
}

return sigChain, nil
}

func GeneratePrivateKey() (sign.PrivKey, error) {
key, _, err := sign.GenerateEd25519Key(rand.Reader)
if err != nil {
return nil, err
}

return key, nil
}

func GetCurrentRendezvousPoint(id, seed []byte) ([]byte, error) {
// FIXME: Disabling rendezvous point rotation for now

return GetRendezvousPointForTime(id, seed, time.Unix(0, 0))
// return m.GetRendezvousPointForTime(id, seed, time.Now())
}

func GetRendezvousPointForTime(id, seed []byte, date time.Time) ([]byte, error) {
buf := make([]byte, 32)
mac := hmac.New(sha256.New, seed)
binary.BigEndian.PutUint64(buf, uint64(date.Unix()))

mac.Write(buf)
sum := mac.Sum(nil)

rendezvousPoint := sha256.Sum256(append(id, sum...))

return rendezvousPoint[:], nil
}

func VerifySig(data []byte, sig []byte, key sign.PubKey) error {
ok, err := key.Verify(data, sig)
if err != nil {
return err
}

if !ok {
return errors.New("unable to verify signature")
}

return nil
}
94 changes: 94 additions & 0 deletions go/internal/cryptohandshake/handshake_module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package cryptohandshake

import (
"crypto/rand"
"errors"

"github.com/libp2p/go-libp2p-core/crypto"
sign "github.com/libp2p/go-libp2p-core/crypto"

"golang.org/x/crypto/nacl/box"

"berty.tech/go/pkg/iface"
)

func bytesSliceToArray(slice []byte) (*[32]byte, error) {
var arr [32]byte

if len(slice) != 32 {
return nil, errors.New("invalid key size")
}

for i, c := range slice {
arr[i] = c
}

return &arr, nil
}

func b32Slice(arr *[32]byte) []byte {
var ret = make([]byte, 32)
for i, c := range arr {
ret[i] = c
}

return ret
}

func initHandshake(ownDevicePrivateKey sign.PrivKey, ownSigChain iface.SigChain) (*handshakeSession, error) {
// TODO: make sure to generate the right type of private key
boxPub, boxPriv, err := box.GenerateKey(rand.Reader)
if err != nil {
return nil, err
}

signPriv, _, err := sign.GenerateEd25519Key(rand.Reader)

if err != nil {
return nil, err
}

return &handshakeSession{
ownDevicePrivateKey: ownDevicePrivateKey,
ownSigChain: ownSigChain,
selfBoxPublicKey: boxPub,
selfBoxPrivateKey: boxPriv,
selfSigningPrivateKey: signPriv,
nonce: 0,
}, nil
}

func NewRequest(ownDevicePrivateKey crypto.PrivKey, ownSigChain iface.SigChain, accountToReach crypto.PubKey) (iface.HandshakeSession, error) {
session, err := initHandshake(ownDevicePrivateKey, ownSigChain)
if err != nil {
return nil, err
}

session.setAccountKeyToProve(accountToReach)

return session, nil
}

func NewResponse(ownDevicePrivateKey crypto.PrivKey, ownSigChain iface.SigChain, marshaledSigKey []byte, boxKey []byte) (iface.HandshakeSession, error) {
// TODO: include cipher suite to allow protocol updates?
sigKey, err := sign.UnmarshalPublicKey(marshaledSigKey)
if err != nil {
return nil, err
}

if sigKey.Type() != SupportedKeyType {
return nil, errors.New("unsupported key type")
}

session, err := initHandshake(ownDevicePrivateKey, ownSigChain)
if err != nil {
return nil, err
}

err = session.SetOtherKeys(sigKey, boxKey)
if err != nil {
return nil, err
}

return session, nil
}

0 comments on commit 755d805

Please sign in to comment.