ocra

package
v0.0.0-...-e11358b Latest Latest
Warning

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

Go to latest
Published: Dec 29, 2015 License: Apache-2.0 Imports: 20 Imported by: 0

Documentation

Overview

Package ocra The OCRA package provides implementation of OATH services as defined by RFC 6287.

The OCRA property:

Challenge–response authentication: is a family of protocols
in which one party presents a question ("challenge") and
another party must provide a valid answer ("response") to be authenticated.
It may be used for mutual authentication
e.g. when a server needs to install a new version on a client.
In the case of the example, the client has to verify that
the server is the one it claims it is (otherwise a  malicious version may be downloaded)
and the server has to verify that it downloads the new version to the right client.

The OATH Challenge-Response Algorithm (OCRA) is a generalization of HOTP with variable data inputs not solely based on an incremented counter and a secret key values.

The definition of OCRA requires a cryptographic function, a key K and a set of DataInput parameters

DataInput = {OCRASuite | 00 | C | Q | P | S | T} where:

  • OCRASuite is a value representing the suite of operations to compute an OCRA response
  • 00 is a byte value used as a separator
  • C is an unsigned 8-byte counter value processed high-order bit
  • Q (mandatory) is a 128-byte list of (concatenated) challenge question(s) generated by the parties
  • P is a hash (SHA-1, SHA-256 and SHA-512) value of PIN/password that is known to all parties
  • S is a UTF-8 encoded string that contains information about the current session
  • T is a number of time-steps (seconds, minutes, hours) since midnight UTC of January 1, 1970

Note that all paramemters except for 'Q' are optional

OCRA usage:

  1. One-Way Challenge-Response A challenge-response is a security mechanism in which the verifier presents a question (challenge) to the prover, who must provide a valid answer (response) to be authenticated
  2. Mutual Challenge-Response Mutual challenge-response is a variation of the one-way challenge- response mechanism where both the client and server mutually authenticate each other.
  3. Plain Signature To use this algorithm in plain signature mode, the server will communicate a signature-challenge value to the client (signer). The signature-challenge is either the data to be signed or is derived from the data to be signed using a hash function
  4. Signature with Server Authentication This mode is a variation of the plain signature mode where the client can first authenticate the server before generating an electronic signature.
Example (Ocra)
package main

import (
	"fmt"
	"strconv"

	"github.com/ibm-security-innovation/libsecurity-go/ocra"
)

const (
	mutualOcraSuite = "OCRA-1:HOTP-SHA256-8:C-QA08"
	mutualPassword  = "123456"
	OKStr           = "OK"
	NOKStr          = "NOK"

	failFmt = "Generate OCRA fail: error: %v"
)

var (
	channel     = make(chan string)
	doneChannel = make(chan string)
)

// Example of Generate an ocra code using the minimal required parameters: ocra key.
// The OCRA suite is the default one and the question is generated automatically
func GenerateOCRA() {
	key := "3132333435363738393031323334353637383930"

	otp, question, err := ocra.GenerateOCRA(key)
	if err != nil {
		fmt.Printf("Error while generaing OCRA with key: %v and random question: %v, otp: %v\n", key, []byte(question), otp)
	} else {
		fmt.Printf("The OCRA for: with key: %v and random question is OK\n", key)
	}
}

// Execute the oneWayChallengeResponse client:
//  1. Wait for the ocra suite defined by the server (in this example)
//     and the server's randomly generated question
//  2. Send to the server the calculated ocra value (using the ocra suite and the server's question)
//  3. Send the server's approval to the "done channel"
func oneWayChallengeResponseClient(key string) {
	oneWayOcraSuite := <-channel
	question := <-channel

	otp, err := ocra.GenerateOCRAAdvance(oneWayOcraSuite, key, "", question, "", "", "")
	if err != nil {
		doneChannel <- fmt.Sprintf(failFmt, err)
	}
	fmt.Printf("Client otp: %v, Ocra suite: %v, Question: '%v'\n", otp, oneWayOcraSuite, question)
	channel <- otp
	ok := <-channel
	doneChannel <- ok
}

