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:
- 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
- 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.
- 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
- 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 ¶
- func GenerateOCRA(key string) (string, string, error)
- func GenerateOCRAAdvance(ocraSuite, key, counter, question, password, session, timeStamp string) (string, error)
- type Serializer
- func (s Serializer) AddToStorage(prefix string, data interface{}, storage *ss.SecureStorage) error
- func (s Serializer) IsEqualProperties(da1 interface{}, da2 interface{}) bool
- func (s Serializer) PrintProperties(data interface{}) string
- func (s Serializer) ReadFromStorage(key string, storage *ss.SecureStorage) (interface{}, error)
- type UserOcra
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func GenerateOCRA ¶
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 ¶
UserOcra : structure that holds the OCRA suite as defined in the RFC and the secret key
func NewOcraUser ¶
NewOcraUser : Generate a new userOcra for a given key and OCRA suite
func (*UserOcra) UpdateOcraKey ¶
UpdateOcraKey : Update the user's secret key
func (*UserOcra) UpdateOcraSuite ¶
UpdateOcraSuite : Update the user's secret key