twofactor

package module
v1.1.8 Latest Latest
Warning

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

Go to latest
Published: Dec 22, 2024 License: ISC Imports: 26 Imported by: 3

README

totp

This package implements the RFC 6238 OATH-TOTP algorithm

Current Status

Build Linter CodeQL Go Report Card Go Reference

Features

  • Built-in support for secure crypto keys generation
  • Built-in encryption of the secret keys when converted to bytes, so that they can be safely transmitted over the network, or stored in a DB
  • Built-in back-off time when a user fails to authenticate more than 3 times
  • Built-in serialization and deserialization to store the one time token struct in a persistence layer
  • Automatic re-synchronization with the client device
  • Built-in generation of a PNG QR Code for easily adding the secret key on the user device
  • Supports 6, 7, 8 digits tokens
  • Supports HMAC-SHA1, HMAC-SHA256, HMAC-SHA512
  • Generation of recovery tokens

Storing Keys

The key is created using Golang crypto random function. It's a secret key and therefore it needs to be protected against unauthorized access. The key cannot be leaked, otherwise the security is completely compromised. The key is presented to the user in a form of QR Code. Once scanned, the key should never be revealed again. In addition when the QR code is shared with the client for scanning, the connection used must be secured (HTTPS).

The totp struct can be easily serialized using the ToBytes() function. The bytes can then be stored on a persistence layer (database for example). The bytes are encrypted using cryptoengine library (NaCl) You can then retrieve the object back with the function: TOTPFromBytes

You can transfer the bytes securely via a network connection (Ex. if the database is in a different server) because they are encrypted and authenticated.

The struct needs to be stored in a persistence layer because its values, like last token verification time, max user authentication failures, etc.. need to be preserved. The secret key needs to be preserved too between the user account and the user device. The secret key is in fact used to derive tokens.

Example Usages

Case 1: Google Authenticator
  • How to use the library

      1. Import the library
    import github.com/pilinux/twofactor
    
      1. Instantiate the totp object via:
    otp, err := twofactor.NewTOTP("info@sec51.com", "Sec51", crypto.SHA1, 8)
    if err != nil {
      return err
    }
    
      1. Display the PNG QR code to the user and an input text field, so that he can insert the token generated from his device
    qrBytes, err := otp.QR()
    if err != nil {
      return err
    }
    
      1. Verify the user-provided token generating by the google authenticator app
    err := otp.Validate(USER_PROVIDED_TOKEN)
    if err != nil {
      return err
    }
    // if there is an error, then the authentication failed
    // if it succeeded, then store this information and do not display the QR code ever again.
    
      1. All following authentications should display only a input field with no QR code.

References

Author

totp was written by Sec51 info@sec51.com.

License

Copyright (c) 2015 Sec51.com <info@sec51.com>

Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above 
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 

Documentation

Overview

Package twofactor -

The package twofactor implements the RFC 6238 TOTP: Time-Based One-Time Password Algorithm

The library provides a simple and secure way to generate and verify the OTP tokens and provides the possibility to display QR codes out of the box

The library supports HMAC-SHA1, HMAC-SHA256, HMAC-SHA512

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BCryptRecoveryCodes added in v1.1.0

func BCryptRecoveryCodes(codes []string) ([]string, error)

BCryptRecoveryCodes hashes each recovery code given and return them in a new slice.

func DecodeRecoveryCodes added in v1.1.0

func DecodeRecoveryCodes(codes string) []string

DecodeRecoveryCodes is an alias for strings.Split(",")

func EncodeRecoveryCodes added in v1.1.0

func EncodeRecoveryCodes(codes []string) string

EncodeRecoveryCodes is an alias for strings.Join(",")

func GenerateRecoveryCodes added in v1.1.0

func GenerateRecoveryCodes() ([]string, error)

GenerateRecoveryCodes creates 10 recovery codes of the form:

abd34-1b24do (using alphabet, of length recoveryCodeLength).

func UseRecoveryCode added in v1.1.0

