nauthy

A library for generating and verifying one-time passwords (OTP). nauthy library implements counter-based OTP (RFC4226) and time-based OTP (RFC6238). Various hash modes are supported: MD5, SHA1, SHA256 and SHA512 as well as custom hash functions.

Basic usage

Some examples to get started:

import nauthy

# Construct a new TOTP with a base-32 encoded key.
var totp = initTotp("HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ")
# Print out the current totp value
echo totp.now()

# Construct a new TOTP from a URI.
var otp = otpFromUri(
 "otpauth://totp/ACME%20Co:john@example.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co"
)
echo otp.totp.now()

# Build a URI from a TOTP
totp.uri = newUri("Example issuer", "accountname@example.com")
echo totp.buildUri()

Types

Bytes = seq[byte]
  Source Edit
HashFunc = tuple[hash: proc (input: Bytes): Bytes {...}{.nimcall.}, blockSize: int,
                 name: string]
  Source Edit
Algorithm = enum
  MD5, SHA1, SHA256, SHA512
  Source Edit
OtpValueLen = range[6 .. 10]
  Source Edit
TimeInterval = range[1 .. int.high]
  Source Edit
EpochSecond = BiggestUInt
  Source Edit
OtpType = enum
  HotpT = "hotp", TotpT = "totp"
  Source Edit
Uri = ref object
  issuer: string
  accountname: string
  Source Edit
Hotp = tuple[key: Bytes, length: OtpValueLen, hashFunc: HashFunc,
             initialCounter: int, uri: Uri]
  Source Edit
Totp = tuple[key: Bytes, length: OtpValueLen, interval: TimeInterval,
             hashFunc: HashFunc, t0: EpochSecond, uri: Uri]
  Source Edit
Otp = ref object
  case otpType*: OtpType
  of HotpT:
    hotp*: Hotp
  of TotpT:
    totp*: Totp
  
  Source Edit

Lets

sha1Hash: HashFunc = (hash: sha1Digest, blockSize: 64, name: "SHA1")
  Source Edit
md5Hash: HashFunc = (hash: md5Digest, blockSize: 64, name: "MD5")
  Source Edit
sha256Hash: HashFunc = (hash: sha256Digest, blockSize: 64, name: "SHA256")
  Source Edit
sha512Hash: HashFunc = (hash: sha512Digest, blockSize: 128, name: "SHA512")
  Source Edit

Procs

proc `$`(u: Uri): string {...}{.raises: [ValueError], tags: [].}
  Source Edit
proc initHotp(key: string | Bytes; b32Decode: bool = false;
              length: OtpValueLen = 6; hashFunc: HashFunc = sha1Hash): Hotp
Constructs a new HOTP. sha1Hash is the default but other hash modes are also available: md5Hash, sha256Hash and sha512Hash. Custom hash functions are also accepted. If the given key is base32-encoded, give the b32Decode argument as true.   Source Edit
proc initTotp(key: string | Bytes; b32Decode: bool = true;
              length: OtpValueLen = 6; interval: TimeInterval = 30;
              hashFunc: HashFunc = sha1Hash; t0: EpochSecond = 0): Totp
Constructs a new TOTP. sha1Hash is the default but other hash modes are also available: md5Hash, sha256Hash and sha512Hash. Custom hash functions are also accepted. If the given key is base32-encoded, give the b32Decode argument as true.   Source Edit
proc newUri(issuer: string; accountname: string): Uri {...}{.raises: [], tags: [].}
Constructs a new URI.   Source Edit
proc getName(uri: Uri): string {...}{.raises: [], tags: [].}
Extract account name from a URI.   Source Edit
proc getIssuer(uri: Uri): string {...}{.raises: [], tags: [].}
Extract issuer from a URI.   Source Edit
proc otpFromUri(uri: string): Otp {...}{.raises: [ValueError, KeyError,
    CatchableError], tags: [].}
Initialize HOTP/TOTP from a URI.

Example:

let otp = otpFromUri(
  "otpauth://totp/ACME:john@dot.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME"
  )
var totp = otp.totp
echo totp.now()
  Source Edit
proc buildUri(hotp: Hotp): string {...}{.raises: [], tags: [].}
Build URI from HOTP.   Source Edit
proc buildUri(totp: Totp): string {...}{.raises: [], tags: [].}
Build URI from TOTP.   Source Edit
proc `$`(hotp: Hotp): string {...}{.raises: [], tags: [].}
This is the same as hotp.buildUri().   Source Edit
proc `$`(totp: Totp): string {...}{.raises: [], tags: [].}
This is the same as totp.buildUri().   Source Edit
proc at(hotp: Hotp; counter: SomeInteger): string
Get HOTP value at counter.   Source Edit
proc at(totp: Totp; utime: EpochSecond): string {...}{.raises: [Exception],
    tags: [RootEffect].}
Get TOTP value at time utime.   Source Edit
proc now(totp: Totp): string {...}{.raises: [Exception],
                               tags: [RootEffect, TimeEffect].}
Get TOTP value at current time.   Source Edit
proc verify(hotp: Hotp; value: string; counter: SomeInteger): bool
Verify that the given HOTP value is correct.   Source Edit
proc verify(totp: Totp; value: string; now: EpochSecond = currentTime()): bool {...}{.
    raises: [Exception], tags: [RootEffect].}
Verify that the given TOTP value is correct.   Source Edit
proc randomBase32(): string {...}{.raises: [], tags: [TimeEffect].}
Generates a random 16-characters Base-32 encoded string. Compatible with other OTP apps such as Google Authenticator and Authy.   Source Edit