// In this example, The oneWayOcraSuite is defined by the server and sent to the client
// 1. Send the ocra suite and the "random" question to the client
// 2. Comapre the expected calculated ocra value with the one recived from the client
// 3. Based on the result of the comparison, send either an 'OK' or a 'NOK' message to the client
func oneWayChallengeResponseServer(key string) {
	oneWayOcraSuite := "OCRA-1:HOTP-SHA1-6:QA08"
	question := "abcd1234"

	channel <- oneWayOcraSuite
	channel <- question

	refOtp, err := ocra.GenerateOCRAAdvance(oneWayOcraSuite, key, "", question, "", "", "")
	if err != nil {
		doneChannel <- fmt.Sprintf(failFmt, err)
	}
	otp := <-channel
	if otp == refOtp {
		channel <- OKStr
	} else {
		channel <- NOKStr
	}
}

// Execute the mutulChallengeResponse client: In this example the ocra suite is predefined both for the client and the server
// 1. Send the client's randomly generated question to the server
// 2. Get from the server the calculated ocra value based on both the client's question and the server's question
// 3. Comapre the ocra value calculated in the previous step with the one recived from the server
// 4. If the values are equal: the server is authenticated
//    4.1. Send the calculated ocra value to the server
//    4.2. If an OK message is received from the server - increase the 'ocra used' counter (to prevent replay attacks)
//    4.3. Send the message recived from the server (OK or NOK) to the "done channel"

func mutualChallengeResponseClient(key string, counter string) {
	QC := "Client 1234"
	channel <- QC

	RS := <-channel
	QS := <-channel

	sOtp, err := ocra.GenerateOCRAAdvance(mutualOcraSuite, key, counter, QC+QS, mutualPassword, "", "")
	if err != nil {
		doneChannel <- fmt.Sprintf(failFmt, err)
	}

	RC, err := ocra.GenerateOCRAAdvance(mutualOcraSuite, key, counter, QS+QC, mutualPassword, "", "")
	if err != nil {
		doneChannel <- fmt.Sprintf(failFmt, err)
	}

	if RS == sOtp {
		channel <- RC
	} else {
		channel <- "0"
	}
	fmt.Printf("Client/Server otp: (%v,%v), Ocra suite: %v, Client/Server questions: ('%v','%v'), counter: %v, password: %v\n",
		RC, RS, mutualOcraSuite, QC, QS, counter, mutualPassword)
	ok := <-channel
	if ok == OKStr {
		val, _ := strconv.Atoi(counter)
		counter = fmt.Sprintf("%06d", val+1)
	}
	doneChannel <- ok
}

// Execute the mutulChallengeResponse server: in this example the ocra suite is predefined both for the client and the server
//  1. Wait for the client's randomly generated question
//  2. Send to the client both the calculated ocra value (based on the ocra suite and client's + server's questions) and the server's question
//  3. Get from the client the calculated ocra value based on the client's and server's questions
//  4. Calculate the expected ocra value based on both the client's and the server's questions
//  5. Comapre the calculated ocra value with the one recived from the client
//  6. If the values are equal: the client is authenticated
//     6.1. Send an OK message to the client
//     6.2. Increase the 'ocra used' counter (to prevent replay attacks)
//  7. Else (the values are not equal) send a NOK message to the client
func mutualChallengeResponseServer(key string, counter string) {
	QS := "Server 9879"

	QC := <-channel

	RS, err := ocra.GenerateOCRAAdvance(mutualOcraSuite, key, counter, QC+QS, mutualPassword, "", "")
	if err != nil {
		doneChannel <- fmt.Sprintf(failFmt, err)
	}

	channel <- RS
	channel <- QS

	RC := <-channel
	cOtp, err := ocra.GenerateOCRAAdvance(mutualOcraSuite, key, counter, QS+QC, mutualPassword, "", "")
	if err != nil {
		doneChannel <- fmt.Sprintf(failFmt, err)
	}

	if RC == cOtp {
		channel <- OKStr
		val, _ := strconv.Atoi(counter)
		counter = fmt.Sprintf("%06d", val+1)
	} else {
		channel <- NOKStr
	}
}

