Example #1
0
func TestTOTP(t *testing.T) {

	keySha1, err := hex.DecodeString(sha1KeyHex)
	checkError(t, err)

	keySha256, err := hex.DecodeString(sha256KeyHex)
	checkError(t, err)

	keySha512, err := hex.DecodeString(sha512KeyHex)
	checkError(t, err)

	// create the OTP
	otp := new(Totp)
	otp.digits = 8
	otp.issuer = "Sec51"
	otp.account = "*****@*****.**"

	// Test SHA1
	otp.key = keySha1
	for index, ts := range timeCounters {
		counter := increment(ts, 30)
		otp.counter = bigendian.ToUint64(counter)
		hash := hmac.New(sha1.New, otp.key)
		token := calculateToken(otp.counter[:], otp.digits, hash)
		expected := sha1TestData[index]
		if token != expected {
			t.Errorf("SHA1 test data, token mismatch. Got %s, expected %s\n", token, expected)
		}
	}

	// Test SHA256
	otp.key = keySha256
	for index, ts := range timeCounters {
		counter := increment(ts, 30)
		otp.counter = bigendian.ToUint64(counter)
		hash := hmac.New(sha256.New, otp.key)
		token := calculateToken(otp.counter[:], otp.digits, hash)
		expected := sha256TestData[index]
		if token != expected {
			t.Errorf("SHA256 test data, token mismatch. Got %s, expected %s\n", token, expected)
		}
	}

	// Test SHA512
	otp.key = keySha512
	for index, ts := range timeCounters {
		counter := increment(ts, 30)
		otp.counter = bigendian.ToUint64(counter)
		hash := hmac.New(sha512.New, otp.key)
		token := calculateToken(otp.counter[:], otp.digits, hash)
		expected := sha512TestData[index]
		if token != expected {
			t.Errorf("SHA512 test data, token mismatch. Got %s, expected %s\n", token, expected)
		}
	}

}
Example #2
0
// 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 (otp *Totp) ToBytes() ([]byte, error) {

	// check Totp initialization
	if err := totpHasBeenInitialized(otp); err != nil {
		return nil, err
	}

	var buffer bytes.Buffer

	// caluclate the length of the key and create its byte representation
	keySize := len(otp.key)
	keySizeBytes := bigendian.ToInt(keySize) //bigEndianInt(keySize)

	// caluclate the length of the issuer and create its byte representation
	issuerSize := len(otp.issuer)
	issuerSizeBytes := bigendian.ToInt(issuerSize)

	// caluclate the length of the account and create its byte representation
	accountSize := len(otp.account)
	accountSizeBytes := bigendian.ToInt(accountSize)

	totalSize := 4 + 4 + keySize + 8 + 4 + 4 + issuerSize + 4 + accountSize + 4 + 4 + 4 + 8 + 4
	totalSizeBytes := bigendian.ToInt(totalSize)

	// at this point we are ready to write the data to the byte buffer
	// total size
	if _, err := buffer.Write(totalSizeBytes[:]); err != nil {
		return nil, err
	}

	// key
	if _, err := buffer.Write(keySizeBytes[:]); err != nil {
		return nil, err
	}
	if _, err := buffer.Write(otp.key); err != nil {
		return nil, err
	}

	// counter
	counterBytes := bigendian.ToUint64(otp.getIntCounter())
	if _, err := buffer.Write(counterBytes[:]); err != nil {
		return nil, err
	}

	// digits
	digitBytes := bigendian.ToInt(otp.digits)
	if _, err := buffer.Write(digitBytes[:]); err != nil {
		return nil, err
	}

	// issuer
	if _, err := buffer.Write(issuerSizeBytes[:]); err != nil {
		return nil, err
	}
	if _, err := buffer.WriteString(otp.issuer); err != nil {
		return nil, err
	}

	// account
	if _, err := buffer.Write(accountSizeBytes[:]); err != nil {
		return nil, err
	}
	if _, err := buffer.WriteString(otp.account); err != nil {
		return nil, err
	}

	// steps
	stepsBytes := bigendian.ToInt(otp.stepSize)
	if _, err := buffer.Write(stepsBytes[:]); err != nil {
		return nil, err
	}

	// offset
	offsetBytes := bigendian.ToInt(otp.clientOffset)
	if _, err := buffer.Write(offsetBytes[:]); err != nil {
		return nil, err
	}

	// total_failures
	totalFailuresBytes := bigendian.ToInt(otp.totalVerificationFailures)
	if _, err := buffer.Write(totalFailuresBytes[:]); err != nil {
		return nil, err
	}

	// last verification time
	verificationTimeBytes := bigendian.ToUint64(uint64(otp.lastVerificationTime.Unix()))
	if _, err := buffer.Write(verificationTimeBytes[:]); err != nil {
		return nil, err
	}

	// has_function_type
	switch otp.hashFunction {
	case crypto.SHA256:
		sha256Bytes := bigendian.ToInt(1)
		if _, err := buffer.Write(sha256Bytes[:]); err != nil {
			return nil, err
		}
		break
	case crypto.SHA512:
		sha512Bytes := bigendian.ToInt(2)
		if _, err := buffer.Write(sha512Bytes[:]); err != nil {
			return nil, err
		}
		break
	default:
		sha1Bytes := bigendian.ToInt(0)
		if _, err := buffer.Write(sha1Bytes[:]); err != nil {
			return nil, err
		}
	}

	// encrypt the TOTP bytes
	engine, err := cryptoengine.InitCryptoEngine(otp.issuer)
	if err != nil {
		return nil, err
	}

	// init the message to be encrypted
	message, err := cryptoengine.NewMessage(buffer.String(), message_type)
	if err != nil {
		return nil, err
	}

	// encrypt it
	encryptedMessage, err := engine.NewEncryptedMessage(message)
	if err != nil {
		return nil, err
	}

	return encryptedMessage.ToBytes()

}
Example #3
0
// Basically, we define TOTP as TOTP = HOTP(K, T), where T is an integer
// and represents the number of time steps between the initial counter
// time T0 and the current Unix time.
// T = (Current Unix time - T0) / X, where the
// default floor function is used in the computation.
// For example, with T0 = 0 and Time Step X = 30, T = 1 if the current
// Unix time is 59 seconds, and T = 2 if the current Unix time is
// 60 seconds.
func (otp *Totp) incrementCounter(index int) {
	// Unix returns t as a Unix time, the number of seconds elapsed since January 1, 1970 UTC.
	counterOffset := time.Duration(index*otp.stepSize) * time.Second
	now := time.Now().UTC().Add(counterOffset).Unix()
	otp.counter = bigendian.ToUint64(increment(now, otp.stepSize))
}