otp

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: 15 Imported by: 0

Documentation

Overview

Package otp : The OTP package provides implementation of One Time Password (OTP) services as defined by RFCs 4226 (HOTP), 6238 (TOTP).

One time password implemenatation

This package implements RFC 6238 "Totp: Time-Based One-Time Password Algorithm"
 and RFC 4226 HOTP: "An HMAC-Based One-Time Password Algorithm"
 - OTP() implements the lower level common layer
 - Totp() (time based OTP) and
 - Hotp (counter based OTP) implement the upper layers.

Comments:

  1. Illegal operations: 1.1. An empty secret key 1.2. Code length other than 6-8 digits (not protected by the code) 1.3. Digest other than MD4, MD5, SHA1, SHA256 or SHA512 (not defined by the RFC) (not protected by the code)
  2. The encoding scheme of the secret key is not define by the RFC. It's the user's responsability to use a legal secret key. The most common encoding scheme is base32 (as used by the Google Authenticator), therefor the testing of the code includes converting a string to a legal base32 encoded string.
  3. The option for resetting a HOTP counter to another value of counter is currently not implemented as it is defined as an extension in the RFC

Package otp : A One Time Password (OTP) is a password that is valid for only one login session or transaction (and may be limited for a specific time period). The most important advantage that is addressed by OTPs is that, in contrast to static passwords, they are not vulnerable to replay attacks. A second major advantage is that a user who uses the same (or similar) password for multiple systems, is not made vulnerable on all of them, if the password for one of these is gained by an attacker. We implemented the 2 possible OTP implementations: A time based one time password algorithm (TOTP) and HMAC-based one time password algorithm (HOTP). Our OTP implementation is based on RFC 2289 for OTP in general, RFC 4226 for HOTP, and RFC 6238 for TOTP.

The OTP implementation has three layers:

  • The base layer includes the secret (e.g. SHA256, SHA1) and the number of digits in the digest.
  • The second layer is the digest algorithm which is time based for TOTP and counter based for HOTP.
  • The topmost layer includes the policy of handing unsuccessful authentication attempts. This includes blocking and throttling. The blocking mechanism allows blocking users for a given duration of time (or until a manual unblock) after they pass a cliff which a limit for the number of allowed consecutive unsuccessful authentication attempts. The throttling mechanism controls the delay between the authentication request and the response. This delay is increased as the number of consecutive unsuccessful attempts grows to avoid brute force password attacks. This layer includes also a time window for avoiding clock drifting errors when TOTPs are used.

OTP per user:

Each OTP property has the following fields:
- Secret - the password itself
- Blocked  - a flag indicating if the user is blocked
- Throttling parameters - Handling of all the throttle parameters (details below), including:
- HOTP information: Current counter and OTP data (details below)
- TOTP information:  Interval, the time interval in seconds which is counted as a 'tick' (e.g. 30 seconds) and OTP data (details bellow)

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Hotp

type Hotp struct {
	Count   int64
	BaseOtp *Otp
}

Hotp : Event-based HMAC One Time Password

Example

The HOTP example demonstrates the following secenarios: Adding 2 users, each with a different initial counter and Repeat the following 10 times:

randomly select one of the users, verify that the calculated HOTP
is as expected by the provider and then increase the internal counter
of the randomly selected user by one
package main

import (
	"fmt"
	"math/rand"

	defs "github.com/ibm-security-innovation/libsecurity-go/defs"
	en "github.com/ibm-security-innovation/libsecurity-go/entity"
	"github.com/ibm-security-innovation/libsecurity-go/otp"
)

var (
	entityManager *en.EntityManager
	secret        = []byte("AaB1@CDABCD12341234")
)

func addOtpUser(id string, secret []byte, startCounter int64) {
	entityManager.AddUser(id)
	otpUser, _ := otp.NewOtpUser(secret, true, false, 10, 1, 100, 2, 0, startCounter)
	entityManager.AddPropertyToEntity(id, defs.OtpPropertyName, otpUser)
}

type HotpUser struct {
	name    string
	counter int64
	hotp    *otp.Hotp
}

