Z-Botan 0.3.0.0 → 0.3.1.0
raw patch · 7 files changed
+70/−29 lines, 7 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Z.Botan.FFI: botan_cipher_get_minimum_final_size :: BotanStructT -> MBA# Int -> IO CInt
Files
- ChangeLog.md +5/−1
- Z-Botan.cabal +1/−1
- Z/Botan/FFI.hsc +1/−0
- Z/Crypto/Cipher.hs +53/−27
- third_party/botan/botan_all.cpp too large to diff
- third_party/botan/src/lib/ffi/ffi.h +5/−0
- third_party/botan/src/lib/ffi/ffi_cipher.cpp +5/−0
ChangeLog.md view
@@ -1,6 +1,10 @@ # Revision history for z-botan -## 0.2.0.0 -- 2020-05-14+## 0.3.1.0 -- 2020-05-14++* Change `cipherBIO` to buffer an extra chunk so that the last chunk is larger than minimum final chunk size, add a file encryption example.++## 0.3.0.0 -- 2020-05-14 * Change `EMEPadding` to `EncParam`, add `SM2EncParam`. * Change `EMSA` to `SignParam`, add `Ed25519Pure`, `Ed25519ph`, `Ed25519Hash`, `SM2SignParam`.
Z-Botan.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: Z-Botan-version: 0.3.0.0+version: 0.3.1.0 synopsis: Crypto for Haskell description: Crypto for Haskell, based on <http://botan.randombit.net/ Botan> license: BSD-3-Clause
Z/Botan/FFI.hsc view
@@ -218,6 +218,7 @@ foreign import ccall unsafe botan_cipher_get_default_nonce_length :: BotanStructT -> MBA## Int -> IO CInt foreign import ccall unsafe botan_cipher_get_update_granularity :: BotanStructT -> MBA## Int -> IO CInt foreign import ccall unsafe botan_cipher_get_tag_length :: BotanStructT -> MBA## Int -> IO CInt+foreign import ccall unsafe botan_cipher_get_minimum_final_size :: BotanStructT -> MBA## Int -> IO CInt -------------------------------------------------------------------------------- -- PBKDF
Z/Crypto/Cipher.hs view
@@ -387,10 +387,13 @@ (t, _) <- allocPrimUnsafe $ \ pt -> botan_cipher_get_tag_length pci pt + (f, _) <- allocPrimUnsafe $ \ pt ->+ botan_cipher_get_minimum_final_size pci pt+ (n, _) <- allocPrimUnsafe $ \ pn -> botan_cipher_get_default_nonce_length pci pn - return (Cipher ci name g (KeySpec a b c) t n)+ return (Cipher ci name g (KeySpec a b c) t f n) -------------------------------------------------------------------------------- --@@ -538,7 +541,8 @@ , cipherKeySpec :: {-# UNPACK #-} !KeySpec -- ^ cipher keyspec , cipherTagLength :: {-# UNPACK #-} !Int -- ^ AEAD tag length, -- will be zero for non-authenticated ciphers.- , defaultNonceLength :: {-# UNPACK #-} !Int -- ^ a proper default nonce length+ , cipherMinFinalSize :: {-# UNPACK #-} !Int -- ^ Minimum input size for final chunk.+ , defaultNonceLength :: {-# UNPACK #-} !Int -- ^ a proper default nonce length. } deriving (Show, Generic) deriving anyclass T.Print@@ -546,7 +550,7 @@ -- | Pass 'Cipher' to FFI as 'botan_cipher_t'. withCipher :: Cipher -> (BotanStructT -> IO r) -> IO r {-# INLINABLE withCipher #-}-withCipher (Cipher c _ _ _ _ _) = withBotanStruct c+withCipher (Cipher c _ _ _ _ _ _) = withBotanStruct c -- | Create a new cipher. --@@ -572,17 +576,20 @@ (t, _) <- allocPrimUnsafe $ \ pt -> botan_cipher_get_tag_length pci pt + (f, _) <- allocPrimUnsafe $ \ pt ->+ botan_cipher_get_minimum_final_size pci pt+ (n, _) <- allocPrimUnsafe $ \ pn -> botan_cipher_get_default_nonce_length pci pn - return (Cipher ci name g (KeySpec a b c) t n)+ return (Cipher ci name g (KeySpec a b c) t f n) -- | Clear the internal state (such as keys) of this cipher object. -- clearCipher :: HasCallStack => Cipher -> IO () {-# INLINABLE clearCipher #-}-clearCipher (Cipher ci _ _ _ _ _) =- withBotanStruct ci (throwBotanIfMinus_ . botan_cipher_clear)+clearCipher ci =+ withCipher ci (throwBotanIfMinus_ . botan_cipher_clear) -- | Reset the message specific state for this cipher. -- Without resetting the keys, this resets the nonce, and any state@@ -593,15 +600,15 @@ -- resetCipher :: HasCallStack => Cipher -> IO () {-# INLINABLE resetCipher #-}-resetCipher (Cipher ci _ _ _ _ _) =- withBotanStruct ci (throwBotanIfMinus_ . botan_cipher_reset)+resetCipher ci =+ withCipher ci (throwBotanIfMinus_ . botan_cipher_reset) -- | Set the key for this cipher object -- setCipherKey :: HasCallStack => Cipher -> V.Bytes -> IO () {-# INLINABLE setCipherKey #-}-setCipherKey (Cipher ci _ _ _ _ _) key =- withBotanStruct ci $ \ pci -> do+setCipherKey ci key =+ withCipher ci $ \ pci -> do withPrimVectorUnsafe key $ \ pkey key_off key_len -> do throwBotanIfMinus_ (hs_botan_cipher_set_key pci pkey key_off key_len)@@ -610,8 +617,8 @@ -- setAssociatedData :: HasCallStack => Cipher -> V.Bytes -> IO () {-# INLINABLE setAssociatedData #-}-setAssociatedData (Cipher ci _ _ _ _ _) ad =- withBotanStruct ci $ \ pci -> do+setAssociatedData ci ad =+ withCipher ci $ \ pci -> do withPrimVectorUnsafe ad $ \ pad ad_off ad_len -> do throwBotanIfMinus_ (hs_botan_cipher_set_associated_data pci pad ad_off ad_len)@@ -623,8 +630,8 @@ -> V.Bytes -- ^ nonce -> IO () {-# INLINABLE startCipher #-}-startCipher (Cipher ci _ _ _ _ _) nonce =- withBotanStruct ci $ \ pci -> do+startCipher ci nonce =+ withCipher ci $ \ pci -> do withPrimVectorUnsafe nonce $ \ pnonce nonce_off nonce_len -> do throwBotanIfMinus_ (hs_botan_cipher_start pci pnonce nonce_off nonce_len)@@ -638,8 +645,8 @@ -> V.Bytes -> IO (V.Bytes, V.Bytes) -- ^ trailing input, output {-# INLINABLE updateCipher #-}-updateCipher (Cipher ci _ _ _ _ _) input =- withBotanStruct ci $ \ pci -> do+updateCipher ci input =+ withCipher ci $ \ pci -> do withPrimVectorUnsafe input $ \ in_p in_off in_len -> do (out, r) <- allocPrimVectorUnsafe in_len $ \ out_p -> throwBotanIfMinus (hs_botan_cipher_update pci@@ -655,7 +662,7 @@ -> V.Bytes -> IO V.Bytes {-# INLINABLE finishCipher #-}-finishCipher (Cipher ci _ ug _ tag_len _) input =+finishCipher (Cipher ci _ ug _ tag_len _ _) input = withBotanStruct ci $ \ pci -> do withPrimVectorUnsafe input $ \ in_p in_off in_len -> do let !out_len = in_len + ug + tag_len@@ -669,25 +676,44 @@ -- | Wrap a cipher into a 'BIO' node(experimental). ----- The cipher should have already started by setting key, nounce, etc.+-- The cipher should have already started by setting key, nounce, etc,+-- for example to encrypt a file in constant memory: ----- Note some cipher modes have a minimal input length requirement for last chunk(CBC_CTS, XTS, etc.),--- which may not be suitable for arbitrary bytes streams.+-- @+-- encryptFile :: CBytes -> CBytes -> IO ()+-- encryptFile origin target = do+-- let demoKey = "12345678123456781234567812345678"+-- nonce = "demo only, use random nonce"+-- cipher <- newCipher (EAX AES256) CipherEncrypt+-- setCipherKey cipher demoKey+-- startCipher cipher nonce+-- encryptor <- cipherBIO cipher --+-- withResource (initSourceFromFile origin) $ \ src ->+-- withResource (initSinkToFile target) $ \ sink ->+-- runBIO_ $ src . encryptor . sink+-- @+--+-- Note that many cipher modes have a maximum length limit on the plaintext under a security context,+-- i.e. a key nonce combination. If you want to encrypt a large message, please consider divide it into+-- smaller chunks, and re-key or change the iv. cipherBIO :: HasCallStack => Cipher -> IO (BIO V.Bytes V.Bytes) {-# INLINABLE cipherBIO #-} cipherBIO c = do trailingRef <- newIORef V.empty return $ \ k mbs -> case mbs of- Just bs -> do+ Just chunk -> do trailing <- readIORef trailingRef- let chunk = trailing `V.append` bs- (rest, out) <- updateCipher c chunk- writeIORef trailingRef rest- unless (V.null out) (k (Just out))+ if (V.length trailing >= cipherUpdateGranularity c)+ && (V.length chunk >= cipherMinFinalSize c)+ then do+ (rest, out) <- updateCipher c trailing+ k (Just out)+ writeIORef trailingRef (rest `V.append` chunk)+ else writeIORef trailingRef (trailing `V.append` chunk) _ -> do trailing <- readIORef trailingRef bs <- finishCipher c trailing if V.null bs- then k (Just bs) >> k EOF- else k EOF+ then k EOF+ else k (Just bs) >> k EOF
third_party/botan/botan_all.cpp view
file too large to diff
third_party/botan/src/lib/ffi/ffi.h view
@@ -451,6 +451,11 @@ BOTAN_PUBLIC_API(2,0) int botan_cipher_get_tag_length(botan_cipher_t cipher, size_t* tag_size); /**+* Get the minimum input size required of the cipher.+*/+BOTAN_PUBLIC_API(2,19) int botan_cipher_get_minimum_final_size(botan_cipher_t cipher, size_t* fs);++/** * Get the default nonce length of this cipher */ BOTAN_PUBLIC_API(2,0) int botan_cipher_get_default_nonce_length(botan_cipher_t cipher, size_t* nl);
third_party/botan/src/lib/ffi/ffi_cipher.cpp view
@@ -224,6 +224,11 @@ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *tl = c.tag_size(); }); } +int botan_cipher_get_minimum_final_size(botan_cipher_t cipher, size_t* fs)+ {+ return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, { *fs = c.minimum_final_size(); });+ }+ int botan_cipher_name(botan_cipher_t cipher, char* name, size_t* name_len) { return BOTAN_FFI_DO(Botan::Cipher_Mode, cipher, c, {