Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Students Click Here

TOTP seeds: Converting Hex to Base32

TOTP seeds: Converting Hex to Base32

TOTP seeds: Converting Hex to Base32

I need to convert a hex number to a base32 number for creating a QR code to use Google Authenticator (or like) for Multi-Factor Authentication. I've found lots of online tools, but no code I can actually put in my program.

Example: If I get a hex number like this: df235768fe4365e6fa3a0a49325d14fb1bc24be1
I need to convert it to the base32 equivalent: 34RVO2H6INS6N6R2BJETEXIU7MN4ES7B

Perhaps I need to go from hex to decimal to base32? Anyone have any advice?

Many thanks in advance!

RE: TOTP seeds: Converting Hex to Base32

Yep, found that. Was really looking for "real code" to do it.

RE: TOTP seeds: Converting Hex to Base32


This is a porting of the C implementation pointed by Wikipedia - only the encoder, so far.


LOCAL Demo AS Base32

m.Demo = CREATEOBJECT("Base32")

? m.Demo.Encode(0hdf235768fe4365e6fa3a0a49325d14fb1bc24be1)
? m.Demo.Encode("Hello, world")



	FUNCTION Encode (Source AS String) AS String

		LOCAL ToEncode AS String
		LOCAL SourceSegment AS String
		LOCAL SegmentSize AS Integer
		LOCAL EncodedIndex AS Integer
		LOCAL ARRAY EncodedSegment(8)

		LOCAL Encoded AS String

		m.Encoded = ""

		m.SourceSegment = LEFT(m.Source, 5)
		m.ToEncode = SUBSTR(m.Source, 6)

		DO WHILE LEN(m.SourceSegment) > 0 

			STORE .NULL. TO m.EncodedSegment

			m.SegmentSize = LEN(m.SourceSegment)
			IF m.SegmentSize = 5
				m.EncodedSegment(8) = BITAND(ASC(RIGHT(m.SourceSegment, 1)), 0x1f)
				m.EncodedSegment(7) = BITRSHIFT(BITAND(ASC(RIGHT(m.SourceSegment, 1)), 0xe0), 5)

			IF m.SegmentSize >= 4
				m.EncodedSegment(7) = BITOR(BITLSHIFT(BITAND(ASC(SUBSTR(m.SourceSegment, 4, 1)), 0x03), 3), NVL(m.EncodedSegment(7), 0))
				m.EncodedSegment(6) = BITRSHIFT(BITAND(ASC(SUBSTR(m.SourceSegment, 4, 1)), 0x7c), 2)
				m.EncodedSegment(5) = BITRSHIFT(BITAND(ASC(SUBSTR(m.SourceSegment, 4, 1)), 0x80), 7)

			IF m.SegmentSize >= 3
				m.EncodedSegment(5) = BITOR(BITLSHIFT(BITAND(ASC(SUBSTR(m.SourceSegment, 3, 1)), 0x0f), 1), NVL(m.EncodedSegment(5), 0))
				m.EncodedSegment(4) = BITRSHIFT(BITAND(ASC(SUBSTR(m.SourceSegment, 3, 1)), 0xf0), 4)

			IF m.SegmentSize >= 2
				m.EncodedSegment(4) = BITOR(BITLSHIFT(BITAND(ASC(SUBSTR(m.SourceSegment, 2, 1)), 0x01), 4), NVL(m.EncodedSegment(4), 0))
				m.EncodedSegment(3) = BITRSHIFT(BITAND(ASC(SUBSTR(m.SourceSegment, 2, 1)), 0x3e), 1)
				m.EncodedSegment(2) = BITRSHIFT(BITAND(ASC(SUBSTR(m.SourceSegment, 2, 1)), 0xc0), 6)

			m.EncodedSegment(2) = BITOR(BITLSHIFT(BITAND(ASC(LEFT(m.SourceSegment, 1)), 0x07), 2), NVL(m.EncodedSegment(2), 0))
			m.EncodedSegment(1) = BITRSHIFT(BITAND(ASC(LEFT(m.SourceSegment, 1)), 0xf8), 3)

			FOR m.EncodedIndex = 1 TO 8
				m.Encoded = m.Encoded + SUBSTR(This.Alphabet, NVL(m.EncodedSegment(m.EncodedIndex), 32) + 1, 1)

			m.SourceSegment = LEFT(m.ToEncode, 5)
			m.ToEncode = SUBSTR(m.ToEncode, 6)


		RETURN m.Encoded



RE: TOTP seeds: Converting Hex to Base32

I don't know why you use double length codes, but maybe that's API specific.

I forgot the comment on Google Authenticator:

Quote (Wikipedia about Google Authenticator)

The service provider (Google) generates an 80-bit secret key for each user (whereas RFC 4226 ยง4 requires 128 bits and recommends 160 bits).[4] This is provided as a 16, 26 or 32 character base32 string or as a QR code.

128bit doesn't fit a multiple of 5 bits, so it's be padded to 130 bits = 26 base32 characters. To avoid that I'd also go for 160 bit = 32 Base32 characters.
It's convenient the FAQ code I wrote does not depend on specific String or bit lengths. So...
:End of Edit

Anyway, I'd neither convert hex to base32 directly nor go through decimal, but use binary, Q(10) or Q(20).

For example with the function as declared in my FAQ I get 34RVO2H6INS6N6R2BJETEXIU7MN4ES7B as necessary.


lcSecret = ''+0hdf235768fe4365e6fa3a0a49325d14fb1bc24be1
_cliptext = Base32Encode(lcSecret)
? _cliptext 

You can also generate a random 20 char long string by using any character or directly create a random 32 char long base32 string by only using A-Z and 2-7, then you never need Base32Encode. The secret only needs to be generated once for the user to have it. Generating a QR Code from it is a topic of its own, I didn't as the Google Authenticator apps for Window Phone and Android also allow you to enter that code manually.

But there also is a QR Barcode image library in the VFPX project on GitHub: https://github.com/VFPX/FoxBarcodeQR

Bye, Olaf.

Olaf Doschke Software Engineering

RE: TOTP seeds: Converting Hex to Base32

Btw, as ASC and SUBSTR etc also work on the binary data type the Base2Encode function also works with lcSecret = 0hdf235768fe4365e6fa3a0a49325d14fb1bc24be1 and if you have some variable hexdigitstring='df235768fe4365e6fa3a0a49325d14fb1bc24be1' as string of hex digits you can use EVAL to convert that to binary: lcString = EVAL('0h'+hexdigitsstring). Also notice Craig Boyds HMAC() function returns a string that's neither binary nor a hex digits string but simply the ASCII bytes the HMAC Sha function creates, VFP does not really need a distinction between a text string and a binary string, the only difference in the types Q and C in tables or cursors are about no codepage conversion so Q is pretty much the same as C NOCPTRAN, but it isn't displayed as the ASCII or ANSI characters of VFPs current codepage, the string bytes are shown as hex digits, it's not really a string of double length with 0-9 and a-f characters.

Bye, Olaf.

Olaf Doschke Software Engineering

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members! Already a Member? Login

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close