module Botan.Low.TOTP (
TOTP(..)
, TOTPHashName
, TOTPTimestep
, TOTPTimestamp
, TOTPCode
, withTOTP
, totpInit
, totpDestroy
, totpGenerate
, totpCheck
, pattern TOTP_SHA1
, pattern TOTP_SHA256
, pattern TOTP_SHA512
, totpHashes
) where
import Botan.Bindings.ConstPtr (ConstPtr (..))
import Botan.Bindings.TOTP
import Botan.Low.Error.Internal
import Botan.Low.Hash
import Botan.Low.Internal.ByteString
import Botan.Low.Remake
import Control.Monad
import Data.ByteString (ByteString)
import Data.Word
import Foreign.C.Types
import Foreign.ForeignPtr
import Foreign.Marshal.Alloc
import Foreign.Ptr
import Foreign.Storable
newtype TOTP = MkTOTP { TOTP -> ForeignPtr BotanTOTPStruct
foreignPtr :: ForeignPtr BotanTOTPStruct }
withTOTP :: TOTP -> (BotanTOTP -> IO a) -> IO a
totpDestroy :: TOTP -> IO ()
createTOTP :: (Ptr BotanTOTP -> IO CInt) -> IO TOTP
(TOTP -> (BotanTOTP -> IO a) -> IO a
withTOTP, TOTP -> IO ()
totpDestroy, (Ptr BotanTOTP -> IO CInt) -> IO TOTP
createTOTP)
= (Ptr BotanTOTPStruct -> BotanTOTP)
-> (BotanTOTP -> Ptr BotanTOTPStruct)
-> (ForeignPtr BotanTOTPStruct -> TOTP)
-> (TOTP -> ForeignPtr BotanTOTPStruct)
-> FinalizerPtr BotanTOTPStruct
-> (TOTP -> (BotanTOTP -> IO a) -> IO a, TOTP -> IO (),
(Ptr BotanTOTP -> IO CInt) -> IO TOTP)
forall botan struct object a.
Storable botan =>
(Ptr struct -> botan)
-> (botan -> Ptr struct)
-> (ForeignPtr struct -> object)
-> (object -> ForeignPtr struct)
-> FinalizerPtr struct
-> (object -> (botan -> IO a) -> IO a, object -> IO (),
(Ptr botan -> IO CInt) -> IO object)
mkBindings
Ptr BotanTOTPStruct -> BotanTOTP
MkBotanTOTP (.ptr)
ForeignPtr BotanTOTPStruct -> TOTP
MkTOTP (.foreignPtr)
FinalizerPtr BotanTOTPStruct
botan_totp_destroy
type TOTPHashName = HashName
pattern TOTP_SHA1
, TOTP_SHA256
, TOTP_SHA512
:: TOTPHashName
pattern $bTOTP_SHA1 :: TOTPHashName
$mTOTP_SHA1 :: forall {r}. TOTPHashName -> ((# #) -> r) -> ((# #) -> r) -> r
TOTP_SHA1 = SHA1
pattern $bTOTP_SHA256 :: TOTPHashName
$mTOTP_SHA256 :: forall {r}. TOTPHashName -> ((# #) -> r) -> ((# #) -> r) -> r
TOTP_SHA256 = SHA256
pattern $bTOTP_SHA512 :: TOTPHashName
$mTOTP_SHA512 :: forall {r}. TOTPHashName -> ((# #) -> r) -> ((# #) -> r) -> r
TOTP_SHA512 = SHA512
totpHashes :: [TOTPHashName]
totpHashes :: [TOTPHashName]
totpHashes =
[ TOTPHashName
TOTP_SHA1
, TOTPHashName
TOTP_SHA256
, TOTPHashName
TOTP_SHA512
]
type TOTPTimestep = Word64
type TOTPTimestamp = Word64
type TOTPCode = Word32
totpInit
:: ByteString
-> TOTPHashName
-> Int
-> TOTPTimestep
-> IO TOTP
totpInit :: TOTPHashName -> TOTPHashName -> Int -> TOTPTimestep -> IO TOTP
totpInit TOTPHashName
key TOTPHashName
algo Int
digits TOTPTimestep
timestep = TOTPHashName -> (Ptr Word8 -> CSize -> IO TOTP) -> IO TOTP
forall byte a. TOTPHashName -> (Ptr byte -> CSize -> IO a) -> IO a
asBytesLen TOTPHashName
key ((Ptr Word8 -> CSize -> IO TOTP) -> IO TOTP)
-> (Ptr Word8 -> CSize -> IO TOTP) -> IO TOTP
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
keyPtr CSize
keyLen -> do
TOTPHashName -> (Ptr CChar -> IO TOTP) -> IO TOTP
forall a. TOTPHashName -> (Ptr CChar -> IO a) -> IO a
asCString TOTPHashName
algo ((Ptr CChar -> IO TOTP) -> IO TOTP)
-> (Ptr CChar -> IO TOTP) -> IO TOTP
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
algoPtr -> do
(Ptr BotanTOTP -> IO CInt) -> IO TOTP
createTOTP ((Ptr BotanTOTP -> IO CInt) -> IO TOTP)
-> (Ptr BotanTOTP -> IO CInt) -> IO TOTP
forall a b. (a -> b) -> a -> b
$ \ Ptr BotanTOTP
out -> Ptr BotanTOTP
-> ConstPtr Word8
-> CSize
-> ConstPtr CChar
-> CSize
-> CSize
-> IO CInt
botan_totp_init
Ptr BotanTOTP
out
(Ptr Word8 -> ConstPtr Word8
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr Word8
keyPtr)
CSize
keyLen
(Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
algoPtr)
(Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
digits)
(TOTPTimestep -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral TOTPTimestep
timestep)
totpGenerate
:: TOTP
-> TOTPTimestamp
-> IO TOTPCode
totpGenerate :: TOTP -> TOTPTimestep -> IO Word32
totpGenerate TOTP
totp TOTPTimestep
timestamp = TOTP -> (BotanTOTP -> IO Word32) -> IO Word32
forall a. TOTP -> (BotanTOTP -> IO a) -> IO a
withTOTP TOTP
totp ((BotanTOTP -> IO Word32) -> IO Word32)
-> (BotanTOTP -> IO Word32) -> IO Word32
forall a b. (a -> b) -> a -> b
$ \ BotanTOTP
totpPtr -> do
(Ptr Word32 -> IO Word32) -> IO Word32
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr Word32 -> IO Word32) -> IO Word32)
-> (Ptr Word32 -> IO Word32) -> IO Word32
forall a b. (a -> b) -> a -> b
$ \ Ptr Word32
outPtr -> do
IO CInt -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO CInt -> IO ()) -> IO CInt -> IO ()
forall a b. (a -> b) -> a -> b
$ HasCallStack => IO CInt -> IO CInt
IO CInt -> IO CInt
throwBotanIfNegative (IO CInt -> IO CInt) -> IO CInt -> IO CInt
forall a b. (a -> b) -> a -> b
$ BotanTOTP -> Ptr Word32 -> TOTPTimestep -> IO CInt
botan_totp_generate BotanTOTP
totpPtr Ptr Word32
outPtr TOTPTimestep
timestamp
Ptr Word32 -> IO Word32
forall a. Storable a => Ptr a -> IO a
peek Ptr Word32
outPtr
totpCheck ::
TOTP
-> TOTPCode
-> TOTPTimestamp
-> Int
-> IO Bool
totpCheck :: TOTP -> Word32 -> TOTPTimestep -> Int -> IO Bool
totpCheck TOTP
totp Word32
code TOTPTimestep
timestamp Int
drift =
TOTP -> (BotanTOTP -> IO Bool) -> IO Bool
forall a. TOTP -> (BotanTOTP -> IO a) -> IO a
withTOTP TOTP
totp ((BotanTOTP -> IO Bool) -> IO Bool)
-> (BotanTOTP -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \ BotanTOTP
totpPtr ->
HasCallStack => IO CInt -> IO Bool
IO CInt -> IO Bool
throwBotanCatchingInvalidVerifier (IO CInt -> IO Bool) -> IO CInt -> IO Bool
forall a b. (a -> b) -> a -> b
$ BotanTOTP -> Word32 -> TOTPTimestep -> CSize -> IO CInt
botan_totp_check BotanTOTP
totpPtr Word32
code TOTPTimestep
timestamp (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
drift)