choonkeat / elm-totp / TOTP

Based on specification in https://datatracker.ietf.org/doc/html/rfc6238

Main function

generateTOTP : Algorithm -> { outputLength : Basics.Int, periodSeconds : Basics.Int } -> Base32String -> Time.Posix -> Result String String

https://datatracker.ietf.org/doc/html/rfc6238#appendix-B

import TOTP.Algorithm
import TOTP.Base32String exposing (Base32String(..))
import Time

seed : Base32String
seed =
    "12345678901234567890"
        |> TOTP.Base32String.stringToBase32
        |> Result.withDefault (TOTP.Base32String.test.base32String "error")

seed32 : Base32String
seed32 =
    "12345678901234567890123456789012"
        |> TOTP.Base32String.stringToBase32
        |> Result.withDefault (TOTP.Base32String.test.base32String "error")

seed64 : Base32String
seed64 =
    "1234567890123456789012345678901234567890123456789012345678901234"
        |> TOTP.Base32String.stringToBase32
        |> Result.withDefault (TOTP.Base32String.test.base32String "error")

testTable : List (Int, String, (TOTP.Algorithm.Algorithm, Base32String))
testTable =
    [ ( 59,         "94287082",  ( TOTP.Algorithm.SHA1,   seed ) )
    , ( 59,         "46119246",  ( TOTP.Algorithm.SHA256, seed32 ) )
    , ( 59,         "90693936",  ( TOTP.Algorithm.SHA512, seed64 ) )
    , ( 1111111109, "07081804",  ( TOTP.Algorithm.SHA1,   seed ) )
    , ( 1111111109, "68084774",  ( TOTP.Algorithm.SHA256, seed32 ) )
    , ( 1111111109, "25091201",  ( TOTP.Algorithm.SHA512, seed64 ) )
    , ( 1111111111, "14050471",  ( TOTP.Algorithm.SHA1,   seed ) )
    , ( 1111111111, "67062674",  ( TOTP.Algorithm.SHA256, seed32 ) )
    , ( 1111111111, "99943326",  ( TOTP.Algorithm.SHA512, seed64 ) )
    , ( 1234567890, "89005924",  ( TOTP.Algorithm.SHA1,   seed ) )
    , ( 1234567890, "91819424",  ( TOTP.Algorithm.SHA256, seed32 ) )
    , ( 1234567890, "93441116",  ( TOTP.Algorithm.SHA512, seed64 ) )
    , ( 2000000000, "69279037",  ( TOTP.Algorithm.SHA1,   seed ) )
    , ( 2000000000, "90698825",  ( TOTP.Algorithm.SHA256, seed32 ) )
    , ( 2000000000, "38618901",  ( TOTP.Algorithm.SHA512, seed64 ) )
    , ( 20000000000, "65353130", ( TOTP.Algorithm.SHA1,   seed ) )
    , ( 20000000000, "77737706", ( TOTP.Algorithm.SHA256, seed32 ) )
    , ( 20000000000, "47863826", ( TOTP.Algorithm.SHA512, seed64 ) )
    ]

testTable
    |> List.map (\(secs, _, (alg, secret)) -> generateTOTP alg { outputLength = 8, periodSeconds = 30 } secret (Time.millisToPosix (secs * 1000)))
--> List.map (\(_, answer, _) -> Ok answer) testTable

Helper functions

test : { valueT : Basics.Int -> Time.Posix -> ValueT, newValueT : Basics.Int -> ValueT, hexCounter : ValueT -> String, dynamicTruncation : Basics.Int -> Array Basics.Int -> Maybe String, base32String : String -> Base32String }

Exposed functions to facilitate unit testing of this library