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 ¶
- type Session
- func (s *Session) Accept(random io.Reader, key *rsa.PrivateKey, exp *big.Int) (*big.Int, []byte, error)
- func (s *Session) Finalize(key *rsa.PublicKey, token []byte) error
- func (s *Session) Initiate() (*big.Int, error)
- func (s *Session) Secret() ([]byte, error)
- func (s *Session) Verify(random io.Reader, skey *rsa.PrivateKey, pkey *rsa.PublicKey, exp *big.Int, ...) ([]byte, error)
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 ¶
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 ¶
Initiates an STS exchange session, returning the local exponential to connect with.
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.