func UseRecoveryCode(codes []string, inputCode string) ([]string, bool)

UseRecoveryCode deletes the code that was used from the string slice and returns it, the bool is true if a code was used

func ValidRecoveryCode added in v1.1.0

func ValidRecoveryCode(code string) bool

ValidRecoveryCode returns true if the code matches recovery code format

Types

type Totp

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

Totp - WARNING: The `Totp` struct should never be instantiated manually!

Use the `NewTOTP` function

func NewTOTP

func NewTOTP(account, issuer string, hash crypto.Hash, digits int) (*Totp, error)

NewTOTP - This function creates a new TOTP object

This is the function which is needed to start the whole process

account: usually the user email

issuer: the name of the company/service

hash: is the crypto function used: crypto.SHA1, crypto.SHA256, crypto.SHA512

digits: is the token amount of digits (6 or 7 or 8)

steps: the amount of second the token is valid

it automatically generates a secret key using the golang crypto rand package. If there is not enough entropy the function returns an error

The key is not encrypted in this package. It's a secret key. Therefore if you transfer the key bytes in the network, please take care of protecting the key or in fact all the bytes.

func TOTPFromBytes

func TOTPFromBytes(encryptedMessage []byte, issuer string) (*Totp, error)

TOTPFromBytes converts a byte array to a totp object. It stores the state of the TOTP object, like the key, the current counter, the client offset, the total amount of verification failures and the last time a verification happened.

func (*Totp) HashFunction added in v1.1.0

func (otp *Totp) HashFunction() crypto.Hash

HashFunction returns the hash function used

func (*Totp) NumDigits added in v1.1.0

func (otp *Totp) NumDigits() int

NumDigits returns total amount of digits of the code displayed on the device

func (*Totp) OTP

func (otp *Totp) OTP() (string, error)

OTP Generates a new one time password with hmac-(HASH-FUNCTION)

func (*Totp) QR

func (otp *Totp) QR() ([]byte, error)

QR generates a byte array containing QR code encoded PNG image, with level Q error correction, needed for the client apps to generate tokens. The QR code should be displayed only the first time the user enabled the Two-Factor authentication. The QR code contains the shared KEY between the server application and the client application, therefore the QR code should be delivered via secure connection.

func (*Totp) Secret added in v1.1.0

func (otp *Totp) Secret() string

Secret returns the underlying base32 encoded secret. This should only be displayed the first time a user enables 2FA, and should be transmitted over a secure connection. Useful for supporting TOTP clients that don't support QR scanning.

func (*Totp) ToBytes

func (otp *Totp) ToBytes() ([]byte, error)

ToBytes serialises a TOTP object in a byte array

Sizes: 4 4 N 8 4 4 N 4 N 4 4 4 8 4

Format: |total_bytes|key_size|key|counter|digits|issuer_size|issuer|account_size|account|steps|offset|total_failures|verification_time|hashFunction_type|

hashFunction_type: 0 = SHA1; 1 = SHA256; 2 = SHA512

The data is encrypted using the cryptoengine library (which is a wrapper around the golang NaCl library)

TODO:

1- improve sizes. For instance the hashFunction_type could be a short.

func (*Totp) URL added in v1.1.0

func (otp *Totp) URL() (string, error)

URL returns a suitable URL, such as for the Google Authenticator app

example: otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example

func (*Totp) Validate

func (otp *Totp) Validate(userCode string) error

Validate - This function validates the user provided token

It calculates 3 different tokens. The current one, one before now and one after now.

The difference is driven by the TOTP step size based on which of the 3 steps it succeeds to validates, the client offset is updated.

It also updates the total amount of verification failures and the last time a verification happened in UTC time.

Returns an error in case of verification failure, with the reason.

There is a very basic method which protects from timing attacks, although if the step time used is low it should not be necessary.

An attacker can still learn the synchronization offset. This is however irrelevant because the attacker has then 30 seconds to guess the code and after 3 failures the function returns an error for the following 5 minutes.

Jump to

Keyboard shortcuts

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