func (u HotpUser) String() string {
	ret := fmt.Sprintf("Entity id: %v, counter %v", u.name, u.counter)
	return ret
}

func initHotpUserslist(users []HotpUser, secret []byte) {
	for i, user := range users {
		addOtpUser(user.name, secret, user.counter)
		hotp, err := otp.NewHotp(secret, user.counter)
		if err != nil {
			fmt.Println("HOTP can't be initialized, error: ", err)
		}
		users[i].hotp = hotp
	}
}

func main() {
	users := []HotpUser{{name: "camera", counter: 2000}, {name: "cell-phone", counter: 1000}}
	initHotpUserslist(users, secret)

	for i := 0; i < 10; i++ {
		idx := rand.Int() % len(users)
		hotp := users[idx].hotp
		code, err := hotp.Next()
		if err != nil {
			fmt.Println("Can't generate HOTP, error: ", err)
		} else {
			entity, _ := entityManager.GetPropertyAttachedToEntity(users[idx].name, defs.OtpPropertyName)
			if entity != nil {
				ok, err := entity.(*otp.UserInfoOtp).VerifyOtpUserCode(code, otp.HotpType)
				if ok {
					fmt.Printf("HOTP: %v, Code: %v as expected\n", users[idx], code)
					users[idx].counter++
				} else {
					fmt.Printf("HOTP: %v code %v is not as expected, error: %v\n", users[idx], code, err)
				}
			}
		}
	}
}
Output:

func NewHotp

func NewHotp(secret []byte, count int64) (*Hotp, error)

NewHotp : Generate new hotp structure

func (Hotp) AtCount

func (hp Hotp) AtCount(count int64) (string, error)

AtCount : Generate an OTP for a given value

func (*Hotp) New

func (hp *Hotp) New() (string, error)

New : Generate a new OTP using a random integer

func (*Hotp) Next

func (hp *Hotp) Next() (string, error)

Next : Generate the next OTP in the sequence

func (Hotp) String

func (hp Hotp) String() string

type Otp

type Otp struct {
	Secret []byte // Assume a legal Secret key
	Digits int    // Number of digits in the code. default is 6
	// contains filtered or unexported fields
}

Otp : One Time Password structure

func NewOtp

func NewOtp(secret []byte) (*Otp, error)

NewOtp : The default OTP: sha1 with 6 digits Any number of digits and any (hash) function are allowed

func NewOtpAdvance

func NewOtpAdvance(secret []byte, numOfDigits int, digest func() hash.Hash) (*Otp, error)

NewOtpAdvance : Generate Otp with the given parameters

func (Otp) Generate

func (otp Otp) Generate(seed int64) (string, error)

Generate : Return the OTP for a given input Input may either be time (for Totp) or integer (for Hotp)

func (Otp) GenerateHmac

func (otp Otp) GenerateHmac(data []byte) string

GenerateHmac : Return the OTP for a given input Input is a byte array

func (Otp) String

func (otp Otp) String() string

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 OTP property information to the secure_storage

func (Serializer) IsEqualProperties

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

IsEqualProperties : Compare 2 OTP properties (without parts of OTP that are not saved)

func (Serializer) PrintProperties

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

PrintProperties : Print the OTP property data

func (Serializer) ReadFromStorage

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

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

type Totp

type Totp struct {
	Interval time.Duration // The time interval in seconds for OT, The default is 30 seconds (the standard)
	BaseOtp  *Otp
}

Totp : Time-based One Time Password

Example

The TOTP example demonstrates the following secenario: Verify that the calculated TOTP for the current time is as expected by the provider

package main

import (
	"fmt"

	defs "github.com/ibm-security-innovation/libsecurity-go/defs"
	en "github.com/ibm-security-innovation/libsecurity-go/entity"
	"github.com/ibm-security-innovation/libsecurity-go/otp"
)

const entityName = "Entity1"

var (
	entityManager *en.EntityManager
	secret        = []byte("AaB1@CDABCD12341234")
)

func addOtpUser(id string, secret []byte, startCounter int64) {
	entityManager.AddUser(id)
	otpUser, _ := otp.NewOtpUser(secret, true, false, 10, 1, 100, 2, 0, startCounter)
	entityManager.AddPropertyToEntity(id, defs.OtpPropertyName, otpUser)
}