// Mutual Challenge-Response example.
// Mutual challenge-response is a variation of the one-way challenge-response
// procedure where both the client and server mutually authenticate each other.
// To use this algorithm, the client will first send a random client-challenge message
// to the server. The server computes the server-response and
// sends it back to the client along with a server-challenge message.
// The client will first verify the server-response to make sure that
// it is talking to a valid server. It will then compute the client-
// response and send it back to the server for authentication. The server
// verifies the client-response in order to complete the two-way authentication	process.
// In this mode there are two computations: client-response and server-response.
// There are two separate challenge questions, generated by	both parties.
func ShowOcraMutualWayChallengeResponse() {
	key := "3132333435363738393031323334353637383930"
	counter := "00010"

	go mutualChallengeResponseClient(key, counter)
	go mutualChallengeResponseServer(key, counter)
	fmt.Println("mutualChallengeResponse status:", <-doneChannel)
}

// Example of One-Way Challenge-Response.
// A challenge-response is a security mechanism in which the verifier
// presents a question (challenge) to the prover, who must provide a
// valid answer (response) to be authenticated.
// To use this algorithm for a one-way challenge-response, the verifier
// will communicate a challenge value (typically randomly generated) to
// the prover. The prover will use the recieved challenge in the computation as
// described above. The prover then communicates the response back to the
// verifier for authentication
func ShowOcraOneWayChallengeResponse() {
	key := "3132333435363738393031323334353637383930"

	go oneWayChallengeResponseClient(key)
	go oneWayChallengeResponseServer(key)
	fmt.Println("oneWayChallengeResponse status:", <-doneChannel)
}

func main() {
	GenerateOCRA()
	ShowOcraMutualWayChallengeResponse()
	ShowOcraOneWayChallengeResponse()
}
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func GenerateOCRA

func GenerateOCRA(key string) (string, string, error)

GenerateOCRA : Generates an OCRA HOTP value for the given minimal parameters: OCRASuite, key and question

func GenerateOCRAAdvance

func GenerateOCRAAdvance(ocraSuite, key, counter, question, password, session, timeStamp string) (string, error)

GenerateOCRAAdvance : Generates an OCRA HOTP value for the given set of parameters as defined by RFC 6287: OCRA suite: <Algorithm>:<CryptoFunction>:<DataInput> key: the shared secret, HEX encoded counter: the counter that changes per use basis, HEX encoded question the challenge question, HEX encoded. This is a mandatory parameter password a password that can be used, HEX encoded sessionInformation Static information that identifies the current session, Hex encoded timeStamp a value that reflects a time in Minutes or Hours IC6 - All the communications SHOULD take place over a secure channel, e.g., SSL/TLS [RFC5246], IPsec connections.

Types

type Serializer

type Serializer struct{}

Serializer : virtual set of functions that must be implemented by each module

func (Serializer) AddToStorage

func (s Serializer) AddToStorage(prefix string, data interface{}, storage *ss.SecureStorage) error

AddToStorage : Add the OCRA property information to the secure_storage

func (Serializer) IsEqualProperties

func (s Serializer) IsEqualProperties(da1 interface{}, da2 interface{}) bool

IsEqualProperties : Compare 2 OCRA properties

func (Serializer) PrintProperties

func (s Serializer) PrintProperties(data interface{}) string

PrintProperties : Print the OCRA property data

func (Serializer) ReadFromStorage

func (s Serializer) ReadFromStorage(key string, storage *ss.SecureStorage) (interface{}, error)

ReadFromStorage : Return the entity OCRA data read from the secure storage (in JSON format)

type UserOcra

type UserOcra struct {
	OcraSuite string
	Key       []byte
}

UserOcra : structure that holds the OCRA suite as defined in the RFC and the secret key

func NewOcraUser

func NewOcraUser(key []byte, ocraSuite string) (*UserOcra, error)

NewOcraUser : Generate a new userOcra for a given key and OCRA suite

func (UserOcra) String

func (u UserOcra) String() string

func (*UserOcra) UpdateOcraKey

func (u *UserOcra) UpdateOcraKey(key []byte) error

UpdateOcraKey : Update the user's secret key

func (*UserOcra) UpdateOcraSuite

func (u *UserOcra) UpdateOcraSuite(ocraSuite string) error

UpdateOcraSuite : Update the user's secret key

Jump to

Keyboard shortcuts

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