コード例 #1
0
ファイル: totp.go プロジェクト: sec51/twofactor
// Counter returns the TOTP's 8-byte counter as unsigned 64-bit integer.
func (otp *Totp) getIntCounter() uint64 {
	return bigendian.FromUint64(otp.counter)
}
コード例 #2
0
ファイル: totp.go プロジェクト: sec51/twofactor
// 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
}