Copyright | (c) Leo D 2023 |
---|---|
License | BSD-3-Clause |
Maintainer | leo@apotheca.io |
Stability | experimental |
Portability | POSIX |
Safe Haskell | Safe-Inferred |
Language | Haskell2010 |
A block cipher by itself, is only able to securely encrypt a single data block. To be able to securely encrypt data of arbitrary length, a mode of operation applies the block cipher’s single block operation repeatedly to encrypt an entire message.
Synopsis
- newtype Cipher = MkCipher {
- getCipherForeignPtr :: ForeignPtr BotanCipherStruct
- type CipherName = ByteString
- type CipherKey = ByteString
- type CipherNonce = ByteString
- type CipherInitFlags = Word32
- pattern MaskDirection :: CipherInitFlags
- pattern Encrypt :: CipherInitFlags
- pattern Decrypt :: CipherInitFlags
- type CipherUpdateFlags = Int
- pattern CipherUpdate :: CipherUpdateFlags
- pattern CipherFinal :: CipherUpdateFlags
- withCipher :: Cipher -> (BotanCipher -> IO a) -> IO a
- cipherInit :: CipherName -> CipherInitFlags -> IO Cipher
- cipherDestroy :: Cipher -> IO ()
- cipherName :: Cipher -> IO CipherName
- cipherOutputLength :: Cipher -> Int -> IO Int
- cipherValidNonceLength :: Cipher -> Int -> IO Bool
- cipherGetTagLength :: Cipher -> IO Int
- cipherGetDefaultNonceLength :: Cipher -> IO Int
- cipherGetUpdateGranularity :: Cipher -> IO Int
- cipherGetIdealUpdateGranularity :: Cipher -> IO Int
- cipherQueryKeylen :: Cipher -> IO (Int, Int)
- cipherGetKeyspec :: Cipher -> IO (Int, Int, Int)
- cipherSetKey :: Cipher -> ByteString -> IO ()
- cipherReset :: Cipher -> IO ()
- cipherSetAssociatedData :: Cipher -> ByteString -> IO ()
- cipherStart :: Cipher -> ByteString -> IO ()
- cipherUpdate :: Cipher -> CipherUpdateFlags -> Int -> ByteString -> IO (Int, ByteString)
- cipherEncrypt :: Cipher -> ByteString -> IO ByteString
- cipherDecrypt :: Cipher -> ByteString -> IO ByteString
- cipherClear :: Cipher -> IO ()
- type CipherMode = ByteString
- cbcMode :: BlockCipherName -> CBCPaddingName -> CipherName
- cfbMode :: BlockCipherName -> CipherName
- cfbModeWith :: BlockCipherName -> Int -> CipherName
- xtsMode :: BlockCipherName -> CipherName
- type CBCPaddingName = ByteString
- pattern PKCS7 :: CBCPaddingName
- pattern OneAndZeros :: CBCPaddingName
- pattern X9_23 :: CBCPaddingName
- pattern ESP :: CBCPaddingName
- pattern CTS :: CBCPaddingName
- pattern NoPadding :: CBCPaddingName
- type AEADName = CipherName
- pattern ChaCha20Poly1305 :: CipherName
- chaCha20Poly1305 :: AEADName
- type AEADMode = ByteString
- gcmMode :: BlockCipher128Name -> AEADName
- gcmModeWith :: BlockCipher128Name -> Int -> AEADName
- ocbMode :: BlockCipher128Name -> AEADName
- ocbModeWith :: BlockCipher128Name -> Int -> AEADName
- eaxMode :: BlockCipherName -> AEADName
- eaxModeWith :: BlockCipherName -> Int -> AEADName
- sivMode :: BlockCipher128Name -> AEADName
- ccmMode :: BlockCipher128Name -> AEADName
- ccmModeWith :: BlockCipher128Name -> Int -> Int -> AEADName
- cipherEncryptOnline :: Cipher -> ByteString -> IO ByteString
- cipherDecryptOnline :: Cipher -> ByteString -> IO ByteString
- cipherModes :: [CipherName]
- cbcPaddings :: [CBCPaddingName]
- aeads :: [AEADName]
- allCiphers :: [CipherName]
Cipher
A cipher
mode is a cryptographic algorithm suitable for encrypting and
decrypting large quantities of arbitrarily-sized data. An aead
is a cipher
mode that also used to provide authentication of the ciphertext, potentially
with plaintext `associated data`.
Usage
Unless you need a specific cipher
or aead
, it is strongly recommended that you use the `cbcMode AES256 PKCS7` and `gcmMode AES256` (or ChaCha20Poly1305
) algorithms respectively.
import Botan.Low.Cipher encrypter <- cipherInit ChaCha20Poly1305 Encrypt
To use a cipher, we first need to generate (if we haven't already) a secret key.
import Botan.Low.RNG rng <- rngInit "user" -- We will use the maximum key size; ChaCha20Poly1305 keys are always 32 bytes (_,keySize,_) <- cipherGetKeyspec encrypter -- Block cipher keys are randomly generated key <- rngGet rng keySize
After the key is generated, we must set it as the cipher key:
cipherSetKey encrypter key
If the cipher is an aead
, we may also set the `associated data`:
cipherSetAssociatedData encrypter "Fee fi fo fum!"
To ensure that the key is not leaked, we should generate a new nonce for every encryption. The range of allowed nonce sizes depends on the specific algorithm.
import Botan.Low.RNG -- The default ChaCha20Poly1305 nonce is always 12 bytes. nonceSize <- cipherGetDefaultNonceLength encrypter nonce <- rngGet rng nonceSize
To encrypt a message, it must be a multiple of the block size. If the cipher was an aead, the authentication tag will automatically be included in the ciphertext
-- Rarely, some cipher modes require that the message size be aligned to the block size -- Consult algorithm-specific documentation if this occurs. message = "I smell the blood of an Englishman!" cipherStart encrypter nonce ciphertext <- cipherEncrypt encrypter message
To decrypt a message, we run the same process with a decrypter, using the same key
and nonce
to decode the ciphertext
:
decrypter <- cipherInit ChaCha20Poly1305 Decrypt cipherSetKey decrypter key cipherSetAssociatedData decrypter "Fee fi fo fum!" cipherStart decrypter nonce plaintext <- cipherDecrypt decrypter ciphertext message == plaintext -- True
You can completely clear a cipher's state, leaving it ready for reuse:
cipherClear encrypter -- You'll have to set the key, nonce, (and ad, if aead) again. cipherSetKey encrypter anotherKey cipherStart encrypter anotherNonce cipherSetAssociatedData encrypter anotherAD -- Process another message anotherCiphertext <- cipherEncrypt encrypter anotherMessage
If you are encrypting or decrypting multiple messages with the same key, you can reset the cipher instead of clearing it, leaving the key set:
cipherClear encrypter -- This is equivalent to calling cipherClear followed by cipherSetKey with the original key. -- You'll have to set the nonce (and ad, if aead) again, but not the key. cipherStart encrypter anotherNonce cipherSetAssociatedData encrypter anotherAD -- Process another message with the same key anotherCiphertext <- cipherEncrypt encrypter anotherMessage
MkCipher | |
|
type CipherName = ByteString Source #
type CipherKey = ByteString Source #
type CipherNonce = ByteString Source #
type CipherInitFlags = Word32 Source #
pattern MaskDirection :: CipherInitFlags Source #
pattern Encrypt :: CipherInitFlags Source #
pattern Decrypt :: CipherInitFlags Source #
type CipherUpdateFlags = Int Source #
pattern CipherUpdate :: CipherUpdateFlags Source #
pattern CipherFinal :: CipherUpdateFlags Source #
:: CipherName | name |
-> CipherInitFlags | flags |
-> IO Cipher | cipher |
Initialize a cipher object
cipherDestroy :: Cipher -> IO () Source #
Destroy the cipher object immediately
Return the output length of this cipher, for a particular input length.
WARNING: This function is of limited use. From the C++ docs: /** * Returns the size of the output if this transform is used to process a * message with input_length bytes. In most cases the answer is precise. * If it is not possible to precise (namely for CBC decryption) instead an * upper bound is returned. */ We need to explicitly calculate padding + tag length
cipherValidNonceLength Source #
Return if the specified nonce length is valid for this cipher
NOTE: This just always seems to return True
, even for -1 and maxBound
Get the tag length of the cipher (0 for non-AEAD modes)
cipherGetDefaultNonceLength Source #
Get the default nonce length of this cipher
cipherGetUpdateGranularity Source #
Return the update granularity of the cipher; botan_cipher_update must be called with blocks of this size, except for the final.
cipherGetIdealUpdateGranularity Source #
Return the ideal update granularity of the cipher. This is some multiple of the update granularity, reflecting possibilities for optimization.
Some ciphers (ChaChaPoly, EAX) may consume less input than the reported ideal granularity
Deprecated: Prefer cipherGetKeyspec.
Get information about the key lengths.
Get information about the supported key lengths.
Reset the message specific state for this cipher. Without resetting the keys, this resets the nonce, and any state associated with any message bits that have been processed so far.
It is conceptually equivalent to calling botan_cipher_clear followed by botan_cipher_set_key with the original key.
cipherSetAssociatedData Source #
:: Cipher | cipher |
-> ByteString | ad |
-> IO () |
Set the associated data. Will fail if cipher is not an AEAD
:: Cipher | cipher |
-> ByteString | nonce |
-> IO () |
Begin processing a new message using the provided nonce
:: Cipher | cipher |
-> CipherUpdateFlags | flags |
-> Int | output_size |
-> ByteString | input_bytes[] |
-> IO (Int, ByteString) | (input_consumed,output[]) |
"Encrypt some data"
This function is ill-documented.
See the source for authoritative details: https://github.com/randombit/botan/blob/72dc18bbf598f2c3bef81a4fb2915e9c3c524ac4/src/lib/ffi/ffi_cipher.cpp#L133
Some ciphers (ChaChaPoly, EAX) may consume less input than the reported ideal granularity
cipherEncrypt :: Cipher -> ByteString -> IO ByteString Source #
Encrypt and finalize a complete piece of data.
This is not a canonical Botan C/C++ function.
cipherDecrypt :: Cipher -> ByteString -> IO ByteString Source #
Encrypt and finalize a complete piece of data.
This is not a canonical Botan C/C++ function.
cipherClear :: Cipher -> IO () Source #
Reset the key, nonce, AD and all other state on this cipher object
Cipher modes
type CipherMode = ByteString Source #
cbcMode :: BlockCipherName -> CBCPaddingName -> CipherName Source #
cfbMode :: BlockCipherName -> CipherName Source #
cfbModeWith :: BlockCipherName -> Int -> CipherName Source #
xtsMode :: BlockCipherName -> CipherName Source #
CBC padding
type CBCPaddingName = ByteString Source #
pattern PKCS7 :: CBCPaddingName Source #
pattern OneAndZeros :: CBCPaddingName Source #
pattern X9_23 :: CBCPaddingName Source #
pattern ESP :: CBCPaddingName Source #
pattern CTS :: CBCPaddingName Source #
pattern NoPadding :: CBCPaddingName Source #
AEAD
type AEADName = CipherName Source #
pattern ChaCha20Poly1305 :: CipherName Source #
AEAD modes
type AEADMode = ByteString Source #
gcmMode :: BlockCipher128Name -> AEADName Source #
gcmModeWith :: BlockCipher128Name -> Int -> AEADName Source #
ocbMode :: BlockCipher128Name -> AEADName Source #
ocbModeWith :: BlockCipher128Name -> Int -> AEADName Source #
eaxMode :: BlockCipherName -> AEADName Source #
eaxModeWith :: BlockCipherName -> Int -> AEADName Source #
sivMode :: BlockCipher128Name -> AEADName Source #
ccmMode :: BlockCipher128Name -> AEADName Source #
ccmModeWith :: BlockCipher128Name -> Int -> Int -> AEADName Source #
Convenience
cipherEncryptOnline :: Cipher -> ByteString -> IO ByteString Source #
Deprecated: Moving from botan-low to botan
cipherDecryptOnline :: Cipher -> ByteString -> IO ByteString Source #
Deprecated: Moving from botan-low to botan
cipherModes :: [CipherName] Source #
cbcPaddings :: [CBCPaddingName] Source #
allCiphers :: [CipherName] Source #