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() }
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 }
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 }
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 }
// 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 }
// 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 }
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 }