botan-low-0.0.2.0: src/Botan/Low/Utility.hs
{-|
Module : Botan.Low.Utility
Description : Utility functions
Copyright : (c) 2023-2024, Apotheca Labs
(c) 2024-2025, Haskell Foundation
License : BSD-3-Clause
Maintainer : joris@well-typed.com, leo@apotheca.io
Stability : experimental
Portability : POSIX
-}
module Botan.Low.Utility
( constantTimeCompare
, scrubMem
, HexEncodingFlags
, pattern HexUpperCase
, pattern HexLowerCase
, hexEncode
, hexDecode
, base64Encode
, base64Decode
) where
import Data.Bool
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text
import qualified Data.ByteString as ByteString
import System.IO.Unsafe
import Botan.Bindings.Utility
import Botan.Low.Error
import Botan.Low.Prelude
import Botan.Low.Make (allocBytesQuerying, allocBytesQueryingCString)
-- NOTE: Use of Text is unique here - leave for Text for `botan`
-- | Returns 0 if x[0..len] == y[0..len], -1 otherwise.
constantTimeCompare
:: ByteString -- ^ __x__
-> ByteString -- ^ __y__
-> Int -- ^ __len__
-> IO Bool
constantTimeCompare x y len = do
asBytesLen x $ \ xPtr xlen -> do
asBytesLen y $ \ yPtr ylen -> do
result <- botan_constant_time_compare
(ConstPtr xPtr)
(ConstPtr yPtr)
xlen
case result of
0 -> return True
_ -> return False
scrubMem
:: Ptr a -- ^ __mem__
-> Int -- ^ __bytes__
-> IO ()
scrubMem ptr sz = throwBotanIfNegative_ $ botan_scrub_mem (castPtr ptr) (fromIntegral sz)
type HexEncodingFlags = Word32
pattern HexUpperCase -- ^ NOTE: Not an actual flag
, HexLowerCase
:: HexEncodingFlags
pattern HexUpperCase = BOTAN_FFI_HEX_UPPER_CASE
pattern HexLowerCase = BOTAN_FFI_HEX_LOWER_CASE
-- | Performs hex encoding of binary data in x of size len bytes. The output buffer out must be of at least x*2 bytes in size. If flags contains BOTAN_FFI_HEX_LOWER_CASE, hex encoding will only contain lower-case letters, upper-case letters otherwise. Returns 0 on success, 1 otherwise.
-- DISCUSS: Handling of positive return code / BOTAN_FFI_INVALID_VERIFIER?
-- DISCUSS: Use of Text.decodeUtf8 - bad, partial function! - but safe here?
hexEncode
:: ByteString -- ^ __x__
-> HexEncodingFlags -- ^ __flags__
-> IO Text -- ^ __y__
hexEncode bytes flags = Text.decodeUtf8 <$> do
asBytesLen bytes $ \ bytesPtr bytesLen -> do
allocBytes (fromIntegral $ 2 * bytesLen) $ \ hexPtr -> do
throwBotanIfNegative_ $ botan_hex_encode
(ConstPtr bytesPtr)
bytesLen
hexPtr
flags
-- | "Hex decode some data"
-- DISCUSS: Return value, maybe vs exception
-- DISCUSS: Botan documentation is lacking here
-- WARNING: Does not actually check that len is a multiple of 2
hexDecode
:: Text -- ^ __hex_str__
-> IO ByteString -- ^ __out__
hexDecode txt = do
asBytesLen (Text.encodeUtf8 txt) $ \ hexPtr hexLen -> do
allocBytesQuerying $ \ bytesPtr szPtr -> do
botan_hex_decode
(ConstPtr hexPtr)
hexLen
bytesPtr
szPtr
-- NOTE: Does not check tht base64Len == peek sizePtr
base64Encode
:: ByteString -- ^ __x__
-> IO Text -- ^ __out__
base64Encode bytes = Text.decodeUtf8 <$> do
asBytesLen bytes $ \ bytesPtr bytesLen -> do
allocBytesQueryingCString $ \ base64Ptr szPtr -> do
botan_base64_encode
(ConstPtr bytesPtr)
bytesLen
base64Ptr
szPtr
-- | Ditto everything hexDecode
base64Decode
:: Text -- ^ __base64_str__
-> IO ByteString -- ^ __out__
base64Decode txt = do
asBytesLen (Text.encodeUtf8 txt) $ \ base64Ptr base64Len -> do
allocBytesQueryingCString $ \ bytesPtr szPtr -> do
botan_base64_decode
(ConstPtr base64Ptr)
base64Len
bytesPtr
szPtr