func main() {
	addOtpUser(entityName, secret, 0)

	totp, err := otp.NewTotp(secret)
	if err != nil {
		fmt.Println("TOTP can't be initialized, Error: ", err)
	}
	code, err := totp.Now()
	if err != nil {
		fmt.Println("Can't generate TOTP, error: ", err)
	} else {
		e, _ := entityManager.GetPropertyAttachedToEntity(entityName, defs.OtpPropertyName)
		if e == nil {
			return
		}
		entity, ok := e.(*otp.UserInfoOtp)
		if ok == true {
			ok, err := entity.VerifyOtpUserCode(code, otp.TotpType)
			if ok {
				fmt.Println("TOTP: Entity:", entityName, "Code:", code, "as expected")
			} else {
				fmt.Println("TOTP: Entity:", entityName, "Code:", code, "is not as expected, error:", err)
			}
		}
	}
}
Output:

func NewTotp

func NewTotp(secret []byte) (*Totp, error)

NewTotp : Generate new totp structure, default lifespan of a Totp is 30 seconds

func (Totp) AtTime

func (totp Totp) AtTime(t time.Time) (string, error)

AtTime : Generate an OTP for a given time

func (Totp) Now

func (totp Totp) Now() (string, error)

Now : Return the Time Based One Time Password for the current time

func (Totp) String

func (totp Totp) String() string

type TypeOfOtp

type TypeOfOtp int

TypeOfOtp define as integer

const (

	// HotpType index is 1
	HotpType TypeOfOtp = 1
	// TotpType index is 2
	TotpType TypeOfOtp = 2
)

type UserInfoOtp

type UserInfoOtp struct {
	Secret   []byte
	Blocked  bool
	Throttle throtteling // Handle all the throttle parameters
	BaseHotp *Hotp
	BaseTotp *Totp
}

UserInfoOtp : structure that holds all the properties associated to a user

func NewOtpUser

func NewOtpUser(secret []byte, checkSecretStrength bool, lock bool, cliffLen int32, thrTimeSec time.Duration, autoUnblockSec time.Duration, hotpWindowSize time.Duration, totpWindowSize time.Duration, startCount int64) (*UserInfoOtp, error)

NewOtpUser : generate a new otp user with the given parameters

func NewSimpleOtpUser

func NewSimpleOtpUser(secret []byte, checkSecretStrength bool) (*UserInfoOtp, error)

NewSimpleOtpUser : generate a new otp user with the default parameters

func (*UserInfoOtp) IsEqual

func (u *UserInfoOtp) IsEqual(u1 interface{}) bool

IsEqual : compare 2 OTP structures

func (UserInfoOtp) IsOtpUserBlocked

func (u UserInfoOtp) IsOtpUserBlocked() (bool, error)

IsOtpUserBlocked : check if the given user account is blocked

func (*UserInfoOtp) SetOtpUserBlockedState

func (u *UserInfoOtp) SetOtpUserBlockedState(block bool) error

SetOtpUserBlockedState : set the user account status to the given status

func (UserInfoOtp) String

func (u UserInfoOtp) String() string

func (*UserInfoOtp) VerifyCode

func (u *UserInfoOtp) VerifyCode(code string, otpType TypeOfOtp) (bool, error)

VerifyCode : Verify that the given code is the expected one, if so, increment the internal counter (for hotp) or block the same code (for totp) The upper layer shell take the action to blocl the user (the upper layer can take more information before blockingthe user) the differences between hotp and totp are: the code check and the action if the code was found

func (*UserInfoOtp) VerifyOtpUserCode

func (u *UserInfoOtp) VerifyOtpUserCode(code string, otpType TypeOfOtp) (bool, error)

VerifyOtpUserCode : Verify that a given code is as expected, If the user is blocked, return an error If the code is as expected, the counter code will be incremented (for HOTP) and saved to avoid replay attack (TOTP) If the code dosn't match and the number of consecutive errors pass the Throtlling parameter for this user, the user acount will be blocked till manuel or automatic unblock

Jump to

Keyboard shortcuts

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