func handleTimeStamp(dataInput string, timeStamp string, p parseData) ([]byte, error) {
	var t2 []byte
	t, _, err := extractDataInputToken(dataInput, p)
	if err != nil {
		return nil, fmt.Errorf("OCRA Suite %v: Time stamp error: %v", dataInput, err)
	}
	if len(t) == 0 {
		return t2, nil
	}
	t1, err := hexStrToHexByte(timeStamp)
	if err != nil {
		return nil, err
	}
	t2 = appendStringToGivenLen(t1, ocraSuiteTimeStampLengthB, dataInputAppendToken, appendToLeft)
	logger.Info.Println("Timestamp calculations: in command:", dataInput, ", The original timeSTamp:",
		timeStamp, ", The new timeStamp is:", t2, ", len:", len(t2))
	return t2, nil
}
If 'timeStamp handling' is defined in the OCRA Suite, extract the information from the
given timeStamp string, append it to the predefined length and return it as a byte array
package ocra
import (
	"crypto/rand"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"hash"
	"io"
	"io/ioutil"
	"math/big"
	"os"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	defs "github.com/ibm-security-innovation/libsecurity-go/defs"
	logger "github.com/ibm-security-innovation/libsecurity-go/logger"
	"github.com/ibm-security-innovation/libsecurity-go/otp"
	ss "github.com/ibm-security-innovation/libsecurity-go/storage"
)
type appendSide int
const (
	ocraSuiteOcraProtocolIdx = 0
	ocraSuiteCryptoIdx       = 1
	ocraSuiteDataInputIdx    = 2
	ocraSuiteNumOfFields     = 3
	ocraSuiteProtocolIdx     = 0
	ocraSuiteHashLengthIdx   = 2
	ocraSuiteSplitToken                    = ":"
	ocraSuiteDigitSplitToken               = "-"
	ocraSuiteDataInputSplitToken           = "-"
	ocraSuiteDataInputCounterToken         = "c"
	ocraSuiteDataInputQuestionToken        = "q"
	ocraSuiteDataInputQuestionNumericToken = "n"
	ocraSuiteDataInputQuestionAlfabetToken = "a"
	ocraSuiteDataInputPasswordToken        = "p"
	ocraSuiteDataInputSessionToken         = "s"
	ocraSuiteDataInputTimeStampToken       = "t"
	dataInputAppendToken                   = 0
	ocraSuiteOcraProtocol                  = "ocra-1"
	ocraSuiteProtocolToken                 = "hotp"
	ocraSuiteDataInputQuestionTypeOptions = "nah"
	minOcraSuiteDataInputQuestionLength   = 4
	maxOcraSuiteDataInputQuestionLength   = 64
	ocraSuiteCounterLengthB   = 8
	ocraSuiteQuestionLengthB  = 128
	ocraSuiteTimeStampLengthB = 8
	minKeyLength = 6
	maxKeyLength = 512
	appendToLeft  appendSide = 0
	appendToRight appendSide = 1
)
var (
	ocraSuiteDataInputParseStruct    []parseData
	ocraSuiteDataInputValidTokensMap = make(map[byte]parseData)
	ocraValidOutputLength            = []int{0, 4, 5, 6, 7, 8, 9, 10}
	ocraValidOutputLengthMap         = make(map[int]int)
	dataInputCounterRegExp           = regexp.MustCompile("^c([a-zA-Z0-9]*-)")
	dataInputQuestionRegExp          = regexp.MustCompile(fmt.Sprintf("%s([%s])([0-9]*)", ocraSuiteDataInputQuestionToken, ocraSuiteDataInputQuestionTypeOptions))
	timeStampRegExp                  = regexp.MustCompile("(t[1-9][sm]|t[1-5][0-9][sm]|t[0-9]h|t[1-3][0-9]h|t4[0-8]h)")
	dataInputTokenFmt                = "%s(%s[a-zA-Z0-9]*)"
	dataInputPasswordTokenRegExp     = regexp.MustCompile(fmt.Sprintf(dataInputTokenFmt, ocraSuiteDataInputSplitToken, ocraSuiteDataInputPasswordToken))
	dataInputSessionTokenRegExp      = regexp.MustCompile(fmt.Sprintf(dataInputTokenFmt, ocraSuiteDataInputSplitToken, ocraSuiteDataInputSessionToken))
	dataInputTimeStampTokenRegExp    = regexp.MustCompile(fmt.Sprintf(dataInputTokenFmt, ocraSuiteDataInputSplitToken, ocraSuiteDataInputTimeStampToken))
)
type UserOcra struct {
	OcraSuite string
	Key       []byte
}
func (u UserOcra) String() string {
	return fmt.Sprintf("Key: %v, OCRA Suite %v", u.Key, u.OcraSuite)
}
type parseData struct {
	token string
	cFunc func(string, string, parseData) (int, error)
	hFunc func(string, string, parseData) ([]byte, error)
	parse *regexp.Regexp
}
type inputData struct {
	name   string
	length int
}
func (d inputData) String() string {
	return fmt.Sprintf("Input data: name - '%v', length - %v", d.name, d.length)
}
type hashesData struct {
	name   string
	digest func() hash.Hash
	length int
}
var hashes = []hashesData{{"sha1", sha1.New, 0}, {"sha256", sha256.New, 0}, {"sha512", sha512.New, 0}}
var passwords = []inputData{{"psha1", 20}, {"psha256", 32}, {"psha512", 64}}
type Serializer struct{}
func init() {
	logger.Init(ioutil.Discard, ioutil.Discard, os.Stdout, os.Stderr)
	defs.Serializers[defs.OcraPropertyName] = &Serializer{}
	for _, val := range ocraValidOutputLength {
		ocraValidOutputLengthMap[val] = val
	}
	ocraSuiteDataInputParseStruct = []parseData{{ocraSuiteDataInputCounterToken, checkOcraDataInputCounterValidity, handleCounter, dataInputCounterRegExp},
		{ocraSuiteDataInputQuestionToken, checkOcraDataInputQuestionValidity, handleQuestion, dataInputQuestionRegExp},
		{ocraSuiteDataInputPasswordToken, checkOcraDataInputPasswordValidity, handlePassword, dataInputPasswordTokenRegExp},
		{ocraSuiteDataInputSessionToken, checkOcraDataInputSessionValidity, handleSession, dataInputSessionTokenRegExp},
		{ocraSuiteDataInputTimeStampToken, checkOcraDataInputTimeStampValidity, handleTimeStamp, dataInputTimeStampTokenRegExp}}
	for _, c := range ocraSuiteDataInputParseStruct {
		ocraSuiteDataInputValidTokensMap[c.token[0]] = c
	}
}
func appendStringToGivenLen(data []byte, l int, appendB byte, side appendSide) []byte {
	filler := []byte{}
	for i := len(data); i < l; i++ {
		filler = append(filler, appendB)
	}
	if side == appendToRight {
		return append(data, filler...)
	}
	return append(filler, data...)
}
func hexStrToHexByte(str string) ([]byte, error) {
	if len(str)%2 == 1 {
		str = "0" + str
	}
	return hex.DecodeString(str)
}
func numericStrToByte(str string) ([]byte, error) {
	n := &big.Int{}
	_, ok := n.SetString(str, 10)
	if ok == false {
		return nil, fmt.Errorf("The string '%v' is not a decimal string", str)
	}
	ret := fmt.Sprintf("%X", n)
	if len(ret)%2 == 1 {
		ret = ret + "0"
	}
	return hex.DecodeString(ret)
}
func handleCounter(dataInput string, counter string, p parseData) ([]byte, error) {
	length, err := p.cFunc(dataInput, "", p)
	if err != nil {
		return nil, err
	} else if length == 0 {
		return nil, nil
	}
	c1, err := hexStrToHexByte(counter)
	if err != nil {
		return nil, err
	}
	c2 := appendStringToGivenLen(c1, ocraSuiteCounterLengthB, dataInputAppendToken, appendToLeft)
	logger.Info.Println("Counter calculations: in command:", dataInput, ", Original counter:", counter, ", convert to:", c1, "The new counter is:", c2, ", len:", len(c2))
	return c2, nil
}
func handleQuestion(dataInput string, question string, p parseData) ([]byte, error) {
	var q1, q2 []byte
	var err error
	format, _, err := parseQuestion(dataInput, p)
	if err != nil {
		return nil, err
	}
	if format == ocraSuiteDataInputQuestionNumericToken {
		q1, err = numericStrToByte(question)
		if err != nil {
			return nil, err
		}
	} else {
		q1 = []byte(question)
	}
	q2 = appendStringToGivenLen(q1, ocraSuiteQuestionLengthB, dataInputAppendToken, appendToRight)
	logger.Info.Println("Question calculations: in command:", dataInput, ", Original question:", question, "converted to:", []byte(q1), "The new question is:", q2, ", len:", len(q2))
	return q2, nil
}
func handlePassword(dataInput string, password string, p parseData) ([]byte, error) {
	var p2 []byte
	pass, _, err := extractDataInputToken(dataInput, p)
	if err != nil {
		return nil, fmt.Errorf("OCRA Suite %v: Password error: %v", dataInput, err)
	}
	if len(pass) == 0 {
		return p2, nil
	}
	for _, p := range passwords {
		if pass == p.name {
			p1, err := hexStrToHexByte(password)
			if err != nil {
				return nil, err
			}
			p2 = appendStringToGivenLen(p1, p.length, dataInputAppendToken, appendToLeft)[0:p.length]
			logger.Info.Println("Password calculations: in command:", dataInput, ", match:", p.name, ", original password:", password, len(password), ", The new password is:", []byte(p2), ", len:", len(p2))
		}
	}
	return p2, nil
}
func handleSession(dataInput string, session string, p parseData) ([]byte, error) {
	var s2 []byte
	ses, _, err := extractDataInputToken(dataInput, p)
	if err != nil {
		return nil, fmt.Errorf("OCRA Suite %v: Session error: %v", dataInput, err)
	}
	if len(ses) == 0 {
		return nil, nil
	}
	length, err := p.cFunc(dataInput, session, p)
	if err != nil || length <= 0 {
		return nil, err
	}
	s1, err := hexStrToHexByte(session)
	if err != nil {
		return nil, err
	}
	s2 = appendStringToGivenLen(s1, length, dataInputAppendToken, appendToLeft)[0:length]
	logger.Info.Println("Session calculations: in command:", dataInput, ", session length:", length, ", The original session:", session, "Convert to:", s1, ", The new session is:", s2, ", len:", len(s2))
	return s2, nil
}