module Botan.Low.HOTP (
HOTP(..)
, HOTPHashName
, HOTPCounter
, HOTPCode
, withHOTP
, hotpInit
, hotpDestroy
, hotpGenerate
, hotpCheck
, pattern HOTP_SHA1
, pattern HOTP_SHA256
, pattern HOTP_SHA512
, hotpHashes
) where
import Botan.Bindings.ConstPtr (ConstPtr (..))
import Botan.Bindings.HOTP
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 HOTP = MkHOTP { HOTP -> ForeignPtr BotanHOTPStruct
foreignPtr :: ForeignPtr BotanHOTPStruct }
withHOTP :: HOTP -> (BotanHOTP -> IO a) -> IO a
hotpDestroy :: HOTP -> IO ()
createHOTP :: (Ptr BotanHOTP -> IO CInt) -> IO HOTP
(HOTP -> (BotanHOTP -> IO a) -> IO a
withHOTP, HOTP -> IO ()
hotpDestroy, (Ptr BotanHOTP -> IO CInt) -> IO HOTP
createHOTP)
= (Ptr BotanHOTPStruct -> BotanHOTP)
-> (BotanHOTP -> Ptr BotanHOTPStruct)
-> (ForeignPtr BotanHOTPStruct -> HOTP)
-> (HOTP -> ForeignPtr BotanHOTPStruct)
-> FinalizerPtr BotanHOTPStruct
-> (HOTP -> (BotanHOTP -> IO a) -> IO a, HOTP -> IO (),
(Ptr BotanHOTP -> IO CInt) -> IO HOTP)
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 BotanHOTPStruct -> BotanHOTP
MkBotanHOTP (.ptr)
ForeignPtr BotanHOTPStruct -> HOTP
MkHOTP (.foreignPtr)
FinalizerPtr BotanHOTPStruct
botan_hotp_destroy
type HOTPHashName = HashName
pattern HOTP_SHA1
, HOTP_SHA256
, HOTP_SHA512
:: HOTPHashName
pattern $bHOTP_SHA1 :: HOTPHashName
$mHOTP_SHA1 :: forall {r}. HOTPHashName -> ((# #) -> r) -> ((# #) -> r) -> r
HOTP_SHA1 = SHA1
pattern $bHOTP_SHA256 :: HOTPHashName
$mHOTP_SHA256 :: forall {r}. HOTPHashName -> ((# #) -> r) -> ((# #) -> r) -> r
HOTP_SHA256 = SHA256
pattern $bHOTP_SHA512 :: HOTPHashName
$mHOTP_SHA512 :: forall {r}. HOTPHashName -> ((# #) -> r) -> ((# #) -> r) -> r
HOTP_SHA512 = SHA512
hotpHashes :: [HOTPHashName]
hotpHashes :: [HOTPHashName]
hotpHashes =
[ HOTPHashName
HOTP_SHA1
, HOTPHashName
HOTP_SHA256
, HOTPHashName
HOTP_SHA512
]
type HOTPCounter = Word64
type HOTPCode = Word32
hotpInit
:: ByteString
-> HashName
-> Int
-> IO HOTP
hotpInit :: HOTPHashName -> HOTPHashName -> Int -> IO HOTP
hotpInit HOTPHashName
key HOTPHashName
algo Int
digits = HOTPHashName -> (Ptr Word8 -> CSize -> IO HOTP) -> IO HOTP
forall byte a. HOTPHashName -> (Ptr byte -> CSize -> IO a) -> IO a
asBytesLen HOTPHashName
key ((Ptr Word8 -> CSize -> IO HOTP) -> IO HOTP)
-> (Ptr Word8 -> CSize -> IO HOTP) -> IO HOTP
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
keyPtr CSize
keyLen -> do
HOTPHashName -> (Ptr CChar -> IO HOTP) -> IO HOTP
forall a. HOTPHashName -> (Ptr CChar -> IO a) -> IO a
asCString HOTPHashName
algo ((Ptr CChar -> IO HOTP) -> IO HOTP)
-> (Ptr CChar -> IO HOTP) -> IO HOTP
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
algoPtr -> do
(Ptr BotanHOTP -> IO CInt) -> IO HOTP
createHOTP ((Ptr BotanHOTP -> IO CInt) -> IO HOTP)
-> (Ptr BotanHOTP -> IO CInt) -> IO HOTP
forall a b. (a -> b) -> a -> b
$ \ Ptr BotanHOTP
out -> Ptr BotanHOTP
-> ConstPtr Word8 -> CSize -> ConstPtr CChar -> CSize -> IO CInt
botan_hotp_init
Ptr BotanHOTP
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)
hotpGenerate
:: HOTP
-> HOTPCounter
-> IO HOTPCode
hotpGenerate :: HOTP -> Word64 -> IO Word32
hotpGenerate HOTP
hotp Word64
counter = HOTP -> (BotanHOTP -> IO Word32) -> IO Word32
forall a. HOTP -> (BotanHOTP -> IO a) -> IO a
withHOTP HOTP
hotp ((BotanHOTP -> IO Word32) -> IO Word32)
-> (BotanHOTP -> IO Word32) -> IO Word32
forall a b. (a -> b) -> a -> b
$ \ BotanHOTP
hotpPtr -> 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
$ BotanHOTP -> Ptr Word32 -> Word64 -> IO CInt
botan_hotp_generate BotanHOTP
hotpPtr Ptr Word32
outPtr Word64
counter
Ptr Word32 -> IO Word32
forall a. Storable a => Ptr a -> IO a
peek Ptr Word32
outPtr
hotpCheck ::
HOTP
-> HOTPCode
-> HOTPCounter
-> Int
-> IO (Bool, HOTPCounter)
hotpCheck :: HOTP -> Word32 -> Word64 -> Int -> IO (Bool, Word64)
hotpCheck HOTP
hotp Word32
code Word64
counter Int
resync =
HOTP -> (BotanHOTP -> IO (Bool, Word64)) -> IO (Bool, Word64)
forall a. HOTP -> (BotanHOTP -> IO a) -> IO a
withHOTP HOTP
hotp ((BotanHOTP -> IO (Bool, Word64)) -> IO (Bool, Word64))
-> (BotanHOTP -> IO (Bool, Word64)) -> IO (Bool, Word64)
forall a b. (a -> b) -> a -> b
$ \ BotanHOTP
hotpPtr ->
(Ptr Word64 -> IO (Bool, Word64)) -> IO (Bool, Word64)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr Word64 -> IO (Bool, Word64)) -> IO (Bool, Word64))
-> (Ptr Word64 -> IO (Bool, Word64)) -> IO (Bool, Word64)
forall a b. (a -> b) -> a -> b
$ \ Ptr Word64
outPtr -> do
Bool
valid <- 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
$ BotanHOTP -> Ptr Word64 -> Word32 -> Word64 -> CSize -> IO CInt
botan_hotp_check BotanHOTP
hotpPtr Ptr Word64
outPtr Word32
code Word64
counter (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
resync)
Word64
nextCounter <- Ptr Word64 -> IO Word64
forall a. Storable a => Ptr a -> IO a
peek Ptr Word64
outPtr
(Bool, Word64) -> IO (Bool, Word64)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool
valid, Word64
nextCounter)