sts

package
v0.3.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 4, 2014 License: GPL-3.0-or-later Imports: 8 Imported by: 0

Documentation

Overview

Package sts implements the Station-to-station (STS) key exchange protocol.

Wikipedia: http://en.wikipedia.org/wiki/Station-to-Station_protocol
Diagram: http://goo.gl/5EiDV

Although STS is a generic key exchange protocol, some assumptions were hard coded into the implementation:

The asymmetric signature algorithm is RSA
The symmetric encryption uses CTR mode
The stream crypto key and IV are expanded with HKDF from the master key

The cryptographic strength of the protocol is based on the analysis of the general number field sieve algorithm, it being the fastest factoring method till now. Matching STS bit sizes to AES (approx!):

AES-128: 2248 bits
AES-192: 5912 bits
AES-256: 11920 bits
Example (Usage)

Full STS communication example illustrated with two concurrent Go routines agreeing on a master key.

// Iris - Decentralized cloud messaging
// Copyright (c) 2013 Project Iris. All rights reserved.
//
// Iris is dual licensed: you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later
// version.
//
// The framework is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
// more details.
//
// Alternatively, the Iris framework may be used in accordance with the terms
// and conditions contained in a signed written agreement between you and the
// author(s).

package main

import (
	"bytes"
	"crypto"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"crypto/rsa"
	_ "crypto/sha1"
	"fmt"
	"math/big"

	"github.com/project-iris/iris/crypto/sts"
)

// Full STS communication example illustrated with two concurrent Go routines agreeing on a master key.
func main() {
	// STS cyclic group parameters, global for the app (small examples, not secure!)
	group := big.NewInt(3910779947)
	generator := big.NewInt(1213725007)

	// STS encryption parameters
	cipher := aes.NewCipher
	bits := 128
	hash := crypto.SHA1

	// RSA key-pairs for the communicating parties, obtained from somewhere else (no error checks)
	iniKey, _ := rsa.GenerateKey(rand.Reader, 1024)
	accKey, _ := rsa.GenerateKey(rand.Reader, 1024)

	// Start two Go routines: one initiator and one acceptor communicating on a channel
	transport := make(chan []byte)
	iniOut := make(chan []byte)
	accOut := make(chan []byte)

	go initiator(group, generator, cipher, bits, hash, iniKey, &accKey.PublicKey, transport, iniOut)
	go acceptor(group, generator, cipher, bits, hash, accKey, &iniKey.PublicKey, transport, accOut)

	// Check that the parties agreed upon the same master key
	iniMaster, iniOk := <-iniOut
	accMaster, accOk := <-accOut

	fmt.Printf("Initiator key valid: %v\n", iniOk && iniMaster != nil)
	fmt.Printf("Acceptor key valid: %v\n", accOk && accMaster != nil)
	fmt.Printf("Keys match: %v\n", bytes.Equal(iniMaster, accMaster))

}

// STS initiator: creates a new session, initiates a key exchange, verifies the other side and authenticates itself.
func initiator(group, generator *big.Int, cipher func([]byte) (cipher.Block, error), bits int,
	hash crypto.Hash, skey *rsa.PrivateKey, pkey *rsa.PublicKey, trans, out chan []byte) {
	// Create a new empty session
	session, err := sts.New(rand.Reader, group, generator, cipher, bits, hash)
	if err != nil {
		fmt.Printf("failed to create new session: %v\n", err)
		close(out)
		return
	}
	// Initiate a key exchange, send the exponential
	exp, err := session.Initiate()
	if err != nil {
		fmt.Printf("failed to initiate key exchange: %v\n", err)
		close(out)
		return
	}
	trans <- exp.Bytes()

	// Receive the foreign exponential and auth token and if verifies, send own auth
	bytes, token := <-trans, <-trans
	exp = new(big.Int).SetBytes(bytes)
	token, err = session.Verify(rand.Reader, skey, pkey, exp, token)
	if err != nil {
		fmt.Printf("failed to verify acceptor auth token: %v\n", err)
		close(out)
		return
	}
	trans <- token

	// Protocol done, other side should finalize if all is correct
	secret, err := session.Secret()
	if err != nil {
		fmt.Printf("failed to retrieve exchanged secret: %v\n", err)
		close(out)
		return
	}
	out <- secret
	return
}

// STS acceptor: creates a new session, accepts an exchange request, authenticates itself and verifies the other side.
func acceptor(group, generator *big.Int, cipher func([]byte) (cipher.Block, error), bits int,
	hash crypto.Hash, skey *rsa.PrivateKey, pkey *rsa.PublicKey, trans, out chan []byte) {
	// Create a new empty session
	session, err := sts.New(rand.Reader, group, generator, cipher, bits, hash)
	if err != nil {
		fmt.Printf("failed to create new session: %v\n", err)
		close(out)
		return
	}
	// Receive foreign exponential, accept the incoming key exchange request and send back own exp + auth token
	bytes := <-trans
	exp := new(big.Int).SetBytes(bytes)
	exp, token, err := session.Accept(rand.Reader, skey, exp)
	if err != nil {
		fmt.Printf("failed to accept incoming exchange: %v\n", err)
		close(out)
		return
	}
	trans <- exp.Bytes()
	trans <- token

	// Receive the foreign auth token and if verifies conclude session
	token = <-trans
	err = session.Finalize(pkey, token)
	if err != nil {
		fmt.Printf("failed to finalize exchange: %v\n", err)
		close(out)
		return
	}
	// Protocol done
	secret, err := session.Secret()
	if err != nil {
		fmt.Printf("failed to retrieve exchanged secret: %v\n", err)
		close(out)
		return
	}
	out <- secret
	return
}
Output:

Initiator key valid: true
Acceptor key valid: true
Keys match: true

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Session

type Session struct {
	// contains filtered or unexported fields
}

Protocol state structure

func New

func New(random io.Reader, group, generator *big.Int, cipher func([]byte) (cipher.Block, error),
	bits int, hash crypto.Hash) (*Session, error)

Creates a new STS session, ready to initiate or accept key exchanges. The group/generator pair defines the cyclic group on which STS will operate. cipher and bits are used during the authentication token's symmetric encryption, whilst hash is needed during RSA signing.

func (*Session) Accept

func (s *Session) Accept(random io.Reader, key *rsa.PrivateKey, exp *big.Int) (*big.Int, []byte, error)

Accepts an incoming STS exchange session, returning the local exponential and the authorization token. The key is used to authenticate the token for teh other side, whilst the exp is the foreign exponential.

func (*Session) Finalize

func (s *Session) Finalize(key *rsa.PublicKey, token []byte) error

Finalizes an STS key exchange by authenticating the initiator's token with the local public key. Returns nil error if verification succeeded.

func (*Session) Initiate

func (s *Session) Initiate() (*big.Int, error)

Initiates an STS exchange session, returning the local exponential to connect with.

func (*Session) Secret

func (s *Session) Secret() ([]byte, error)

Retrieves the shared secret that the communicating parties agreed upon.

func (*Session) Verify

func (s *Session) Verify(random io.Reader, skey *rsa.PrivateKey, pkey *rsa.PublicKey,
	exp *big.Int, token []byte) ([]byte, error)

Verifies the authenticity of a remote STS acceptor and returns the local auth token if successful. The exp is the foreign exponential used in calculating the token. pkey is used to verify the foreign signature whilst skey to generate the local signature.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL