// Counter returns the TOTP's 8-byte counter as unsigned 64-bit integer. func (otp *Totp) getIntCounter() uint64 { return bigendian.FromUint64(otp.counter) }
// 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 TOTPFromBytes(encryptedMessage []byte, issuer string) (*Totp, error) { // init the cryptoengine engine, err := cryptoengine.InitCryptoEngine(issuer) if err != nil { return nil, err } // decrypt the message data, err := engine.Decrypt(encryptedMessage) if err != nil { return nil, err } // new reader reader := bytes.NewReader([]byte(data.Text)) // otp object otp := new(Totp) // get the lenght lenght := make([]byte, 4) _, err = reader.Read(lenght) // read the 4 bytes for the total lenght if err != nil && err != io.EOF { return otp, err } totalSize := bigendian.FromInt([4]byte{lenght[0], lenght[1], lenght[2], lenght[3]}) buffer := make([]byte, totalSize-4) _, err = reader.Read(buffer) if err != nil && err != io.EOF { return otp, err } // skip the total bytes size startOffset := 0 // read key size endOffset := startOffset + 4 keyBytes := buffer[startOffset:endOffset] keySize := bigendian.FromInt([4]byte{keyBytes[0], keyBytes[1], keyBytes[2], keyBytes[3]}) // read the key startOffset = endOffset endOffset = startOffset + keySize otp.key = buffer[startOffset:endOffset] // read the counter startOffset = endOffset endOffset = startOffset + 8 b := buffer[startOffset:endOffset] otp.counter = [8]byte{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]} // read the digits startOffset = endOffset endOffset = startOffset + 4 b = buffer[startOffset:endOffset] otp.digits = bigendian.FromInt([4]byte{b[0], b[1], b[2], b[3]}) // // read the issuer size startOffset = endOffset endOffset = startOffset + 4 b = buffer[startOffset:endOffset] issuerSize := bigendian.FromInt([4]byte{b[0], b[1], b[2], b[3]}) // read the issuer string startOffset = endOffset endOffset = startOffset + issuerSize otp.issuer = string(buffer[startOffset:endOffset]) // read the account size startOffset = endOffset endOffset = startOffset + 4 b = buffer[startOffset:endOffset] accountSize := bigendian.FromInt([4]byte{b[0], b[1], b[2], b[3]}) // read the account string startOffset = endOffset endOffset = startOffset + accountSize otp.account = string(buffer[startOffset:endOffset]) // read the steps startOffset = endOffset endOffset = startOffset + 4 b = buffer[startOffset:endOffset] otp.stepSize = bigendian.FromInt([4]byte{b[0], b[1], b[2], b[3]}) // read the offset startOffset = endOffset endOffset = startOffset + 4 b = buffer[startOffset:endOffset] otp.clientOffset = bigendian.FromInt([4]byte{b[0], b[1], b[2], b[3]}) // read the total failuers startOffset = endOffset endOffset = startOffset + 4 b = buffer[startOffset:endOffset] otp.totalVerificationFailures = bigendian.FromInt([4]byte{b[0], b[1], b[2], b[3]}) // read the offset startOffset = endOffset endOffset = startOffset + 8 b = buffer[startOffset:endOffset] ts := bigendian.FromUint64([8]byte{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]}) otp.lastVerificationTime = time.Unix(int64(ts), 0) // read the hash type startOffset = endOffset endOffset = startOffset + 4 b = buffer[startOffset:endOffset] hashType := bigendian.FromInt([4]byte{b[0], b[1], b[2], b[3]}) switch hashType { case 1: otp.hashFunction = crypto.SHA256 break case 2: otp.hashFunction = crypto.SHA512 break default: otp.hashFunction = crypto.SHA1 } return otp, err }