Ejemplo n.º 1
0
func takeSharedKey(pair *DHKeyPair, opub []byte) []byte {
	g, _ := dhkx.GetGroup(0)
	// Recover Bob's public key
	opubkey := dhkx.NewPublicKey(opub)
	// Compute the key
	k, _ := g.ComputeKey(opubkey, pair.priv)
	// Get the key in the form of []byte
	return k.Bytes()
}
Ejemplo n.º 2
0
func (d *DHEKey) ComputeKey(pub []byte) ([]byte, error) {
	g, _ := dhkx.GetGroup(_DH_GROUP_ID)
	// Recover Bob's public key
	opubkey := dhkx.NewPublicKey(pub)
	// Compute the key
	k, e := g.ComputeKey(opubkey, d.priv)
	if e == nil {
		// Get the key in the form of []byte
		return k.Bytes(), nil
	}
	return nil, e
}
Ejemplo n.º 3
0
func GenerateDHEKey() (k *DHEKey, err error) {
	// Get a group. Use the default one would be enough.
	g, _ := dhkx.GetGroup(_DH_GROUP_ID)
	k = new(DHEKey)
	// Generate a private key from the group.
	// Use the default random number generator.
	k.priv, err = g.GeneratePrivateKey(nil)
	if k.priv != nil {
		// Get the public key from the private key.
		k.pub = k.priv.Bytes()
	}
	return k, err
}
Ejemplo n.º 4
0
func GenerateDHKeyPairs() *DHKeyPair {
	// Get a group. Use the default one would be enough.
	g, _ := dhkx.GetGroup(0)
	pair := new(DHKeyPair)
	// Generate a private key from the group.
	// Use the default random number generator.
	priv, _ := g.GeneratePrivateKey(nil)
	pair.priv = priv
	// Get the public key from the private key.
	pair.pub = priv.Bytes()
	pair.pubLen = make([]byte, 2)
	binary.BigEndian.PutUint16(pair.pubLen, uint16(len(pair.pub)))
	return pair
}
Ejemplo n.º 5
0
// First argument is the algorithm used. "plain" (AlgoPlain) and
// "dh-ietf1024-sha256-aes128-cbc-pkcs7" (AlgoDH) are supported.
//
// The dbus api has the caller supply their DH public key and returns
// the other side's public key, but this implementation generates a
// new keypair, does the exchange, derives the encryption key, and then
// stores it in the returned Session.
func (s Service) OpenSession(algo string, args ...interface{}) (Session, error) {
	// spec: OpenSession(IN String algorithm, IN Variant input, OUT Variant output, OUT ObjectPath result);
	var ret Session
	conn, err := dbus.SessionBus()
	if err != nil {
		return ret, err
	}
	switch algo {
	case AlgoPlain:
		var discard dbus.Variant
		var sessionPath dbus.ObjectPath
		err = s.Call(_ServiceOpenSession, 0, algo, dbus.MakeVariant("")).Store(&discard, &sessionPath)
		if err != nil {
			return ret, err
		}
		ret = Session{conn.Object(ServiceName, sessionPath), algo, nil}
	case AlgoDH:
		// see http://standards.freedesktop.org/secret-service/ch07s03.html
		var sessionPath dbus.ObjectPath
		var srvReply dbus.Variant
		var srvPub []byte
		symKey := make([]byte, aes.BlockSize)
		grp, err := dhkx.GetGroup(2)
		if err != nil {
			return ret, err
		}
		privKey, err := grp.GeneratePrivateKey(rand.Reader)
		if err != nil {
			return ret, err
		}
		err = s.Call(_ServiceOpenSession, 0, algo, dbus.MakeVariant(privKey.Bytes())).Store(&srvReply, &sessionPath)
		if err != nil {
			return ret, err
		}
		srvPub = srvReply.Value().([]byte)
		sharedKey, err := grp.ComputeKey(dhkx.NewPublicKey(srvPub), privKey)
		if err != nil {
			return ret, err
		}
		_, err = io.ReadFull(hkdf.New(sha256.New, sharedKey.Bytes(), nil, nil), symKey)
		ret = Session{conn.Object(ServiceName, sessionPath), algo, symKey}
	default:
		err = InvalidAlgorithm
	}
	return ret, err
}
Ejemplo n.º 6
0
// The authentication here is quite similar with, if not same as, tarsnap's auth algorithm.
//
// First, server generate a Diffie-Hellman public key, dhpub1, sign it with
// server's private key using RSASSA-PSS signing algorithm.
// Send dhpub1, its signature and a nonce to client.
// An nonce is just a sequence of random bytes.
//
// Server -- dhpub1 + sign(dhpub1) + nonce --> Client
//
// Then client generate its own Diffie-Hellman key. It now can calculate
// a key, K, using its own Diffie-Hellman key and server's DH public key.
// (According to DH key exchange algorithm)
//
// Now, we can use K to derive any key we need on server and client side.
// master key, mkey = MGF1(nonce || K, 48)
func ServerKeyExchange(privKey *rsa.PrivateKey, conn net.Conn) (ks *keySet, err error) {
	group, _ := dhkx.GetGroup(dhGroupID)
	priv, _ := group.GeneratePrivateKey(nil)

	mypub := priv.Bytes()
	mypub = leftPaddingZero(mypub, dhPubkeyLen)

	salt := make([]byte, pssSaltLen)
	n, err := io.ReadFull(rand.Reader, salt)
	if err != nil || n != len(salt) {
		err = ErrZeroEntropy
		return
	}

	sha := sha256.New()
	hashed := make([]byte, sha.Size())
	sha.Write([]byte{currentProtocolVersion})
	sha.Write(mypub)
	hashed = sha.Sum(hashed[:0])

	sig, err := pss.SignPSS(rand.Reader, privKey, crypto.SHA256, hashed, salt)
	if err != nil {
		return
	}

	siglen := (privKey.N.BitLen() + 7) / 8
	keyExPkt := make([]byte, dhPubkeyLen+siglen+nonceLen+1)
	keyExPkt[0] = currentProtocolVersion
	copy(keyExPkt[1:], mypub)
	copy(keyExPkt[dhPubkeyLen+1:], sig)
	nonce := keyExPkt[dhPubkeyLen+siglen+1:]
	n, err = io.ReadFull(rand.Reader, nonce)
	if err != nil || n != len(nonce) {
		err = ErrZeroEntropy
		return
	}

	// Send to client:
	// - Server's version (1 byte)
	// - DH public key: g ^ x
	// - Signature of DH public key RSASSA-PSS(version || g ^ x)
	// - nonce
	err = writen(conn, keyExPkt)
	if err != nil {
		return
	}

	// Receive from client:
	// - Client's version (1 byte)
	// - Client's DH public key: g ^ y
	// - HMAC of client's DH public key: HMAC(version || g ^ y, clientAuthKey)
	keyExPkt = keyExPkt[:1+dhPubkeyLen+authKeyLen]

	// Receive the data from client
	n, err = io.ReadFull(conn, keyExPkt)
	if err != nil {
		return
	}
	if n != len(keyExPkt) {
		err = ErrBadKeyExchangePacket
		return
	}

	version := keyExPkt[0]
	if version > currentProtocolVersion {
		err = ErrImcompatibleProtocol
		return
	}
	// First, recover client's DH public key
	clientpub := dhkx.NewPublicKey(keyExPkt[1 : dhPubkeyLen+1])

	// Compute a shared key K.
	K, err := group.ComputeKey(clientpub, priv)
	if err != nil {
		return
	}

	// Generate keys from the shared key
	ks, err = generateKeys(K.Bytes(), nonce)
	if err != nil {
		return
	}

	// Check client's hmac
	err = ks.checkClientHMAC(keyExPkt[:dhPubkeyLen+1], keyExPkt[dhPubkeyLen+1:])
	if err != nil {
		return
	}
	return
}
Ejemplo n.º 7
0
func ClientKeyExchange(pubKey *rsa.PublicKey, conn net.Conn) (ks *keySet, err error) {
	// Receive the data from server, which contains:
	// - version
	// - Server's DH public key: g ^ x
	// - Signature of server's DH public key RSASSA-PSS(g ^ x)
	// - nonce
	siglen := (pubKey.N.BitLen() + 7) / 8
	keyExPkt := make([]byte, dhPubkeyLen+siglen+nonceLen+1)
	n, err := io.ReadFull(conn, keyExPkt)
	if err != nil {
		return
	}
	if n != len(keyExPkt) {
		err = ErrBadKeyExchangePacket
		return
	}

	version := keyExPkt[0]
	if version != currentProtocolVersion {
		err = ErrImcompatibleProtocol
		return
	}

	serverPubData := keyExPkt[1 : dhPubkeyLen+1]
	signature := keyExPkt[dhPubkeyLen+1 : dhPubkeyLen+siglen+1]
	nonce := keyExPkt[dhPubkeyLen+siglen+1:]

	sha := sha256.New()
	hashed := make([]byte, sha.Size())
	sha.Write(keyExPkt[:dhPubkeyLen+1])
	hashed = sha.Sum(hashed[:0])

	// Verify the signature
	err = pss.VerifyPSS(pubKey, crypto.SHA256, hashed, signature, pssSaltLen)

	if err != nil {
		return
	}

	// Generate a DH key
	group, _ := dhkx.GetGroup(dhGroupID)
	priv, _ := group.GeneratePrivateKey(nil)
	mypub := leftPaddingZero(priv.Bytes(), dhPubkeyLen)

	// Generate the shared key from server's DH public key and client DH private key
	serverpub := dhkx.NewPublicKey(serverPubData)
	K, err := group.ComputeKey(serverpub, priv)
	if err != nil {
		return
	}

	ks, err = generateKeys(K.Bytes(), nonce)
	if err != nil {
		return
	}

	keyExPkt = keyExPkt[:1+dhPubkeyLen+authKeyLen]
	keyExPkt[0] = currentProtocolVersion
	copy(keyExPkt[1:], mypub)
	err = ks.clientHMAC(keyExPkt[:dhPubkeyLen+1], keyExPkt[dhPubkeyLen+1:])
	if err != nil {
		return
	}

	// Send the client message to server, which contains:
	// - Protocol version (1 byte)
	// - Client's DH public key: g ^ y
	// - HMAC of client's DH public key: HMAC(g ^ y, clientAuthKey)
	err = writen(conn, keyExPkt)

	return
}