{"id":20904836,"url":"https://github.com/haskell-cryptography/botan","last_synced_at":"2025-05-13T05:30:56.596Z","repository":{"id":179035674,"uuid":"662732080","full_name":"haskell-cryptography/botan","owner":"haskell-cryptography","description":"Haskell bindings for the Botan cryptography library","archived":false,"fork":false,"pushed_at":"2025-01-20T03:46:09.000Z","size":1057,"stargazers_count":36,"open_issues_count":8,"forks_count":6,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-01T18:15:55.736Z","etag":null,"topics":["botan","cryptography","haskell"],"latest_commit_sha":null,"homepage":"","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/haskell-cryptography.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-05T19:06:11.000Z","updated_at":"2025-03-02T20:14:50.000Z","dependencies_parsed_at":"2023-11-15T20:29:42.541Z","dependency_job_id":"dd2f4e5a-6693-4459-a128-06fbaa1c2d4d","html_url":"https://github.com/haskell-cryptography/botan","commit_stats":null,"previous_names":["apotheca/botan","haskellfoundation/botan","haskell-cryptography/botan"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell-cryptography%2Fbotan","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell-cryptography%2Fbotan/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell-cryptography%2Fbotan/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haskell-cryptography%2Fbotan/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/haskell-cryptography","download_url":"https://codeload.github.com/haskell-cryptography/botan/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253882792,"owners_count":21978548,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["botan","cryptography","haskell"],"created_at":"2024-11-18T13:19:12.196Z","updated_at":"2025-05-13T05:30:56.099Z","avatar_url":"https://github.com/haskell-cryptography.png","language":"Haskell","funding_links":["https://ko-fi.com/V7V1S5JTG"],"categories":[],"sub_categories":[],"readme":"# Welcome to botan\n\n\u003c!-- TODO: Badges: hackage)  --\u003e\n\n![CI](https://github.com/haskellfoundation/botan/actions/workflows/CI.yml/badge.svg)\n\n`botan` is a set of Haskell bindings for the [Botan](https://botan.randombit.net/) cryptography library.\n\n\u003e Botan's goal is to be the best option for cryptography in C++ by offering the tools necessary to implement a range of practical systems, such as TLS protocol, X.509 certificates, modern AEAD ciphers, PKCS#11 and TPM hardware support, password hashing, and post quantum crypto schemes.\n\n# Acknowledgements\n\nThis project has received support from the [Haskell Foundation](https://haskell.foundation/), and was made possible through funding provided by [Mercury](https://mercury.com/).\n\n\u003ca href=\"https://mercury.com/\" alt=\"Mercury\"\u003e\u003cimg src=\"https://github.com/haskellfoundation/botan/blob/main/contributors/mercury.svg\" width=\"320\"\u003e\u003c/a\u003e\n\n# Navigation\n\n\u003cdetails open\u003e\u003csummary\u003eExpand / Collapse Navigation\u003c/summary\u003e\n\n- [Welcome to botan](#Welcome-to-botan)\n- [Acknowledgements](#Acknowledgements)\n- [Introduction](#Introduction)\n- [Installation](#Installation)\n    - [Unix package](#Unix-package)\n    - [MacOS package](#MacOS-package)\n    - [From source](#From-source)\n    - [Windows from source](#Windows-from-source)\n- [Usage](#Usage)\n- [Tutorials](#Tutorials)\n- [Enabling experimental support](#Enabling-experimental-support)\n- [Resources](#Resources)\n- [License](#License)\n- [Contributing](#Contributing)\n    - [Reporting Bugs](#Reporting-Bugs)\n    - [Assist in Development](#Assist-in-Development)\n- [Donations](#Donations)\n\n\u003c/details\u003e\n\n# Introduction\n\nThis project has the goal of providing a set of safe and performant bindings to the Botan C++ cryptography library via its C FFI (Foreign Function Interface). It does this by providing 3 libraries at varying levels of complexity and abstraction:\n\n- `botan-bindings` contains raw bindings with buffers and pointers, and is otherwise an almost a 1:1 translation of the C FFI into Haskell\n- `botan-low` contains low-level bindings with imperative IO and exceptions, and safely wraps buffers and pointers into bytestrings and autoreleased objects\n- `botan` contains high-level bindings with strong types and idiomatic Haskell, and provides algebraic data types and convenience functions\n\nWe suggest using the highest-level library possible, unless you wish to build your own abstraction over the Botan C++ library. The highest-level stable library is currently: `botan-low`\n\n\u003cdetails\u003e\n\n\u003csummary\u003eFeatures\u003c/summary\u003e\n\nThis library provides its bindings through the Botan C FFI, which does not currently cover the entire range of features available in C++. As such, it provides a sizeable yet limited subset of those features.\n\nThese bindings provide the following features:\n\n- Random number generators\n- Hashing and non-cryptographic checksums\n- Message authentication codes\n- Block, mode, and AEAD ciphers\n- Password hashing and key derivation functions\n- Hash- and time-based one-time passwords\n- Post-quantum crypto schemes\n- SRP6 password authenticated key exchange\n- X.509 certificate systems (experimental)\n- ZFEC forward error correction\n\n\u003e NOTE: This project includes efforts to expand this subset of features through a fork of the Botan C++ library - see [Enabling experimental support](#Enabling-experimental-support) for more details. This fork will be contributed back to the original library when it becomes sufficiently stable.\n    \n\u003c/details\u003e\n\n# Installation\n\nThis library requires Botan 3 to be installed in order to work. See [Building the Library](https://botan.randombit.net/handbook/building.html) in the handbook for more details.\n\n## Unix package\n\n~~Botan is available already in nearly all [packaging systems](https://repology.org/project/botan/versions) so you can probably install it through your distribution / system package manager.~~\n\nAt current, Botan **2** is readily available, but Botan **3** is not yet available as a prebuilt linux package. Please see 'Building from source'.\n\n\u003cdetails\u003e\u003csummary\u003eArch\u003c/summary\u003e\n\n\u003e Untested.\n\n```shell\npacman -S botan\n# or maybe\npacman -S botan3\n```\n    \n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eDebian\u003c/summary\u003e\n\n\u003e Untested.\n\n```shell\napt-get update\napt-get install botan\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eRed Hat\u003c/summary\u003e\n\n\u003e Untested.\n\n```shell\nyum update\nyum install botan\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eUbuntu\u003c/summary\u003e\n\n\u003e Untested.\n\n```shell\nsudo apt update\nsudo apt install botan\n```\n\n\u003c/details\u003e\n\n## MacOS package\n\nBotan is available through the [Homebrew](https://brew.sh/) package manager:\n\n\u003cdetails\u003e\u003csummary\u003eHomebrew\u003c/summary\u003e\n\n```shell\nbrew install botan\n```\n\n\u003c/details\u003e\n\n## From source\n\nBotan can be built from source, for additional configuration options and customization.\n\n\u003cdetails\u003e\u003csummary\u003eBuild from source\u003c/summary\u003e\n\nFirst, clone the Botan C++ repository:\n\n```shell\ngit clone https://github.com/randombit/botan\n```\n\nBotan’s build configuration is controlled by `configure.py`, and requires Python 3.x or later.\n\nThis works for most systems:\n\n```shell\n./configure.py [--prefix=/some/directory]\nmake\nmake install\n```\n\nIf you wish to run unit tests before installation, run `make check` before `make install`.\n\nOn platforms that do not understand the `#!` convention for beginning script files, or that have Python installed in an unusual spot, you might need to prefix the `configure.py` command with `python3` or `/path/to/python`:\n\n```shell\npython3 ./configure.py [arguments]\n```\n\nThe `make install` target has a default directory in which it will install Botan (typically `/usr/local`). You can override this by using the `--prefix` argument to `configure.py`, like so:\n\n```shell\n./configure.py --prefix=/botan [arguments]\n```\n\nSome features rely on third party libraries which your system might not have or that you might not want the resulting binary to depend on. For instance to enable `sqlite3` support, add `--with-sqlite3` to your invocation of `configure.py`.\n\n```shell\n./configure.py --with-sqlite3 [arguments]\n```\n\n\u003c/details\u003e\n\n## Windows from source\n\nPrebuilt botan is not available for windows, and it must be built from source. The process is similar to building from source in Unix or MacOS.\n\n\u003cdetails\u003e\u003csummary\u003eWindows from source\u003c/summary\u003e\n\n\u003e Untested.\n\nYou need to have a copy of Python installed, and have both Python and your chosen compiler in your path. Open a command shell (or the SDK shell), and run:\n\n```shell\npython3 configure.py --cc=msvc --os=windows\nnmake\nnmake check\nnmake install\n```\n\nAlternately, starting in Botan 3.2, there is additionally support for using the ninja build tool as an alternative to nmake:\n\n```shell\npython3 configure.py --cc=msvc --os=windows --build-tool=ninja\nninja\nninja check\nninja install\n```\n\nFor MinGW, use:\n\n```shell\npython3 configure.py --cc=gcc --os=mingw\nmake\n```\n\nBy default the install target will be `C:\\botan`; you can modify this with the `--prefix` option.\n\nWhen building your applications, all you have to do is tell the compiler to look for both include files and library files in C:\\botan, and it will find both. Or you can move them to a place where they will be in the default compiler search paths (consult your documentation and/or local expert for details).\n\n\u003c/details\u003e\n\n# Usage\n\nYou will need to add `botan` as a package dependency in order to use it.\n\n\u003cdetails\u003e\u003csummary\u003eCabal\u003c/summary\u003e\n\n\u003c!-- This package is not yet available on hackage, so you'll have to add the repo to your `cabal.project` file using a `source-repository-package` stanza:\n\n```\nsource-repository-package\n    type: git\n    location: git://github.com/haskellfoundation/botan.git\n    tag: [commit-hash]\n```\n--\u003e\n\nThis package is now available on hackage. Simply add it to your `[project].cabal` under the `build-depends` stanza:\n\n```\nbuild-depends:\n    botan-low\n```\n\nIf you installed botan in a non-standard location, you may need to specify where using `--extra-include-dirs` and `--extra-lib-dirs` flags:\n\n```shell\ncabal repl TARGET --extra-include-dirs /botan/include --extra-lib-dirs /botan/lib\n```\n\nYou can add these flags permanently to your `cabal.project` or `cabal.project.local` file:\n\n```\nextra-include-dirs:\n- /botan/include\nextra-lib-dirs:\n- /botan/lib\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eStack\u003c/summary\u003e\n\n\u003e Untested.\n\nThis package is not yet available on stackage, so you'll have to add the repo to your `stack.yaml` file under the `extra-deps` stanza:\n\n```\nextra-deps:\n- github: haskellfoundation/botan\n  commit: [commit-hash]\n```\n\nThen, add it to your `package.yaml` file under the `dependencies` stanza:\n\n```\ndependencies:\n- botan-low\n```\n\nIf you installed botan in a non-standard location, you may need to specify where using `--extra-include-dirs` and `--extra-lib-dirs` flags:\n\n```shell\nstack repl TARGET --extra-include-dirs /botan/include --extra-lib-dirs /botan/lib\n```\n\nYou can add these flags permanently to your `stack.yaml` or global `config.yaml` file:\n\n```\nextra-include-dirs:\n- /botan/include\nextra-lib-dirs:\n- /botan/lib\n```\n\n\u003c/details\u003e\n\nAfter you have added `botan` as a dependency, you can begin importing modules and using them in your code.\n\n```haskell\nimport Botan.Low.Hash\n\nmain = do\n    hash \u003c- hashInit \"SHA-256\"\n    digest \u003c- hashUpdateFinalize hash \"Fee fi fo fum!\"\n    print digest\n```\n\n# Tutorials\n\n\u003cdetails\u003e\u003csummary\u003eBotan.Low.Bcrypt\u003c/summary\u003e\n\n`bcrypt` is a password-hashing algorithm designed to protect your passwords against hackers using an expensive key setup phase. Instead of storing a user's password in plaintext in the database, the server may instead generate a salted bcrypt digest upon signup, and verify it upon login. \n\nThe `bcrypt` implementation provided by `botan` generates a random salt for you automatically. A work factor of 12 or greater is recommended.\n\nTo generate a bcrypt digest:\n\n```haskell\nimport Botan.Low.RNG\nimport Botan.Low.Bcrypt\n\n-- The user has sent us a username and password in order to sign up \nonUserSignup :: ByteString -\u003e ByteString -\u003e IO ()\nonUserSignup username password = do\n    rng \u003c- rngInit \"user\"\n    digest \u003c- bcryptGenerate password rng 12\n    createAndStoreNewUser username digest\n```\n\nTo validate a bcrypt digest:\n\n```haskell\nimport Botan.Low.RNG\nimport Botan.Low.Bcrypt\n\n-- The user has sent us a username and password in order to log in\nonUserLogin :: ByteString -\u003e ByteString -\u003e IO Bool\nonUserLogin username password = do\n    rng \u003c- rngInit \"user\"\n    digestMaybe \u003c- getStoredUserDigest username\n    case digestMaybe of\n        Nothing     -\u003e return False\n        Just digest -\u003e bcryptIsValid password digest\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eBotan.Low.BlockCipher\u003c/summary\u003e\n\nA `block cipher` is a deterministic, cryptographic primitive suitable for encrypting or decrypting a single, fixed-size block of data at a time. Block ciphers are used as building blocks for more complex cryptographic operations. If you are looking to encrypt user data, you are probably looking for `Botan.Low.Cipher` instead.\n\nUnless you need a specific block cipher, it is strongly recommended that you use the `AES256` algorithm.\n\n```haskell\nimport Botan.Low.BlockCipher\nblockCipher \u003c- blockCipherInit AES256\n```\n\nTo use a block cipher, we first need to generate (if we haven't already) a secret key.\n\n```haskell\nimport Botan.Low.RNG\nrng \u003c- rngInit \"user\"\n-- We will use the maximum key size; AES256 keys are always 16 bytes\n(_,keySize,_) \u003c- blockCipherGetKeyspec blockCipher\n-- Block cipher keys are randomly generated\nkey \u003c- rngGet rng keySize\n```\n\nAfter the key is generated, we must set it as the block cipher key:\n\n```haskell\nblockCipherSetKey blockCipher key\n```\n\nTo encrypt a message, it must be a multiple of the block size.\n\n```haskell\nblockSize \u003c- blockCipherBlockSize blockCipher\n-- AES256 block size is always 16 bytes\nmessage = \"0000DEADBEEF0000\" :: ByteString\nciphertext \u003c- blockCipherEncryptBlocks blockCipher message\n```\n\nTo decrypt a message, simply reverse the process:\n\n```haskell\nplaintext \u003c- blockCipherDecryptBlocks blockCipher ciphertext\nmessage == plaintext -- True\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eBotan.Low.Cipher\u003c/summary\u003e\n\nA `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`.\n\nUnless 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.\n\n```haskell\nimport Botan.Low.Cipher\nencrypter \u003c- cipherInit ChaCha20Poly1305 Encrypt\n```\n\nTo use a cipher, we first need to generate (if we haven't already) a secret key.\n\n```haskell\nimport Botan.Low.RNG\nrng \u003c- rngInit \"user\"\n-- We will use the maximum key size; ChaCha20Poly1305 keys are always 32 bytes\n(_,keySize,_) \u003c- cipherGetKeyspec encrypter\n-- Block cipher keys are randomly generated\nkey \u003c- rngGet rng keySize\n```\n\nAfter the key is generated, we must set it as the cipher key:\n\n```haskell\ncipherSetKey encrypter key\n```\n\nIf the cipher is an `aead`, we may also set the `associated data`:\n\n```haskell\ncipherSetAssociatedData encrypter \"Fee fi fo fum!\"\n```\n\nTo 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.\n\n```haskell\nimport Botan.Low.RNG\n-- The default ChaCha20Poly1305 nonce is always 12 bytes.\nnonceSize \u003c- cipherGetDefaultNonceLength encrypter\nnonce \u003c- rngGet rng nonceSize\n```\n\nTo 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\n\n```haskell\n-- Rarely, some cipher modes require that the message size be aligned to the block size\n-- Consult algorithm-specific documentation if this occurs. \nmessage = \"I smell the blood of an Englishman!\"\ncipherStart encrypter nonce\nciphertext \u003c- cipherEncrypt encrypter message\n```\n\nTo decrypt a message, we run the same process with a decrypter, using the same `key` and `nonce` to decode the `ciphertext`:\n\n```haskell\ndecrypter \u003c- cipherInit ChaCha20Poly1305 Decrypt\ncipherSetKey decrypter key\ncipherSetAssociatedData decrypter \"Fee fi fo fum!\"\ncipherStart decrypter nonce\nplaintext \u003c- cipherDecrypt decrypter ciphertext\nmessage == plaintext -- True\n```\n\nYou can completely clear a cipher's state, leaving it ready for reuse:\n\n```haskell\ncipherClear encrypter\n-- You'll have to set the key, nonce, (and ad, if aead) again.\ncipherSetKey encrypter anotherKey\ncipherStart encrypter anotherNonce\ncipherSetAssociatedData encrypter anotherAD\n-- Process another message\nanotherCiphertext \u003c- cipherEncrypt encrypter anotherMessage\n```\n\nIf you are encrypting or decrypting multiple messages with the same key, you can reset the cipher instead of clearing it, leaving the key set:\n\n```haskell\ncipherClear encrypter\n-- This is equivalent to calling cipherClear followed by cipherSetKey with the original key.\n-- You'll have to set the nonce  (and ad, if aead) again, but not the key.\ncipherStart encrypter anotherNonce\ncipherSetAssociatedData encrypter anotherAD\n-- Process another message with the same key\nanotherCiphertext \u003c- cipherEncrypt encrypter anotherMessage\n```\n\n\n\u003c/details\u003e\n\n\u003c!-- \u003cdetails\u003e\u003csummary\u003eBotan.Low.FPE\u003c/summary\u003e\n\n\u003c/details\u003e --\u003e\n\n\u003cdetails\u003e\u003csummary\u003eBotan.Low.Hash\u003c/summary\u003e\n\nA `hash` is deterministic, one-way function suitable for producing a deterministic, fixed-size digest from an arbitrarily-sized message, which is used to verify the integrity of the data.\n\nUnless you need a specific `hash`, it is strongly recommended that you use the `SHA3` algorithm.\n\n```haskell\nimport Botan.Low.Hash\nhash \u003c- hashInit SHA3\nmessage = \"Fee fi fo fum!\"\nhashUpdate hash message\ndigest \u003c- hashFinal hash\n```\n\nYou can verify a digest by hashing the message a second time, and comparing the two:\n\n```haskell\nrehash \u003c- hashInit SHA3\nhashUpdate rehash message\nredigest \u003c- hashFinal rehash\ndigest == redigest -- True\n```\n\nYou can clear a hash's state, leaving it ready for reuse:\n\n```haskell\nhashClear hash\n-- Process another message\nhashUpdate hash anotherMessage\nanotherDigest \u003c- hashFinal hash\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eBotan.Low.HOTP\u003c/summary\u003e\n\nTo use HOTP for MFA / 2FA, the client authenticator must generate a\nclient-specific shared secret and counter value, and securely communicate\nthem to the server authenticator.\n\nThe secret key may be any bytestring value with more than 160 bits, such as\na Bcrypt digest or SRP6 shared key. The counter value is not required to be\na secret; it may start at 0 for simplicity, or it may start at a value that\nwas selected at random.\n\n```haskell\nimport Botan.Low.HOTP\nimport Botan.Low.RNG\nimport Botan.Low.MPI\nimport Data.Bits\nsharedSecret \u003c- systemRNGGet 16\n-- TODO: Use random:System.Random.Stateful.Uniform instead of MPI in `botan`\n(hi :: Word32) \u003c- mpInit \u003e\u003e= \\ w -\u003e mpRandBits w rng 32 \u003e\u003e mpToWord32 w\n(lo :: Word32) \u003c- mpInit \u003e\u003e= \\ w -\u003e mpRandBits w rng 32 \u003e\u003e mpToWord32 w\n(counter :: Word64) = shiftL (fromIntegral hi) 32 `xor` fromIntegral lo \n```\n\nThe client and server authenticators are now in a shared state, and any login\nattempts from a new device may be authenticated using HOTP as MFA.\n\nA client has requested a new connection, and HOTP is being used as MFA/2FA to\nauthenticate their request. The server authenticator receives the client connection\nrequest and initializes a HOTP session using the stored client-specific shared\nsecret, and then sends an authentication request to the client authenticator:\n\n```haskell\n-- (serverSharedSecret, serverCounter) \u003c- lookupServerSharedSecretAndCounter\nserverSession \u003c- hotpInit serverSharedSecret HOTP_SHA512 8\n-- sendMFAAuthenticationRequest\n```\n\nThe client authenticator receives the authentication request, generates a\nclient-side code, increments their counter, and displays the HOTP code to\nthe user:\n\n```haskell\n-- (clientSharedSecret, clientCounter) \u003c- lookupClientSharedSecretAndCounter\nclientSession \u003c- hotpInit clientSharedSecret HOTP_SHA512 8\nclientCode \u003c- hotpGenerate clientSession clientCounter\n-- incrementAndPersistClientCounter\n-- displayClientCode clientCode\n```\n\n\u003e NOTE: The client authenticator is responsible for incrementing and persisting\n\u003e their own counter manually.\n\nThe client then sends the client code to the server authenticator using the\nunauthenticated / requested connection:\n\n```haskell\n-- clientCode \u003c- readClientCode\n-- sendMFAAuthenticationResponse clientCode\n```\n\nThe server authenticator receives the authentication response, and performs\na check of the key, with a resync range of R in case the client has generated\na few codes without logging in successfully:\n\n```haskell\n-- serverClientCode \u003c- didreceiveMFAAuthenticationResponse\n(isValid,nextCounter) \u003c- hotpCheck serverSession serverClientCode serverCounter 10\npersistClientCounter nextCounter\n```\n\n\u003e NOTE: The server authentication check returns an incremented and resynced\n\u003e counter which must be persisted manually. If the authentication check fails,\n\u003e the counter value is return unchanged.\n\nIf the code is valid, then the signin may be completed on the new connection\nas normal.\n\nThe server should discontinue the session and refuse any new connections\nto the account after T unsuccessful authentication attempts, where T \u003c R.\nThe user should then be notified.\n\n\u003c/details\u003e\n\n\u003c!-- \u003cdetails\u003e\u003csummary\u003eBotan.Low.KDF\u003c/summary\u003e\n\n\u003c/details\u003e --\u003e\n\n\u003c!-- \u003cdetails\u003e\u003csummary\u003eBotan.Low.KeyWrap\u003c/summary\u003e\n\n\u003c/details\u003e --\u003e\n\n\u003cdetails\u003e\u003csummary\u003eBotan.Low.MAC\u003c/summary\u003e\n\nA `mac` (or message authentication code) is a cryptographic algorithm that uses a secret key to produce a fixed-size digest from an arbitrarily-sized message, which is then used to verify the integrity and authenticity of the data.\n\nUnless you need a specific `mac`, it is strongly recommended that you use the `hmac SHA3` algorithm.\n\n```haskell\nimport Botan.Low.MAC\nimport Botan.Low.Hash\nmac \u003c- macInit (hmac SHA3)\n```\n\nTo use a MAC, we first need to generate (if we haven't already) a secret key.\n\n```haskell\nimport Botan.Low.RNG\nrng \u003c- rngInit \"user\"\n-- HMAC allows for an arbitrary key size, but we can check the key spec if necessary\n(keyMin,keyMax,keyMod) \u003c- macGetKeyspec mac\n-- MAC are randomly generated; 32 bytes is acceptable\nkey \u003c- rngGet rng 32\n```\n\nAfter the key is generated, we must set it as the mac key:\n\n```haskell\nmacSetKey mac key\n```\n\nThen, we may produce an authentication code from a message using the secret key:\n\n```haskell\nmacUpdate mac \"Fee fi fo fum!\"\nauth \u003c- macFinal mac\n```\n\nTo verify an message authentication code, we can reproduce it using the secret key and message, and then check for equality:\n\n```haskell\nverify \u003c- macInit (hmac SHA3)\nmacSetKey verify key\nmacUpdate verify \"Fee fi fo fum!\"\nverifyAuth \u003c- macFinal verify\nauth == verifyAuth -- True\n```\n\nYou can completely clear a mac's state, leaving it ready for reuse:\n\n```haskell\nmacClear mac\n-- You'll have to set the key again\nmacSetKey mac anotherKey\n-- Process another message\nmacUpdate mac anotherMessage\nanotherAuth \u003c- macFinal mac\n```\n\nSome algorithms (GMAC, Poly1305) have additional requirements for use. Avoid if possible, and consult algorithm-specific documentation for GMAC and Poly1305. If you must use GMAC, a nonce needs to be set:\n\n```haskell\nmac \u003c- macInit (gmac AES256)\nk \u003c- systemRNGGet 32\nn \u003c- systemRNGGet 32    -- Here\nmacSetKey mac k\nmacSetNonce mac n       -- Here\nmacUpdate mac \"Fee fi fo fum!\"\nauth \u003c- macFinal mac\n```\n\n\u003c/details\u003e\n\n\u003c!-- \u003cdetails\u003e\u003csummary\u003eBotan.Low.MPI\u003c/summary\u003e\n\n\u003c/details\u003e --\u003e\n\n\u003cdetails\u003e\u003csummary\u003eBotan.Low.PubKey\u003c/summary\u003e\n\nUnless you need a specific `public key cryptosystem`, it is strongly recommended that you use the `RSA`, `Ed25519`, or `Curve25519` algorithms, depending on your desired operation.\n\nCreate an RSA keypair:\n\n```haskell\nimport Botan.Low.RNG\nimport Botan.Low.PubKey\nrng \u003c- rngInit \"user\"\n-- Alice generates her keys\nalicePrivKey \u003c- privKeyCreate RSA \"4096\" rng\nalicePubKey \u003c- privKeyExportPubKey alicePrivKey\n```\n\n\u003e NOTE: For algorithm-specific parameters, consult the Botan documentation and source\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eBotan.Low.PubKey.Encrypt\u003c/summary\u003e\n\nEncrypt a message:\n\n```haskell\nimport Botan.Low.PubKey.Encrypt\nmessage = \"Fee fi fo fum!\"\n-- Bob encrypts a message for Alice using her public key\n-- Unlike `Crypto.Saltine.Core.Box`, the message is only encrypted, not signed.\nencrypter \u003c- encryptCreate alicePubKey EME_PKCS1_v1_5\nciphertext \u003c- encrypt encrypter rng message\n```\n\n\u003e NOTE: For algorithm-specific padding parameters, consult the Botan documentation and source\n\nDecrypt a message:\n\n```haskell\nimport Botan.Low.PubKey.Decrypt\n-- Alice decrypts the message from Bob using her private key\ndecrypter \u003c- decryptCreate alicePrivKey EME_PKCS1_v1_5\nplaintext \u003c- decrypt decrypter ciphertext\nmessage == plaintext -- True\n```\n\n\u003e NOTE: The same padding must be used for both encryption and decryption\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eBotan.Low.PubKey.Sign\u003c/summary\u003e\n\nSign a message:\n\n```haskell\nimport Botan.Low.PubKey.Sign\nimport Botan.Low.Hash\nmessage = \"Fee fi fo fum!\"\n-- Alice signs the message using her private key\nsigner \u003c- signCreate alicePrivKey (emsa_emsa4 SHA3) StandardFormatSignature\nsignUpdate signer message\nsig \u003c- signFinish signer rng\n```\n\n\u003e NOTE: Signing uses a different set of padding algorithms `EMSA` from encryption `EME`, and different signing / encryption algorithms support different specific padding algorithms\n\n\u003e NOTE: Signing does not yet have proper constants for selecting a padding mechanism. For more information, refer to the `Botan.PubKey`, `Botan.PubKey.Sign`, or the Botan C++ documentation. This area will be improved in the near future.\n\nVerify a message:\n\n```haskell\nimport Botan.Low.PubKey.Verify\n-- Bob verifies the message using Alice's public key\nverifier \u003c- verifyCreate alicePubKey (emsa_emsa4 SHA3) StandardFormatSignature\nverifyUpdate verifier message\nverified \u003c- verifyFinish verifier sig\nverified -- True\n```\n\n\u003e NOTE: The same padding must be used for both encryption and decryption\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eBotan.Low.PubKey.KeyAgreement\u003c/summary\u003e\n\nFirst, Alice and Bob generate their private keys:\n\n```haskell\nimport Botan.Low.PubKey\nimport Botan.Low.PubKey.KeyAgreement\nimport Botan.Low.RNG\nimport Botan.Low.Hash\nimport Botan.Low.KDF\nrng \u003c- rngInit \"system\"\n-- Alice creates her private key\nalicePrivKey \u003c- privKeyCreate ECDH Secp521r1 rng \n-- Bob creates his private key\nbobPrivKey \u003c-  privKeyCreate ECDH Secp521r1 rng \n```\n\nThen, they exchange their public keys using any channel, private or public:\n\n```haskell\n-- Alice and Bob exchange public keys\nalicePubKey \u003c- keyAgreementExportPublic alicePrivKey\nbobPubKey \u003c- keyAgreementExportPublic bobPrivKey\n-- ...\n```\n\nThen, they may separately generate the same agreed-upon key and a randomized,\nagreed-upon salt:\n\n```haskell\nsalt \u003c- rngGet rng 4\n-- Alice generates her shared key:\naliceKeyAgreement \u003c- keyAgreementCreate alicePrivKey (kdf2 SHA256)\naliceSharedKey    \u003c- keyAgreement aliceKeyAgreement bobPubKey salt\n-- Bob generates his shared key:\nbobKeyAgreement   \u003c- keyAgreementCreate bobPrivKey (kdf2 SHA256)\nbobSharedKey      \u003c- keyAgreement bobKeyAgreement alicePubKey salt\n-- They are the same\naliceSharedKey == bobSharedKey\n-- True\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eBotan.Low.PubKey.KeyEncapsulation\u003c/summary\u003e\n\nFirst, Alice generates her private and public key pair:\n\n```haskell\nimport Botan.Low.PubKey\nimport Botan.Low.PubKey.KeyEncapsulation\nimport Botan.Low.Hash\nimport Botan.Low.KDF\nimport Botan.Low.RNG\nrng \u003c- rngInit UserRNG\n-- Alice generates her private and public keys\nalicePrivKey \u003c- privKeyCreate RSA \"2048\" rng\nalicePubKey \u003c- privKeyExportPubKey alicePrivKey\n```\n\nThen, Alice shares her public key somewhere where others can see. When Bob\nwants to create a shared key with Alice, they choose a KDF algorithm, generate\na salt, and choose a shared key length.\n\n```haskell\nkdfAlg = hkdf SHA256\nsalt \u003c- rngGet rng 4\nsharedKeyLength = 256\n```\n\nThen, Bob generates the shared + encapsulated key, and sends the\nencapsulated key to Alice:\n\n```haskell\nencryptCtx \u003c- kemEncryptCreate alicePubKey kdfAlg\n(bobSharedKey, encapsulatedKey) \u003c- kemEncryptCreateSharedKey encryptCtx rng salt sharedKeyLength\n-- sendToAlice encapsulatedKey\n```\n\nUpon receiving the encapsulated key, Alice can decrypt and extract the shared\nkey using her private key:\n\n```haskell\ndecryptCtx \u003c- kemDecryptCreate alicePrivKey kdfAlg\naliceSharedKey \u003c- kemDecryptSharedKey decryptCtx salt encapsulatedKey sharedKeyLength\nbobSharedKey == aliceSharedKey\n-- True\n```\n\nThen, this shared key may be used for any suitable purpose.\n\n\n\u003c/details\u003e\n\n\u003c!--  \u003cdetails\u003e\u003csummary\u003eBotan.Low.PwdHash\u003c/summary\u003e\n\n\u003c/details\u003e --\u003e\n\n\u003cdetails\u003e\u003csummary\u003eBotan.Low.RNG\u003c/summary\u003e\n\nA `random number generator` is used to generate uniform samples of pseudorandom bytes.\n\nYou can always use the system `RNG`:\n\n```haskell\nimport Botan.Low.RNG\nrandomBytes \u003c- systemRNGGet 16\n```\n\nUnless you need a specific `RNG`, it is strongly recommended that you use the autoseeded `user` RNG.\n\n```haskell\nimport Botan.Low.RNG\nrng \u003c- rngInit \"user\"\nrandomBytes \u003c- rngGet rng 16\n```\n\nYou can reseed a generator using the system generator:\n\n```haskell\nrngReseed rng 64\n```\n\nYou can also reseed a generator using a specific generator:\n\n```haskell\nsystemRNG \u003c- rngInit \"system\"\nrngReseedFromRNG rng systemRNG 64\n```\n\nYou can also seed it with your own entropy; this is safe and can never *decrease* the amount of entropy in the generator.\n\n```haskell\nrngAddEntropy rng \"Fee fi fo fum!\"\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eBotan.Low.SRP6\u003c/summary\u003e\n\nOn signup, the client generates a salt and verifier, and securely sends them to a server:\n\n```haskell\nimport Botan.Low.SRP6\nimport Botan.Low.Hash\nimport Botan.Low.RNG\nimport Botan.Low.MAC\nrng \u003c- rngInit UserRNG\ngroup = MODP_SRP_4096\nhash = SHA512\nidentifier = \"alice\"\npassword = \"Fee fi fo fum!\"\nsalt \u003c- rngGet rng 12\nverifier \u003c- srp6GenerateVerifier identifier password salt group hash\n-- signUpUserWithServer identifier verifier salt group hash\n```\n\nLater, on the server when the client request authentication, the server\nlooks up the verfier, generates a server key (a SRP6 'B' value), and sends\nit back to the client:\n\n```haskell\n-- rng \u003c- rngInit UserRNG\nsession \u003c- srp6ServerSessionInit \n-- (verifier, salt, group, hash) \u003c- lookupUser identifier\nserverKey \u003c- srp6ServerSessionStep1 session verifier group hash rng\n```\n\nOnce the client receives the server key, it generates a client key (SRP6 'A' value)\nand the session key, and sends the client key to the server:\n\n```haskell\n-- serverKey \u003c- didReceiveServerKey\n(clientKey, clientSessionKey) \u003c- srp6ClientAgree identifier password group hash salt serverKey rng\n-- sendClientKey clientKey\n```\n\nThe server then receives client key, and generates a matching session key:\n\n```haskell\n-- clientKey \u003c- didReceiveClientKey\nserverSessionKey \u003c- srp6ServerSessionStep2 session clientKey\n```\n\nAt this point, clientSessionKey and serverSessionKey should be equal,\nbut this should be confirmed by exchanging a hash digest to check for integrity,\nusing the exchange's session key, identifier, salt, and client and server keys.\n\nThere are many ways to do this, but preferrably, an (h)mac digest should be used\nto also include authentication and avoid impersonation.\n\n\u003e NOTE: Both sides could calculate 'identifier \u003c\u003e salt \u003c\u003e serverKey \u003c\u003e clientKey'\n\u003e individually but then we need to prove that each side has calculated it without\nrelying on the copy received for validation, so we do this song and dance:\n\nThe client should first calculate and send the HMAC auth, using identifier + salt + clientKey:\n\n```haskell\nmac \u003c- macInit (hmac SHA3)\nmacSetKey mac clientSessionKey\nmacUpdate mac $ identifier \u003c\u003e salt \u003c\u003e clientKey\nclientAuth \u003c- macFinal mac\n-- sendClientAuth clientAuth\n```\n\nThe server should then verify the client auth, and send its own HMAC\nauth back to the client using serverKey + clientAuth:\n\n```haskell\n-- clientAuth \u003c- didReceiveClientAuth\nmac \u003c- macInit (hmac SHA3)\nmacSetKey mac serverSessionKey\nmacUpdate mac $ identifier \u003c\u003e salt \u003c\u003e clientKey\nverifiedClientAuth \u003c- macFinal mac\n-- clientAuth == verifiedClientAuth\nmacClear mac\nmacSetKey mac serverSessionKey\nmacUpdate mac $ serverKey \u003c\u003e clientAuth\nserverAuth \u003c- macFinal mac\n-- sendServerAuth serverAuth\n```\n\nThe client then receives the server HMAC auth, and validates it\n\n```haskell\n-- serverAuth \u003c- didReceiveServerAuth\nmacClear mac\nmacSetKey mac clientSessionKey\nmacUpdate mac $ serverKey \u003c\u003e clientAuth\nverifiedServerAuth \u003c- macFinal mac\n-- serverAuth == verifiedServerAuth\n```\n\nAfter this, the shared session key may be safely used.\n\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eBotan.Low.TOTP\u003c/summary\u003e\n\nTo use TOTP for MFA / 2FA, the client authenticator must generate a\nclient-specific shared secret, and securely communicate it to the\nserver authenticator.\n\nThe secret key may be any bytestring value with more than 160 bits, such as\na Bcrypt digest or SRP6 shared key.\n\n```haskell\nimport Botan.Low.TOTP\nimport Botan.Low.RNG\nimport Data.Time.Clock.POSIX\ntimestep = 30\ndrift = 3\nsharedSecret \u003c- systemRNGGet 16\n```\n\nThe client and server authenticators are now in a shared state, and any login\nattempts from a new device may be authenticated using TOTP as MFA.\n\nA client has requested a new connection, and TOTP is being used as MFA/2FA to\nauthenticate their request. The server authenticator receives the client connection\nrequest and initializes a TOTP session using the stored client-specific shared\nsecret, and then sends an authentication request to the client authenticator:\n\n```haskell\n-- serverSharedSecret \u003c- lookupServerSharedSecret\nserverSession \u003c- totpInit serverSharedSecret TOTP_SHA512 8 timestep\n-- sendMFAAuthenticationRequest\n```\n\n\u003e NOTE: We are using a timestep value of 30 seconds, which means that the\n\u003e code will refresh every 30 seconds\n\nThe client authenticator receives the authentication request, generates a\nclient-side code using their timestamp, and displays the TOTP code to\nthe user:\n\n```haskell\n-- clientSharedSecret \u003c- lookupClientSharedSecret\nclientSession \u003c- totpInit clientSharedSecret TOTP_SHA512 8 timestep\n(clientTimestamp :: TOTPTimestamp) \u003c- round \u003c$\u003e getPOSIXTime\nclientCode \u003c- totpGenerate clientSession clientTimestamp\n-- displayClientCode clientCode\n```\n\nThe client then sends the client code to the server authenticator using the\nunauthenticated / requested connection:\n\n```haskell\n-- clientCode \u003c- readClientCode\n-- sendMFAAuthenticationResponse clientCode\n```\n\nThe server authenticator receives the authentication response, and performs\na check of the key, with an acceptable clock drift in steps, in case the client\nand server are slightly desynchronized. \n\n```haskell\n-- serverClientCode \u003c- didreceiveMFAAuthenticationResponse\n(serverTimestamp :: TOTPTimestamp) \u003c- round \u003c$\u003e getPOSIXTime\nisValid \u003c- totpCheck serverSession serverClientCode serverTimestamp drift\n```\n\n\u003e NOTE: We are using a acceptable clock drift value of 3, which means that the\n\u003e codes for the previous 3 time steps are still valid.\n\nIf the code is valid, then the signin may be completed on the new connection\nas normal.\n\nThe server should discontinue the session and refuse any new connections\nto the account after multiple unsuccessful authentication attempts.\nThe user should then be notified.\n\n\u003c/details\u003e\n\n\u003c!-- \u003cdetails\u003e\u003csummary\u003eBotan.Low.X509\u003c/summary\u003e\n\n\u003c/details\u003e --\u003e\n\n\u003cdetails\u003e\u003csummary\u003eBotan.Low.ZFEC\u003c/summary\u003e\n\nForward error correction takes an input and creates multiple\n“shares”, such that any K of N shares is sufficient to recover\nthe entire original input.\n\nFirst, we choose a K value appropriate to our message - the higher K is,\nthe smaller (but more numerous) the resulting shares will be:\n\n```haskell\nk = 7\nmessage = \"The length of this message must be divisible by K\"\n```\n\n\u003e NOTE: ZFEC requires that the input length be exactly divisible by K; if\nneeded define a padding scheme to pad your input to the necessary\nsize.\n\nWe can calculate N = K + R, where R is the number of redundant shares,\nmeaning we can tolerate the loss of up to R shares and still recover\nthe original message.\n\nWe want 2 additional shares of redundancy, so we set R and N appropriately:\n\n```haskell\nr = 2\nn = k + r -- 7 + 2 = 9\n```\n\nThen, we encode the message into N shares:\n\n```haskell\nshares \u003c- zfecEncode k n message\nlength shares\n-- 9\n```\n\nThen, we can recover the message from any K of N shares:\n\n```haskell\nsomeShares \u003c- take k \u003c$\u003e shuffle shares\nrecoveredMessage \u003c- zfecDecode k n someShares\nmessage == recoveredMessage\n-- True\n```\n\n\u003c/details\u003e\n\n# Enabling experimental support\n\nSome features rely on an experimental fork of the Botan C++ library, which will be contributed back upstream to Botan C++ when it is stable.\n\n\u003cdetails\u003e\u003csummary\u003eBuild with experimental features\u003c/summary\u003e\n\n1.  Clone the experimental [fork](https://github.com/apotheca/botan-upstream)\n\n```shell\ngit clone https://github.com/apotheca/botan-upstream $BOTAN_CPP\n```\n\n2.  Build and install the experimental fork as [from source](#From-source). You may wish to install to a non-standard location using `--prefix` during configuration, to avoid overwriting any pre-existing install.\n\n```shell\ncd $BOTAN_CPP\n./configure.py --prefix=$BOTAN_OUT\nmake\nmake install\n```\n\n3.  Use the `XFFI` flag to enable the experimental FFI modules. If you installed the experimental fork to a non-standard location, you may also need to specify where using `--extra-include-dirs` and `--extra-lib-dirs` flags.\n\n```shell\ncd $BOTAN_HASKELL\ncabal build TARGET -fXFFI --extra-include-dirs $BOTAN_OUT/include --extra-lib-dirs $BOTAN_OUT/lib\n# or\nstack build TARGET --flag XFFI --extra-include-dirs $BOTAN_OUT/include --extra-lib-dirs $BOTAN_OUT/lib\n```\n\nTo check that you've done everything correctly, you can run the following:\n\n```\nimport Botan.Bindings.Version \nimport Foreign.C.String\nimport Prelude\nbotan_version_string \u003e\u003e= peekCString\n```\n\nThe version will say `unreleased` if it is properly pointing to our built Botan.\n\n\u003c/details\u003e\n\n# Resources\n\nThere are several resources for this project that might be helpful:\n\n- **[Devlog](https://discourse.haskell.org/t/botan-bindings-devlog/6855?u=apothecalabs)** for project status and updates.\n- **[GitHub](https://github.com/haskellfoundation/botan)** for Haskell source code, issues, and pull requests.\n- **[Upstream C++ Github](https://github.com/apotheca/botan-upstream)** experimental fork of Botan C++\n- **[Proposal](https://github.com/haskellfoundation/tech-proposals/pull/57)** Haskell Foundation funding proposal submission thread.\n\nAs well, there are resources for the original Botan C++ library:\n\n- **[Botan](https://botan.randombit.net/)** Crypto and TLS for Modern C++\n- **[Botan C++ Github](https://github.com/randombit/botan/)** for original Botan C++ source code, issues, and pull requests.\n- **[Botan Handbook](https://botan.randombit.net/handbook/)** for documentation on the original library\n- **[Botan FFI](https://botan.randombit.net/handbook/api_ref/ffi.html)** for documentation on the Botan C FFI\n- **[Issue](https://github.com/randombit/botan/issues/3627)** FFI APIs for X.509 are insufficient\n\n# License\n\nThis project is licensed under the [BSD 3-Clause License](https://github.com/haskellfoundation/botan/blob/main/LICENSE) and is free, open-source software.\n\n# Contributing\n\nThere are several ways to contribute to the development of this project, and we are happy to receive any bug reports, fixes, documentation, and any other improvements to this project. \n\n## Reporting Bugs\n\nSee a bug? \n\n1. Describe the issue\n\n2. Write down the steps required to reproduce the issue\n\n3. Report the issue by [opening a ticket!](https://github.com/haskellfoundation/botan/issues/new)\n\n## Assist in Development\n\nWant to help?\n\n1. Fork or clone the repo, and create a new branch:\n\n```shell\ngit checkout https://github.com/haskellfoundation/botan -b some_new_branch\n```\n\n2. Make your changes, and test them\n\n3. Submit a pull request with a comprehensive description of the changes\n\n\u003c!-- # Contributors --\u003e\n\n\u003c!-- TODO: Acknowlege code contributors --\u003e\n\u003c!-- TODO: Adding a CONTRIBUTING file: https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/setting-guidelines-for-repository-contributors --\u003e\n\n# Donations\n\nThis is free, open-source software. If you'd like to support the continued development of this project and future projects like this, or just to say thanks, you can donate directly using the following link(s):\n\n[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/V7V1S5JTG)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaskell-cryptography%2Fbotan","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhaskell-cryptography%2Fbotan","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaskell-cryptography%2Fbotan/lists"}