Compare commits

...

461 Commits

Author SHA1 Message Date
Sarah Vaupel
f78fca2504 Merge branch 'master' into uni2work 2024-01-09 02:48:31 +01:00
Vincent Hanquez
d163f69512
Merge pull request #371 from Vlix/patch-1
Small refactor
2022-10-03 08:11:46 +08:00
Felix Paulusma
9401b4e3fd
Small refactor
The same parameter was matched on twice, so why not just do it once?
2022-10-03 01:01:30 +02:00
Vincent Hanquez
b96ec42d3e
Merge pull request #348 from robx/fix-segfault
Fix alignment in gfmul_generic (closes #334)
2022-05-02 12:31:16 +08:00
Vincent Hanquez
7dfaf914e6
release 0.30 2022-03-13 20:54:14 +08:00
Vincent Hanquez
aca61fa1b6
update stackage 2022-03-13 20:49:31 +08:00
Vincent Hanquez
20b194fc97
fix byteswap32 to work on Word32# instead of Word# (with compat for ghc < 9.2) 2022-03-13 20:49:11 +08:00
Vincent Hanquez
cca5d72bf1
Merge pull request #359 from iquerejeta/build-issue
Include prefix to missing functions
2022-02-23 10:10:20 +08:00
iquerejeta
495eca0bb5
include prefix to missing functions 2022-02-17 11:43:52 +00:00
Vincent Hanquez
309abe378d
missing symbols renaming 2021-10-28 20:27:17 +08:00
iquerejeta
f4f92b702c
recapitalised constant 2021-10-28 10:57:03 +02:00
iquerejeta
93f50b49b7 ref folder changes, and minor sse 2021-09-15 12:28:06 +01:00
iquerejeta
a8d1d401bc linker complaints 2021-09-13 15:11:27 +01:00
Robert Vollmert
b3db979ca0 Fix alignment in gfmul_generic (closes #334)
This fixes a test-suite segfault on Darwin with -O0. Before this change:

$ cabal run -O0 test-cryptonite -- -p AE1
Segmentation fault: 11

with

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   test-cryptonite               	0x0000000108f7f61f gfmul_generic + 47
1   test-cryptonite               	0x0000000108f76f17 ghash_add + 71
2   test-cryptonite               	0x0000000108f743b4 cryptonite_aesni_gcm_encrypt128 + 2244
3   test-cryptonite               	0x0000000108f97f20 cryptonite_aes_gcm_encrypt + 96
4   test-cryptonite               	0x0000000108eeadf5 Lc8Pq_info + 197
2021-09-10 17:50:05 +02:00
Gregor Kleen
71a630edaf resumable hashing 2021-06-23 12:29:34 +02:00
Gregor Kleen
365c8978a2 build support 2021-06-23 12:29:12 +02:00
Vincent Hanquez
8698c9fd94
Merge pull request #221 from Porges/hmac-lazy
Add `hmacLazy` for lazy `ByteString`s
2021-06-03 08:01:10 +08:00
George Pollard
e9c9c770d3
Update HMAC.hs 2021-06-03 08:34:34 +12:00
George Pollard
9961606e5b
Merge branch 'master' into hmac-lazy 2021-06-03 08:33:55 +12:00
Vincent Hanquez
4b4a641970
cryptonite-0.29 2021-05-08 23:00:34 +08:00
Vincent Hanquez
a6fbe0ed4c
fix miscompilation with ghc9 2021-05-08 22:57:36 +08:00
Vincent Hanquez
b6981a4ea5
latest integer-gmp breaks advance GMP functions again (...) 2021-05-08 22:57:26 +08:00
Vincent Hanquez
cf89276b5c
Merge pull request #312 from ocheron/eddsa-gen
Generic EdDSA implementation
2021-04-14 23:17:34 +08:00
Vincent Hanquez
f449a54eb2
Merge pull request #345 from hamishmack/hkm/32bit-fix
Fix for 32 bit platforms
2021-04-14 23:08:10 +08:00
Hamish Mackenzie
95b247e5eb
Fix for 32 bit platforms
The use of `(fromIntegral (maxBound :: Word32))` causes problems.  It is used to make an `Int` and 32 bit systems it winds up being -1.
2021-04-14 17:16:15 +12:00
Vincent Hanquez
955f94b784
release 0.28 2021-01-27 10:48:00 +08:00
Vincent Hanquez
d0ead79fed
Merge pull request #331 from chpatrick/hash-4gb
Hash data in 4GB chunks to avoid uint32_t overflow.
2020-08-08 09:24:47 +08:00
Patrick Chilton
b29dc159fb Hash data in 4GB chunks to avoid uint32_t overflow. 2020-08-07 21:36:19 +02:00
Olivier Chéron
10dc63c51f Merge pull request #328 from ocheron/aead-thunks
Avoid thunk leak with AEAD state
2020-07-20 19:06:59 +02:00
Olivier Chéron
18ae7a7b40 Remove redundant brackets 2020-07-19 15:45:49 +02:00
Olivier Chéron
fa19117dfe Avoid thunk leak with AEAD state 2020-07-19 15:44:10 +02:00
Olivier Chéron
d49408156e Warn about instances exposing internals 2020-07-05 09:20:29 +02:00
Olivier Chéron
81cc351800 Note about drgNewTest and endianness 2020-07-05 09:20:29 +02:00
Olivier Chéron
9eadf707c4 Merge pull request #325 from ocheron/hash-ct
Hashing independent from input length
2020-07-05 08:46:38 +02:00
Olivier Chéron
72544ea9aa Removed extra semicolon 2020-07-02 19:35:06 +02:00
Olivier Chéron
63d427ee77 Add note about other package flags 2020-06-28 08:49:28 +02:00
Olivier Chéron
c8199872e7 Test HashAlgorithmPrefix API 2020-06-26 07:16:49 +02:00
Olivier Chéron
e67d8fb223 Generate HashAlgorithmPrefix instances 2020-06-26 07:16:41 +02:00
Olivier Chéron
caec601cd1 Add finalize_prefix functions 2020-06-26 07:16:30 +02:00
Olivier Chéron
ba3ab1f0cd Add HashAlgorithmPrefix API 2020-06-26 07:16:18 +02:00
Vincent Hanquez
0254f16e83
release 0.27 2020-06-21 12:07:25 +08:00
Olivier Chéron
cf9631dd7f Merge pull request #322 from incertia/square-root-f2m
implement square roots in f2m
2020-06-14 09:16:16 +02:00
Olivier Chéron
c123752de4 Use isNothing 2020-06-13 09:24:47 +02:00
Olivier Chéron
edbd9e09fb Test properties of powF2m 2020-06-12 19:06:58 +02:00
Olivier Chéron
dfc9fb9fb2 Fix powF2m when exponent is not a power of 2
Integer multiplication cannot be used because it includes carry
propagation.  This needs to use carry-less mulF2m instead.
2020-06-12 19:01:52 +02:00
Olivier Chéron
5f657fda2e Remove powF2m'
We keep only the function providing the base service, negative
exponents can be still computed with invF2m.
2020-06-12 18:54:37 +02:00
Will Song
f64efafbad update sqrtF2m 2020-06-08 10:16:42 -05:00
Will Song
17336857c5 implement square roots in f2m 2020-06-01 20:56:42 -05:00
Olivier Chéron
775855994c Use notElem 2020-03-15 15:44:35 +01:00
Olivier Chéron
5d63ef7c4f Merge pull request #316 from ocheron/target-attrs
AESNI and PCLMUL as per-function attributes
2020-03-15 15:43:27 +01:00
Olivier Chéron
f84f7e3009 Enable flag by default 2020-03-15 15:39:56 +01:00
Olivier Chéron
0cf0d076ab Add flag use_target_attributes 2020-03-14 08:44:44 +01:00
Olivier Chéron
f5706959a4 AES-NI and PCLMUL with per-function target compiler options 2020-03-14 08:43:44 +01:00
Olivier Chéron
dae01d056d AES-NI with per-file target compiler options 2020-03-14 08:09:12 +01:00
Olivier Chéron
a1072948ca Avoid error "Unknown mingw32 arch" with hlint 2020-03-14 08:07:35 +01:00
Olivier Chéron
d8a39637f5 Ignore hint "Use camelCase" globally 2020-03-14 07:39:06 +01:00
Olivier Chéron
64f097788e Merge pull request #315 from ocheron/i386-sse
Fix support_sse on i386 architecture
2020-03-14 07:36:30 +01:00
Olivier Chéron
b9e1e75a10 Fix support_sse on i386 architecture
On i386 compilation failed with support_sse enabled and support_aesni
disabled.  This enables the minimum required instruction set, guarded
with an architecture condition.
2020-03-11 19:15:32 +01:00
Olivier Chéron
e56308f9d0 Fix ignored allow_failures and weeder build in Travis CI
Used haskell-ci commit cbf9d90 from PR vincenthz/haskell-ci#5 to
regenerate the files.
2020-03-08 18:34:59 +01:00
Olivier Chéron
981b97a132 Protect against negative argument 2020-02-24 06:54:23 +01:00
Olivier Chéron
2e0a60f7f7 Use Semigroup API 2020-02-24 06:54:23 +01:00
Olivier Chéron
b01f610aa2 Add and use Builder module
Avoids intermediate allocations and conversions when concatenating
byte arrays of different types.
2020-02-24 06:54:23 +01:00
Olivier Chéron
ef880291e3 Add EdDSA 'ctx' and 'ph' variants 2020-02-24 06:54:23 +01:00
Olivier Chéron
977c72cac9 Test EdDSA with both SHA-2 and BLAKE2 2020-02-24 06:54:23 +01:00
Olivier Chéron
1cb2cd2f12 Ability to select the hash algorithm 2020-02-24 06:54:23 +01:00
Olivier Chéron
436b9abc13 Benchmark EdDSA implementations 2020-02-24 06:54:23 +01:00
Olivier Chéron
6f932998ad Fast hashing for EdDSA 2020-02-24 06:54:23 +01:00
Olivier Chéron
bd84c75f3e Use unsafe FFI calls
Changed Edwards primitives to unsafe when overhead of FFI call is
approximately 5% or more of total execution time.
2020-02-24 06:54:23 +01:00
Olivier Chéron
6f70986cb1 Avoid signature padding when not required 2020-02-24 06:54:23 +01:00
Olivier Chéron
633879f801 Avoid repeated point encoding 2020-02-24 06:54:23 +01:00
Olivier Chéron
6075b698e1 Generic EdDSA implementation 2020-02-24 06:54:23 +01:00
Olivier Chéron
4b9584dbe4 Use lts-15 in CI and bump versions 2020-02-24 06:53:19 +01:00
Olivier Chéron
4b8a8229cf Remove redundant where 2020-02-24 06:53:03 +01:00
Olivier Chéron
43a9967b1d Remove redundant superclass in MonadRandom
Reported by @frasertweedale
2020-02-16 19:49:49 +01:00
Olivier Chéron
86470d5563 Use conventional declaration order 2020-02-10 06:43:26 +01:00
Olivier Chéron
d2df760e34 Use zipWith 2020-02-10 06:43:26 +01:00
Vincent Hanquez
be517c9273
Merge pull request #307 from ocheron/p256-b64
Add 64-bit implementation for P256
2020-01-21 10:33:56 +08:00
Olivier Chéron
2579d1e7aa Use smaller value in felem_diff 2020-01-14 21:11:51 +01:00
Olivier Chéron
44a1651d26 Remove NULL checks in inner loop 2020-01-12 18:33:32 +01:00
Olivier Chéron
b08ce5e3ae Add 64-bit implementation for p256 2020-01-12 18:33:32 +01:00
Olivier Chéron
f9a6a35ce3 Prepare 64-bit implementation for p256 2020-01-12 18:33:32 +01:00
Olivier Chéron
f291bd08ef Move p256 felem code 2020-01-12 18:33:32 +01:00
Olivier Chéron
b5d9b6cba5 Add AppVeyor file 2020-01-12 18:21:17 +01:00
Olivier Chéron
7f1c2980e2 Merge pull request #305 from ocheron/p256-point-mul
Better P256.pointMul performance
2020-01-12 18:20:17 +01:00
Olivier Chéron
7ac3060873 Better P256.pointMul performance
Use dedicated function to avoid multiplying the basepoint with 0.
2020-01-06 18:49:12 +01:00
Olivier Chéron
1f6ed5711c Warn about non-uniform distribution with QuickCheck 2020-01-04 10:58:22 +01:00
Olivier Chéron
17879cbecd Merge pull request #303 from ocheron/square-root
Modular square root
2020-01-04 10:55:48 +01:00
Olivier Chéron
9e0dbb3231 Modular square root 2019-12-07 08:35:14 +01:00
Olivier Chéron
0a1aa3517c Fix warnings and whitespace 2019-12-03 21:06:17 +01:00
Olivier Chéron
18c6e37ef1 Merge pull request #300 from ocheron/tc-ecdsa
ECDSA with a type class
2019-12-01 08:47:33 +01:00
Olivier Chéron
95ebd3996f Merge pull request #301 from bwignall/typo
Fix typos
2019-12-01 08:45:37 +01:00
Brian Wignall
78684bc62b Fix typos 2019-11-30 18:22:26 -05:00
Olivier Chéron
99820c742d Truncate the digest without Integer conversion 2019-11-11 17:46:16 +01:00
Olivier Chéron
b9a8a6b83d ECDSA with digest 2019-11-11 17:46:16 +01:00
Olivier Chéron
15327ecd4f ECDSA with a type class 2019-11-11 17:46:16 +01:00
Olivier Chéron
8f75165f8b Time-constant P256 scalar inversion 2019-11-11 17:46:16 +01:00
Olivier Chéron
977e75f478 Add P256 functions to implement ECDSA 2019-11-11 17:46:16 +01:00
Olivier Chéron
19b7ab375a Time-constant modular inverse 2019-11-11 17:46:16 +01:00
Olivier Chéron
ce35a1e07d Merge pull request #299 from ocheron/ecc-scalar-ext
Extended ECC type class
2019-11-11 17:45:18 +01:00
Olivier Chéron
6f2a59e470 Apply hlint suggestions 2019-10-05 08:34:12 +02:00
Olivier Chéron
db8d47a76c ECC arithmetic in prime-order subgroup
A type-class extension packs together additional functions related to
a chosen basepoint as well as scalar serialization and arithmetic
modulo the subgroup order.
2019-10-05 08:34:12 +02:00
Olivier Chéron
bdf1a7a133 Require point equality in EllipticCurveArith
This is an incompatible API change but is very useful to test
properties and algorithms derived from the primitives.  An ECC
instance sufficiently advanced to have math primitives should
implement equality too.
2019-10-05 08:34:12 +02:00
Olivier Chéron
e0b201b5e7 Test P256.pointMul 2019-10-05 08:34:12 +02:00
Olivier Chéron
2e92639679 Add P256.scalarMul 2019-10-05 08:34:12 +02:00
Olivier Chéron
68c93ccbb1 Add GHC 8.8.1 to CI and bump versions 2019-10-05 08:23:45 +02:00
Olivier Chéron
e8b8a199e8 Merge pull request #293 from ocheron/xsalsa-derive
Add XSalsa.derive
2019-09-14 08:53:43 +02:00
Olivier Chéron
2433893730 Test XSalsa.derive
Adds a test case taken from NaCl paper, but without the parts related
to Curve25519 and Poly1305 because we want to test only XSalsa here.
2019-09-14 08:35:43 +02:00
Olivier Chéron
096e2ec0bd Add XSalsa.derive and example
This function adds one more HSalsa key derivation to an XSalsa context
that has previously been initialized.  It allows multi-level cascades
like the 2-level done by NaCl crypto_box.
2019-09-09 19:32:24 +02:00
Olivier Chéron
65643a3bea Merge pull request #292 from ocheron/aes-gcm-siv
AES-GCM-SIV
2019-09-08 09:49:35 +02:00
Olivier Chéron
3ae08ed509 Add API to generate a random nonce
This AEAD scheme is compatible with choosing the nonce randomly.
2019-08-25 16:38:08 +02:00
Olivier Chéron
29f0fd1b7a Test AES-GCM-SIV
Includes the test vectors from RFC 8452 and QuickCheck properties with
encryption-decryption round trip.
2019-08-25 16:38:03 +02:00
Olivier Chéron
73719cbe88 Add AES-GCM-SIV to AEAD benchmarks 2019-08-25 16:38:03 +02:00
Olivier Chéron
908f979d44 Add AES-GCM-SIV 2019-08-25 16:38:01 +02:00
Olivier Chéron
0075b57f90 Add internal AES CTR variant with 32-bit counter
This variant of CTR mode is used by AES-GCM-SIV.  The counter is in
little-endian format and uses the first four bytes of the IV only.
2019-08-25 08:55:49 +02:00
Olivier Chéron
262252a5c4 Merge pull request #291 from ocheron/p256-point-add
Faster P256.pointAdd
2019-08-25 08:51:58 +02:00
Olivier Chéron
f2fa7836cb Merge pull request #290 from ocheron/gcm-wrapping
Fix counter wrapping in AES GCM
2019-08-25 08:51:03 +02:00
Olivier Chéron
4ca77b8cf5 Faster P256.pointAdd
Convert to projective coordinates without expansive calls to function
'scalar_mult'.
2019-08-21 09:32:53 +02:00
Olivier Chéron
fc07a8b931 Fix counter wrapping in AES GCM
The generic and AESNI implementations used different conventions
regarding counter wrapping in GCM.  The generic code was based on
function block128_inc_be, for which the counter is a 128-bit value.
Whereas the AESNI code used intrinsic function _mm_add_epi64, and
therefore wrapping at 2^64.

In NIST.SP.800-38d the GCM specification mandates to use incrementing
function inc32, wrapping after 2^32 blocks.  This commit changes both
generic and AESNI implementations to align to the specification and
adds a test vector specially crafted to start encryption with IV block
0xfffffffffffffffffffffffffffffffe.
2019-08-20 10:34:40 +02:00
Olivier Chéron
0d32f9b833 Remove unused variables 2019-08-12 21:11:01 +02:00
Olivier Chéron
7e6aeaa8da Add Crypto.System.CPU to QA 2019-08-12 21:10:47 +02:00
Olivier Chéron
00221a494c Ignore stack.yaml.lock 2019-07-28 08:46:18 +02:00
Olivier Chéron
a0ad444ec1 Merge pull request #288 from 3for/P256-bench
bench for P256.pointAdd and P256.pointMul
2019-07-28 08:42:21 +02:00
Olivier Chéron
3e4ce8d2ed Merge pull request #287 from tom-audm/master
Fix typo ("strive" -> "strives")
2019-07-28 08:38:28 +02:00
root
a64a058153 warning remove and benchF2m okay 2019-07-23 11:14:09 +08:00
root
d3a60abf28 warning remove 2019-07-23 10:57:33 +08:00
root
7ca1f2e4d6 bench for P256.pointAdd and P256.pointMul 2019-07-15 10:47:58 +08:00
tom-audm
71184beb15 Fix typo ("strive" -> "strives") 2019-07-11 16:36:27 -04:00
Olivier Chéron
cdd0821eee Merge pull request #281 from ocheron/cpu-options
Add module Crypto.System.CPU
2019-06-23 09:05:13 +02:00
Olivier Chéron
53a1bf7ebf Report info about runtime environment in the test suite 2019-06-15 09:28:02 +02:00
Olivier Chéron
91c87deae1 Add Crypto.System.CPU 2019-06-15 09:28:02 +02:00
Olivier Chéron
f121d1b8d1 Merge pull request #280 from ocheron/gcm-small-table
More optimizations for AES GCM and CCM
2019-06-15 09:27:48 +02:00
Olivier Chéron
2cf3b75636 AES CCM: use AESNI in CBC-MAC computation when possible 2019-06-06 06:48:22 +02:00
Olivier Chéron
4df2a95276 AES GCM: use Shoup's method with 4-bit table 2019-06-06 06:48:16 +02:00
Olivier Chéron
5b39ae3e48 Add missing void and const 2019-05-26 11:50:07 +02:00
Olivier Chéron
c8a4e48e0c Remove unused variables 2019-05-26 11:50:07 +02:00
Vincent Hanquez
7596e2959d release 0.26 2019-05-21 08:49:16 +01:00
Vincent Hanquez
60ddb49298
Merge pull request #277 from ocheron/little-endian
Little-endian integer serialization
2019-05-19 21:56:41 +01:00
Vincent Hanquez
982ded8ad5
Merge pull request #278 from ocheron/gcm-pclmul
Faster AES GCM with PCLMULQDQ
2019-05-19 21:53:57 +01:00
Olivier Chéron
d25e44ea61 Add GHASH implementation with PCLMULQDQ 2019-05-19 11:18:40 +02:00
Olivier Chéron
cddbc2cef9 Remove unopt_gf_mul 2019-05-19 11:16:34 +02:00
Olivier Chéron
76ba39fc95 Add benchmark with AES GCM and CCM 2019-05-19 11:16:34 +02:00
Olivier Chéron
5b4845dd0e Use GHC 8.6.5 for CI and bump versions 2019-05-16 06:55:01 +02:00
Olivier Chéron
af98a837d1 Add missing INLINABLE pragma 2019-05-16 06:33:35 +02:00
Olivier Chéron
7ecb259aae Fix LE.i2osp 0
Little-endian bytes are stored at the beginning of the buffer.
2019-05-16 06:33:35 +02:00
Olivier Chéron
6893eae70a Make os2ip loop argument strict 2019-05-16 06:33:35 +02:00
Olivier Chéron
393aeac8cd Test LE serialization 2019-05-16 06:33:35 +02:00
Olivier Chéron
6e1b6fdb90 Little-endian integer serialization 2019-05-16 06:33:35 +02:00
Olivier Chéron
3161630390 Update CHANGELOG 2019-05-08 10:22:30 +02:00
Olivier Chéron
158d8dfd0c Remove unnecessary imports 2019-05-08 10:22:30 +02:00
Olivier Chéron
687765cacd Merge pull request #276 from ocheron/kmac
Keccak Message Authentication Code (KMAC)
2019-05-08 10:06:25 +02:00
Olivier Chéron
ae107a9285 Merge last cshakeUpdate with cshakeFinalize 2019-05-01 07:03:45 +02:00
Olivier Chéron
8b235612be Merge cshakeInit with first cshakeUpdate 2019-04-28 09:14:25 +02:00
Olivier Chéron
14093ac298 Optimize KMAC allocations
Adds a minimalist Builder type to merge intermediate allocations into
a single ByteArray.  Key is now copied to a ScrubbedBytes only.
2019-04-28 09:14:25 +02:00
Olivier Chéron
1551436111 Add KMAC 2019-04-28 09:14:25 +02:00
Olivier Chéron
c9f8dac6b0 Merge pull request #274 from ocheron/p256-add-sub
Improve P256.scalarAdd and P256.scalarSub
2019-04-28 09:12:47 +02:00
Olivier Chéron
7e5dbeb146 Use vector/vectorOf from QuickCheck and simplify 2019-03-26 06:25:45 +01:00
Olivier Chéron
6f67cefa3d Remove code duplication 2019-03-26 06:24:00 +01:00
Olivier Chéron
15f117d9c3 Remove tests add-n-1 and sub-n-1
Operation with value close to the curve order is now tested in other
tests.  This tests substraction with 0 instead.
2019-03-25 06:47:21 +01:00
Olivier Chéron
399fc891da Test P256 primitives will full scalar range 2019-03-24 08:31:58 +01:00
Olivier Chéron
47123ed97a Better P256 scalar primitives
Allows scalars in full range [ 0 .. 2^256-1 ].  Modular reduction is
added a few more operations with conditional selection.
2019-03-24 08:31:45 +01:00
Olivier Chéron
e3edc100c3 Remove unnecessary import 2019-03-24 07:59:57 +01:00
Olivier Chéron
3253501166 Time-constant P256.scalarAdd and P256.scalarSub 2019-03-21 07:04:01 +01:00
Olivier Chéron
f4be05eb2e Merge pull request #240 from lpeterse/bcrypt_pbkdf
Add bcrypt_pbkdf key derivation function
2019-03-17 19:02:27 +01:00
Lars Petersen
2a26202a32 Add implementation of bcrypt_pbkdf 2019-03-14 21:30:29 +01:00
Olivier Chéron
0ce2e5f325 Remove -fno-warn-unused-imports
Changing the build so that we don't diverge again after cleanup done
in #267.
2019-03-09 09:08:53 +01:00
Olivier Chéron
d67a21f95f Remove unnecessary imports and calls 2019-03-09 09:08:53 +01:00
Olivier Chéron
107317c84d Improve strictness in Blowfish rounds 2019-03-04 06:39:55 +01:00
Olivier Chéron
0f8dc3588d Add BCrypt benchmark 2019-03-04 06:39:46 +01:00
Olivier Chéron
717de392cd Merge pull request #238 from lpeterse/master
Extend the internal interface of the Blowfish module.
2019-03-04 06:37:15 +01:00
Olivier Chéron
8e28d7b2cd Merge pull request #271 from ocheron/hash-nat-constraints
Hash algorithms with runtime output length
2019-03-04 06:33:59 +01:00
Olivier Chéron
26057fa0f6 Merge pull request #270 from ocheron/pr-241-rebased
add ECDSA sign/verify digest APIs
2019-03-04 06:32:43 +01:00
Olivier Chéron
299140f884 Remove unnecessary hash arguments
We don't need to give the hash algorithm as a separate argument since
it is already available from the digest value itself.
2019-03-01 06:28:55 +01:00
Olivier Chéron
997cea369b Rename to signDigestWith 2019-03-01 06:28:55 +01:00
Baojun Wang
b55a93dfdc add ECDSA sign/verify digest APIs
(rebased from commit 045793427e8d46594b0b2afedb314d027ec707ab)
2019-03-01 06:28:32 +01:00
Olivier Chéron
3c41966b9a Add module Crypto.Number.Nat
This new module exposes type constraints required by some hash
algorithms and provides functions to check whether the constraints are
satisfied with runtime values.

Resolves #256.
2019-02-28 07:07:48 +01:00
Olivier Chéron
eccbc11824 Remove Crypto.Internal.Proxy
Data.Proxy can be used instead now that GHC >= 8.0.  In Data.Proxy the
Proxy type is poly-kinded.
2019-02-28 07:07:48 +01:00
Olivier Chéron
8c77f0c1ea Update generation templates per latest changes 2019-02-25 06:42:44 +01:00
Olivier Chéron
65932e5a7e Add missing Data instances in Crypto.Hash.Blake2 2019-02-25 06:40:53 +01:00
Olivier Chéron
540ef78abb Merge pull request #267 from crockeea/master-clean
Code maintenance and cleanup
2019-02-25 06:36:11 +01:00
Crockett
133c6e1b2d Added some redundant constraints for documentation/consistency. Added an INLINABLE pragma to i2ospOf to hopefully increase specializations. 2019-02-24 17:04:10 -08:00
Olivier Chéron
101c2c05cf Merge pull request #268 from psibi/blake2-update
Update blake2 with upstream
2019-02-24 17:47:22 +01:00
Sibi Prabakaran
dee3782a83
Add Changelog 2019-02-22 03:28:57 +05:30
Sibi Prabakaran
af9f9548d6
Update reference blake2 implementation with upstream 2019-02-21 17:16:00 +05:30
Olivier Chéron
1d82f647a4 Merge pull request #265 from crockeea/master
Fixed hash truncation bug in DSA
2019-02-04 21:22:04 +01:00
Crockett
0fb8a73d3b Fixed compiler warnings 2019-02-03 16:06:05 -08:00
Crockett
88596509f0 Changed imports to match style of rest of library 2019-02-03 13:51:01 -08:00
Crockett
109600cec2 Added missing imports and removed duplicate imports. Tests pass. 2019-02-03 13:43:54 -08:00
Crockett
c71a6733dd Unified DSA and ECDSA truncate&hash function. 2019-02-03 13:30:56 -08:00
Crockett
d5003a46a6 Fixed hash truncation bug in DSA; added more KATs from RFC 6979. 2019-01-26 15:15:34 -08:00
Olivier Chéron
69ef95b0de Use GHC 8.6.3 for CI and bump versions 2019-01-19 08:54:31 +01:00
Olivier Chéron
f81c08c089 Merge pull request #262 from ocheron/rsapss-any-length
RSA-PSS with arbitrary key size
2019-01-19 08:49:38 +01:00
Olivier Chéron
1d5947f055 Use any instead of not all 2019-01-15 21:24:31 +01:00
Olivier Chéron
ae0e9c0f3e Remove commented example 10 2019-01-12 17:43:49 +01:00
Olivier Chéron
8eb8d01577 RSASSA-PSS vectors with key size 1025, 1026, 1031 2019-01-12 17:43:49 +01:00
Olivier Chéron
f9ae52327c RSASSA-PSS with key of arbitrary length
Instead of public_size / private_size which are in bytes only, this
uses function numBits to recover the effective length of the modulus
in bits.  The patch also handles removal of unneeded initial byte when
the length is 1 modulo 8.
2019-01-12 17:43:49 +01:00
Olivier Chéron
274911c608 Accept hlint suggestions 2019-01-12 17:43:49 +01:00
Olivier Chéron
d964064d80 Use heterogeneous equality 2019-01-12 17:43:49 +01:00
Vincent Hanquez
3de65a43a1 fix QA building command 2019-01-06 16:08:48 +00:00
Vincent Hanquez
7fc7acb38b
Merge pull request #247 from crodriguezvega/master
Add Rabin (and variants) cryptosystem
2018-12-18 21:44:44 +00:00
Carlos Rodriguez
ddfdbbd4be Removed unnecessary reference to random. 2018-12-18 20:19:14 +01:00
Carlos Rodriguez
cc18bf41ee
Corrected value boundaries in description of function. 2018-11-11 17:14:23 +01:00
Carlos Rodriguez
95f0f3d0c9 Fixed typos in name. 2018-11-03 21:17:46 +01:00
Carlos Rodriguez
3165027840
Fixed typo in name. 2018-11-03 21:12:53 +01:00
Carlos Rodriguez
314a9caba7 Merge branch 'master' of https://github.com/haskell-crypto/cryptonite
# Conflicts:
#	cryptonite.cabal
#	tests/KAT_PubKey.hs
2018-11-03 20:23:25 +01:00
Olivier Chéron
9847554392 Fixed comment about expSafe 2018-11-01 09:08:39 +01:00
Olivier Chéron
8da892da5d Merge pull request #258 from ocheron/pkcs1_5-padding
Correction to PKCS#1 v1.5 padding
2018-11-01 09:06:57 +01:00
Olivier Chéron
01faa66fd4 Add tests for RSA signature and verification
This includes tests for SignatureTooLong edge cases.
2018-10-29 20:43:07 +01:00
Olivier Chéron
f4e094aacb Fix PKCS#1 v1.5 padding
The padding string is at least 8 bytes long + 3 other bytes,
so it should be 11.
2018-10-29 20:43:02 +01:00
Olivier Chéron
0f43451b4f Merge pull request #257 from ocheron/hash-shake-truncate
SHAKE with output length not divisible by 8
2018-10-29 19:09:40 +01:00
Olivier Chéron
d4bd9287f2 Test with GHC 8.4.4 2018-10-28 17:52:36 +01:00
Olivier Chéron
ee9c485a4d Update tested-with 2018-10-26 18:31:29 +02:00
Olivier Chéron
77bc512a87 Add a default stack.yaml
Will be useful for the weeder build in CI.
2018-10-24 21:25:41 +02:00
Olivier Chéron
6a7594d2be Add GHC 8.6 to CI and bump LTS versions 2018-10-24 06:28:39 +02:00
Olivier Chéron
455504b8e2 Implement SHAKE output not divisible by 8 bits 2018-10-23 06:59:07 +02:00
Olivier Chéron
0ab1c41ac8 Add missing Data instances 2018-10-23 06:59:07 +02:00
Olivier Chéron
e10ef06885 Remove unnecessary language extension 2018-10-23 06:59:07 +02:00
Carlos Rodriguez
c285d7f527 Added OAEP scheme and created test vectors for Rabin cryptosystem. 2018-10-06 16:53:22 +02:00
Vincent Hanquez
a8875e462d
Merge pull request #242 from LeifW/derive_data_digest
Derive a Data instance for Digest.
2018-09-13 14:31:56 +01:00
Carlos Rodriguez
aa745ba250 Replaced tab with spaces. 2018-09-06 20:48:15 +02:00
Carlos Rodriguez
e7b3abebf8 Implemented Rabin cryptosystem and some of its variations (including Rabin-Williams). 2018-09-06 20:27:32 +02:00
Carlos Rodriguez
95320826f9
Merge pull request #1 from haskell-crypto/master
Fix typo in bcrypt example
2018-09-06 14:13:48 +02:00
tom-bop
1288127d8e Fix typo in bcrypt example 2018-08-30 17:47:59 +01:00
Leif Warner
8a61d8e5e2 Derive a Data instance for Digest. 2018-06-18 00:20:48 -07:00
Lars Petersen
ff8a1c524d Extend the internal interface of the Blowfish module.
In preparation of an implementation of the bcrypt_pbkdf (a
variant of PBKDF2 used by OpenSSH) algorithm,
certain low-level operations of the Blowfish algorithm need to
be generalized and exposed.

The Blowfish.Primitive module has already been extended to
account for the requirements imposed by the BCrypt algorithm,
but the salt length was limited to 16 bytes and the BCrypt
specific key schedule setup has been hard-coded into the Blowfish
module.

This commit makes a clear distintion between the expandKey and
expandKeyWithSalt operation. Both take arbitrary sized salts
and keys now. The specialized operation for 16 byte salts as used
by BCrypt has been preserved and is selected automatically.
Also, the BCrypt specific parts have been move to the BCrypt
module with regard to separation of concern.

A benchmark for generating BCrypt hashes with cost 10 shows a
performance improvement from 158 to 141ms on average (Intel i5-6500)
after this refactoring.
Further experiments suggest that the specialized expandKeyWithSalt128
does not have any advantage over the generalized version
and might be removed in favour of less branches and exceptional
behaviour.
2018-05-08 22:08:20 +02:00
Olivier Chéron
4622e5fc8e Fix ECC failures on arm64
Resolves #234.
2018-05-01 08:23:08 +02:00
Olivier Chéron
74463d1bf1 Merge pull request #235 from ocheron/powModSecInteger
Enable powModSecInteger again
2018-05-01 07:47:47 +02:00
Olivier Chéron
d0ac50c1af Additional QA clean-up 2018-04-29 10:43:55 +02:00
Olivier Chéron
b3a1506d82 Remove conditionals related to SHAKE and Blake2
Not needed anymore now that GHC > 8.0.
2018-04-28 08:09:25 +02:00
Olivier Chéron
1fa6c35c35 Update tested-with 2018-04-28 08:08:43 +02:00
Olivier Chéron
9d961e92e9 Comment about not having Show instance for HMAC
Closes #232.
2018-04-22 19:44:29 +02:00
Olivier Chéron
a2a2372412 Use newer GHC and lts for CI 2018-04-22 19:44:29 +02:00
Olivier Chéron
15f63fd849 Enable powModSecInteger with integer-gmp >= 1.0.2.0 2018-04-20 20:40:53 +02:00
Luke Taylor
d27d464627 Fix cost parsing for bcrypt
The tens value was wrong for values of 20+, as reported in #230.
It should be 10*costTens not 10^costTens. This wasn't detected because
the values are the same when costTens is 1, and using high cost values
is rare with bcrypt because of the performance hit.

Also added a simple hash and validate test since the KAT tests only do
validation. This doesn't cover this bug since the cost value is too
high to include in the test. It allows similar issues to be tested
locally though.
2018-04-17 13:51:04 +01:00
Chris Martin
d2da00445d fix spelling of "exponent" 2018-04-05 21:44:40 -04:00
Vincent Hanquez
8b508302eb
Merge pull request #223 from haskell-crypto/dropold
Drop GHC 7.8 and GHC 7.10 support, refer to pkg-guidelines
2018-03-26 10:19:00 +01:00
Vincent Hanquez
dfd8ff7e8d
Merge pull request #219 from ocheron/digest-read-basement
Add Read instance for Digest type
2018-03-12 08:41:38 +00:00
Vincent Hanquez
467ed66c16 Drop GHC 7.8 and GHC 7.10 support, refer to pkg-guidelines 2018-03-12 08:35:49 +00:00
George Pollard
f55636bd43 Add hmacLazy for lazy ByteStrings
Modeled off `hashLazy`.
2018-03-06 18:05:02 +13:00
Olivier Chéron
3e5be5fdf3 Add Read instance for Digest type 2018-02-11 09:15:05 +01:00
Vincent Hanquez
ec8366bbd2
release 0.25 2018-02-06 15:35:32 +00:00
Vincent Hanquez
41d610fb18
Merge pull request #217 from haskell-crypto/hash-use-block
Hash: use Block instead of UArray to reduce memory usage
2018-02-05 14:34:04 +00:00
Vincent Hanquez
e8350e03bd add proper dependency for tests 2018-02-05 12:26:25 +00:00
Vincent Hanquez
b4add57955 Hash: use Block instead of UArray to reduce memory usage 2018-02-04 23:06:02 +00:00
Vincent Hanquez
2d87929a4e
Merge pull request #215 from haskell-crypto/haskell-ci
Bring CI to 2018
2018-02-04 23:05:09 +00:00
Vincent Hanquez
8b95917572 fix some more reference to criterion 2018-02-04 22:18:07 +00:00
Vincent Hanquez
6c84a1605d
Merge pull request #216 from haskell-crypto/aesccm-rebase
AES CCM mode
2018-02-04 21:38:16 +00:00
Vincent Hanquez
d291f9f5bb move to gauge 2018-02-04 21:33:36 +00:00
Vincent Hanquez
fb800bd2b6 fix for 7.10 2018-02-04 21:28:48 +00:00
Vincent Hanquez
5400fdf5ae use haskell-ci 2018-02-04 14:43:40 +00:00
Olivier Chéron
07be32728e Avoid warning with tasty-quickcheck-0.9.2 2018-02-04 15:27:45 +01:00
Olivier Chéron
1490f080a5 Use aligned block128 functions
Applies similar changes to what was done in #175.
2018-02-04 14:36:03 +01:00
Olivier Chéron
325c87febf Use pattern matching 2018-02-04 14:35:43 +01:00
Olivier Chéron
4926cbb143 Improve types and indentation, fix typo 2018-02-03 19:05:20 +01:00
Baojun Wang
1e57f41e1d check AESCCM IV length in ccmInit instead of aeadInit 2018-02-03 09:34:57 +01:00
Baojun Wang
f6d9fb0cf1 aeadInit (ccm) returns CryptoError_IvSizeInvalid when iv size is wrong 2018-02-03 09:34:57 +01:00
Baojun Wang
d5f8348a4b use nonce_len for memcpy 2018-02-03 09:34:57 +01:00
Baojun Wang
ccc7c3e7a6 kill unused imports 2018-02-03 09:34:57 +01:00
Baojun Wang
6fef094e90 Add KATCCM test file 2018-02-03 09:34:57 +01:00
Baojun Wang
e01ef4386e Add AESCCM test vectors for testing 2018-02-03 09:34:57 +01:00
Baojun Wang
035693240d fix wrong condition check in cryptonite_aes_ccm_aad 2018-02-03 09:34:57 +01:00
Baojun Wang
fefe5d75e3 flavor condition checks instead of asserts 2018-02-03 09:34:57 +01:00
Baojun Wang
48770bf79f fix aes ccm decryption cbcmac mis-match 2018-02-03 09:34:57 +01:00
Baojun Wang
1e04890d73 Add ccm decrypt 2018-02-03 09:34:57 +01:00
Baojun Wang
55bf620365 add aes ccm support 2018-02-03 09:31:36 +01:00
Vincent Hanquez
28f604f7bd
Merge pull request #210 from avieth/avieth/bs_copy
More efficient digestFromByteString
2018-01-09 22:18:54 +00:00
Alexander Vieth
6dca020660 improve digestFromByteString efficiency 2018-01-09 17:10:12 -05:00
Vincent Hanquez
c02c43bfc7
Merge pull request #205 from osa1/close_dev_handle
withDev: Close the FD on exception
2017-12-17 18:15:31 +00:00
Vincent Hanquez
6346b8289c
Merge pull request #202 from ocheron/ed25519-arith-negate
Ed25519 arithmetic primitives
2017-12-17 18:12:50 +00:00
Vincent Hanquez
82c22d50c7
Merge pull request #206 from haskell-crypto/replace-foundation-by-basement
remove dependency on foundation and moving to basement
2017-12-17 18:12:41 +00:00
Olivier Chéron
3217038a1a Add pointMulByCofactor and pointHasPrimeOrder 2017-12-17 11:56:33 +01:00
Olivier Chéron
9cd77ed3e2 Test points with a torsion component 2017-12-17 09:46:42 +01:00
Olivier Chéron
251f164f47 Apply bugfix to Edwards25519.pointsMulVarTime 2017-12-17 09:46:42 +01:00
Olivier Chéron
b962952c30 Add introduction and warnings about possible pitfalls 2017-12-17 09:46:42 +01:00
Olivier Chéron
0820cd5c38 Simpler Edwards25519.scalarGenerate 2017-12-16 11:33:38 +01:00
Olivier Chéron
fbe1c213e2 Use throwCryptoError 2017-12-11 06:40:41 +01:00
Olivier Chéron
45723e3542 Rename to Edwards25519 2017-12-10 21:14:47 +01:00
Olivier Chéron
d472d9b74f Import Ed25519 unqualified 2017-12-10 21:13:09 +01:00
Vincent Hanquez
85575fae41
Merge pull request #204 from ocheron/ecdh-bench
FFDH and ECDH benchmarks
2017-12-10 15:54:16 +00:00
Vincent Hanquez
a61db59a22 bump version again 2017-12-06 11:44:44 +00:00
Vincent Hanquez
76e92e6d29 force latest memory 2017-12-01 09:14:07 +00:00
Vincent Hanquez
f861a52b1b remove dependency on foundation and moving to basement 2017-11-30 12:08:08 +00:00
Ömer Sinan Ağacan
d7aeb5f545 withDev: Close the FD on exception 2017-11-30 10:30:29 +03:00
Olivier Chéron
4d25832bcf Benchmark FFDH with 5 standard TLS groups
Uses short exponents explained in RFC 7919 to better stand comparison
with ECDH.
2017-11-27 20:43:08 +01:00
Olivier Chéron
ee50734b39 Benchmark ECDH with 5 curves 2017-11-27 20:43:08 +01:00
Olivier Chéron
3aaa89d52e Add missing NFData instances 2017-11-27 20:43:08 +01:00
Olivier Chéron
2a60551e34 Use criterion 'env' function 2017-11-27 20:43:08 +01:00
Luke Taylor
5e354f9bfc Use "2b" version prefix in bcrypt hashes
Makes docs and code consistent - the code now generates hashes
with the "2b" prefix instead of "2a". Shouldn't make any difference
in practice since previously generated hashes should still validate.
2017-11-27 15:19:23 +00:00
Vincent Hanquez
2293c69f87
Merge pull request #200 from NicolasDP/master
add instance of MonadFailure to CryptoFailable
2017-11-25 15:25:21 +00:00
Olivier Chéron
8567bacc2e Add pointNegate to class EllipticCurveArith 2017-11-20 19:28:17 +01:00
Olivier Chéron
8d7e0d236c Add P256.pointNegate 2017-11-20 19:28:17 +01:00
Olivier Chéron
e8f1bc08c8 Decrease iterations of ECC tests 2017-11-20 19:28:17 +01:00
Olivier Chéron
b8b59be5a5 Normalize result of ECC.pointNegate 2017-11-20 19:28:17 +01:00
Olivier Chéron
4f7d742461 Export and test ECC.pointNegate 2017-11-20 19:28:16 +01:00
Olivier Chéron
c55dd4d27f Add Curve_Ed25519 2017-11-20 19:28:16 +01:00
Olivier Chéron
6b3bf37eea Use only fixed-window implementation 2017-11-20 19:28:16 +01:00
Olivier Chéron
d497040ddd Avoid direct indexed access in precomputed table 2017-11-20 19:28:16 +01:00
Olivier Chéron
123e22ec08 Ed25519 scalar multiplication with 4-bit fixed window 2017-11-20 19:28:16 +01:00
Olivier Chéron
5778909761 Add Ed25519.pointsMulVarTime 2017-11-20 19:28:16 +01:00
Olivier Chéron
416fc649e1 Test Ed25519 arithmetic primitives 2017-11-20 19:28:16 +01:00
Olivier Chéron
35f1d20b79 Ed25519 scalar add & multiply 2017-11-20 19:28:15 +01:00
Olivier Chéron
7d61abff03 Ed25519 point negation 2017-11-20 19:28:15 +01:00
Olivier Chéron
9ea718f55e Arithmetic primitives over curve Ed25519 2017-11-20 19:28:15 +01:00
Olivier Chéron
fcf1ff55fb Reorder C sources
ed25519 uses sha512 code and must come later when using GHCi
dynamic linker on macOS.
2017-11-19 20:52:32 +01:00
Vincent Hanquez
896382dfbc
Merge pull request #201 from chris-martin/pr/caps
Various documentation copy editing
2017-11-19 16:04:40 +00:00
Vincent Hanquez
c26b331c8e
Merge pull request #199 from ocheron/proxy-backend
Use Proxy for openBackend
2017-11-19 16:00:41 +00:00
Vincent Hanquez
b3f6786d08
Merge pull request #195 from haskell-crypto/blake2-update-context-size
Blake2 update context size
2017-11-19 15:59:20 +00:00
Chris Martin
f77994a729 Various documentation copy editing 2017-11-18 14:27:44 -05:00
Nicolas Di Prima
393d5804b7 add instance of MonadFailure to CryptoFailable 2017-11-16 20:16:29 +00:00
Olivier Chéron
4723dc0b39 Use Proxy in openBackend
Replaces 'undefined' and fixes #198.
2017-10-23 20:39:00 +02:00
Olivier Chéron
4ef50d8092 Bump dependencies to base >= 4.6
This is needed for GHC.TypeLits.
2017-10-14 11:32:46 +02:00
Vincent Hanquez
84e96d2fa3 Update context size for Blake2bp and Blake2sp
Also fix Blake2bp to not use blake2sp functions
2017-10-02 21:05:30 +01:00
Vincent Hanquez
74f1c1872b [BLAKE2] update context size on the haskell to the latest code 2017-10-02 20:44:51 +01:00
Vincent Hanquez
ba39c9c18d Merge pull request #190 from haskell-crypto/travis-update
update .travis
2017-09-22 23:29:03 +09:00
Vincent Hanquez
69c194d0fc cleanup 2017-09-18 14:42:00 +01:00
Vincent Hanquez
36575c7a45 update .travis 2017-09-18 13:16:53 +01:00
Vincent Hanquez
2ecbd5c052 Merge pull request #189 from ocheron/cast5-wordarray
CAST5 block cipher
2017-09-18 21:09:49 +09:00
Vincent Hanquez
110ad7b510 Merge pull request #188 from ocheron/hash-tutorial
More content for Crypto.Tutorial
2017-09-18 20:54:40 +09:00
Vincent Hanquez
23e9947d15 Merge pull request #187 from ocheron/decaf-update
Fix link error with OpenBSD
2017-09-18 20:53:53 +09:00
Vincent Hanquez
57fc438c83 typo in documentation 2017-09-18 10:32:21 +01:00
Vincent Hanquez
c8569d871a Fix the old blurb about versioning since it confuses some people.
Reflect what's already been in place for more than a year now regarding
versioning and API stability
2017-09-18 10:29:09 +01:00
Olivier Chéron
cdc1a1aa17 Fix link error with OpenBSD and strip --strip-unneeded
Resolves #186
2017-09-17 18:15:00 +02:00
Olivier Chéron
72c3fa0f6a Update decaf to upstream commit '807a7e6'
* Don't use vector arithmetic in generic arch_32

* fix comments add/subtract
2017-09-17 11:45:26 +02:00
Olivier Chéron
bb2363eea7 Add CAST5 aka CAST-128
Haskell translation of RFC 2144.
2017-09-17 11:28:56 +02:00
Olivier Chéron
c6c715f465 Add note about Digest implementing ByteArrayAccess 2017-08-22 20:39:29 +02:00
Olivier Chéron
007f69c557 Add Crypto.Hash examples to tutorial 2017-08-22 20:39:27 +02:00
Olivier Chéron
80ed642f85 Add introduction to tutorial 2017-08-22 20:39:24 +02:00
Vincent Hanquez
06dc3de5c4 Merge pull request #184 from domenkozar/pthread-gold
Link against pthread on Linux to support gold linker
2017-08-09 09:29:06 +01:00
Domen Kožar
e7c6dcd107
Link against pthread on Linux
Since we're using pthread_join and pthread_create,
to make the gold linker happy on linux we need to explicitly
link against pthread library.
2017-08-02 11:23:01 +02:00
Vincent Hanquez
1992594f82 bump version to 0.24 2017-07-08 08:15:36 +01:00
Vincent Hanquez
2a78dec2ea add CHANGELOG 2017-07-08 08:07:16 +01:00
Vincent Hanquez
9d43c332de fix digest size for nat-typed blake2 2017-07-08 07:58:09 +01:00
Vincent Hanquez
ccc3930072 Merge pull request #182 from haskell-crypto/hash-type-nat
Add HashBlockSize & HashDigestSize & HashInternalContextSize type family
2017-07-07 21:45:22 +01:00
Vincent Hanquez
d13ce585ab add further unrolling of Div8 to match Mod8 2017-07-07 21:44:29 +01:00
Vincent Hanquez
b18ec653b8 rename bitLen -> bitlen. GHC 8.2 is stricted about name of type variables 2017-07-07 19:26:59 +01:00
Vincent Hanquez
b8a8e47b29 Merge pull request #181 from haskell-crypto/remove-76
remove GHC 7.6 from supported list
2017-07-07 19:24:01 +01:00
Vincent Hanquez
23ba060c73 Merge pull request #180 from haskell-crypto/chacha-drg-expose
Expose properly things to create ChaChaDRG
2017-07-07 19:23:46 +01:00
Vincent Hanquez
0dc0f30b86 Add HashBlockSize & HashDigestSize & HashInternalContextSize type family for all Hash algorithms
supercedes PR #158
2017-07-07 18:28:06 +01:00
Vincent Hanquez
fe2fb33acb remove 7.6 from supported list 2017-07-07 18:10:00 +01:00
Vincent Hanquez
664a37c16d [ChaCha] only required byteArrayAccess and add a way to convert from binary 2017-07-07 17:32:09 +01:00
Vincent Hanquez
f559c7bd9d [ChaCha] only need ByteArrayAccess for initialization 2017-07-07 17:31:30 +01:00
Vincent Hanquez
cb293eb6db Merge pull request #175 from jrtc27/unaligned-access
Fix many cases of unaligned accesses
2017-07-07 16:52:17 +01:00
Vincent Hanquez
35c8174dcc Merge pull request #179 from ocheron/ec-point-validation
Validate result of P256.pointFromBinary and EllipticCurveDH.ecdh
2017-07-07 16:38:51 +01:00
Olivier Chéron
5c4458d626 Test ECC functions ecdh and ecdhRaw 2017-07-05 22:24:22 +02:00
Olivier Chéron
9b56689885 Check that ECDH and ECIES result is not point-at-infinity
This guards against invalid public keys when curves have a cofactor.

Fixes #178
2017-07-05 22:24:22 +02:00
Olivier Chéron
aec6af5de4 Add note about P256 encoding of point-at-infinity 2017-07-05 22:24:22 +02:00
Olivier Chéron
adc192ac17 Add constAllZero 2017-07-05 22:24:22 +02:00
Olivier Chéron
8e274f8e60 Validate output point when calling P256.pointFromBinary
Function unsafePointFromBinary is added when validation is not needed.
2017-07-05 22:24:22 +02:00
Olivier Chéron
099f3405cb Add ECC tests to Other-modules 2017-07-02 18:41:44 +02:00
Vincent Hanquez
88c2bc9b7a Update README.md 2017-06-26 14:58:55 +01:00
Fraser Tweedale
f6c1f21e59 clarify padding requirements for PKCS15 encrypt/decrypt
The types do not say whether it is necessary to apply pad/unpad to
the input/output of the PKCS15 encrypt/decrypt functions.  Add
comments to clarify that it is not necessary to manually pad/unpad
the message.
2017-06-26 15:30:01 +02:00
James Clarke
2b43be4d84 Fix many cases of unaligned accesses 2017-06-25 18:10:55 +01:00
Olivier Chéron
bc72179d89 Merge pull request #174 from vorlonofportland/master
Actually process unaligned data through trampoline buffer
2017-06-24 09:07:21 +02:00
Steve Langasek
7f0f5bd3fa Actually process unaligned data through trampoline buffer
Follow-on to commit ba10930, which implemented a trampoline buffer but then
used the unaligned input character array instead.  This commit /actually/
fixes #108, having been tested on an affected architecture :)
2017-06-23 21:46:43 -07:00
Olivier Chéron
c80df7ffc3 Merge pull request #173 from remove-blake2-sse-flag 2017-06-22 21:26:48 +02:00
Olivier Chéron
bf0a476187 Update decaf to upstream commit 'b29565f'
Fix assertion on x448(0)
2017-06-19 21:15:03 +02:00
John Galt
1cb7bdfc5f Remove support_blake2_sse flag in favor of support_sse 2017-06-19 08:57:26 -04:00
Vincent Hanquez
1bcfa2e087 Merge pull request #167 from ocheron/eddsa-minimal
Improve Curve448 and add Ed448
2017-06-19 13:49:07 +01:00
Vincent Hanquez
8c39200e00 Merge pull request #172 from trofi/master
fix build failure with -f-support_deepseq disabled
2017-06-19 13:28:26 +01:00
Sergei Trofimovich
d911a34258 fix build failure with -f-support_deepseq disabled
How to reproduce:

```
$ cabal configure -f-support_deepseq
Resolving dependencies...
Configuring cryptonite-0.23...

$ cabal build
Building cryptonite-0.23...
Preprocessing library cryptonite-0.23...
[114 of 120] Compiling Crypto.PubKey.RSA.Types ( Crypto/PubKey/RSA/Types.hs, dist/build/Crypto/PubKey/RSA/Types

Crypto/PubKey/RSA/Types.hs:48:30: error:
    • No instance for (NFData Integer) arising from a use of ‘rnf’
    • In the first argument of ‘seq’, namely ‘rnf n’
      In the expression: rnf n `seq` rnf e `seq` sz `seq` ()
      In an equation for ‘rnf’:
          rnf (PublicKey sz n e) = rnf n `seq` rnf e `seq` sz `seq` ()
```

The fix is to inctoruce 'NFData Integer' instance to `Crypto/Internal/DeepSeq`.

Closes: https://github.com/haskell-crypto/cryptonite/issues/171
Signed-off-by: Sergei Trofimovich <slyfox@gentoo.org>
2017-06-19 10:37:23 +01:00
Vincent Hanquez
588c61406e Merge pull request #168 from ocheron/decode-p256
Validate P256 point when decoding
2017-06-18 07:43:52 +01:00
Olivier Chéron
b0d207c77b Test point encoding/decoding with Crypto.ECC 2017-06-10 14:33:37 +02:00
Olivier Chéron
e71d9b135c Derive Show,Data,Typeable when defining curve singletons 2017-06-10 14:26:59 +02:00
Olivier Chéron
5c2988716e Validate P256 point when decoding
Fixes #165.
2017-06-10 14:26:59 +02:00
Olivier Chéron
a879845434 Add note about the optional all-zero test
This is actually a lie: the condition is tested in both curve
implementations but not returned by the Haskell API.  Will be a reminder to
add this in the future.  A function 'allocRetAndFreeze' could be useful.
2017-06-04 19:25:19 +02:00
Olivier Chéron
8d51bce071 Reorder C sources based on symbol dependencies
GHCi dynamic loader processes modules in order and expects to resolve
symbols at each intermediate step.
2017-06-04 19:25:19 +02:00
Olivier Chéron
8ecde60853 Compilation warnings on Windows 2017-06-04 19:25:19 +02:00
Olivier Chéron
8be9856402 Compilation warnings on OpenBSD
Replaces unnecessary aligned(32) with aligned(16) instead.
2017-06-04 19:25:19 +02:00
Olivier Chéron
75e3bd555e Add Show instances for EdDSA secret keys
Other algorithms define Show instances for their secrets.
Here ScrubbedBytes will obfuscate the content anyway.

Will be useful for X509.PrivKey, which requires a Show instance.
2017-06-04 19:25:19 +02:00
Olivier Chéron
3c89f0d0b7 Simplify decaf build with Cabal
Keeping only one finite field, header 'f_field.h' can be included
from Cabal standard 'include-dirs'.
2017-06-04 19:25:19 +02:00
Olivier Chéron
961dd63eaf Remove decaf code related to SHAKE
Use cryptonite code instead.
2017-06-04 19:25:19 +02:00
Olivier Chéron
4392ef57b8 More EdDSA vectors from RFC 8032 2017-06-04 19:25:19 +02:00
Olivier Chéron
6805ddd4f7 Add support for Ed448
This replaces the Diffie-Hellman API that was previously exported.
2017-06-04 19:25:19 +02:00
Olivier Chéron
6fb412e2af Use decaf_x448_derive_public_key 2017-06-04 19:25:19 +02:00
Olivier Chéron
6b4621b14f Remove previous X448 implementation
This ensures it is not necessary anymore.
2017-06-04 19:25:19 +02:00
Olivier Chéron
23b359d842 Switch Haskell APIs to decaf implementation
Module 'Curve448' now use decaf.
2017-06-04 19:25:19 +02:00
Olivier Chéron
efcae3ac11 Added generation tools
This generates all decaf files from the original repo.
2017-06-04 19:25:19 +02:00
Olivier Chéron
b3d9156846 Added code from decaf library
In sync with upstream commit '0a6e968'.
2017-06-04 19:25:19 +02:00
Olivier Chéron
7472caf838 Test Curve25519.toPublic 2017-06-02 19:37:25 +02:00
Olivier Chéron
ac7eaac523 Simplify Ed25519.generateSecretKey 2017-06-02 19:37:25 +02:00
Olivier Chéron
51b36f77b8 Test for Ed25519 signature verification 2017-06-02 19:37:25 +02:00
Olivier Chéron
b3b2e86b53 Merge pull request #164 from ocheron/iv-arith
Fix ivAdd overflow behaviour
2017-06-01 21:04:55 +02:00
Olivier Chéron
edd5d94bd4 Make ivAdd more constant-time
All IV bytes are processed even if accumulator is zero.
2017-05-31 23:31:29 +02:00
Olivier Chéron
07592ab237 Fix ivAdd overflow behaviour 2017-05-26 09:59:54 +02:00
Olivier Chéron
8fb59dfc19 Test IV arithmetic
With emphasis on ivAdd overflow behaviour.
2017-05-26 09:59:54 +02:00
Olivier Chéron
c6caba88ed Merge pull request #159 from wangbj/patch-1
Allow sign/verify digest directly
2017-05-26 09:52:53 +02:00
Baojun Wang
a8902fe119 remove redundant condition test on `hashLen /= B.length mHash` 2017-05-18 21:00:14 -07:00
Olivier Chéron
a32489ce32 Merge pull request #162 from 3noch/patch-1
Fix docs for Argon variants
2017-05-18 20:40:34 +02:00
Elliot Cameron
8971458e06 Fix docs for Argon variants 2017-05-17 17:11:00 -04:00
Baojun Wang
4270f00277 Use `Digest hash` to represent message digest 2017-05-16 10:54:31 -07:00
Baojun Wang
f9a0bc3c53 Allow sign/verify digest directly
currently sign/verify works on message directly, it would be nice if PSS could sign/verify digest directly. This is useful for:

  1) for some signing server it only has a digest (without message)
  2) message could be very large, for cases when client need request a singing server to sign, it may make more sense for the client to compute digest, then ask server to (PSS) sign the digest
  3) openSSL pkeyutl (PSS) sign operation signs with digest only, not the message, it would be nice to work with openSSL more easily 

*openSSL command line:
```shell
openssl pkeyutl -pkeyopt rsa_padding_mode:pss -pkeyopt rsa_pss_saltlen:-1  -pkeyopt digest:sha256 -sign -inkey "pri.key" -in hmac.bin > sig.bin
openssl pkeyutl -pkeyopt rsa_padding_mode:pss -pkeyopt rsa_pss_saltlen:-1  -pkeyopt digest:sha256 -verify -inkey "pri.key" -in hmac.bin -sigfile sig.bin
```
2017-05-15 19:42:19 -07:00
Olivier Chéron
554f0fc701 Restore Haddock comment in tutorial module
Need to use ordinary comments instead of nested comments
because LANGUAGE pragmas were removed otherwise.

Also adds a table of contents.  We may have other examples
in the future.
2017-05-05 07:21:52 +02:00
Vincent Hanquez
8a9bd75dc7 Merge pull request #157 from ixmatus/parnell/adding-ed25519-seckey-generator
ed25519: Adding generateSecretKey and a unit test
2017-05-03 04:32:48 +01:00
Parnell Springmeyer
94d67ad86d
ed25519: Adding generateSecretKey and a unit test 2017-05-02 16:18:26 -05:00
Vincent Hanquez
f26c02278f bump version to 0.23 2017-04-25 17:21:14 +01:00
Vincent Hanquez
274c422be2 update CHANGELOG 2017-04-25 17:19:31 +01:00
Vincent Hanquez
737959dc76 Merge pull request #156 from haskell-crypto/hash-update
Hash update
2017-04-25 17:15:44 +01:00
Vincent Hanquez
468d8fe582 require memory at least 0.14.5 2017-04-25 16:06:49 +01:00
Vincent Hanquez
67dd8ed7fc [Hash] change Digest to use a foundation UArray that have configurable pinnable memory setting 2017-04-25 14:23:13 +01:00
Vincent Hanquez
a9fd1f079d [Hash] update part of Crypto.Hash.IO to ScopeTypeVariable 2017-04-25 14:22:20 +01:00
Vincent Hanquez
53bd6c13b7 Add missing extension 2017-04-25 14:21:53 +01:00
Vincent Hanquez
ba1dfdf66d [Hash] stylistic improvement using ScopedTypeVariables
remove the inner function with magic argument in favor of direct
call pinning some types with signature
2017-04-25 14:16:11 +01:00
Olivier Chéron
30bb81a307 Merge pull request #155 from dimitri-xyz/master
Fix issue #154: `generateBetween` excludes upper bound if lower bound is 1
2017-04-23 08:50:14 +02:00
Dimitri DeFigueiredo
4aec5fc98e Fix issue #154 2017-04-21 13:51:52 -06:00
Vincent Hanquez
4f988181c7 Merge pull request #150 from SamProtas/twofish
Twofish
2017-04-12 07:47:19 +01:00
Olivier Chéron
a64f0b2e1c Merge pull request #152 from kazu-yamamoto/fix-p256
using pointSize in withTempPoint to fix #151.
2017-04-11 19:54:50 +02:00
Kazu Yamamoto
697fe61f9b using pointSize in withTempPoint to fix #151. 2017-04-11 20:32:57 +09:00
Sam Protas
04b4c945c0 Add import to fix backwards compatibility 2017-04-10 00:57:49 -04:00
Sam Protas
67e9a0d187 Merge pull request #1 from SamProtas/twofish-256
Twofish 192 and 256 bit key support
2017-04-10 00:36:24 -04:00
Sam Protas
762d818ec0 Twofish 192 and 256 bit key support 2017-04-10 00:33:54 -04:00
Olivier Chéron
79aa6fb957 Merge pull request #149 from ocheron/hash-bench
Hash benchmarks
2017-04-09 17:27:13 +02:00
Olivier Chéron
112d2fbb15 Decrease Argon2 maximum output length
Fixes #148.
2017-04-09 17:18:26 +02:00
Sam Protas
b658c8a99b Cleanup and performance 2017-04-04 19:29:40 -04:00
Sam Protas
b1a9c7c047 Performance improvements 2017-04-02 19:36:58 -04:00
Sam Protas
7eedbaa112 Initial implementaiton with passing tests 2017-04-02 18:34:10 -04:00
Olivier Chéron
d65fc88477 Benchmark for hash algorithms
A first step in the direction of #144.
2017-03-29 11:38:32 +02:00
Olivier Chéron
762f2d9032 Consolidate cryptonite benchmark code
Enables `cabal bench' or `stack bench' to run benchmarks
that depend only on cryptonite.
2017-03-29 11:38:32 +02:00
Vincent Hanquez
2d25b27042 Merge pull request #145 from tdietert/tutorial
Tutorial Improvement
2017-03-26 09:27:58 +01:00
tdietert
f639ac9f0d
Update tutorial based on suggestions 2017-03-26 00:47:02 +00:00
tdietert
fd75eac415 Fix Crypto.Tutorial module name 2017-03-19 00:37:36 +00:00
tdietert
ec49ea659e Move language pragmas inside haddocks 2017-03-19 00:02:07 +00:00
tdietert
c76217f75d Added more comprehensive tutorial 2017-03-18 23:57:24 +00:00
Vincent Hanquez
666eb4e58e Merge pull request #140 from NicolasDP/master
Blake2: add modern interface using Nat
2017-03-18 14:12:02 +00:00
Nicolas DI PRIMA
8b6bd1ed5e check for at least one byte and at most 256 or 512 (blake2s or blake2b) 2017-03-13 18:53:07 +00:00
Nicolas DI PRIMA
f0286281fb add new constraints 2017-03-13 18:52:24 +00:00
Nicolas DI PRIMA
653e67d221 add tests for the new digest sizes 2017-03-13 00:25:04 +00:00
Nicolas DI PRIMA
c0c33c5254 Use Nat for the Blake2's digest sizes 2017-03-13 00:24:17 +00:00
Nicolas DI PRIMA
cd552ae5f6 move Nat specific to Cryptonite's insternal module 2017-03-13 00:22:53 +00:00
Olivier Chéron
f9b593520f Fixed test suite when base < 4.7
ExistentialQuantification is needed for HashAlg.
2017-02-26 16:27:55 +01:00
Vincent Hanquez
6440a7ebab bump version to 0.22 2017-02-24 18:11:31 +00:00
Vincent Hanquez
9b0e2538f1 reinstall ghc 7.6 2017-02-24 16:47:14 +00:00
Vincent Hanquez
e12d68a018 missing item 2017-02-24 16:18:02 +00:00
Vincent Hanquez
9e06b38953 prepare CHANGELOG 2017-02-24 16:14:48 +00:00
Vincent Hanquez
c45bb19aba update QA to latest haskell-src-exts 2017-02-24 16:05:12 +00:00
Vincent Hanquez
ef27301a8f update description 2017-02-24 16:04:24 +00:00
Vincent Hanquez
baa2b6d9c9 extra-doc-files requires cabal 1.18 2017-02-24 16:04:14 +00:00
Vincent Hanquez
c9aeb98744 add 7.6 back as advisory 2017-02-24 15:57:52 +00:00
Vincent Hanquez
75e98e9699 Merge pull request #138 from haskell-crypto/blake2-update
Blake2 & Argon2
2017-02-24 15:31:38 +00:00
Vincent Hanquez
c4936ce6d8 remove Typeable 2017-02-24 14:03:33 +00:00
Vincent Hanquez
d898c41136 Merge pull request #139 from cielavenir/merge_keccak
Merged Keccak code into SHA3
2017-02-24 13:43:02 +00:00
Vincent Hanquez
253bf0cb8b Argon2: add working hash function
* Cleanup argon c files:
  * Remove encoded format and base64 encoder
  * Remove verification code
  * Remove all variants based simple caller
* Add basic hashing function
* Add a simple KAT test
* Define more things at the haskell level
2017-02-24 13:37:40 +00:00
cielavenir
ad40f40818 Merged Keccak code into SHA3 2017-02-24 21:04:46 +09:00
Vincent Hanquez
a5b6fdc36e add Argon2 C sources 2017-02-20 11:46:17 +00:00
Vincent Hanquez
b4db1dab33 remove executable attribute on sha3.[ch] 2017-02-20 11:34:48 +00:00
Vincent Hanquez
956904e3c2 hide X448 base point export 2017-02-20 11:27:19 +00:00
Vincent Hanquez
139b204c6b add latest version of blake2 and reference to it 2017-02-20 07:32:50 +00:00
Vincent Hanquez
2932df9e24 Merge branch 'master' of https://github.com/haskell-crypto/cryptonite 2017-02-20 07:06:14 +00:00
Vincent Hanquez
bcada64bf5 fix compilation on openbsd and introduce more alignment compat fucntions 2017-02-20 07:05:44 +00:00
Vincent Hanquez
c673bfdc62 Merge pull request #134 from haskell-crypto/hash-shake
SHAKE128 / SHAKE256 support
2017-02-20 06:12:01 +00:00
Vincent Hanquez
26237c5c6d remove spurious header modification 2017-02-19 17:17:49 +00:00
Vincent Hanquez
10d72c8779 remove unneeded extensions 2017-02-19 17:17:35 +00:00
Vincent Hanquez
7286cb832a Add better constants for trampoline buffer 2017-02-14 23:01:18 +00:00
Vincent Hanquez
c342d28436 Compatibility with older version 2017-02-14 23:01:18 +00:00
Vincent Hanquez
343b7593b5 add Constraint for divisibility 2017-02-14 23:01:18 +00:00
Vincent Hanquez
4b5ee83396 revert base back to >= 4.3 2017-02-14 23:01:18 +00:00
Vincent Hanquez
eb661e653e add Typeable for SHAKE 2017-02-14 23:01:18 +00:00
Olivier Chéron
d8ed5ce9f1 Add SHAKE128 and SHAKE256 as HashAlgorithm instances
Generalizes SHA-3 code for SHAKE support and uses GHC type-level literals
to keep the output length variable.
2017-02-14 23:01:18 +00:00
Vincent Hanquez
df85d00891 Merge pull request #136 from haskell-crypto/more-blake2
add some missing blake2 modes
2017-02-14 16:50:35 +00:00
Vincent Hanquez
7378fe3f45 add some missing blake2 modes 2017-02-14 16:26:44 +00:00
Vincent Hanquez
3eff8021eb Merge branch 'master' of https://github.com/haskell-crypto/cryptonite 2017-02-14 16:13:05 +00:00
Vincent Hanquez
ad07371c71 [travis] update to 8.0.2 and enable tests 2017-02-14 16:12:44 +00:00
Vincent Hanquez
25671da789 Merge pull request #135 from haskell-crypto/data
Add Data also to Hash algorithms
2017-02-14 13:26:16 +00:00
307 changed files with 24600 additions and 20990 deletions

29
.appveyor.yml Normal file
View File

@ -0,0 +1,29 @@
# ~*~ auto-generated by haskell-ci with config : 4fdddfa41dd039e198b8d125a70471f7dd140fa01001d99126af56fb31429ece ~*~
version: "{build}"
clone_folder: C:\project
build: off
cache:
- "C:\\SR -> .appveyor.yml"
environment:
global:
STACK_ROOT: "C:\\SR"
matrix:
- { BUILD: "ghc-8.6", STACKCMD: "stack --no-terminal build --install-ghc --coverage --test --bench --no-run-benchmarks --haddock --no-haddock-deps", STACKCFG: "{ resolver: lts-14.27, packages: [ '.' ], extra-deps: [], flags: {} }", STACKURL: "https://www.stackage.org/stack/windows-x86_64" }
- { BUILD: "ghc-8.8", STACKCMD: "stack --no-terminal build --install-ghc --coverage --test --bench --no-run-benchmarks --haddock --no-haddock-deps", STACKCFG: "{ resolver: lts-15.1, packages: [ '.' ], extra-deps: [], flags: {} }", STACKURL: "https://www.stackage.org/stack/windows-x86_64" }
matrix:
fast_finish: true
install:
- set PATH=C:\Program Files\Git\mingw64\bin;%PATH%
- curl -ostack.zip -L %STACKURL%
- 7z x stack.zip stack.exe
- refreshenv
test_script:
- echo %STACKCFG% > stack.yaml
- stack setup > nul
- echo "" | %STACKCMD%

1
.envrc Normal file
View File

@ -0,0 +1 @@
use flake

1
.gitignore vendored
View File

@ -12,3 +12,4 @@ benchs/Hash
*.sublime-workspace *.sublime-workspace
.cabal-sandbox/ .cabal-sandbox/
cabal.sandbox.config cabal.sandbox.config
stack.yaml.lock

26
.haskell-ci Normal file
View File

@ -0,0 +1,26 @@
# compiler supported and their equivalent LTS
compiler: ghc-8.0 lts-9.21
compiler: ghc-8.2 lts-11.22
compiler: ghc-8.4 lts-12.26
compiler: ghc-8.6 lts-14.27
compiler: ghc-8.8 lts-15.1
# options
# option: alias x=y z=v
option: gaugedeps extradep=gauge-0.2.1
option: basementmin extradep=basement-0.0.8 extradep=memory-0.14.18
# builds
build: ghc-8.0 basementmin gaugedeps
build: ghc-8.2 basementmin
build: ghc-8.4
build: ghc-8.6 os=linux,osx,windows
build: ghc-8.8 os=linux,windows
# packages
package: '.'
# extra builds
hlint: allowed-failure
weeder: allowed-failure
coverall: false

3
.hlint.yaml Normal file
View File

@ -0,0 +1,3 @@
- arguments: [ --cpp-define=ARCH_X86_64
]
- ignore: { name: Use camelCase }

View File

@ -1,50 +1,83 @@
sudo: false # ~*~ auto-generated by haskell-ci with config : 4fdddfa41dd039e198b8d125a70471f7dd140fa01001d99126af56fb31429ece ~*~
env: # Caching so the next build will be fast too.
- CABALVER=1.18 GHCVER=7.8.4 cache:
- CABALVER=1.22 GHCVER=7.10.3 directories:
- CABALVER=1.24 GHCVER=8.0.1 RUNTEST=0 - $HOME/.ghc
- CABALVER=head GHCVER=head RUNTEST=0 - $HOME/.stack
- $HOME/.local
matrix: language: generic
os: linux
jobs:
include:
- { env: BUILD=stack RESOLVER=ghc-8.0, addons: { apt: { packages: [ libgmp-dev ] } } }
- { env: BUILD=stack RESOLVER=ghc-8.2, addons: { apt: { packages: [ libgmp-dev ] } } }
- { env: BUILD=stack RESOLVER=ghc-8.4, addons: { apt: { packages: [ libgmp-dev ] } } }
- { env: BUILD=stack RESOLVER=ghc-8.6, addons: { apt: { packages: [ libgmp-dev ] } } }
- { env: BUILD=stack RESOLVER=ghc-8.6, addons: { apt: { packages: [ libgmp-dev ] } }, os: osx }
- { env: BUILD=stack RESOLVER=ghc-8.8, addons: { apt: { packages: [ libgmp-dev ] } } }
- { env: BUILD=hlint }
- { env: BUILD=weeder, addons: { apt: { packages: [ libgmp-dev ] } } }
allow_failures: allow_failures:
- env: CABALVER=head GHCVER=head RUNTEST=0 - { env: BUILD=hlint }
- { env: BUILD=weeder, addons: { apt: { packages: [ libgmp-dev ] } } }
addons:
apt:
sources:
- hvr-ghc
packages:
- cabal-install-1.18
- cabal-install-1.20
- cabal-install-1.22
- cabal-install-1.24
- cabal-install-head
- ghc-7.8.4
- ghc-7.10.3
- ghc-8.0.1
- ghc-head
before_install:
- export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
install: install:
- cabal --version - export PATH=$HOME/.local/bin:$HOME/.cabal/bin:$PATH
- echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]" - mkdir -p ~/.local/bin
- travis_retry cabal update - |
- if [ "${RUNTEST}" != "0" ]; then cabal install --only-dependencies --enable-tests; else cabal install --only-dependencies; fi case "$BUILD" in
stack|weeder)
if [ `uname` = "Darwin" ]
then
travis_retry curl -L https://www.stackage.org/stack/osx-x86_64 | tar xz --strip-components=1 --include '*/stack' -C ~/.local/bin
else
travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'
fi
;;
cabal)
;;
esac
script: script:
- if [ "${RUNTEST}" != "0" ]; then cabal configure --enable-tests -v2; else cabal configure -v2; fi - |
- cabal build set -ex
- if [ "${RUNTEST}" != "0" ]; then cabal test; fi; if [ "x${RUNTEST}" = "xfalse" ]; then exit 0; fi
- cabal check case "$BUILD" in
- cabal sdist stack)
- export SRC_TGZ=$(cabal info . | awk '{print $2 ".tar.gz";exit}') ; # create the build stack.yaml
cd dist/; case "$RESOLVER" in
if [ -f "$SRC_TGZ" ]; then ghc-8.0)
cabal install --force-reinstalls "$SRC_TGZ"; echo "{ resolver: lts-9.21, packages: [ '.' ], extra-deps: [ basement-0.0.8, memory-0.14.18, gauge-0.2.1 ], flags: {} }" > stack.yaml
else stack --no-terminal build --install-ghc --coverage --test --bench --no-run-benchmarks --haddock --no-haddock-deps
echo "expected '$SRC_TGZ' not found"; ;;
exit 1; ghc-8.2)
fi echo "{ resolver: lts-11.22, packages: [ '.' ], extra-deps: [ basement-0.0.8, memory-0.14.18 ], flags: {} }" > stack.yaml
stack --no-terminal build --install-ghc --coverage --test --bench --no-run-benchmarks --haddock --no-haddock-deps
;;
ghc-8.4)
echo "{ resolver: lts-12.26, packages: [ '.' ], extra-deps: [], flags: {} }" > stack.yaml
stack --no-terminal build --install-ghc --coverage --test --bench --no-run-benchmarks --haddock --no-haddock-deps
;;
ghc-8.6)
echo "{ resolver: lts-14.27, packages: [ '.' ], extra-deps: [], flags: {} }" > stack.yaml
stack --no-terminal build --install-ghc --coverage --test --bench --no-run-benchmarks --haddock --no-haddock-deps
;;
ghc-8.8)
echo "{ resolver: lts-15.1, packages: [ '.' ], extra-deps: [], flags: {} }" > stack.yaml
stack --no-terminal build --install-ghc --coverage --test --bench --no-run-benchmarks --haddock --no-haddock-deps
;;
esac
;;
hlint)
curl -sL https://raw.github.com/ndmitchell/hlint/master/misc/travis.sh | sh -s . --cpp-define=__GLASGOW_HASKELL__=800 --cpp-define=x86_64_HOST_ARCH=1 --cpp-define=mingw32_HOST_OS=1
;;
weeder)
stack --no-terminal build --install-ghc --ghc-options="-ddump-to-file -ddump-hi" --test --no-run-tests --bench --no-run-benchmarks
curl -sL https://raw.github.com/ndmitchell/weeder/master/misc/travis.sh | sh -s .
;;
esac
set +ex

View File

@ -1,3 +1,115 @@
## 0.30
* Fix some C symbol blake2b prefix to be cryptonite_ prefix (fix mixing with other C library)
* add hmac-lazy
* Fix compilation with GHC 9.2
* Drop support for GHC8.0, GHC8.2, GHC8.4, GHC8.6
## 0.29
* advance compilation with gmp breakage due to change upstream
* Add native EdDSA support
## 0.28
* Add hash constant time capability
* Prevent possible overflow during hashing by hashing in 4GB chunks
## 0.27
* Optimise AES GCM and CCM
* Optimise P256R1 implementation
* Various AES-NI building improvements
* Add better ECDSA support
* Add XSalsa derive
* Implement square roots for ECC binary curve
* Various tests and benchmarks
## 0.26
* Add Rabin cryptosystem (and variants)
* Add bcrypt_pbkdf key derivation function
* Optimize Blowfish implementation
* Add KMAC (Keccak Message Authentication Code)
* Add ECDSA sign/verify digest APIs
* Hash algorithms with runtime output length
* Update blake2 to latest upstream version
* RSA-PSS with arbitrary key size
* SHAKE with output length not divisible by 8
* Add Read and Data instances for Digest type
* Improve P256 scalar primitives
* Fix hash truncation bug in DSA
* Fix cost parsing for bcrypt
* Fix ECC failures on arm64
* Correction to PKCS#1 v1.5 padding
* Use powModSecInteger when available
* Drop GHC 7.8 and GHC 7.10 support, refer to pkg-guidelines
* Optimise GCM mode
* Add little endian serialization of integer
## 0.25
* Improve digest binary conversion efficiency
* AES CCM support
* Add MonadFailure instance for CryptoFailable
* Various misc improvements on documentation
* Edwards25519 lowlevel arithmetic support
* P256 add point negation
* Improvement in ECC (benchmark, better normalization)
* Blake2 improvements to context size
* Use gauge instead of criterion
* Use haskell-ci for CI scripts
* Improve Digest memory representation to be 2 less Ints and one less boxing
moving from `UArray` to `Block`
## 0.24
* Ed25519: generateSecret & Documentation updates
* Repair tutorial
* RSA: Allow signing digest directly
* IV add: fix overflow behavior
* P256: validate point when decoding
* Compilation fix with deepseq disabled
* Improve Curve448 and use decaf for Ed448
* Compilation flag blake2 sse merged in sse support
* Process unaligned data better in hashes and AES, on architecture needing alignment
* Drop support for ghc 7.6
* Add ability to create random generator Seed from binary data and
loosen constraint on ChaChaDRG seed from ByteArray to ByteArrayAccess.
* Add 3 associated types with the HashAlgorithm class, to get
access to the constant for BlockSize, DigestSize and ContextSize at the type level.
the related function that this replaced will be deprecated in later release, and
eventually removed.
API CHANGES:
* Improve ECDH safety to return failure for bad inputs (e.g. public point in small order subgroup).
To go back to previous behavior you can replace `ecdh` by `ecdhRaw`. It's recommended to
use `ecdh` and handle the error appropriately.
* Users defining their own HashAlgorithm needs to define the
HashBlockSize, HashDigest, HashInternalContextSize associated types
## 0.23
* Digest memory usage improvement by using unpinned memory
* Fix generateBetween to generate within the right bounds
* Add pure Twofish implementation
* Fix memory allocation in P256 when using a temp point
* Consolidate hash benchmark code
* Add Nat-length Blake2 support (GHC > 8.0)
* Update tutorial
## 0.22
* Add Argon2 (Password Hashing Competition winner) hash function
* Update blake2 to latest upstream version
* Add extra blake2 hashing size
* Add faster PBKDF2 functions for SHA1/SHA256/SHA512
* Add SHAKE128 and SHAKE256
* Cleanup prime generation, and add tests
* Add Time-based One Time Password (TOTP) and HMAC-based One Time Password (HOTP)
* Rename Ed448 module name to Curve448, old module name still valid for now
## 0.21 ## 0.21
* Drop automated tests with GHC 7.0, GHC 7.4, GHC 7.6. support dropped, but probably still working. * Drop automated tests with GHC 7.0, GHC 7.4, GHC 7.6. support dropped, but probably still working.

View File

@ -14,12 +14,11 @@ module Crypto.Cipher.AES
import Crypto.Error import Crypto.Error
import Crypto.Cipher.Types import Crypto.Cipher.Types
import Crypto.Cipher.Utils
import Crypto.Cipher.Types.Block import Crypto.Cipher.Types.Block
import Crypto.Cipher.AES.Primitive import Crypto.Cipher.AES.Primitive
import Crypto.Internal.Imports import Crypto.Internal.Imports
import Data.ByteArray as BA
-- | AES with 128 bit key -- | AES with 128 bit key
newtype AES128 = AES128 AES newtype AES128 = AES128 AES
deriving (NFData) deriving (NFData)
@ -47,15 +46,6 @@ instance Cipher AES256 where
cipherKeySize _ = KeySizeFixed 32 cipherKeySize _ = KeySizeFixed 32
cipherInit k = AES256 <$> (initAES =<< validateKeySize (undefined :: AES256) k) cipherInit k = AES256 <$> (initAES =<< validateKeySize (undefined :: AES256) k)
validateKeySize :: (ByteArrayAccess key, Cipher cipher) => cipher -> key -> CryptoFailable key
validateKeySize c k = if validKeyLength
then CryptoPassed k
else CryptoFailed CryptoError_KeySizeInvalid
where keyLength = BA.length k
validKeyLength = case cipherKeySize c of
KeySizeRange low high -> keyLength >= low && keyLength <= high
KeySizeEnum lengths -> keyLength `elem` lengths
KeySizeFixed s -> keyLength == s
#define INSTANCE_BLOCKCIPHER(CSTR) \ #define INSTANCE_BLOCKCIPHER(CSTR) \
instance BlockCipher CSTR where \ instance BlockCipher CSTR where \
@ -67,6 +57,7 @@ instance BlockCipher CSTR where \
; ctrCombine (CSTR aes) (IV iv) = encryptCTR aes (IV iv) \ ; ctrCombine (CSTR aes) (IV iv) = encryptCTR aes (IV iv) \
; aeadInit AEAD_GCM (CSTR aes) iv = CryptoPassed $ AEAD (gcmMode aes) (gcmInit aes iv) \ ; aeadInit AEAD_GCM (CSTR aes) iv = CryptoPassed $ AEAD (gcmMode aes) (gcmInit aes iv) \
; aeadInit AEAD_OCB (CSTR aes) iv = CryptoPassed $ AEAD (ocbMode aes) (ocbInit aes iv) \ ; aeadInit AEAD_OCB (CSTR aes) iv = CryptoPassed $ AEAD (ocbMode aes) (ocbInit aes iv) \
; aeadInit (AEAD_CCM n m l) (CSTR aes) iv = AEAD (ccmMode aes) <$> ccmInit aes iv n m l \
; aeadInit _ _ _ = CryptoFailed CryptoError_AEADModeNotSupported \ ; aeadInit _ _ _ = CryptoFailed CryptoError_AEADModeNotSupported \
}; \ }; \
instance BlockCipher128 CSTR where \ instance BlockCipher128 CSTR where \

View File

@ -11,39 +11,46 @@
-- --
module Crypto.Cipher.AES.Primitive module Crypto.Cipher.AES.Primitive
( (
-- * block cipher data types -- * Block cipher data types
AES AES
-- * Authenticated encryption block cipher types -- * Authenticated encryption block cipher types
, AESGCM , AESGCM
, AESOCB , AESOCB
-- * creation -- * Creation
, initAES , initAES
-- * misc -- * Miscellanea
, genCTR , genCTR
, genCounter , genCounter
-- * encryption -- * Encryption
, encryptECB , encryptECB
, encryptCBC , encryptCBC
, encryptCTR , encryptCTR
, encryptXTS , encryptXTS
-- * decryption -- * Decryption
, decryptECB , decryptECB
, decryptCBC , decryptCBC
, decryptCTR , decryptCTR
, decryptXTS , decryptXTS
-- * incremental GCM -- * CTR with 32-bit wrapping
, combineC32
-- * Incremental GCM
, gcmMode , gcmMode
, gcmInit , gcmInit
-- * incremental OCB -- * Incremental OCB
, ocbMode , ocbMode
, ocbInit , ocbInit
-- * CCM
, ccmMode
, ccmInit
) where ) where
import Data.Word import Data.Word
@ -73,6 +80,7 @@ instance BlockCipher AES where
ctrCombine = encryptCTR ctrCombine = encryptCTR
aeadInit AEAD_GCM aes iv = CryptoPassed $ AEAD (gcmMode aes) (gcmInit aes iv) aeadInit AEAD_GCM aes iv = CryptoPassed $ AEAD (gcmMode aes) (gcmInit aes iv)
aeadInit AEAD_OCB aes iv = CryptoPassed $ AEAD (ocbMode aes) (ocbInit aes iv) aeadInit AEAD_OCB aes iv = CryptoPassed $ AEAD (ocbMode aes) (ocbInit aes iv)
aeadInit (AEAD_CCM n m l) aes iv = AEAD (ccmMode aes) <$> ccmInit aes iv n m l
aeadInit _ _ _ = CryptoFailed CryptoError_AEADModeNotSupported aeadInit _ _ _ = CryptoFailed CryptoError_AEADModeNotSupported
instance BlockCipher128 AES where instance BlockCipher128 AES where
xtsEncrypt = encryptXTS xtsEncrypt = encryptXTS
@ -96,6 +104,15 @@ ocbMode aes = AEADModeImpl
, aeadImplFinalize = ocbFinish aes , aeadImplFinalize = ocbFinish aes
} }
-- | Create an AES AEAD implementation for CCM
ccmMode :: AES -> AEADModeImpl AESCCM
ccmMode aes = AEADModeImpl
{ aeadImplAppendHeader = ccmAppendAAD aes
, aeadImplEncrypt = ccmEncrypt aes
, aeadImplDecrypt = ccmDecrypt aes
, aeadImplFinalize = ccmFinish aes
}
-- | AES Context (pre-processed key) -- | AES Context (pre-processed key)
newtype AES = AES ScrubbedBytes newtype AES = AES ScrubbedBytes
@ -109,12 +126,19 @@ newtype AESGCM = AESGCM ScrubbedBytes
newtype AESOCB = AESOCB ScrubbedBytes newtype AESOCB = AESOCB ScrubbedBytes
deriving (NFData) deriving (NFData)
-- | AESCCM State
newtype AESCCM = AESCCM ScrubbedBytes
deriving (NFData)
sizeGCM :: Int sizeGCM :: Int
sizeGCM = 80 sizeGCM = 320
sizeOCB :: Int sizeOCB :: Int
sizeOCB = 160 sizeOCB = 160
sizeCCM :: Int
sizeCCM = 80
keyToPtr :: AES -> (Ptr AES -> IO a) -> IO a keyToPtr :: AES -> (Ptr AES -> IO a) -> IO a
keyToPtr (AES b) f = withByteArray b (f . castPtr) keyToPtr (AES b) f = withByteArray b (f . castPtr)
@ -152,6 +176,13 @@ withOCBKeyAndCopySt aes (AESOCB gcmSt) f =
a <- withByteArray newSt $ \gcmStPtr -> f (castPtr gcmStPtr) aesPtr a <- withByteArray newSt $ \gcmStPtr -> f (castPtr gcmStPtr) aesPtr
return (a, AESOCB newSt) return (a, AESOCB newSt)
withCCMKeyAndCopySt :: AES -> AESCCM -> (Ptr AESCCM -> Ptr AES -> IO a) -> IO (a, AESCCM)
withCCMKeyAndCopySt aes (AESCCM ccmSt) f =
keyToPtr aes $ \aesPtr -> do
newSt <- B.copy ccmSt (\_ -> return ())
a <- withByteArray newSt $ \ccmStPtr -> f (castPtr ccmStPtr) aesPtr
return (a, AESCCM newSt)
-- | Initialize a new context with a key -- | Initialize a new context with a key
-- --
-- Key needs to be of length 16, 24 or 32 bytes. Any other values will return failure -- Key needs to be of length 16, 24 or 32 bytes. Any other values will return failure
@ -289,6 +320,21 @@ decryptXTS :: ByteArray ba
-> ba -- ^ output decrypted -> ba -- ^ output decrypted
decryptXTS = doXTS c_aes_decrypt_xts decryptXTS = doXTS c_aes_decrypt_xts
-- | encrypt/decrypt using Counter mode (32-bit wrapping used in AES-GCM-SIV)
{-# NOINLINE combineC32 #-}
combineC32 :: ByteArray ba
=> AES -- ^ AES Context
-> IV AES -- ^ initial vector of AES block size (usually representing a 128 bit integer)
-> ba -- ^ plaintext input
-> ba -- ^ ciphertext output
combineC32 ctx iv input
| len <= 0 = B.empty
| B.length iv /= 16 = error $ "AES error: IV length must be block size (16). Its length is: " ++ show (B.length iv)
| otherwise = B.allocAndFreeze len doEncrypt
where doEncrypt o = withKeyAndIV ctx iv $ \k v -> withByteArray input $ \i ->
c_aes_encrypt_c32 (castPtr o) k v i (fromIntegral len)
len = B.length input
{-# INLINE doECB #-} {-# INLINE doECB #-}
doECB :: ByteArray ba doECB :: ByteArray ba
=> (Ptr b -> Ptr AES -> CString -> CUInt -> IO ()) => (Ptr b -> Ptr AES -> CString -> CUInt -> IO ())
@ -447,6 +493,78 @@ ocbFinish ctx ocb taglen = AuthTag $ B.take taglen computeTag
where computeTag = B.allocAndFreeze 16 $ \t -> where computeTag = B.allocAndFreeze 16 $ \t ->
withOCBKeyAndCopySt ctx ocb (c_aes_ocb_finish (castPtr t)) >> return () withOCBKeyAndCopySt ctx ocb (c_aes_ocb_finish (castPtr t)) >> return ()
ccmGetM :: CCM_M -> Int
ccmGetL :: CCM_L -> Int
ccmGetM m = case m of
CCM_M4 -> 4
CCM_M6 -> 6
CCM_M8 -> 8
CCM_M10 -> 10
CCM_M12 -> 12
CCM_M14 -> 14
CCM_M16 -> 16
ccmGetL l = case l of
CCM_L2 -> 2
CCM_L3 -> 3
CCM_L4 -> 4
-- | initialize a ccm context
{-# NOINLINE ccmInit #-}
ccmInit :: ByteArrayAccess iv => AES -> iv -> Int -> CCM_M -> CCM_L -> CryptoFailable AESCCM
ccmInit ctx iv n m l
| 15 - li /= B.length iv = CryptoFailed CryptoError_IvSizeInvalid
| otherwise = unsafeDoIO $ do
sm <- B.alloc sizeCCM $ \ccmStPtr ->
withKeyAndIV ctx iv $ \k v ->
c_aes_ccm_init (castPtr ccmStPtr) k v (fromIntegral $ B.length iv) (fromIntegral n) (fromIntegral mi) (fromIntegral li)
return $ CryptoPassed (AESCCM sm)
where
mi = ccmGetM m
li = ccmGetL l
-- | append data which is only going to be authenticated to the CCM context.
--
-- needs to happen after initialization and before appending encryption/decryption data.
{-# NOINLINE ccmAppendAAD #-}
ccmAppendAAD :: ByteArrayAccess aad => AES -> AESCCM -> aad -> AESCCM
ccmAppendAAD ctx ccm input = unsafeDoIO $ snd <$> withCCMKeyAndCopySt ctx ccm doAppend
where doAppend ccmStPtr aesPtr =
withByteArray input $ \i -> c_aes_ccm_aad ccmStPtr aesPtr i (fromIntegral $ B.length input)
-- | append data to encrypt and append to the CCM context
--
-- the bytearray needs to be a multiple of AES block size, unless it's the last call to this function.
-- needs to happen after AAD appending, or after initialization if no AAD data.
{-# NOINLINE ccmEncrypt #-}
ccmEncrypt :: ByteArray ba => AES -> AESCCM -> ba -> (ba, AESCCM)
ccmEncrypt ctx ccm input = unsafeDoIO $ withCCMKeyAndCopySt ctx ccm cbcmacAndIv
where len = B.length input
cbcmacAndIv ccmStPtr aesPtr =
B.alloc len $ \o ->
withByteArray input $ \i ->
c_aes_ccm_encrypt (castPtr o) ccmStPtr aesPtr i (fromIntegral len)
-- | append data to decrypt and append to the CCM context
--
-- the bytearray needs to be a multiple of AES block size, unless it's the last call to this function.
-- needs to happen after AAD appending, or after initialization if no AAD data.
{-# NOINLINE ccmDecrypt #-}
ccmDecrypt :: ByteArray ba => AES -> AESCCM -> ba -> (ba, AESCCM)
ccmDecrypt ctx ccm input = unsafeDoIO $ withCCMKeyAndCopySt ctx ccm cbcmacAndIv
where len = B.length input
cbcmacAndIv ccmStPtr aesPtr =
B.alloc len $ \o ->
withByteArray input $ \i ->
c_aes_ccm_decrypt (castPtr o) ccmStPtr aesPtr i (fromIntegral len)
-- | Generate the Tag from CCM context
{-# NOINLINE ccmFinish #-}
ccmFinish :: AES -> AESCCM -> Int -> AuthTag
ccmFinish ctx ccm taglen = AuthTag $ B.take taglen computeTag
where computeTag = B.allocAndFreeze 16 $ \t ->
withCCMKeyAndCopySt ctx ccm (c_aes_ccm_finish (castPtr t)) >> return ()
------------------------------------------------------------------------ ------------------------------------------------------------------------
foreign import ccall "cryptonite_aes.h cryptonite_aes_initkey" foreign import ccall "cryptonite_aes.h cryptonite_aes_initkey"
c_aes_init :: Ptr AES -> CString -> CUInt -> IO () c_aes_init :: Ptr AES -> CString -> CUInt -> IO ()
@ -478,6 +596,9 @@ foreign import ccall unsafe "cryptonite_aes.h cryptonite_aes_gen_ctr_cont"
foreign import ccall "cryptonite_aes.h cryptonite_aes_encrypt_ctr" foreign import ccall "cryptonite_aes.h cryptonite_aes_encrypt_ctr"
c_aes_encrypt_ctr :: CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO () c_aes_encrypt_ctr :: CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()
foreign import ccall "cryptonite_aes.h cryptonite_aes_encrypt_c32"
c_aes_encrypt_c32 :: CString -> Ptr AES -> Ptr Word8 -> CString -> CUInt -> IO ()
foreign import ccall "cryptonite_aes.h cryptonite_aes_gcm_init" foreign import ccall "cryptonite_aes.h cryptonite_aes_gcm_init"
c_aes_gcm_init :: Ptr AESGCM -> Ptr AES -> Ptr Word8 -> CUInt -> IO () c_aes_gcm_init :: Ptr AESGCM -> Ptr AES -> Ptr Word8 -> CUInt -> IO ()
@ -508,3 +629,17 @@ foreign import ccall "cryptonite_aes.h cryptonite_aes_ocb_decrypt"
foreign import ccall "cryptonite_aes.h cryptonite_aes_ocb_finish" foreign import ccall "cryptonite_aes.h cryptonite_aes_ocb_finish"
c_aes_ocb_finish :: CString -> Ptr AESOCB -> Ptr AES -> IO () c_aes_ocb_finish :: CString -> Ptr AESOCB -> Ptr AES -> IO ()
foreign import ccall "cryptonite_aes.h cryptonite_aes_ccm_init"
c_aes_ccm_init :: Ptr AESCCM -> Ptr AES -> Ptr Word8 -> CUInt -> CUInt -> CInt -> CInt -> IO ()
foreign import ccall "cryptonite_aes.h cryptonite_aes_ccm_aad"
c_aes_ccm_aad :: Ptr AESCCM -> Ptr AES -> CString -> CUInt -> IO ()
foreign import ccall "cryptonite_aes.h cryptonite_aes_ccm_encrypt"
c_aes_ccm_encrypt :: CString -> Ptr AESCCM -> Ptr AES -> CString -> CUInt -> IO ()
foreign import ccall "cryptonite_aes.h cryptonite_aes_ccm_decrypt"
c_aes_ccm_decrypt :: CString -> Ptr AESCCM -> Ptr AES -> CString -> CUInt -> IO ()
foreign import ccall "cryptonite_aes.h cryptonite_aes_ccm_finish"
c_aes_ccm_finish :: CString -> Ptr AESCCM -> Ptr AES -> IO ()

193
Crypto/Cipher/AESGCMSIV.hs Normal file
View File

@ -0,0 +1,193 @@
-- |
-- Module : Crypto.Cipher.AESGCMSIV
-- License : BSD-style
-- Maintainer : Olivier Chéron <olivier.cheron@gmail.com>
-- Stability : experimental
-- Portability : unknown
--
-- Implementation of AES-GCM-SIV, an AEAD scheme with nonce misuse resistance
-- defined in <https://tools.ietf.org/html/rfc8452 RFC 8452>.
--
-- To achieve the nonce misuse-resistance property, encryption requires two
-- passes on the plaintext, hence no streaming API is provided. This AEAD
-- operates on complete inputs held in memory. For simplicity, the
-- implementation of decryption uses a similar pattern, with performance
-- penalty compared to an implementation which is able to merge both passes.
--
-- The specification allows inputs up to 2^36 bytes but this implementation
-- requires AAD and plaintext/ciphertext to be both smaller than 2^32 bytes.
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Crypto.Cipher.AESGCMSIV
( Nonce
, nonce
, generateNonce
, encrypt
, decrypt
) where
import Data.Bits
import Data.Word
import Foreign.C.Types
import Foreign.C.String
import Foreign.Ptr (Ptr, plusPtr)
import Foreign.Storable (peekElemOff, poke, pokeElemOff)
import Data.ByteArray
import qualified Data.ByteArray as B
import Data.Memory.Endian (toLE)
import Data.Memory.PtrMethods (memXor)
import Crypto.Cipher.AES.Primitive
import Crypto.Cipher.Types
import Crypto.Error
import Crypto.Internal.Compat (unsafeDoIO)
import Crypto.Random
-- 12-byte nonces
-- | Nonce value for AES-GCM-SIV, always 12 bytes.
newtype Nonce = Nonce Bytes deriving (Show, Eq, ByteArrayAccess)
-- | Nonce smart constructor. Accepts only 12-byte inputs.
nonce :: ByteArrayAccess iv => iv -> CryptoFailable Nonce
nonce iv
| B.length iv == 12 = CryptoPassed (Nonce $ B.convert iv)
| otherwise = CryptoFailed CryptoError_IvSizeInvalid
-- | Generate a random nonce for use with AES-GCM-SIV.
generateNonce :: MonadRandom m => m Nonce
generateNonce = Nonce <$> getRandomBytes 12
-- POLYVAL (mutable context)
newtype Polyval = Polyval Bytes
polyvalInit :: ScrubbedBytes -> IO Polyval
polyvalInit h = Polyval <$> doInit
where doInit = B.alloc 272 $ \pctx -> B.withByteArray h $ \ph ->
c_aes_polyval_init pctx ph
polyvalUpdate :: ByteArrayAccess ba => Polyval -> ba -> IO ()
polyvalUpdate (Polyval ctx) bs = B.withByteArray ctx $ \pctx ->
B.withByteArray bs $ \pbs -> c_aes_polyval_update pctx pbs sz
where sz = fromIntegral (B.length bs)
polyvalFinalize :: Polyval -> IO ScrubbedBytes
polyvalFinalize (Polyval ctx) = B.alloc 16 $ \dst ->
B.withByteArray ctx $ \pctx -> c_aes_polyval_finalize pctx dst
foreign import ccall unsafe "cryptonite_aes.h cryptonite_aes_polyval_init"
c_aes_polyval_init :: Ptr Polyval -> CString -> IO ()
foreign import ccall "cryptonite_aes.h cryptonite_aes_polyval_update"
c_aes_polyval_update :: Ptr Polyval -> CString -> CUInt -> IO ()
foreign import ccall unsafe "cryptonite_aes.h cryptonite_aes_polyval_finalize"
c_aes_polyval_finalize :: Ptr Polyval -> CString -> IO ()
-- Key Generation
le32iv :: Word32 -> Nonce -> Bytes
le32iv n (Nonce iv) = B.allocAndFreeze 16 $ \ptr -> do
poke ptr (toLE n)
copyByteArrayToPtr iv (ptr `plusPtr` 4)
deriveKeys :: BlockCipher128 aes => aes -> Nonce -> (ScrubbedBytes, AES)
deriveKeys aes iv =
case cipherKeySize aes of
KeySizeFixed sz | sz `mod` 8 == 0 ->
let mak = buildKey [0 .. 1]
key = buildKey [2 .. fromIntegral (sz `div` 8) + 1]
mek = throwCryptoError (cipherInit key)
in (mak, mek)
_ -> error "AESGCMSIV: invalid cipher"
where
idx n = ecbEncrypt aes (le32iv n iv) `takeView` 8
buildKey = B.concat . map idx
-- Encryption and decryption
lengthInvalid :: ByteArrayAccess ba => ba -> Bool
lengthInvalid bs
| finiteBitSize len > 32 = len >= 1 `unsafeShiftL` 32
| otherwise = False
where len = B.length bs
-- | AEAD encryption with the specified key and nonce. The key must be given
-- as an initialized 'Crypto.Cipher.AES.AES128' or 'Crypto.Cipher.AES.AES256'
-- cipher.
--
-- Lengths of additional data and plaintext must be less than 2^32 bytes,
-- otherwise an exception is thrown.
encrypt :: (BlockCipher128 aes, ByteArrayAccess aad, ByteArray ba)
=> aes -> Nonce -> aad -> ba -> (AuthTag, ba)
encrypt aes iv aad plaintext
| lengthInvalid aad = error "AESGCMSIV: aad is too large"
| lengthInvalid plaintext = error "AESGCMSIV: plaintext is too large"
| otherwise = (AuthTag tag, ciphertext)
where
(mak, mek) = deriveKeys aes iv
ss = getSs mak aad plaintext
tag = buildTag mek ss iv
ciphertext = combineC32 mek (transformTag tag) plaintext
-- | AEAD decryption with the specified key and nonce. The key must be given
-- as an initialized 'Crypto.Cipher.AES.AES128' or 'Crypto.Cipher.AES.AES256'
-- cipher.
--
-- Lengths of additional data and ciphertext must be less than 2^32 bytes,
-- otherwise an exception is thrown.
decrypt :: (BlockCipher128 aes, ByteArrayAccess aad, ByteArray ba)
=> aes -> Nonce -> aad -> ba -> AuthTag -> Maybe ba
decrypt aes iv aad ciphertext (AuthTag tag)
| lengthInvalid aad = error "AESGCMSIV: aad is too large"
| lengthInvalid ciphertext = error "AESGCMSIV: ciphertext is too large"
| tag `constEq` buildTag mek ss iv = Just plaintext
| otherwise = Nothing
where
(mak, mek) = deriveKeys aes iv
ss = getSs mak aad plaintext
plaintext = combineC32 mek (transformTag tag) ciphertext
-- Calculate S_s = POLYVAL(mak, X_1, X_2, ...).
getSs :: (ByteArrayAccess aad, ByteArrayAccess ba)
=> ScrubbedBytes -> aad -> ba -> ScrubbedBytes
getSs mak aad plaintext = unsafeDoIO $ do
ctx <- polyvalInit mak
polyvalUpdate ctx aad
polyvalUpdate ctx plaintext
polyvalUpdate ctx (lb :: Bytes) -- the "length block"
polyvalFinalize ctx
where
lb = B.allocAndFreeze 16 $ \ptr -> do
pokeElemOff ptr 0 (toLE64 $ B.length aad)
pokeElemOff ptr 1 (toLE64 $ B.length plaintext)
toLE64 x = toLE (fromIntegral x * 8 :: Word64)
-- XOR the first 12 bytes of S_s with the nonce and clear the most significant
-- bit of the last byte.
tagInput :: ScrubbedBytes -> Nonce -> Bytes
tagInput ss (Nonce iv) =
B.copyAndFreeze ss $ \ptr ->
B.withByteArray iv $ \ivPtr -> do
memXor ptr ptr ivPtr 12
b <- peekElemOff ptr 15
pokeElemOff ptr 15 (b .&. (0x7f :: Word8))
-- Encrypt the result with AES using the message-encryption key to produce the
-- tag.
buildTag :: BlockCipher128 aes => aes -> ScrubbedBytes -> Nonce -> Bytes
buildTag mek ss iv = ecbEncrypt mek (tagInput ss iv)
-- The initial counter block is the tag with the most significant bit of the
-- last byte set to one.
transformTag :: Bytes -> IV AES
transformTag tag = toIV $ B.copyAndFreeze tag $ \ptr ->
peekElemOff ptr 15 >>= pokeElemOff ptr 15 . (.|. (0x80 :: Word8))
where toIV bs = let Just iv = makeIV (bs :: Bytes) in iv

View File

@ -5,15 +5,33 @@
-- Portability : Good -- Portability : Good
{-# LANGUAGE MagicHash #-} {-# LANGUAGE MagicHash #-}
module Crypto.Cipher.Blowfish.Box module Crypto.Cipher.Blowfish.Box
( createKeySchedule ( KeySchedule(..)
, createKeySchedule
, copyKeySchedule
) where ) where
import Crypto.Internal.WordArray (mutableArray32FromAddrBE, MutableArray32) import Crypto.Internal.WordArray (MutableArray32,
mutableArray32FromAddrBE,
mutableArrayRead32,
mutableArrayWrite32)
newtype KeySchedule = KeySchedule MutableArray32
-- | Copy the state of one key schedule into the other.
-- The first parameter is the destination and the second the source.
copyKeySchedule :: KeySchedule -> KeySchedule -> IO ()
copyKeySchedule (KeySchedule dst) (KeySchedule src) = loop 0
where
loop 1042 = return ()
loop i = do
w32 <-mutableArrayRead32 src i
mutableArrayWrite32 dst i w32
loop (i + 1)
-- | Create a key schedule mutable array of the pbox followed by -- | Create a key schedule mutable array of the pbox followed by
-- all the sboxes. -- all the sboxes.
createKeySchedule :: IO MutableArray32 createKeySchedule :: IO KeySchedule
createKeySchedule = mutableArray32FromAddrBE 1042 "\ createKeySchedule = KeySchedule `fmap` mutableArray32FromAddrBE 1042 "\
\\x24\x3f\x6a\x88\x85\xa3\x08\xd3\x13\x19\x8a\x2e\x03\x70\x73\x44\ \\x24\x3f\x6a\x88\x85\xa3\x08\xd3\x13\x19\x8a\x2e\x03\x70\x73\x44\
\\xa4\x09\x38\x22\x29\x9f\x31\xd0\x08\x2e\xfa\x98\xec\x4e\x6c\x89\ \\xa4\x09\x38\x22\x29\x9f\x31\xd0\x08\x2e\xfa\x98\xec\x4e\x6c\x89\
\\x45\x28\x21\xe6\x38\xd0\x13\x77\xbe\x54\x66\xcf\x34\xe9\x0c\x6c\ \\x45\x28\x21\xe6\x38\xd0\x13\x77\xbe\x54\x66\xcf\x34\xe9\x0c\x6c\

View File

@ -5,197 +5,254 @@
-- Portability : Good -- Portability : Good
-- Rewritten by Vincent Hanquez (c) 2015 -- Rewritten by Vincent Hanquez (c) 2015
-- Lars Petersen (c) 2018
-- --
-- Original code: -- Original code:
-- Crypto.Cipher.Blowfish.Primitive, copyright (c) 2012 Stijn van Drongelen -- Crypto.Cipher.Blowfish.Primitive, copyright (c) 2012 Stijn van Drongelen
-- based on: BlowfishAux.hs (C) 2002 HardCore SoftWare, Doug Hoyte -- based on: BlowfishAux.hs (C) 2002 HardCore SoftWare, Doug Hoyte
-- (as found in Crypto-4.2.4) -- (as found in Crypto-4.2.4)
{-# LANGUAGE BangPatterns #-}
module Crypto.Cipher.Blowfish.Primitive module Crypto.Cipher.Blowfish.Primitive
( Context ( Context
, initBlowfish , initBlowfish
, encrypt , encrypt
, decrypt , decrypt
, eksBlowfish , KeySchedule
, createKeySchedule
, freezeKeySchedule
, expandKey
, expandKeyWithSalt
, cipherBlockMutable
) where ) where
import Control.Monad (when) import Control.Monad (when)
import Data.Bits import Data.Bits
import Data.Memory.Endian import Data.Memory.Endian
import Data.Word import Data.Word
import Crypto.Cipher.Blowfish.Box
import Crypto.Error import Crypto.Error
import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess)
import qualified Crypto.Internal.ByteArray as B
import Crypto.Internal.Compat import Crypto.Internal.Compat
import Crypto.Internal.Imports import Crypto.Internal.Imports
import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, Bytes)
import qualified Crypto.Internal.ByteArray as B
import Crypto.Internal.Words
import Crypto.Internal.WordArray import Crypto.Internal.WordArray
import Crypto.Cipher.Blowfish.Box
-- | variable keyed blowfish state newtype Context = Context Array32
data Context = BF (Int -> Word32) -- p
(Int -> Word32) -- sbox0
(Int -> Word32) -- sbox1
(Int -> Word32) -- sbox2
(Int -> Word32) -- sbox2
instance NFData Context where instance NFData Context where
rnf (BF p a b c d) = p `seq` a `seq` b `seq` c `seq` d `seq` () rnf a = a `seq` ()
-- | Encrypt blocks
--
-- Input need to be a multiple of 8 bytes
encrypt :: ByteArray ba => Context -> ba -> ba
encrypt = cipher
-- | Decrypt blocks
--
-- Input need to be a multiple of 8 bytes
decrypt :: ByteArray ba => Context -> ba -> ba
decrypt = cipher . decryptContext
decryptContext :: Context -> Context
decryptContext (BF p s0 s1 s2 s3) = BF (\i -> p (17-i)) s0 s1 s2 s3
cipher :: ByteArray ba => Context -> ba -> ba
cipher ctx b
| B.length b == 0 = B.empty
| B.length b `mod` 8 /= 0 = error "invalid data length"
| otherwise = B.mapAsWord64 (coreCrypto ctx) b
-- | Initialize a new Blowfish context from a key. -- | Initialize a new Blowfish context from a key.
-- --
-- key needs to be between 0 and 448 bits. -- key needs to be between 0 and 448 bits.
initBlowfish :: ByteArrayAccess key => key -> CryptoFailable Context initBlowfish :: ByteArrayAccess key => key -> CryptoFailable Context
initBlowfish key initBlowfish key
| len > (448 `div` 8) = CryptoFailed CryptoError_KeySizeInvalid | B.length key > (448 `div` 8) = CryptoFailed CryptoError_KeySizeInvalid
| otherwise = CryptoPassed $ makeKeySchedule key (Nothing :: Maybe (Bytes, Int)) | otherwise = CryptoPassed $ unsafeDoIO $ do
where len = B.length key ks <- createKeySchedule
expandKey ks key
freezeKeySchedule ks
-- | The BCrypt "expensive key schedule" version of blowfish. -- | Get an immutable Blowfish context by freezing a mutable key schedule.
freezeKeySchedule :: KeySchedule -> IO Context
freezeKeySchedule (KeySchedule ma) = Context `fmap` mutableArray32Freeze ma
expandKey :: (ByteArrayAccess key) => KeySchedule -> key -> IO ()
expandKey ks@(KeySchedule ma) key = do
when (B.length key > 0) $ iterKeyStream key 0 0 $ \i l r a0 a1 cont-> do
mutableArrayWriteXor32 ma i l
mutableArrayWriteXor32 ma (i + 1) r
when (i + 2 < 18) (cont a0 a1)
loop 0 0 0
where
loop i l r = do
n <- cipherBlockMutable ks (fromIntegral l `shiftL` 32 .|. fromIntegral r)
let nl = fromIntegral (n `shiftR` 32)
nr = fromIntegral (n .&. 0xffffffff)
mutableArrayWrite32 ma i nl
mutableArrayWrite32 ma (i + 1) nr
when (i < 18 + 1024) (loop (i + 2) nl nr)
expandKeyWithSalt :: (ByteArrayAccess key, ByteArrayAccess salt)
=> KeySchedule
-> key
-> salt
-> IO ()
expandKeyWithSalt ks key salt
| B.length salt == 16 = expandKeyWithSalt128 ks key (fromBE $ B.toW64BE salt 0) (fromBE $ B.toW64BE salt 8)
| otherwise = expandKeyWithSaltAny ks key salt
expandKeyWithSaltAny :: (ByteArrayAccess key, ByteArrayAccess salt)
=> KeySchedule -- ^ The key schedule
-> key -- ^ The key
-> salt -- ^ The salt
-> IO ()
expandKeyWithSaltAny ks@(KeySchedule ma) key salt = do
when (B.length key > 0) $ iterKeyStream key 0 0 $ \i l r a0 a1 cont-> do
mutableArrayWriteXor32 ma i l
mutableArrayWriteXor32 ma (i + 1) r
when (i + 2 < 18) (cont a0 a1)
-- Go through the entire key schedule overwriting the P-Array and S-Boxes
when (B.length salt > 0) $ iterKeyStream salt 0 0 $ \i l r a0 a1 cont-> do
let l' = xor l a0
let r' = xor r a1
n <- cipherBlockMutable ks (fromIntegral l' `shiftL` 32 .|. fromIntegral r')
let nl = fromIntegral (n `shiftR` 32)
nr = fromIntegral (n .&. 0xffffffff)
mutableArrayWrite32 ma i nl
mutableArrayWrite32 ma (i + 1) nr
when (i + 2 < 18 + 1024) (cont nl nr)
expandKeyWithSalt128 :: ByteArrayAccess ba
=> KeySchedule -- ^ The key schedule
-> ba -- ^ The key
-> Word64 -- ^ First word of the salt
-> Word64 -- ^ Second word of the salt
-> IO ()
expandKeyWithSalt128 ks@(KeySchedule ma) key salt1 salt2 = do
when (B.length key > 0) $ iterKeyStream key 0 0 $ \i l r a0 a1 cont-> do
mutableArrayWriteXor32 ma i l
mutableArrayWriteXor32 ma (i + 1) r
when (i + 2 < 18) (cont a0 a1)
-- Go through the entire key schedule overwriting the P-Array and S-Boxes
loop 0 salt1 salt1 salt2
where
loop i input slt1 slt2
| i == 1042 = return ()
| otherwise = do
n <- cipherBlockMutable ks input
let nl = fromIntegral (n `shiftR` 32)
nr = fromIntegral (n .&. 0xffffffff)
mutableArrayWrite32 ma i nl
mutableArrayWrite32 ma (i+1) nr
loop (i+2) (n `xor` slt2) slt2 slt1
-- | Encrypt blocks
-- --
-- Salt must be 128 bits -- Input need to be a multiple of 8 bytes
-- Cost must be between 4 and 31 inclusive encrypt :: ByteArray ba => Context -> ba -> ba
-- See <https://www.usenix.org/conference/1999-usenix-annual-technical-conference/future-adaptable-password-scheme> encrypt ctx ba
eksBlowfish :: (ByteArrayAccess salt, ByteArrayAccess password) => Int -> salt -> password -> Context | B.length ba == 0 = B.empty
eksBlowfish cost salt key | B.length ba `mod` 8 /= 0 = error "invalid data length"
| B.length salt /= 16 = error "bcrypt salt must be 16 bytes" | otherwise = B.mapAsWord64 (cipherBlock ctx False) ba
| otherwise = makeKeySchedule key (Just (salt, cost))
coreCrypto :: Context -> Word64 -> Word64 -- | Decrypt blocks
coreCrypto (BF p s0 s1 s2 s3) input = doRound input 0 --
where -- Input need to be a multiple of 8 bytes
-- transform the input over 16 rounds decrypt :: ByteArray ba => Context -> ba -> ba
decrypt ctx ba
| B.length ba == 0 = B.empty
| B.length ba `mod` 8 /= 0 = error "invalid data length"
| otherwise = B.mapAsWord64 (cipherBlock ctx True) ba
-- | Encrypt or decrypt a single block of 64 bits.
--
-- The inverse argument decides whether to encrypt or decrypt.
cipherBlock :: Context -> Bool -> Word64 -> Word64
cipherBlock (Context ar) inverse input = doRound input 0
where
-- | Transform the input over 16 rounds
doRound :: Word64 -> Int -> Word64 doRound :: Word64 -> Int -> Word64
doRound i roundIndex doRound !i roundIndex
| roundIndex == 16 = | roundIndex == 16 =
let final = (fromIntegral (p 16) `shiftL` 32) .|. fromIntegral (p 17) let final = (fromIntegral (p 16) `shiftL` 32) .|. fromIntegral (p 17)
in rotateL (i `xor` final) 32 in rotateL (i `xor` final) 32
| otherwise = | otherwise =
let newr = fromIntegral (i `shiftR` 32) `xor` (p roundIndex) let newr = fromIntegral (i `shiftR` 32) `xor` p roundIndex
newi = ((i `shiftL` 32) `xor` (f newr)) .|. (fromIntegral newr) newi = ((i `shiftL` 32) `xor` f newr) .|. fromIntegral newr
in doRound newi (roundIndex+1) in doRound newi (roundIndex+1)
-- | The Blowfish Feistel function F
f :: Word32 -> Word64 f :: Word32 -> Word64
f t = let a = s0 (fromIntegral $ (t `shiftR` 24) .&. 0xff) f t = let a = s0 (0xff .&. (t `shiftR` 24))
b = s1 (fromIntegral $ (t `shiftR` 16) .&. 0xff) b = s1 (0xff .&. (t `shiftR` 16))
c = s2 (fromIntegral $ (t `shiftR` 8) .&. 0xff) c = s2 (0xff .&. (t `shiftR` 8))
d = s3 (fromIntegral $ t .&. 0xff) d = s3 (0xff .&. t)
in fromIntegral (((a + b) `xor` c) + d) `shiftL` 32 in fromIntegral (((a + b) `xor` c) + d) `shiftL` 32
-- | S-Box arrays, each containing 256 32-bit words
-- The first 18 words contain the P-Array of subkeys
s0, s1, s2, s3 :: Word32 -> Word32
s0 i = arrayRead32 ar (fromIntegral i + 18)
s1 i = arrayRead32 ar (fromIntegral i + 274)
s2 i = arrayRead32 ar (fromIntegral i + 530)
s3 i = arrayRead32 ar (fromIntegral i + 786)
p :: Int -> Word32
p i | inverse = arrayRead32 ar (17 - i)
| otherwise = arrayRead32 ar i
-- | Create a key schedule for either plain Blowfish or the BCrypt "EKS" version -- | Blowfish encrypt a Word using the current state of the key schedule
-- For the expensive version, the salt and cost factor are supplied. Salt must be cipherBlockMutable :: KeySchedule -> Word64 -> IO Word64
-- a 128-bit byte array. cipherBlockMutable (KeySchedule ma) input = doRound input 0
-- where
-- The standard case is just a single key expansion with the salt set to zero. -- | Transform the input over 16 rounds
makeKeySchedule :: (ByteArrayAccess key, ByteArrayAccess salt) => key-> Maybe (salt, Int) -> Context doRound !i roundIndex
makeKeySchedule keyBytes saltCost = | roundIndex == 16 = do
let v = unsafeDoIO $ do pVal1 <- mutableArrayRead32 ma 16
mv <- createKeySchedule pVal2 <- mutableArrayRead32 ma 17
case saltCost of let final = (fromIntegral pVal1 `shiftL` 32) .|. fromIntegral pVal2
-- Standard blowfish return $ rotateL (i `xor` final) 32
Nothing -> expandKey mv 0 0 keyBytes | otherwise = do
-- The expensive case pVal <- mutableArrayRead32 ma roundIndex
Just (s, cost) -> do let newr = fromIntegral (i `shiftR` 32) `xor` pVal
let (salt1, salt2) = splitSalt s newr' <- f newr
expandKey mv salt1 salt2 keyBytes let newi = ((i `shiftL` 32) `xor` newr') .|. fromIntegral newr
forM_ [1..2^cost :: Int] $ \_ -> do doRound newi (roundIndex+1)
expandKey mv 0 0 keyBytes
expandKey mv 0 0 s
mutableArray32Freeze mv
in BF (\i -> arrayRead32 v i)
(\i -> arrayRead32 v (s0+i))
(\i -> arrayRead32 v (s1+i))
(\i -> arrayRead32 v (s2+i))
(\i -> arrayRead32 v (s3+i))
where
splitSalt s = (fromBE (B.toW64BE s 0), fromBE (B.toW64BE s 8))
-- Indices of the S-Box arrays, each containing 256 32-bit words -- | The Blowfish Feistel function F
-- The first 18 words contain the P-Array of subkeys f :: Word32 -> IO Word64
s0 = 18 f t = do
s1 = 274 a <- s0 (0xff .&. (t `shiftR` 24))
s2 = 530 b <- s1 (0xff .&. (t `shiftR` 16))
s3 = 786 c <- s2 (0xff .&. (t `shiftR` 8))
d <- s3 (0xff .&. t)
return (fromIntegral (((a + b) `xor` c) + d) `shiftL` 32)
expandKey :: ByteArrayAccess ba -- | S-Box arrays, each containing 256 32-bit words
=> MutableArray32 -- ^ The key schedule -- The first 18 words contain the P-Array of subkeys
-> Word64 -- ^ First word of the salt s0, s1, s2, s3 :: Word32 -> IO Word32
-> Word64 -- ^ Second word of the salt s0 i = mutableArrayRead32 ma (fromIntegral i + 18)
-> ba -- ^ The key s1 i = mutableArrayRead32 ma (fromIntegral i + 274)
-> IO () s2 i = mutableArrayRead32 ma (fromIntegral i + 530)
expandKey mv salt1 salt2 key = do s3 i = mutableArrayRead32 ma (fromIntegral i + 786)
when (len > 0) $ forM_ [0..17] $ \i -> do
let a = B.index key ((i * 4 + 0) `mod` len)
b = B.index key ((i * 4 + 1) `mod` len)
c = B.index key ((i * 4 + 2) `mod` len)
d = B.index key ((i * 4 + 3) `mod` len)
k = (fromIntegral a `shiftL` 24) .|.
(fromIntegral b `shiftL` 16) .|.
(fromIntegral c `shiftL` 8) .|.
(fromIntegral d)
mutableArrayWriteXor32 mv i k
prepare mv
return ()
where
len = B.length key
-- | Go through the entire key schedule overwriting the P-Array and S-Boxes iterKeyStream :: (ByteArrayAccess x)
prepare mctx = loop 0 salt1 salt1 salt2 => x
where loop i input slt1 slt2 -> Word32
| i == 1042 = return () -> Word32
| otherwise = do -> (Int -> Word32 -> Word32 -> Word32 -> Word32 -> (Word32 -> Word32 -> IO ()) -> IO ())
ninput <- coreCryptoMutable input -> IO ()
let (nl, nr) = w64to32 ninput iterKeyStream x a0 a1 g = f 0 0 a0 a1
mutableArrayWrite32 mctx i nl where
mutableArrayWrite32 mctx (i+1) nr len = B.length x
loop (i+2) (ninput `xor` slt2) slt2 slt1 -- Avoiding the modulo operation when interating over the ring
-- buffer is assumed to be more efficient here. All other
-- | Blowfish encrypt a Word using the current state of the key schedule -- implementations do this, too. The branch prediction shall prefer
coreCryptoMutable :: Word64 -> IO Word64 -- the branch with the increment.
coreCryptoMutable input = doRound input 0 n j = if j + 1 >= len then 0 else j + 1
where doRound i roundIndex f i j0 b0 b1 = g i l r b0 b1 (f (i + 2) j8)
| roundIndex == 16 = do where
pVal1 <- mutableArrayRead32 mctx 16 j1 = n j0
pVal2 <- mutableArrayRead32 mctx 17 j2 = n j1
let final = (fromIntegral pVal1 `shiftL` 32) .|. fromIntegral pVal2 j3 = n j2
return $ rotateL (i `xor` final) 32 j4 = n j3
| otherwise = do j5 = n j4
pVal <- mutableArrayRead32 mctx roundIndex j6 = n j5
let newr = fromIntegral (i `shiftR` 32) `xor` pVal j7 = n j6
newr' <- f newr j8 = n j7
let newi = ((i `shiftL` 32) `xor` newr') .|. (fromIntegral newr) x0 = fromIntegral (B.index x j0)
doRound newi (roundIndex+1) x1 = fromIntegral (B.index x j1)
x2 = fromIntegral (B.index x j2)
-- The Blowfish Feistel function F x3 = fromIntegral (B.index x j3)
f :: Word32 -> IO Word64 x4 = fromIntegral (B.index x j4)
f t = do a <- mutableArrayRead32 mctx (s0 + fromIntegral ((t `shiftR` 24) .&. 0xff)) x5 = fromIntegral (B.index x j5)
b <- mutableArrayRead32 mctx (s1 + fromIntegral ((t `shiftR` 16) .&. 0xff)) x6 = fromIntegral (B.index x j6)
c <- mutableArrayRead32 mctx (s2 + fromIntegral ((t `shiftR` 8) .&. 0xff)) x7 = fromIntegral (B.index x j7)
d <- mutableArrayRead32 mctx (s3 + fromIntegral (t .&. 0xff)) l = shiftL x0 24 .|. shiftL x1 16 .|. shiftL x2 8 .|. x3
return (fromIntegral (((a + b) `xor` c) + d) `shiftL` 32) r = shiftL x4 24 .|. shiftL x5 16 .|. shiftL x6 8 .|. x7
where s0 = 18 {-# INLINE iterKeyStream #-}
s1 = 274 -- Benchmarking shows that GHC considers this function too big to inline
s2 = 530 -- although forcing inlining causes an actual improvement.
s3 = 786 -- It is assumed that all function calls (especially the continuation)
-- collapse into a tight loop after inlining.

43
Crypto/Cipher/CAST5.hs Normal file
View File

@ -0,0 +1,43 @@
-- |
-- Module : Crypto.Cipher.CAST5
-- License : BSD-style
-- Maintainer : Olivier Chéron <olivier.cheron@gmail.com>
-- Stability : stable
-- Portability : good
--
module Crypto.Cipher.CAST5
( CAST5
) where
import Crypto.Error
import Crypto.Cipher.Types
import Crypto.Cipher.CAST5.Primitive
import Crypto.Internal.ByteArray (ByteArrayAccess)
import qualified Crypto.Internal.ByteArray as B
-- | CAST5 block cipher (also known as CAST-128). Key is between
-- 40 and 128 bits.
newtype CAST5 = CAST5 Key
instance Cipher CAST5 where
cipherName _ = "CAST5"
cipherKeySize _ = KeySizeRange 5 16
cipherInit = initCAST5
instance BlockCipher CAST5 where
blockSize _ = 8
ecbEncrypt (CAST5 k) = B.mapAsWord64 (encrypt k)
ecbDecrypt (CAST5 k) = B.mapAsWord64 (decrypt k)
initCAST5 :: ByteArrayAccess key => key -> CryptoFailable CAST5
initCAST5 bs
| len < 5 = CryptoFailed CryptoError_KeySizeInvalid
| len < 16 = CryptoPassed (CAST5 $ buildKey short padded)
| len == 16 = CryptoPassed (CAST5 $ buildKey False bs)
| otherwise = CryptoFailed CryptoError_KeySizeInvalid
where
len = B.length bs
short = len <= 10
padded :: B.Bytes
padded = B.convert bs `B.append` B.replicate (16 - len) 0

View File

@ -0,0 +1,573 @@
{-# LANGUAGE MagicHash #-}
-----------------------------------------------------------------------------
-- |
-- Module : Crypto.Cipher.CAST5.Primitive
-- License : BSD-style
--
-- Haskell implementation of the CAST-128 Encryption Algorithm
--
-----------------------------------------------------------------------------
module Crypto.Cipher.CAST5.Primitive
( encrypt
, decrypt
, Key()
, buildKey
) where
import Control.Monad (void, (>=>))
import Data.Bits
import Data.Memory.Endian
import Data.Word
import Crypto.Internal.ByteArray (ByteArrayAccess)
import qualified Crypto.Internal.ByteArray as B
import Crypto.Internal.WordArray
-- Data Types
data P = P {-# UNPACK #-} !Word32 -- left word
{-# UNPACK #-} !Word32 -- right word
data Q = Q {-# UNPACK #-} !Word32 {-# UNPACK #-} !Word32
{-# UNPACK #-} !Word32 {-# UNPACK #-} !Word32
-- | All subkeys for 12 or 16 rounds
data Key = K12 {-# UNPACK #-} !Array32 -- [ km1, kr1, km2, kr2, ..., km12, kr12 ]
| K16 {-# UNPACK #-} !Array32 -- [ km1, kr1, km2, kr2, ..., km16, kr16 ]
-- Big-endian Transformations
decomp64 :: Word64 -> P
decomp64 x = P (fromIntegral (x `shiftR` 32)) (fromIntegral x)
comp64 :: P -> Word64
comp64 (P l r) = (fromIntegral l `shiftL` 32) .|. fromIntegral r
decomp32 :: Word32 -> (Word8, Word8, Word8, Word8)
decomp32 x =
let a = fromIntegral (x `shiftR` 24)
b = fromIntegral (x `shiftR` 16)
c = fromIntegral (x `shiftR` 8)
d = fromIntegral x
in (a, b, c, d)
-- Encryption
-- | Encrypts a block using the specified key
encrypt :: Key -> Word64 -> Word64
encrypt k = comp64 . cast_enc k . decomp64
cast_enc :: Key -> P -> P
cast_enc (K12 a) (P l0 r0) = P r12 r11
where
r1 = type1 a 0 l0 r0
r2 = type2 a 2 r0 r1
r3 = type3 a 4 r1 r2
r4 = type1 a 6 r2 r3
r5 = type2 a 8 r3 r4
r6 = type3 a 10 r4 r5
r7 = type1 a 12 r5 r6
r8 = type2 a 14 r6 r7
r9 = type3 a 16 r7 r8
r10 = type1 a 18 r8 r9
r11 = type2 a 20 r9 r10
r12 = type3 a 22 r10 r11
cast_enc (K16 a) p = P r16 r15
where
P r12 r11 = cast_enc (K12 a) p
r13 = type1 a 24 r11 r12
r14 = type2 a 26 r12 r13
r15 = type3 a 28 r13 r14
r16 = type1 a 30 r14 r15
-- Decryption
-- | Decrypts a block using the specified key
decrypt :: Key -> Word64 -> Word64
decrypt k = comp64 . cast_dec k . decomp64
cast_dec :: Key -> P -> P
cast_dec (K12 a) (P r12 r11) = P l0 r0
where
r10 = type3 a 22 r12 r11
r9 = type2 a 20 r11 r10
r8 = type1 a 18 r10 r9
r7 = type3 a 16 r9 r8
r6 = type2 a 14 r8 r7
r5 = type1 a 12 r7 r6
r4 = type3 a 10 r6 r5
r3 = type2 a 8 r5 r4
r2 = type1 a 6 r4 r3
r1 = type3 a 4 r3 r2
r0 = type2 a 2 r2 r1
l0 = type1 a 0 r1 r0
cast_dec (K16 a) (P r16 r15) = cast_dec (K12 a) (P r12 r11)
where
r14 = type1 a 30 r16 r15
r13 = type3 a 28 r15 r14
r12 = type2 a 26 r14 r13
r11 = type1 a 24 r13 r12
-- Non-Identical Rounds
type1 :: Array32 -> Int -> Word32 -> Word32 -> Word32
type1 arr idx l r =
let km = arrayRead32 arr idx
kr = arrayRead32 arr (idx + 1)
j = (km + r) `rotateL` fromIntegral kr
(ja, jb, jc, jd) = decomp32 j
in l `xor` (((sbox_s1 ja `xor` sbox_s2 jb) - sbox_s3 jc) + sbox_s4 jd)
type2 :: Array32 -> Int -> Word32 -> Word32 -> Word32
type2 arr idx l r =
let km = arrayRead32 arr idx
kr = arrayRead32 arr (idx + 1)
j = (km `xor` r) `rotateL` fromIntegral kr
(ja, jb, jc, jd) = decomp32 j
in l `xor` (((sbox_s1 ja - sbox_s2 jb) + sbox_s3 jc) `xor` sbox_s4 jd)
type3 :: Array32 -> Int -> Word32 -> Word32 -> Word32
type3 arr idx l r =
let km = arrayRead32 arr idx
kr = arrayRead32 arr (idx + 1)
j = (km - r) `rotateL` fromIntegral kr
(ja, jb, jc, jd) = decomp32 j
in l `xor` (((sbox_s1 ja + sbox_s2 jb) `xor` sbox_s3 jc) - sbox_s4 jd)
-- Key Schedule
-- | Precompute "masking" and "rotation" subkeys
buildKey :: ByteArrayAccess key
=> Bool -- ^ @True@ for short keys that only need 12 rounds
-> key -- ^ Input key padded to 16 bytes
-> Key -- ^ Output data structure
buildKey isShort key =
let P x0123 x4567 = decomp64 (fromBE $ B.toW64BE key 0)
P x89AB xCDEF = decomp64 (fromBE $ B.toW64BE key 8)
in keySchedule isShort (Q x0123 x4567 x89AB xCDEF)
keySchedule :: Bool -> Q -> Key
keySchedule isShort x
| isShort = K12 $ allocArray32AndFreeze 24 $ \ma ->
void (steps123 ma 0 x >>= skip4 >>= steps123 ma 1)
| otherwise = K16 $ allocArray32AndFreeze 32 $ \ma ->
void (steps123 ma 0 x >>= step4 ma 24 >>= steps123 ma 1 >>= step4 ma 25)
where
sbox_s56785 a b c d e = sbox_s5 a `xor` sbox_s6 b `xor` sbox_s7 c `xor` sbox_s8 d `xor` sbox_s5 e
sbox_s56786 a b c d e = sbox_s5 a `xor` sbox_s6 b `xor` sbox_s7 c `xor` sbox_s8 d `xor` sbox_s6 e
sbox_s56787 a b c d e = sbox_s5 a `xor` sbox_s6 b `xor` sbox_s7 c `xor` sbox_s8 d `xor` sbox_s7 e
sbox_s56788 a b c d e = sbox_s5 a `xor` sbox_s6 b `xor` sbox_s7 c `xor` sbox_s8 d `xor` sbox_s8 e
steps123 ma off = step1 ma off >=> step2 ma (off + 8) >=> step3 ma (off + 16)
step1 :: MutableArray32 -> Int -> Q -> IO Q
step1 ma off (Q x0123 x4567 x89AB xCDEF) = do
let (x8, x9, xA, xB) = decomp32 x89AB
(xC, xD, xE, xF) = decomp32 xCDEF
z0123 = x0123 `xor` sbox_s56787 xD xF xC xE x8
z4567 = x89AB `xor` sbox_s56788 z0 z2 z1 z3 xA
z89AB = xCDEF `xor` sbox_s56785 z7 z6 z5 z4 x9
zCDEF = x4567 `xor` sbox_s56786 zA z9 zB z8 xB
(z0, z1, z2, z3) = decomp32 z0123
(z4, z5, z6, z7) = decomp32 z4567
(z8, z9, zA, zB) = decomp32 z89AB
(zC, zD, zE, zF) = decomp32 zCDEF
mutableArrayWrite32 ma (off + 0) $ sbox_s56785 z8 z9 z7 z6 z2
mutableArrayWrite32 ma (off + 2) $ sbox_s56786 zA zB z5 z4 z6
mutableArrayWrite32 ma (off + 4) $ sbox_s56787 zC zD z3 z2 z9
mutableArrayWrite32 ma (off + 6) $ sbox_s56788 zE zF z1 z0 zC
return (Q z0123 z4567 z89AB zCDEF)
step2 :: MutableArray32 -> Int -> Q -> IO Q
step2 ma off (Q z0123 z4567 z89AB zCDEF) = do
let (z0, z1, z2, z3) = decomp32 z0123
(z4, z5, z6, z7) = decomp32 z4567
x0123 = z89AB `xor` sbox_s56787 z5 z7 z4 z6 z0
x4567 = z0123 `xor` sbox_s56788 x0 x2 x1 x3 z2
x89AB = z4567 `xor` sbox_s56785 x7 x6 x5 x4 z1
xCDEF = zCDEF `xor` sbox_s56786 xA x9 xB x8 z3
(x0, x1, x2, x3) = decomp32 x0123
(x4, x5, x6, x7) = decomp32 x4567
(x8, x9, xA, xB) = decomp32 x89AB
(xC, xD, xE, xF) = decomp32 xCDEF
mutableArrayWrite32 ma (off + 0) $ sbox_s56785 x3 x2 xC xD x8
mutableArrayWrite32 ma (off + 2) $ sbox_s56786 x1 x0 xE xF xD
mutableArrayWrite32 ma (off + 4) $ sbox_s56787 x7 x6 x8 x9 x3
mutableArrayWrite32 ma (off + 6) $ sbox_s56788 x5 x4 xA xB x7
return (Q x0123 x4567 x89AB xCDEF)
step3 :: MutableArray32 -> Int -> Q -> IO Q
step3 ma off (Q x0123 x4567 x89AB xCDEF) = do
let (x8, x9, xA, xB) = decomp32 x89AB
(xC, xD, xE, xF) = decomp32 xCDEF
z0123 = x0123 `xor` sbox_s56787 xD xF xC xE x8
z4567 = x89AB `xor` sbox_s56788 z0 z2 z1 z3 xA
z89AB = xCDEF `xor` sbox_s56785 z7 z6 z5 z4 x9
zCDEF = x4567 `xor` sbox_s56786 zA z9 zB z8 xB
(z0, z1, z2, z3) = decomp32 z0123
(z4, z5, z6, z7) = decomp32 z4567
(z8, z9, zA, zB) = decomp32 z89AB
(zC, zD, zE, zF) = decomp32 zCDEF
mutableArrayWrite32 ma (off + 0) $ sbox_s56785 z3 z2 zC zD z9
mutableArrayWrite32 ma (off + 2) $ sbox_s56786 z1 z0 zE zF zC
mutableArrayWrite32 ma (off + 4) $ sbox_s56787 z7 z6 z8 z9 z2
mutableArrayWrite32 ma (off + 6) $ sbox_s56788 z5 z4 zA zB z6
return (Q z0123 z4567 z89AB zCDEF)
step4 :: MutableArray32 -> Int -> Q -> IO Q
step4 ma off (Q z0123 z4567 z89AB zCDEF) = do
let (z0, z1, z2, z3) = decomp32 z0123
(z4, z5, z6, z7) = decomp32 z4567
x0123 = z89AB `xor` sbox_s56787 z5 z7 z4 z6 z0
x4567 = z0123 `xor` sbox_s56788 x0 x2 x1 x3 z2
x89AB = z4567 `xor` sbox_s56785 x7 x6 x5 x4 z1
xCDEF = zCDEF `xor` sbox_s56786 xA x9 xB x8 z3
(x0, x1, x2, x3) = decomp32 x0123
(x4, x5, x6, x7) = decomp32 x4567
(x8, x9, xA, xB) = decomp32 x89AB
(xC, xD, xE, xF) = decomp32 xCDEF
mutableArrayWrite32 ma (off + 0) $ sbox_s56785 x8 x9 x7 x6 x3
mutableArrayWrite32 ma (off + 2) $ sbox_s56786 xA xB x5 x4 x7
mutableArrayWrite32 ma (off + 4) $ sbox_s56787 xC xD x3 x2 x8
mutableArrayWrite32 ma (off + 6) $ sbox_s56788 xE xF x1 x0 xD
return (Q x0123 x4567 x89AB xCDEF)
skip4 :: Q -> IO Q
skip4 (Q z0123 z4567 z89AB zCDEF) = do
let (z0, z1, z2, z3) = decomp32 z0123
(z4, z5, z6, z7) = decomp32 z4567
x0123 = z89AB `xor` sbox_s56787 z5 z7 z4 z6 z0
x4567 = z0123 `xor` sbox_s56788 x0 x2 x1 x3 z2
x89AB = z4567 `xor` sbox_s56785 x7 x6 x5 x4 z1
xCDEF = zCDEF `xor` sbox_s56786 xA x9 xB x8 z3
(x0, x1, x2, x3) = decomp32 x0123
(x4, x5, x6, x7) = decomp32 x4567
(x8, x9, xA, xB) = decomp32 x89AB
return (Q x0123 x4567 x89AB xCDEF)
-- S-Boxes
sbox_s1 :: Word8 -> Word32
sbox_s1 i = arrayRead32 t (fromIntegral i)
where
t = array32FromAddrBE 256
"\x30\xfb\x40\xd4\x9f\xa0\xff\x0b\x6b\xec\xcd\x2f\x3f\x25\x8c\x7a\x1e\x21\x3f\x2f\x9c\x00\x4d\xd3\x60\x03\xe5\x40\xcf\x9f\xc9\x49\
\\xbf\xd4\xaf\x27\x88\xbb\xbd\xb5\xe2\x03\x40\x90\x98\xd0\x96\x75\x6e\x63\xa0\xe0\x15\xc3\x61\xd2\xc2\xe7\x66\x1d\x22\xd4\xff\x8e\
\\x28\x68\x3b\x6f\xc0\x7f\xd0\x59\xff\x23\x79\xc8\x77\x5f\x50\xe2\x43\xc3\x40\xd3\xdf\x2f\x86\x56\x88\x7c\xa4\x1a\xa2\xd2\xbd\x2d\
\\xa1\xc9\xe0\xd6\x34\x6c\x48\x19\x61\xb7\x6d\x87\x22\x54\x0f\x2f\x2a\xbe\x32\xe1\xaa\x54\x16\x6b\x22\x56\x8e\x3a\xa2\xd3\x41\xd0\
\\x66\xdb\x40\xc8\xa7\x84\x39\x2f\x00\x4d\xff\x2f\x2d\xb9\xd2\xde\x97\x94\x3f\xac\x4a\x97\xc1\xd8\x52\x76\x44\xb7\xb5\xf4\x37\xa7\
\\xb8\x2c\xba\xef\xd7\x51\xd1\x59\x6f\xf7\xf0\xed\x5a\x09\x7a\x1f\x82\x7b\x68\xd0\x90\xec\xf5\x2e\x22\xb0\xc0\x54\xbc\x8e\x59\x35\
\\x4b\x6d\x2f\x7f\x50\xbb\x64\xa2\xd2\x66\x49\x10\xbe\xe5\x81\x2d\xb7\x33\x22\x90\xe9\x3b\x15\x9f\xb4\x8e\xe4\x11\x4b\xff\x34\x5d\
\\xfd\x45\xc2\x40\xad\x31\x97\x3f\xc4\xf6\xd0\x2e\x55\xfc\x81\x65\xd5\xb1\xca\xad\xa1\xac\x2d\xae\xa2\xd4\xb7\x6d\xc1\x9b\x0c\x50\
\\x88\x22\x40\xf2\x0c\x6e\x4f\x38\xa4\xe4\xbf\xd7\x4f\x5b\xa2\x72\x56\x4c\x1d\x2f\xc5\x9c\x53\x19\xb9\x49\xe3\x54\xb0\x46\x69\xfe\
\\xb1\xb6\xab\x8a\xc7\x13\x58\xdd\x63\x85\xc5\x45\x11\x0f\x93\x5d\x57\x53\x8a\xd5\x6a\x39\x04\x93\xe6\x3d\x37\xe0\x2a\x54\xf6\xb3\
\\x3a\x78\x7d\x5f\x62\x76\xa0\xb5\x19\xa6\xfc\xdf\x7a\x42\x20\x6a\x29\xf9\xd4\xd5\xf6\x1b\x18\x91\xbb\x72\x27\x5e\xaa\x50\x81\x67\
\\x38\x90\x10\x91\xc6\xb5\x05\xeb\x84\xc7\xcb\x8c\x2a\xd7\x5a\x0f\x87\x4a\x14\x27\xa2\xd1\x93\x6b\x2a\xd2\x86\xaf\xaa\x56\xd2\x91\
\\xd7\x89\x43\x60\x42\x5c\x75\x0d\x93\xb3\x9e\x26\x18\x71\x84\xc9\x6c\x00\xb3\x2d\x73\xe2\xbb\x14\xa0\xbe\xbc\x3c\x54\x62\x37\x79\
\\x64\x45\x9e\xab\x3f\x32\x8b\x82\x77\x18\xcf\x82\x59\xa2\xce\xa6\x04\xee\x00\x2e\x89\xfe\x78\xe6\x3f\xab\x09\x50\x32\x5f\xf6\xc2\
\\x81\x38\x3f\x05\x69\x63\xc5\xc8\x76\xcb\x5a\xd6\xd4\x99\x74\xc9\xca\x18\x0d\xcf\x38\x07\x82\xd5\xc7\xfa\x5c\xf6\x8a\xc3\x15\x11\
\\x35\xe7\x9e\x13\x47\xda\x91\xd0\xf4\x0f\x90\x86\xa7\xe2\x41\x9e\x31\x36\x62\x41\x05\x1e\xf4\x95\xaa\x57\x3b\x04\x4a\x80\x5d\x8d\
\\x54\x83\x00\xd0\x00\x32\x2a\x3c\xbf\x64\xcd\xdf\xba\x57\xa6\x8e\x75\xc6\x37\x2b\x50\xaf\xd3\x41\xa7\xc1\x32\x75\x91\x5a\x0b\xf5\
\\x6b\x54\xbf\xab\x2b\x0b\x14\x26\xab\x4c\xc9\xd7\x44\x9c\xcd\x82\xf7\xfb\xf2\x65\xab\x85\xc5\xf3\x1b\x55\xdb\x94\xaa\xd4\xe3\x24\
\\xcf\xa4\xbd\x3f\x2d\xea\xa3\xe2\x9e\x20\x4d\x02\xc8\xbd\x25\xac\xea\xdf\x55\xb3\xd5\xbd\x9e\x98\xe3\x12\x31\xb2\x2a\xd5\xad\x6c\
\\x95\x43\x29\xde\xad\xbe\x45\x28\xd8\x71\x0f\x69\xaa\x51\xc9\x0f\xaa\x78\x6b\xf6\x22\x51\x3f\x1e\xaa\x51\xa7\x9b\x2a\xd3\x44\xcc\
\\x7b\x5a\x41\xf0\xd3\x7c\xfb\xad\x1b\x06\x95\x05\x41\xec\xe4\x91\xb4\xc3\x32\xe6\x03\x22\x68\xd4\xc9\x60\x0a\xcc\xce\x38\x7e\x6d\
\\xbf\x6b\xb1\x6c\x6a\x70\xfb\x78\x0d\x03\xd9\xc9\xd4\xdf\x39\xde\xe0\x10\x63\xda\x47\x36\xf4\x64\x5a\xd3\x28\xd8\xb3\x47\xcc\x96\
\\x75\xbb\x0f\xc3\x98\x51\x1b\xfb\x4f\xfb\xcc\x35\xb5\x8b\xcf\x6a\xe1\x1f\x0a\xbc\xbf\xc5\xfe\x4a\xa7\x0a\xec\x10\xac\x39\x57\x0a\
\\x3f\x04\x44\x2f\x61\x88\xb1\x53\xe0\x39\x7a\x2e\x57\x27\xcb\x79\x9c\xeb\x41\x8f\x1c\xac\xd6\x8d\x2a\xd3\x7c\x96\x01\x75\xcb\x9d\
\\xc6\x9d\xff\x09\xc7\x5b\x65\xf0\xd9\xdb\x40\xd8\xec\x0e\x77\x79\x47\x44\xea\xd4\xb1\x1c\x32\x74\xdd\x24\xcb\x9e\x7e\x1c\x54\xbd\
\\xf0\x11\x44\xf9\xd2\x24\x0e\xb1\x96\x75\xb3\xfd\xa3\xac\x37\x55\xd4\x7c\x27\xaf\x51\xc8\x5f\x4d\x56\x90\x75\x96\xa5\xbb\x15\xe6\
\\x58\x03\x04\xf0\xca\x04\x2c\xf1\x01\x1a\x37\xea\x8d\xbf\xaa\xdb\x35\xba\x3e\x4a\x35\x26\xff\xa0\xc3\x7b\x4d\x09\xbc\x30\x6e\xd9\
\\x98\xa5\x26\x66\x56\x48\xf7\x25\xff\x5e\x56\x9d\x0c\xed\x63\xd0\x7c\x63\xb2\xcf\x70\x0b\x45\xe1\xd5\xea\x50\xf1\x85\xa9\x28\x72\
\\xaf\x1f\xbd\xa7\xd4\x23\x48\x70\xa7\x87\x0b\xf3\x2d\x3b\x4d\x79\x42\xe0\x41\x98\x0c\xd0\xed\xe7\x26\x47\x0d\xb8\xf8\x81\x81\x4c\
\\x47\x4d\x6a\xd7\x7c\x0c\x5e\x5c\xd1\x23\x19\x59\x38\x1b\x72\x98\xf5\xd2\xf4\xdb\xab\x83\x86\x53\x6e\x2f\x1e\x23\x83\x71\x9c\x9e\
\\xbd\x91\xe0\x46\x9a\x56\x45\x6e\xdc\x39\x20\x0c\x20\xc8\xc5\x71\x96\x2b\xda\x1c\xe1\xe6\x96\xff\xb1\x41\xab\x08\x7c\xca\x89\xb9\
\\x1a\x69\xe7\x83\x02\xcc\x48\x43\xa2\xf7\xc5\x79\x42\x9e\xf4\x7d\x42\x7b\x16\x9c\x5a\xc9\xf0\x49\xdd\x8f\x0f\x00\x5c\x81\x65\xbf"#
sbox_s2 :: Word8 -> Word32
sbox_s2 i = arrayRead32 t (fromIntegral i)
where
t = array32FromAddrBE 256
"\x1f\x20\x10\x94\xef\x0b\xa7\x5b\x69\xe3\xcf\x7e\x39\x3f\x43\x80\xfe\x61\xcf\x7a\xee\xc5\x20\x7a\x55\x88\x9c\x94\x72\xfc\x06\x51\
\\xad\xa7\xef\x79\x4e\x1d\x72\x35\xd5\x5a\x63\xce\xde\x04\x36\xba\x99\xc4\x30\xef\x5f\x0c\x07\x94\x18\xdc\xdb\x7d\xa1\xd6\xef\xf3\
\\xa0\xb5\x2f\x7b\x59\xe8\x36\x05\xee\x15\xb0\x94\xe9\xff\xd9\x09\xdc\x44\x00\x86\xef\x94\x44\x59\xba\x83\xcc\xb3\xe0\xc3\xcd\xfb\
\\xd1\xda\x41\x81\x3b\x09\x2a\xb1\xf9\x97\xf1\xc1\xa5\xe6\xcf\x7b\x01\x42\x0d\xdb\xe4\xe7\xef\x5b\x25\xa1\xff\x41\xe1\x80\xf8\x06\
\\x1f\xc4\x10\x80\x17\x9b\xee\x7a\xd3\x7a\xc6\xa9\xfe\x58\x30\xa4\x98\xde\x8b\x7f\x77\xe8\x3f\x4e\x79\x92\x92\x69\x24\xfa\x9f\x7b\
\\xe1\x13\xc8\x5b\xac\xc4\x00\x83\xd7\x50\x35\x25\xf7\xea\x61\x5f\x62\x14\x31\x54\x0d\x55\x4b\x63\x5d\x68\x11\x21\xc8\x66\xc3\x59\
\\x3d\x63\xcf\x73\xce\xe2\x34\xc0\xd4\xd8\x7e\x87\x5c\x67\x2b\x21\x07\x1f\x61\x81\x39\xf7\x62\x7f\x36\x1e\x30\x84\xe4\xeb\x57\x3b\
\\x60\x2f\x64\xa4\xd6\x3a\xcd\x9c\x1b\xbc\x46\x35\x9e\x81\x03\x2d\x27\x01\xf5\x0c\x99\x84\x7a\xb4\xa0\xe3\xdf\x79\xba\x6c\xf3\x8c\
\\x10\x84\x30\x94\x25\x37\xa9\x5e\xf4\x6f\x6f\xfe\xa1\xff\x3b\x1f\x20\x8c\xfb\x6a\x8f\x45\x8c\x74\xd9\xe0\xa2\x27\x4e\xc7\x3a\x34\
\\xfc\x88\x4f\x69\x3e\x4d\xe8\xdf\xef\x0e\x00\x88\x35\x59\x64\x8d\x8a\x45\x38\x8c\x1d\x80\x43\x66\x72\x1d\x9b\xfd\xa5\x86\x84\xbb\
\\xe8\x25\x63\x33\x84\x4e\x82\x12\x12\x8d\x80\x98\xfe\xd3\x3f\xb4\xce\x28\x0a\xe1\x27\xe1\x9b\xa5\xd5\xa6\xc2\x52\xe4\x97\x54\xbd\
\\xc5\xd6\x55\xdd\xeb\x66\x70\x64\x77\x84\x0b\x4d\xa1\xb6\xa8\x01\x84\xdb\x26\xa9\xe0\xb5\x67\x14\x21\xf0\x43\xb7\xe5\xd0\x58\x60\
\\x54\xf0\x30\x84\x06\x6f\xf4\x72\xa3\x1a\xa1\x53\xda\xdc\x47\x55\xb5\x62\x5d\xbf\x68\x56\x1b\xe6\x83\xca\x6b\x94\x2d\x6e\xd2\x3b\
\\xec\xcf\x01\xdb\xa6\xd3\xd0\xba\xb6\x80\x3d\x5c\xaf\x77\xa7\x09\x33\xb4\xa3\x4c\x39\x7b\xc8\xd6\x5e\xe2\x2b\x95\x5f\x0e\x53\x04\
\\x81\xed\x6f\x61\x20\xe7\x43\x64\xb4\x5e\x13\x78\xde\x18\x63\x9b\x88\x1c\xa1\x22\xb9\x67\x26\xd1\x80\x49\xa7\xe8\x22\xb7\xda\x7b\
\\x5e\x55\x2d\x25\x52\x72\xd2\x37\x79\xd2\x95\x1c\xc6\x0d\x89\x4c\x48\x8c\xb4\x02\x1b\xa4\xfe\x5b\xa4\xb0\x9f\x6b\x1c\xa8\x15\xcf\
\\xa2\x0c\x30\x05\x88\x71\xdf\x63\xb9\xde\x2f\xcb\x0c\xc6\xc9\xe9\x0b\xee\xff\x53\xe3\x21\x45\x17\xb4\x54\x28\x35\x9f\x63\x29\x3c\
\\xee\x41\xe7\x29\x6e\x1d\x2d\x7c\x50\x04\x52\x86\x1e\x66\x85\xf3\xf3\x34\x01\xc6\x30\xa2\x2c\x95\x31\xa7\x08\x50\x60\x93\x0f\x13\
\\x73\xf9\x84\x17\xa1\x26\x98\x59\xec\x64\x5c\x44\x52\xc8\x77\xa9\xcd\xff\x33\xa6\xa0\x2b\x17\x41\x7c\xba\xd9\xa2\x21\x80\x03\x6f\
\\x50\xd9\x9c\x08\xcb\x3f\x48\x61\xc2\x6b\xd7\x65\x64\xa3\xf6\xab\x80\x34\x26\x76\x25\xa7\x5e\x7b\xe4\xe6\xd1\xfc\x20\xc7\x10\xe6\
\\xcd\xf0\xb6\x80\x17\x84\x4d\x3b\x31\xee\xf8\x4d\x7e\x08\x24\xe4\x2c\xcb\x49\xeb\x84\x6a\x3b\xae\x8f\xf7\x78\x88\xee\x5d\x60\xf6\
\\x7a\xf7\x56\x73\x2f\xdd\x5c\xdb\xa1\x16\x31\xc1\x30\xf6\x6f\x43\xb3\xfa\xec\x54\x15\x7f\xd7\xfa\xef\x85\x79\xcc\xd1\x52\xde\x58\
\\xdb\x2f\xfd\x5e\x8f\x32\xce\x19\x30\x6a\xf9\x7a\x02\xf0\x3e\xf8\x99\x31\x9a\xd5\xc2\x42\xfa\x0f\xa7\xe3\xeb\xb0\xc6\x8e\x49\x06\
\\xb8\xda\x23\x0c\x80\x82\x30\x28\xdc\xde\xf3\xc8\xd3\x5f\xb1\x71\x08\x8a\x1b\xc8\xbe\xc0\xc5\x60\x61\xa3\xc9\xe8\xbc\xa8\xf5\x4d\
\\xc7\x2f\xef\xfa\x22\x82\x2e\x99\x82\xc5\x70\xb4\xd8\xd9\x4e\x89\x8b\x1c\x34\xbc\x30\x1e\x16\xe6\x27\x3b\xe9\x79\xb0\xff\xea\xa6\
\\x61\xd9\xb8\xc6\x00\xb2\x48\x69\xb7\xff\xce\x3f\x08\xdc\x28\x3b\x43\xda\xf6\x5a\xf7\xe1\x97\x98\x76\x19\xb7\x2f\x8f\x1c\x9b\xa4\
\\xdc\x86\x37\xa0\x16\xa7\xd3\xb1\x9f\xc3\x93\xb7\xa7\x13\x6e\xeb\xc6\xbc\xc6\x3e\x1a\x51\x37\x42\xef\x68\x28\xbc\x52\x03\x65\xd6\
\\x2d\x6a\x77\xab\x35\x27\xed\x4b\x82\x1f\xd2\x16\x09\x5c\x6e\x2e\xdb\x92\xf2\xfb\x5e\xea\x29\xcb\x14\x58\x92\xf5\x91\x58\x4f\x7f\
\\x54\x83\x69\x7b\x26\x67\xa8\xcc\x85\x19\x60\x48\x8c\x4b\xac\xea\x83\x38\x60\xd4\x0d\x23\xe0\xf9\x6c\x38\x7e\x8a\x0a\xe6\xd2\x49\
\\xb2\x84\x60\x0c\xd8\x35\x73\x1d\xdc\xb1\xc6\x47\xac\x4c\x56\xea\x3e\xbd\x81\xb3\x23\x0e\xab\xb0\x64\x38\xbc\x87\xf0\xb5\xb1\xfa\
\\x8f\x5e\xa2\xb3\xfc\x18\x46\x42\x0a\x03\x6b\x7a\x4f\xb0\x89\xbd\x64\x9d\xa5\x89\xa3\x45\x41\x5e\x5c\x03\x83\x23\x3e\x5d\x3b\xb9\
\\x43\xd7\x95\x72\x7e\x6d\xd0\x7c\x06\xdf\xdf\x1e\x6c\x6c\xc4\xef\x71\x60\xa5\x39\x73\xbf\xbe\x70\x83\x87\x76\x05\x45\x23\xec\xf1"#
sbox_s3 :: Word8 -> Word32
sbox_s3 i = arrayRead32 t (fromIntegral i)
where
t = array32FromAddrBE 256
"\x8d\xef\xc2\x40\x25\xfa\x5d\x9f\xeb\x90\x3d\xbf\xe8\x10\xc9\x07\x47\x60\x7f\xff\x36\x9f\xe4\x4b\x8c\x1f\xc6\x44\xae\xce\xca\x90\
\\xbe\xb1\xf9\xbf\xee\xfb\xca\xea\xe8\xcf\x19\x50\x51\xdf\x07\xae\x92\x0e\x88\x06\xf0\xad\x05\x48\xe1\x3c\x8d\x83\x92\x70\x10\xd5\
\\x11\x10\x7d\x9f\x07\x64\x7d\xb9\xb2\xe3\xe4\xd4\x3d\x4f\x28\x5e\xb9\xaf\xa8\x20\xfa\xde\x82\xe0\xa0\x67\x26\x8b\x82\x72\x79\x2e\
\\x55\x3f\xb2\xc0\x48\x9a\xe2\x2b\xd4\xef\x97\x94\x12\x5e\x3f\xbc\x21\xff\xfc\xee\x82\x5b\x1b\xfd\x92\x55\xc5\xed\x12\x57\xa2\x40\
\\x4e\x1a\x83\x02\xba\xe0\x7f\xff\x52\x82\x46\xe7\x8e\x57\x14\x0e\x33\x73\xf7\xbf\x8c\x9f\x81\x88\xa6\xfc\x4e\xe8\xc9\x82\xb5\xa5\
\\xa8\xc0\x1d\xb7\x57\x9f\xc2\x64\x67\x09\x4f\x31\xf2\xbd\x3f\x5f\x40\xff\xf7\xc1\x1f\xb7\x8d\xfc\x8e\x6b\xd2\xc1\x43\x7b\xe5\x9b\
\\x99\xb0\x3d\xbf\xb5\xdb\xc6\x4b\x63\x8d\xc0\xe6\x55\x81\x9d\x99\xa1\x97\xc8\x1c\x4a\x01\x2d\x6e\xc5\x88\x4a\x28\xcc\xc3\x6f\x71\
\\xb8\x43\xc2\x13\x6c\x07\x43\xf1\x83\x09\x89\x3c\x0f\xed\xdd\x5f\x2f\x7f\xe8\x50\xd7\xc0\x7f\x7e\x02\x50\x7f\xbf\x5a\xfb\x9a\x04\
\\xa7\x47\xd2\xd0\x16\x51\x19\x2e\xaf\x70\xbf\x3e\x58\xc3\x13\x80\x5f\x98\x30\x2e\x72\x7c\xc3\xc4\x0a\x0f\xb4\x02\x0f\x7f\xef\x82\
\\x8c\x96\xfd\xad\x5d\x2c\x2a\xae\x8e\xe9\x9a\x49\x50\xda\x88\xb8\x84\x27\xf4\xa0\x1e\xac\x57\x90\x79\x6f\xb4\x49\x82\x52\xdc\x15\
\\xef\xbd\x7d\x9b\xa6\x72\x59\x7d\xad\xa8\x40\xd8\x45\xf5\x45\x04\xfa\x5d\x74\x03\xe8\x3e\xc3\x05\x4f\x91\x75\x1a\x92\x56\x69\xc2\
\\x23\xef\xe9\x41\xa9\x03\xf1\x2e\x60\x27\x0d\xf2\x02\x76\xe4\xb6\x94\xfd\x65\x74\x92\x79\x85\xb2\x82\x76\xdb\xcb\x02\x77\x81\x76\
\\xf8\xaf\x91\x8d\x4e\x48\xf7\x9e\x8f\x61\x6d\xdf\xe2\x9d\x84\x0e\x84\x2f\x7d\x83\x34\x0c\xe5\xc8\x96\xbb\xb6\x82\x93\xb4\xb1\x48\
\\xef\x30\x3c\xab\x98\x4f\xaf\x28\x77\x9f\xaf\x9b\x92\xdc\x56\x0d\x22\x4d\x1e\x20\x84\x37\xaa\x88\x7d\x29\xdc\x96\x27\x56\xd3\xdc\
\\x8b\x90\x7c\xee\xb5\x1f\xd2\x40\xe7\xc0\x7c\xe3\xe5\x66\xb4\xa1\xc3\xe9\x61\x5e\x3c\xf8\x20\x9d\x60\x94\xd1\xe3\xcd\x9c\xa3\x41\
\\x5c\x76\x46\x0e\x00\xea\x98\x3b\xd4\xd6\x78\x81\xfd\x47\x57\x2c\xf7\x6c\xed\xd9\xbd\xa8\x22\x9c\x12\x7d\xad\xaa\x43\x8a\x07\x4e\
\\x1f\x97\xc0\x90\x08\x1b\xdb\x8a\x93\xa0\x7e\xbe\xb9\x38\xca\x15\x97\xb0\x3c\xff\x3d\xc2\xc0\xf8\x8d\x1a\xb2\xec\x64\x38\x0e\x51\
\\x68\xcc\x7b\xfb\xd9\x0f\x27\x88\x12\x49\x01\x81\x5d\xe5\xff\xd4\xdd\x7e\xf8\x6a\x76\xa2\xe2\x14\xb9\xa4\x03\x68\x92\x5d\x95\x8f\
\\x4b\x39\xff\xfa\xba\x39\xae\xe9\xa4\xff\xd3\x0b\xfa\xf7\x93\x3b\x6d\x49\x86\x23\x19\x3c\xbc\xfa\x27\x62\x75\x45\x82\x5c\xf4\x7a\
\\x61\xbd\x8b\xa0\xd1\x1e\x42\xd1\xce\xad\x04\xf4\x12\x7e\xa3\x92\x10\x42\x8d\xb7\x82\x72\xa9\x72\x92\x70\xc4\xa8\x12\x7d\xe5\x0b\
\\x28\x5b\xa1\xc8\x3c\x62\xf4\x4f\x35\xc0\xea\xa5\xe8\x05\xd2\x31\x42\x89\x29\xfb\xb4\xfc\xdf\x82\x4f\xb6\x6a\x53\x0e\x7d\xc1\x5b\
\\x1f\x08\x1f\xab\x10\x86\x18\xae\xfc\xfd\x08\x6d\xf9\xff\x28\x89\x69\x4b\xcc\x11\x23\x6a\x5c\xae\x12\xde\xca\x4d\x2c\x3f\x8c\xc5\
\\xd2\xd0\x2d\xfe\xf8\xef\x58\x96\xe4\xcf\x52\xda\x95\x15\x5b\x67\x49\x4a\x48\x8c\xb9\xb6\xa8\x0c\x5c\x8f\x82\xbc\x89\xd3\x6b\x45\
\\x3a\x60\x94\x37\xec\x00\xc9\xa9\x44\x71\x52\x53\x0a\x87\x4b\x49\xd7\x73\xbc\x40\x7c\x34\x67\x1c\x02\x71\x7e\xf6\x4f\xeb\x55\x36\
\\xa2\xd0\x2f\xff\xd2\xbf\x60\xc4\xd4\x3f\x03\xc0\x50\xb4\xef\x6d\x07\x47\x8c\xd1\x00\x6e\x18\x88\xa2\xe5\x3f\x55\xb9\xe6\xd4\xbc\
\\xa2\x04\x80\x16\x97\x57\x38\x33\xd7\x20\x7d\x67\xde\x0f\x8f\x3d\x72\xf8\x7b\x33\xab\xcc\x4f\x33\x76\x88\xc5\x5d\x7b\x00\xa6\xb0\
\\x94\x7b\x00\x01\x57\x00\x75\xd2\xf9\xbb\x88\xf8\x89\x42\x01\x9e\x42\x64\xa5\xff\x85\x63\x02\xe0\x72\xdb\xd9\x2b\xee\x97\x1b\x69\
\\x6e\xa2\x2f\xde\x5f\x08\xae\x2b\xaf\x7a\x61\x6d\xe5\xc9\x87\x67\xcf\x1f\xeb\xd2\x61\xef\xc8\xc2\xf1\xac\x25\x71\xcc\x82\x39\xc2\
\\x67\x21\x4c\xb8\xb1\xe5\x83\xd1\xb7\xdc\x3e\x62\x7f\x10\xbd\xce\xf9\x0a\x5c\x38\x0f\xf0\x44\x3d\x60\x6e\x6d\xc6\x60\x54\x3a\x49\
\\x57\x27\xc1\x48\x2b\xe9\x8a\x1d\x8a\xb4\x17\x38\x20\xe1\xbe\x24\xaf\x96\xda\x0f\x68\x45\x84\x25\x99\x83\x3b\xe5\x60\x0d\x45\x7d\
\\x28\x2f\x93\x50\x83\x34\xb3\x62\xd9\x1d\x11\x20\x2b\x6d\x8d\xa0\x64\x2b\x1e\x31\x9c\x30\x5a\x00\x52\xbc\xe6\x88\x1b\x03\x58\x8a\
\\xf7\xba\xef\xd5\x41\x42\xed\x9c\xa4\x31\x5c\x11\x83\x32\x3e\xc5\xdf\xef\x46\x36\xa1\x33\xc5\x01\xe9\xd3\x53\x1c\xee\x35\x37\x83"#
sbox_s4 :: Word8 -> Word32
sbox_s4 i = arrayRead32 t (fromIntegral i)
where
t = array32FromAddrBE 256
"\x9d\xb3\x04\x20\x1f\xb6\xe9\xde\xa7\xbe\x7b\xef\xd2\x73\xa2\x98\x4a\x4f\x7b\xdb\x64\xad\x8c\x57\x85\x51\x04\x43\xfa\x02\x0e\xd1\
\\x7e\x28\x7a\xff\xe6\x0f\xb6\x63\x09\x5f\x35\xa1\x79\xeb\xf1\x20\xfd\x05\x9d\x43\x64\x97\xb7\xb1\xf3\x64\x1f\x63\x24\x1e\x4a\xdf\
\\x28\x14\x7f\x5f\x4f\xa2\xb8\xcd\xc9\x43\x00\x40\x0c\xc3\x22\x20\xfd\xd3\x0b\x30\xc0\xa5\x37\x4f\x1d\x2d\x00\xd9\x24\x14\x7b\x15\
\\xee\x4d\x11\x1a\x0f\xca\x51\x67\x71\xff\x90\x4c\x2d\x19\x5f\xfe\x1a\x05\x64\x5f\x0c\x13\xfe\xfe\x08\x1b\x08\xca\x05\x17\x01\x21\
\\x80\x53\x01\x00\xe8\x3e\x5e\xfe\xac\x9a\xf4\xf8\x7f\xe7\x27\x01\xd2\xb8\xee\x5f\x06\xdf\x42\x61\xbb\x9e\x9b\x8a\x72\x93\xea\x25\
\\xce\x84\xff\xdf\xf5\x71\x88\x01\x3d\xd6\x4b\x04\xa2\x6f\x26\x3b\x7e\xd4\x84\x00\x54\x7e\xeb\xe6\x44\x6d\x4c\xa0\x6c\xf3\xd6\xf5\
\\x26\x49\xab\xdf\xae\xa0\xc7\xf5\x36\x33\x8c\xc1\x50\x3f\x7e\x93\xd3\x77\x20\x61\x11\xb6\x38\xe1\x72\x50\x0e\x03\xf8\x0e\xb2\xbb\
\\xab\xe0\x50\x2e\xec\x8d\x77\xde\x57\x97\x1e\x81\xe1\x4f\x67\x46\xc9\x33\x54\x00\x69\x20\x31\x8f\x08\x1d\xbb\x99\xff\xc3\x04\xa5\
\\x4d\x35\x18\x05\x7f\x3d\x5c\xe3\xa6\xc8\x66\xc6\x5d\x5b\xcc\xa9\xda\xec\x6f\xea\x9f\x92\x6f\x91\x9f\x46\x22\x2f\x39\x91\x46\x7d\
\\xa5\xbf\x6d\x8e\x11\x43\xc4\x4f\x43\x95\x83\x02\xd0\x21\x4e\xeb\x02\x20\x83\xb8\x3f\xb6\x18\x0c\x18\xf8\x93\x1e\x28\x16\x58\xe6\
\\x26\x48\x6e\x3e\x8b\xd7\x8a\x70\x74\x77\xe4\xc1\xb5\x06\xe0\x7c\xf3\x2d\x0a\x25\x79\x09\x8b\x02\xe4\xea\xbb\x81\x28\x12\x3b\x23\
\\x69\xde\xad\x38\x15\x74\xca\x16\xdf\x87\x1b\x62\x21\x1c\x40\xb7\xa5\x1a\x9e\xf9\x00\x14\x37\x7b\x04\x1e\x8a\xc8\x09\x11\x40\x03\
\\xbd\x59\xe4\xd2\xe3\xd1\x56\xd5\x4f\xe8\x76\xd5\x2f\x91\xa3\x40\x55\x7b\xe8\xde\x00\xea\xe4\xa7\x0c\xe5\xc2\xec\x4d\xb4\xbb\xa6\
\\xe7\x56\xbd\xff\xdd\x33\x69\xac\xec\x17\xb0\x35\x06\x57\x23\x27\x99\xaf\xc8\xb0\x56\xc8\xc3\x91\x6b\x65\x81\x1c\x5e\x14\x61\x19\
\\x6e\x85\xcb\x75\xbe\x07\xc0\x02\xc2\x32\x55\x77\x89\x3f\xf4\xec\x5b\xbf\xc9\x2d\xd0\xec\x3b\x25\xb7\x80\x1a\xb7\x8d\x6d\x3b\x24\
\\x20\xc7\x63\xef\xc3\x66\xa5\xfc\x9c\x38\x28\x80\x0a\xce\x32\x05\xaa\xc9\x54\x8a\xec\xa1\xd7\xc7\x04\x1a\xfa\x32\x1d\x16\x62\x5a\
\\x67\x01\x90\x2c\x9b\x75\x7a\x54\x31\xd4\x77\xf7\x91\x26\xb0\x31\x36\xcc\x6f\xdb\xc7\x0b\x8b\x46\xd9\xe6\x6a\x48\x56\xe5\x5a\x79\
\\x02\x6a\x4c\xeb\x52\x43\x7e\xff\x2f\x8f\x76\xb4\x0d\xf9\x80\xa5\x86\x74\xcd\xe3\xed\xda\x04\xeb\x17\xa9\xbe\x04\x2c\x18\xf4\xdf\
\\xb7\x74\x7f\x9d\xab\x2a\xf7\xb4\xef\xc3\x4d\x20\x2e\x09\x6b\x7c\x17\x41\xa2\x54\xe5\xb6\xa0\x35\x21\x3d\x42\xf6\x2c\x1c\x7c\x26\
\\x61\xc2\xf5\x0f\x65\x52\xda\xf9\xd2\xc2\x31\xf8\x25\x13\x0f\x69\xd8\x16\x7f\xa2\x04\x18\xf2\xc8\x00\x1a\x96\xa6\x0d\x15\x26\xab\
\\x63\x31\x5c\x21\x5e\x0a\x72\xec\x49\xba\xfe\xfd\x18\x79\x08\xd9\x8d\x0d\xbd\x86\x31\x11\x70\xa7\x3e\x9b\x64\x0c\xcc\x3e\x10\xd7\
\\xd5\xca\xd3\xb6\x0c\xae\xc3\x88\xf7\x30\x01\xe1\x6c\x72\x8a\xff\x71\xea\xe2\xa1\x1f\x9a\xf3\x6e\xcf\xcb\xd1\x2f\xc1\xde\x84\x17\
\\xac\x07\xbe\x6b\xcb\x44\xa1\xd8\x8b\x9b\x0f\x56\x01\x39\x88\xc3\xb1\xc5\x2f\xca\xb4\xbe\x31\xcd\xd8\x78\x28\x06\x12\xa3\xa4\xe2\
\\x6f\x7d\xe5\x32\x58\xfd\x7e\xb6\xd0\x1e\xe9\x00\x24\xad\xff\xc2\xf4\x99\x0f\xc5\x97\x11\xaa\xc5\x00\x1d\x7b\x95\x82\xe5\xe7\xd2\
\\x10\x98\x73\xf6\x00\x61\x30\x96\xc3\x2d\x95\x21\xad\xa1\x21\xff\x29\x90\x84\x15\x7f\xbb\x97\x7f\xaf\x9e\xb3\xdb\x29\xc9\xed\x2a\
\\x5c\xe2\xa4\x65\xa7\x30\xf3\x2c\xd0\xaa\x3f\xe8\x8a\x5c\xc0\x91\xd4\x9e\x2c\xe7\x0c\xe4\x54\xa9\xd6\x0a\xcd\x86\x01\x5f\x19\x19\
\\x77\x07\x91\x03\xde\xa0\x3a\xf6\x78\xa8\x56\x5e\xde\xe3\x56\xdf\x21\xf0\x5c\xbe\x8b\x75\xe3\x87\xb3\xc5\x06\x51\xb8\xa5\xc3\xef\
\\xd8\xee\xb6\xd2\xe5\x23\xbe\x77\xc2\x15\x45\x29\x2f\x69\xef\xdf\xaf\xe6\x7a\xfb\xf4\x70\xc4\xb2\xf3\xe0\xeb\x5b\xd6\xcc\x98\x76\
\\x39\xe4\x46\x0c\x1f\xda\x85\x38\x19\x87\x83\x2f\xca\x00\x73\x67\xa9\x91\x44\xf8\x29\x6b\x29\x9e\x49\x2f\xc2\x95\x92\x66\xbe\xab\
\\xb5\x67\x6e\x69\x9b\xd3\xdd\xda\xdf\x7e\x05\x2f\xdb\x25\x70\x1c\x1b\x5e\x51\xee\xf6\x53\x24\xe6\x6a\xfc\xe3\x6c\x03\x16\xcc\x04\
\\x86\x44\x21\x3e\xb7\xdc\x59\xd0\x79\x65\x29\x1f\xcc\xd6\xfd\x43\x41\x82\x39\x79\x93\x2b\xcd\xf6\xb6\x57\xc3\x4d\x4e\xdf\xd2\x82\
\\x7a\xe5\x29\x0c\x3c\xb9\x53\x6b\x85\x1e\x20\xfe\x98\x33\x55\x7e\x13\xec\xf0\xb0\xd3\xff\xb3\x72\x3f\x85\xc5\xc1\x0a\xef\x7e\xd2"#
sbox_s5 :: Word8 -> Word32
sbox_s5 i = arrayRead32 t (fromIntegral i)
where
t = array32FromAddrBE 256
"\x7e\xc9\x0c\x04\x2c\x6e\x74\xb9\x9b\x0e\x66\xdf\xa6\x33\x79\x11\xb8\x6a\x7f\xff\x1d\xd3\x58\xf5\x44\xdd\x9d\x44\x17\x31\x16\x7f\
\\x08\xfb\xf1\xfa\xe7\xf5\x11\xcc\xd2\x05\x1b\x00\x73\x5a\xba\x00\x2a\xb7\x22\xd8\x38\x63\x81\xcb\xac\xf6\x24\x3a\x69\xbe\xfd\x7a\
\\xe6\xa2\xe7\x7f\xf0\xc7\x20\xcd\xc4\x49\x48\x16\xcc\xf5\xc1\x80\x38\x85\x16\x40\x15\xb0\xa8\x48\xe6\x8b\x18\xcb\x4c\xaa\xde\xff\
\\x5f\x48\x0a\x01\x04\x12\xb2\xaa\x25\x98\x14\xfc\x41\xd0\xef\xe2\x4e\x40\xb4\x8d\x24\x8e\xb6\xfb\x8d\xba\x1c\xfe\x41\xa9\x9b\x02\
\\x1a\x55\x0a\x04\xba\x8f\x65\xcb\x72\x51\xf4\xe7\x95\xa5\x17\x25\xc1\x06\xec\xd7\x97\xa5\x98\x0a\xc5\x39\xb9\xaa\x4d\x79\xfe\x6a\
\\xf2\xf3\xf7\x63\x68\xaf\x80\x40\xed\x0c\x9e\x56\x11\xb4\x95\x8b\xe1\xeb\x5a\x88\x87\x09\xe6\xb0\xd7\xe0\x71\x56\x4e\x29\xfe\xa7\
\\x63\x66\xe5\x2d\x02\xd1\xc0\x00\xc4\xac\x8e\x05\x93\x77\xf5\x71\x0c\x05\x37\x2a\x57\x85\x35\xf2\x22\x61\xbe\x02\xd6\x42\xa0\xc9\
\\xdf\x13\xa2\x80\x74\xb5\x5b\xd2\x68\x21\x99\xc0\xd4\x21\xe5\xec\x53\xfb\x3c\xe8\xc8\xad\xed\xb3\x28\xa8\x7f\xc9\x3d\x95\x99\x81\
\\x5c\x1f\xf9\x00\xfe\x38\xd3\x99\x0c\x4e\xff\x0b\x06\x24\x07\xea\xaa\x2f\x4f\xb1\x4f\xb9\x69\x76\x90\xc7\x95\x05\xb0\xa8\xa7\x74\
\\xef\x55\xa1\xff\xe5\x9c\xa2\xc2\xa6\xb6\x2d\x27\xe6\x6a\x42\x63\xdf\x65\x00\x1f\x0e\xc5\x09\x66\xdf\xdd\x55\xbc\x29\xde\x06\x55\
\\x91\x1e\x73\x9a\x17\xaf\x89\x75\x32\xc7\x91\x1c\x89\xf8\x94\x68\x0d\x01\xe9\x80\x52\x47\x55\xf4\x03\xb6\x3c\xc9\x0c\xc8\x44\xb2\
\\xbc\xf3\xf0\xaa\x87\xac\x36\xe9\xe5\x3a\x74\x26\x01\xb3\xd8\x2b\x1a\x9e\x74\x49\x64\xee\x2d\x7e\xcd\xdb\xb1\xda\x01\xc9\x49\x10\
\\xb8\x68\xbf\x80\x0d\x26\xf3\xfd\x93\x42\xed\xe7\x04\xa5\xc2\x84\x63\x67\x37\xb6\x50\xf5\xb6\x16\xf2\x47\x66\xe3\x8e\xca\x36\xc1\
\\x13\x6e\x05\xdb\xfe\xf1\x83\x91\xfb\x88\x7a\x37\xd6\xe7\xf7\xd4\xc7\xfb\x7d\xc9\x30\x63\xfc\xdf\xb6\xf5\x89\xde\xec\x29\x41\xda\
\\x26\xe4\x66\x95\xb7\x56\x64\x19\xf6\x54\xef\xc5\xd0\x8d\x58\xb7\x48\x92\x54\x01\xc1\xba\xcb\x7f\xe5\xff\x55\x0f\xb6\x08\x30\x49\
\\x5b\xb5\xd0\xe8\x87\xd7\x2e\x5a\xab\x6a\x6e\xe1\x22\x3a\x66\xce\xc6\x2b\xf3\xcd\x9e\x08\x85\xf9\x68\xcb\x3e\x47\x08\x6c\x01\x0f\
\\xa2\x1d\xe8\x20\xd1\x8b\x69\xde\xf3\xf6\x57\x77\xfa\x02\xc3\xf6\x40\x7e\xda\xc3\xcb\xb3\xd5\x50\x17\x93\x08\x4d\xb0\xd7\x0e\xba\
\\x0a\xb3\x78\xd5\xd9\x51\xfb\x0c\xde\xd7\xda\x56\x41\x24\xbb\xe4\x94\xca\x0b\x56\x0f\x57\x55\xd1\xe0\xe1\xe5\x6e\x61\x84\xb5\xbe\
\\x58\x0a\x24\x9f\x94\xf7\x4b\xc0\xe3\x27\x88\x8e\x9f\x7b\x55\x61\xc3\xdc\x02\x80\x05\x68\x77\x15\x64\x6c\x6b\xd7\x44\x90\x4d\xb3\
\\x66\xb4\xf0\xa3\xc0\xf1\x64\x8a\x69\x7e\xd5\xaf\x49\xe9\x2f\xf6\x30\x9e\x37\x4f\x2c\xb6\x35\x6a\x85\x80\x85\x73\x49\x91\xf8\x40\
\\x76\xf0\xae\x02\x08\x3b\xe8\x4d\x28\x42\x1c\x9a\x44\x48\x94\x06\x73\x6e\x4c\xb8\xc1\x09\x29\x10\x8b\xc9\x5f\xc6\x7d\x86\x9c\xf4\
\\x13\x4f\x61\x6f\x2e\x77\x11\x8d\xb3\x1b\x2b\xe1\xaa\x90\xb4\x72\x3c\xa5\xd7\x17\x7d\x16\x1b\xba\x9c\xad\x90\x10\xaf\x46\x2b\xa2\
\\x9f\xe4\x59\xd2\x45\xd3\x45\x59\xd9\xf2\xda\x13\xdb\xc6\x54\x87\xf3\xe4\xf9\x4e\x17\x6d\x48\x6f\x09\x7c\x13\xea\x63\x1d\xa5\xc7\
\\x44\x5f\x73\x82\x17\x56\x83\xf4\xcd\xc6\x6a\x97\x70\xbe\x02\x88\xb3\xcd\xcf\x72\x6e\x5d\xd2\xf3\x20\x93\x60\x79\x45\x9b\x80\xa5\
\\xbe\x60\xe2\xdb\xa9\xc2\x31\x01\xeb\xa5\x31\x5c\x22\x4e\x42\xf2\x1c\x5c\x15\x72\xf6\x72\x1b\x2c\x1a\xd2\xff\xf3\x8c\x25\x40\x4e\
\\x32\x4e\xd7\x2f\x40\x67\xb7\xfd\x05\x23\x13\x8e\x5c\xa3\xbc\x78\xdc\x0f\xd6\x6e\x75\x92\x22\x83\x78\x4d\x6b\x17\x58\xeb\xb1\x6e\
\\x44\x09\x4f\x85\x3f\x48\x1d\x87\xfc\xfe\xae\x7b\x77\xb5\xff\x76\x8c\x23\x02\xbf\xaa\xf4\x75\x56\x5f\x46\xb0\x2a\x2b\x09\x28\x01\
\\x3d\x38\xf5\xf7\x0c\xa8\x1f\x36\x52\xaf\x4a\x8a\x66\xd5\xe7\xc0\xdf\x3b\x08\x74\x95\x05\x51\x10\x1b\x5a\xd7\xa8\xf6\x1e\xd5\xad\
\\x6c\xf6\xe4\x79\x20\x75\x81\x84\xd0\xce\xfa\x65\x88\xf7\xbe\x58\x4a\x04\x68\x26\x0f\xf6\xf8\xf3\xa0\x9c\x7f\x70\x53\x46\xab\xa0\
\\x5c\xe9\x6c\x28\xe1\x76\xed\xa3\x6b\xac\x30\x7f\x37\x68\x29\xd2\x85\x36\x0f\xa9\x17\xe3\xfe\x2a\x24\xb7\x97\x67\xf5\xa9\x6b\x20\
\\xd6\xcd\x25\x95\x68\xff\x1e\xbf\x75\x55\x44\x2c\xf1\x9f\x06\xbe\xf9\xe0\x65\x9a\xee\xb9\x49\x1d\x34\x01\x07\x18\xbb\x30\xca\xb8\
\\xe8\x22\xfe\x15\x88\x57\x09\x83\x75\x0e\x62\x49\xda\x62\x7e\x55\x5e\x76\xff\xa8\xb1\x53\x45\x46\x6d\x47\xde\x08\xef\xe9\xe7\xd4"#
sbox_s6 :: Word8 -> Word32
sbox_s6 i = arrayRead32 t (fromIntegral i)
where
t = array32FromAddrBE 256
"\xf6\xfa\x8f\x9d\x2c\xac\x6c\xe1\x4c\xa3\x48\x67\xe2\x33\x7f\x7c\x95\xdb\x08\xe7\x01\x68\x43\xb4\xec\xed\x5c\xbc\x32\x55\x53\xac\
\\xbf\x9f\x09\x60\xdf\xa1\xe2\xed\x83\xf0\x57\x9d\x63\xed\x86\xb9\x1a\xb6\xa6\xb8\xde\x5e\xbe\x39\xf3\x8f\xf7\x32\x89\x89\xb1\x38\
\\x33\xf1\x49\x61\xc0\x19\x37\xbd\xf5\x06\xc6\xda\xe4\x62\x5e\x7e\xa3\x08\xea\x99\x4e\x23\xe3\x3c\x79\xcb\xd7\xcc\x48\xa1\x43\x67\
\\xa3\x14\x96\x19\xfe\xc9\x4b\xd5\xa1\x14\x17\x4a\xea\xa0\x18\x66\xa0\x84\xdb\x2d\x09\xa8\x48\x6f\xa8\x88\x61\x4a\x29\x00\xaf\x98\
\\x01\x66\x59\x91\xe1\x99\x28\x63\xc8\xf3\x0c\x60\x2e\x78\xef\x3c\xd0\xd5\x19\x32\xcf\x0f\xec\x14\xf7\xca\x07\xd2\xd0\xa8\x20\x72\
\\xfd\x41\x19\x7e\x93\x05\xa6\xb0\xe8\x6b\xe3\xda\x74\xbe\xd3\xcd\x37\x2d\xa5\x3c\x4c\x7f\x44\x48\xda\xb5\xd4\x40\x6d\xba\x0e\xc3\
\\x08\x39\x19\xa7\x9f\xba\xee\xd9\x49\xdb\xcf\xb0\x4e\x67\x0c\x53\x5c\x3d\x9c\x01\x64\xbd\xb9\x41\x2c\x0e\x63\x6a\xba\x7d\xd9\xcd\
\\xea\x6f\x73\x88\xe7\x0b\xc7\x62\x35\xf2\x9a\xdb\x5c\x4c\xdd\x8d\xf0\xd4\x8d\x8c\xb8\x81\x53\xe2\x08\xa1\x98\x66\x1a\xe2\xea\xc8\
\\x28\x4c\xaf\x89\xaa\x92\x82\x23\x93\x34\xbe\x53\x3b\x3a\x21\xbf\x16\x43\x4b\xe3\x9a\xea\x39\x06\xef\xe8\xc3\x6e\xf8\x90\xcd\xd9\
\\x80\x22\x6d\xae\xc3\x40\xa4\xa3\xdf\x7e\x9c\x09\xa6\x94\xa8\x07\x5b\x7c\x5e\xcc\x22\x1d\xb3\xa6\x9a\x69\xa0\x2f\x68\x81\x8a\x54\
\\xce\xb2\x29\x6f\x53\xc0\x84\x3a\xfe\x89\x36\x55\x25\xbf\xe6\x8a\xb4\x62\x8a\xbc\xcf\x22\x2e\xbf\x25\xac\x6f\x48\xa9\xa9\x93\x87\
\\x53\xbd\xdb\x65\xe7\x6f\xfb\xe7\xe9\x67\xfd\x78\x0b\xa9\x35\x63\x8e\x34\x2b\xc1\xe8\xa1\x1b\xe9\x49\x80\x74\x0d\xc8\x08\x7d\xfc\
\\x8d\xe4\xbf\x99\xa1\x11\x01\xa0\x7f\xd3\x79\x75\xda\x5a\x26\xc0\xe8\x1f\x99\x4f\x95\x28\xcd\x89\xfd\x33\x9f\xed\xb8\x78\x34\xbf\
\\x5f\x04\x45\x6d\x22\x25\x86\x98\xc9\xc4\xc8\x3b\x2d\xc1\x56\xbe\x4f\x62\x8d\xaa\x57\xf5\x5e\xc5\xe2\x22\x0a\xbe\xd2\x91\x6e\xbf\
\\x4e\xc7\x5b\x95\x24\xf2\xc3\xc0\x42\xd1\x5d\x99\xcd\x0d\x7f\xa0\x7b\x6e\x27\xff\xa8\xdc\x8a\xf0\x73\x45\xc1\x06\xf4\x1e\x23\x2f\
\\x35\x16\x23\x86\xe6\xea\x89\x26\x33\x33\xb0\x94\x15\x7e\xc6\xf2\x37\x2b\x74\xaf\x69\x25\x73\xe4\xe9\xa9\xd8\x48\xf3\x16\x02\x89\
\\x3a\x62\xef\x1d\xa7\x87\xe2\x38\xf3\xa5\xf6\x76\x74\x36\x48\x53\x20\x95\x10\x63\x45\x76\x69\x8d\xb6\xfa\xd4\x07\x59\x2a\xf9\x50\
\\x36\xf7\x35\x23\x4c\xfb\x6e\x87\x7d\xa4\xce\xc0\x6c\x15\x2d\xaa\xcb\x03\x96\xa8\xc5\x0d\xfe\x5d\xfc\xd7\x07\xab\x09\x21\xc4\x2f\
\\x89\xdf\xf0\xbb\x5f\xe2\xbe\x78\x44\x8f\x4f\x33\x75\x46\x13\xc9\x2b\x05\xd0\x8d\x48\xb9\xd5\x85\xdc\x04\x94\x41\xc8\x09\x8f\x9b\
\\x7d\xed\xe7\x86\xc3\x9a\x33\x73\x42\x41\x00\x05\x6a\x09\x17\x51\x0e\xf3\xc8\xa6\x89\x00\x72\xd6\x28\x20\x76\x82\xa9\xa9\xf7\xbe\
\\xbf\x32\x67\x9d\xd4\x5b\x5b\x75\xb3\x53\xfd\x00\xcb\xb0\xe3\x58\x83\x0f\x22\x0a\x1f\x8f\xb2\x14\xd3\x72\xcf\x08\xcc\x3c\x4a\x13\
\\x8c\xf6\x31\x66\x06\x1c\x87\xbe\x88\xc9\x8f\x88\x60\x62\xe3\x97\x47\xcf\x8e\x7a\xb6\xc8\x52\x83\x3c\xc2\xac\xfb\x3f\xc0\x69\x76\
\\x4e\x8f\x02\x52\x64\xd8\x31\x4d\xda\x38\x70\xe3\x1e\x66\x54\x59\xc1\x09\x08\xf0\x51\x30\x21\xa5\x6c\x5b\x68\xb7\x82\x2f\x8a\xa0\
\\x30\x07\xcd\x3e\x74\x71\x9e\xef\xdc\x87\x26\x81\x07\x33\x40\xd4\x7e\x43\x2f\xd9\x0c\x5e\xc2\x41\x88\x09\x28\x6c\xf5\x92\xd8\x91\
\\x08\xa9\x30\xf6\x95\x7e\xf3\x05\xb7\xfb\xff\xbd\xc2\x66\xe9\x6f\x6f\xe4\xac\x98\xb1\x73\xec\xc0\xbc\x60\xb4\x2a\x95\x34\x98\xda\
\\xfb\xa1\xae\x12\x2d\x4b\xd7\x36\x0f\x25\xfa\xab\xa4\xf3\xfc\xeb\xe2\x96\x91\x23\x25\x7f\x0c\x3d\x93\x48\xaf\x49\x36\x14\x00\xbc\
\\xe8\x81\x6f\x4a\x38\x14\xf2\x00\xa3\xf9\x40\x43\x9c\x7a\x54\xc2\xbc\x70\x4f\x57\xda\x41\xe7\xf9\xc2\x5a\xd3\x3a\x54\xf4\xa0\x84\
\\xb1\x7f\x55\x05\x59\x35\x7c\xbe\xed\xbd\x15\xc8\x7f\x97\xc5\xab\xba\x5a\xc7\xb5\xb6\xf6\xde\xaf\x3a\x47\x9c\x3a\x53\x02\xda\x25\
\\x65\x3d\x7e\x6a\x54\x26\x8d\x49\x51\xa4\x77\xea\x50\x17\xd5\x5b\xd7\xd2\x5d\x88\x44\x13\x6c\x76\x04\x04\xa8\xc8\xb8\xe5\xa1\x21\
\\xb8\x1a\x92\x8a\x60\xed\x58\x69\x97\xc5\x5b\x96\xea\xec\x99\x1b\x29\x93\x59\x13\x01\xfd\xb7\xf1\x08\x8e\x8d\xfa\x9a\xb6\xf6\xf5\
\\x3b\x4c\xbf\x9f\x4a\x5d\xe3\xab\xe6\x05\x1d\x35\xa0\xe1\xd8\x55\xd3\x6b\x4c\xf1\xf5\x44\xed\xeb\xb0\xe9\x35\x24\xbe\xbb\x8f\xbd\
\\xa2\xd7\x62\xcf\x49\xc9\x2f\x54\x38\xb5\xf3\x31\x71\x28\xa4\x54\x48\x39\x29\x05\xa6\x5b\x1d\xb8\x85\x1c\x97\xbd\xd6\x75\xcf\x2f"#
sbox_s7 :: Word8 -> Word32
sbox_s7 i = arrayRead32 t (fromIntegral i)
where
t = array32FromAddrBE 256
"\x85\xe0\x40\x19\x33\x2b\xf5\x67\x66\x2d\xbf\xff\xcf\xc6\x56\x93\x2a\x8d\x7f\x6f\xab\x9b\xc9\x12\xde\x60\x08\xa1\x20\x28\xda\x1f\
\\x02\x27\xbc\xe7\x4d\x64\x29\x16\x18\xfa\xc3\x00\x50\xf1\x8b\x82\x2c\xb2\xcb\x11\xb2\x32\xe7\x5c\x4b\x36\x95\xf2\xb2\x87\x07\xde\
\\xa0\x5f\xbc\xf6\xcd\x41\x81\xe9\xe1\x50\x21\x0c\xe2\x4e\xf1\xbd\xb1\x68\xc3\x81\xfd\xe4\xe7\x89\x5c\x79\xb0\xd8\x1e\x8b\xfd\x43\
\\x4d\x49\x50\x01\x38\xbe\x43\x41\x91\x3c\xee\x1d\x92\xa7\x9c\x3f\x08\x97\x66\xbe\xba\xee\xad\xf4\x12\x86\xbe\xcf\xb6\xea\xcb\x19\
\\x26\x60\xc2\x00\x75\x65\xbd\xe4\x64\x24\x1f\x7a\x82\x48\xdc\xa9\xc3\xb3\xad\x66\x28\x13\x60\x86\x0b\xd8\xdf\xa8\x35\x6d\x1c\xf2\
\\x10\x77\x89\xbe\xb3\xb2\xe9\xce\x05\x02\xaa\x8f\x0b\xc0\x35\x1e\x16\x6b\xf5\x2a\xeb\x12\xff\x82\xe3\x48\x69\x11\xd3\x4d\x75\x16\
\\x4e\x7b\x3a\xff\x5f\x43\x67\x1b\x9c\xf6\xe0\x37\x49\x81\xac\x83\x33\x42\x66\xce\x8c\x93\x41\xb7\xd0\xd8\x54\xc0\xcb\x3a\x6c\x88\
\\x47\xbc\x28\x29\x47\x25\xba\x37\xa6\x6a\xd2\x2b\x7a\xd6\x1f\x1e\x0c\x5c\xba\xfa\x44\x37\xf1\x07\xb6\xe7\x99\x62\x42\xd2\xd8\x16\
\\x0a\x96\x12\x88\xe1\xa5\xc0\x6e\x13\x74\x9e\x67\x72\xfc\x08\x1a\xb1\xd1\x39\xf7\xf9\x58\x37\x45\xcf\x19\xdf\x58\xbe\xc3\xf7\x56\
\\xc0\x6e\xba\x30\x07\x21\x1b\x24\x45\xc2\x88\x29\xc9\x5e\x31\x7f\xbc\x8e\xc5\x11\x38\xbc\x46\xe9\xc6\xe6\xfa\x14\xba\xe8\x58\x4a\
\\xad\x4e\xbc\x46\x46\x8f\x50\x8b\x78\x29\x43\x5f\xf1\x24\x18\x3b\x82\x1d\xba\x9f\xaf\xf6\x0f\xf4\xea\x2c\x4e\x6d\x16\xe3\x92\x64\
\\x92\x54\x4a\x8b\x00\x9b\x4f\xc3\xab\xa6\x8c\xed\x9a\xc9\x6f\x78\x06\xa5\xb7\x9a\xb2\x85\x6e\x6e\x1a\xec\x3c\xa9\xbe\x83\x86\x88\
\\x0e\x08\x04\xe9\x55\xf1\xbe\x56\xe7\xe5\x36\x3b\xb3\xa1\xf2\x5d\xf7\xde\xbb\x85\x61\xfe\x03\x3c\x16\x74\x62\x33\x3c\x03\x4c\x28\
\\xda\x6d\x0c\x74\x79\xaa\xc5\x6c\x3c\xe4\xe1\xad\x51\xf0\xc8\x02\x98\xf8\xf3\x5a\x16\x26\xa4\x9f\xee\xd8\x2b\x29\x1d\x38\x2f\xe3\
\\x0c\x4f\xb9\x9a\xbb\x32\x57\x78\x3e\xc6\xd9\x7b\x6e\x77\xa6\xa9\xcb\x65\x8b\x5c\xd4\x52\x30\xc7\x2b\xd1\x40\x8b\x60\xc0\x3e\xb7\
\\xb9\x06\x8d\x78\xa3\x37\x54\xf4\xf4\x30\xc8\x7d\xc8\xa7\x13\x02\xb9\x6d\x8c\x32\xeb\xd4\xe7\xbe\xbe\x8b\x9d\x2d\x79\x79\xfb\x06\
\\xe7\x22\x53\x08\x8b\x75\xcf\x77\x11\xef\x8d\xa4\xe0\x83\xc8\x58\x8d\x6b\x78\x6f\x5a\x63\x17\xa6\xfa\x5c\xf7\xa0\x5d\xda\x00\x33\
\\xf2\x8e\xbf\xb0\xf5\xb9\xc3\x10\xa0\xea\xc2\x80\x08\xb9\x76\x7a\xa3\xd9\xd2\xb0\x79\xd3\x42\x17\x02\x1a\x71\x8d\x9a\xc6\x33\x6a\
\\x27\x11\xfd\x60\x43\x80\x50\xe3\x06\x99\x08\xa8\x3d\x7f\xed\xc4\x82\x6d\x2b\xef\x4e\xeb\x84\x76\x48\x8d\xcf\x25\x36\xc9\xd5\x66\
\\x28\xe7\x4e\x41\xc2\x61\x0a\xca\x3d\x49\xa9\xcf\xba\xe3\xb9\xdf\xb6\x5f\x8d\xe6\x92\xae\xaf\x64\x3a\xc7\xd5\xe6\x9e\xa8\x05\x09\
\\xf2\x2b\x01\x7d\xa4\x17\x3f\x70\xdd\x1e\x16\xc3\x15\xe0\xd7\xf9\x50\xb1\xb8\x87\x2b\x9f\x4f\xd5\x62\x5a\xba\x82\x6a\x01\x79\x62\
\\x2e\xc0\x1b\x9c\x15\x48\x8a\xa9\xd7\x16\xe7\x40\x40\x05\x5a\x2c\x93\xd2\x9a\x22\xe3\x2d\xbf\x9a\x05\x87\x45\xb9\x34\x53\xdc\x1e\
\\xd6\x99\x29\x6e\x49\x6c\xff\x6f\x1c\x9f\x49\x86\xdf\xe2\xed\x07\xb8\x72\x42\xd1\x19\xde\x7e\xae\x05\x3e\x56\x1a\x15\xad\x6f\x8c\
\\x66\x62\x6c\x1c\x71\x54\xc2\x4c\xea\x08\x2b\x2a\x93\xeb\x29\x39\x17\xdc\xb0\xf0\x58\xd4\xf2\xae\x9e\xa2\x94\xfb\x52\xcf\x56\x4c\
\\x98\x83\xfe\x66\x2e\xc4\x05\x81\x76\x39\x53\xc3\x01\xd6\x69\x2e\xd3\xa0\xc1\x08\xa1\xe7\x16\x0e\xe4\xf2\xdf\xa6\x69\x3e\xd2\x85\
\\x74\x90\x46\x98\x4c\x2b\x0e\xdd\x4f\x75\x76\x56\x5d\x39\x33\x78\xa1\x32\x23\x4f\x3d\x32\x1c\x5d\xc3\xf5\xe1\x94\x4b\x26\x93\x01\
\\xc7\x9f\x02\x2f\x3c\x99\x7e\x7e\x5e\x4f\x95\x04\x3f\xfa\xfb\xbd\x76\xf7\xad\x0e\x29\x66\x93\xf4\x3d\x1f\xce\x6f\xc6\x1e\x45\xbe\
\\xd3\xb5\xab\x34\xf7\x2b\xf9\xb7\x1b\x04\x34\xc0\x4e\x72\xb5\x67\x55\x92\xa3\x3d\xb5\x22\x93\x01\xcf\xd2\xa8\x7f\x60\xae\xb7\x67\
\\x18\x14\x38\x6b\x30\xbc\xc3\x3d\x38\xa0\xc0\x7d\xfd\x16\x06\xf2\xc3\x63\x51\x9b\x58\x9d\xd3\x90\x54\x79\xf8\xe6\x1c\xb8\xd6\x47\
\\x97\xfd\x61\xa9\xea\x77\x59\xf4\x2d\x57\x53\x9d\x56\x9a\x58\xcf\xe8\x4e\x63\xad\x46\x2e\x1b\x78\x65\x80\xf8\x7e\xf3\x81\x79\x14\
\\x91\xda\x55\xf4\x40\xa2\x30\xf3\xd1\x98\x8f\x35\xb6\xe3\x18\xd2\x3f\xfa\x50\xbc\x3d\x40\xf0\x21\xc3\xc0\xbd\xae\x49\x58\xc2\x4c\
\\x51\x8f\x36\xb2\x84\xb1\xd3\x70\x0f\xed\xce\x83\x87\x8d\xda\xda\xf2\xa2\x79\xc7\x94\xe0\x1b\xe8\x90\x71\x6f\x4b\x95\x4b\x8a\xa3"#
sbox_s8 :: Word8 -> Word32
sbox_s8 i = arrayRead32 t (fromIntegral i)
where
t = array32FromAddrBE 256
"\xe2\x16\x30\x0d\xbb\xdd\xff\xfc\xa7\xeb\xda\xbd\x35\x64\x80\x95\x77\x89\xf8\xb7\xe6\xc1\x12\x1b\x0e\x24\x16\x00\x05\x2c\xe8\xb5\
\\x11\xa9\xcf\xb0\xe5\x95\x2f\x11\xec\xe7\x99\x0a\x93\x86\xd1\x74\x2a\x42\x93\x1c\x76\xe3\x81\x11\xb1\x2d\xef\x3a\x37\xdd\xdd\xfc\
\\xde\x9a\xde\xb1\x0a\x0c\xc3\x2c\xbe\x19\x70\x29\x84\xa0\x09\x40\xbb\x24\x3a\x0f\xb4\xd1\x37\xcf\xb4\x4e\x79\xf0\x04\x9e\xed\xfd\
\\x0b\x15\xa1\x5d\x48\x0d\x31\x68\x8b\xbb\xde\x5a\x66\x9d\xed\x42\xc7\xec\xe8\x31\x3f\x8f\x95\xe7\x72\xdf\x19\x1b\x75\x80\x33\x0d\
\\x94\x07\x42\x51\x5c\x7d\xcd\xfa\xab\xbe\x6d\x63\xaa\x40\x21\x64\xb3\x01\xd4\x0a\x02\xe7\xd1\xca\x53\x57\x1d\xae\x7a\x31\x82\xa2\
\\x12\xa8\xdd\xec\xfd\xaa\x33\x5d\x17\x6f\x43\xe8\x71\xfb\x46\xd4\x38\x12\x90\x22\xce\x94\x9a\xd4\xb8\x47\x69\xad\x96\x5b\xd8\x62\
\\x82\xf3\xd0\x55\x66\xfb\x97\x67\x15\xb8\x0b\x4e\x1d\x5b\x47\xa0\x4c\xfd\xe0\x6f\xc2\x8e\xc4\xb8\x57\xe8\x72\x6e\x64\x7a\x78\xfc\
\\x99\x86\x5d\x44\x60\x8b\xd5\x93\x6c\x20\x0e\x03\x39\xdc\x5f\xf6\x5d\x0b\x00\xa3\xae\x63\xaf\xf2\x7e\x8b\xd6\x32\x70\x10\x8c\x0c\
\\xbb\xd3\x50\x49\x29\x98\xdf\x04\x98\x0c\xf4\x2a\x9b\x6d\xf4\x91\x9e\x7e\xdd\x53\x06\x91\x85\x48\x58\xcb\x7e\x07\x3b\x74\xef\x2e\
\\x52\x2f\xff\xb1\xd2\x47\x08\xcc\x1c\x7e\x27\xcd\xa4\xeb\x21\x5b\x3c\xf1\xd2\xe2\x19\xb4\x7a\x38\x42\x4f\x76\x18\x35\x85\x60\x39\
\\x9d\x17\xde\xe7\x27\xeb\x35\xe6\xc9\xaf\xf6\x7b\x36\xba\xf5\xb8\x09\xc4\x67\xcd\xc1\x89\x10\xb1\xe1\x1d\xbf\x7b\x06\xcd\x1a\xf8\
\\x71\x70\xc6\x08\x2d\x5e\x33\x54\xd4\xde\x49\x5a\x64\xc6\xd0\x06\xbc\xc0\xc6\x2c\x3d\xd0\x0d\xb3\x70\x8f\x8f\x34\x77\xd5\x1b\x42\
\\x26\x4f\x62\x0f\x24\xb8\xd2\xbf\x15\xc1\xb7\x9e\x46\xa5\x25\x64\xf8\xd7\xe5\x4e\x3e\x37\x81\x60\x78\x95\xcd\xa5\x85\x9c\x15\xa5\
\\xe6\x45\x97\x88\xc3\x7b\xc7\x5f\xdb\x07\xba\x0c\x06\x76\xa3\xab\x7f\x22\x9b\x1e\x31\x84\x2e\x7b\x24\x25\x9f\xd7\xf8\xbe\xf4\x72\
\\x83\x5f\xfc\xb8\x6d\xf4\xc1\xf2\x96\xf5\xb1\x95\xfd\x0a\xf0\xfc\xb0\xfe\x13\x4c\xe2\x50\x6d\x3d\x4f\x9b\x12\xea\xf2\x15\xf2\x25\
\\xa2\x23\x73\x6f\x9f\xb4\xc4\x28\x25\xd0\x49\x79\x34\xc7\x13\xf8\xc4\x61\x81\x87\xea\x7a\x6e\x98\x7c\xd1\x6e\xfc\x14\x36\x87\x6c\
\\xf1\x54\x41\x07\xbe\xde\xee\x14\x56\xe9\xaf\x27\xa0\x4a\xa4\x41\x3c\xf7\xc8\x99\x92\xec\xba\xe6\xdd\x67\x01\x6d\x15\x16\x82\xeb\
\\xa8\x42\xee\xdf\xfd\xba\x60\xb4\xf1\x90\x7b\x75\x20\xe3\x03\x0f\x24\xd8\xc2\x9e\xe1\x39\x67\x3b\xef\xa6\x3f\xb8\x71\x87\x30\x54\
\\xb6\xf2\xcf\x3b\x9f\x32\x64\x42\xcb\x15\xa4\xcc\xb0\x1a\x45\x04\xf1\xe4\x7d\x8d\x84\x4a\x1b\xe5\xba\xe7\xdf\xdc\x42\xcb\xda\x70\
\\xcd\x7d\xae\x0a\x57\xe8\x5b\x7a\xd5\x3f\x5a\xf6\x20\xcf\x4d\x8c\xce\xa4\xd4\x28\x79\xd1\x30\xa4\x34\x86\xeb\xfb\x33\xd3\xcd\xdc\
\\x77\x85\x3b\x53\x37\xef\xfc\xb5\xc5\x06\x87\x78\xe5\x80\xb3\xe6\x4e\x68\xb8\xf4\xc5\xc8\xb3\x7e\x0d\x80\x9e\xa2\x39\x8f\xeb\x7c\
\\x13\x2a\x4f\x94\x43\xb7\x95\x0e\x2f\xee\x7d\x1c\x22\x36\x13\xbd\xdd\x06\xca\xa2\x37\xdf\x93\x2b\xc4\x24\x82\x89\xac\xf3\xeb\xc3\
\\x57\x15\xf6\xb7\xef\x34\x78\xdd\xf2\x67\x61\x6f\xc1\x48\xcb\xe4\x90\x52\x81\x5e\x5e\x41\x0f\xab\xb4\x8a\x24\x65\x2e\xda\x7f\xa4\
\\xe8\x7b\x40\xe4\xe9\x8e\xa0\x84\x58\x89\xe9\xe1\xef\xd3\x90\xfc\xdd\x07\xd3\x5b\xdb\x48\x56\x94\x38\xd7\xe5\xb2\x57\x72\x01\x01\
\\x73\x0e\xde\xbc\x5b\x64\x31\x13\x94\x91\x7e\x4f\x50\x3c\x2f\xba\x64\x6f\x12\x82\x75\x23\xd2\x4a\xe0\x77\x96\x95\xf9\xc1\x7a\x8f\
\\x7a\x5b\x21\x21\xd1\x87\xb8\x96\x29\x26\x3a\x4d\xba\x51\x0c\xdf\x81\xf4\x7c\x9f\xad\x11\x63\xed\xea\x7b\x59\x65\x1a\x00\x72\x6e\
\\x11\x40\x30\x92\x00\xda\x6d\x77\x4a\x0c\xdd\x61\xad\x1f\x46\x03\x60\x5b\xdf\xb0\x9e\xed\xc3\x64\x22\xeb\xe6\xa8\xce\xe7\xd2\x8a\
\\xa0\xe7\x36\xa0\x55\x64\xa6\xb9\x10\x85\x32\x09\xc7\xeb\x8f\x37\x2d\xe7\x05\xca\x89\x51\x57\x0f\xdf\x09\x82\x2b\xbd\x69\x1a\x6c\
\\xaa\x12\xe4\xf2\x87\x45\x1c\x0f\xe0\xf6\xa2\x7a\x3a\xda\x48\x19\x4c\xf1\x76\x4f\x0d\x77\x1c\x2b\x67\xcd\xb1\x56\x35\x0d\x83\x84\
\\x59\x38\xfa\x0f\x42\x39\x9e\xf3\x36\x99\x7b\x07\x0e\x84\x09\x3d\x4a\xa9\x3e\x61\x83\x60\xd8\x7b\x1f\xa9\x8b\x0c\x11\x49\x38\x2c\
\\xe9\x76\x25\xa5\x06\x14\xd1\xb7\x0e\x25\x24\x4b\x0c\x76\x83\x47\x58\x9e\x8d\x82\x0d\x20\x59\xd1\xa4\x66\xbb\x1e\xf8\xda\x0a\x82\
\\x04\xf1\x91\x30\xba\x6e\x4e\xc0\x99\x26\x51\x64\x1e\xe7\x23\x0d\x50\xb2\xad\x80\xea\xee\x68\x01\x8d\xb2\xa2\x83\xea\x8b\xf5\x9e"#

View File

@ -6,8 +6,8 @@
-- Stability : experimental -- Stability : experimental
-- Portability : Good -- Portability : Good
-- --
-- this only cover Camellia 128 bits for now, API will change once -- This only cover Camellia 128 bits for now. The API will change once
-- 192 and 256 mode are implemented too -- 192 and 256 mode are implemented too.
{-# LANGUAGE MagicHash #-} {-# LANGUAGE MagicHash #-}
module Crypto.Cipher.Camellia.Primitive module Crypto.Cipher.Camellia.Primitive
( Camellia ( Camellia

View File

@ -12,7 +12,7 @@ module Crypto.Cipher.ChaCha
, combine , combine
, generate , generate
, State , State
-- * simple interface for DRG purpose -- * Simple interface for DRG purpose
, initializeSimple , initializeSimple
, generateSimple , generateSimple
, StateSimple , StateSimple
@ -41,24 +41,26 @@ initialize :: (ByteArrayAccess key, ByteArrayAccess nonce)
-> nonce -- ^ the nonce (64 or 96 bits) -> nonce -- ^ the nonce (64 or 96 bits)
-> State -- ^ the initial ChaCha state -> State -- ^ the initial ChaCha state
initialize nbRounds key nonce initialize nbRounds key nonce
| not (kLen `elem` [16,32]) = error "ChaCha: key length should be 128 or 256 bits" | kLen `notElem` [16,32] = error "ChaCha: key length should be 128 or 256 bits"
| not (nonceLen `elem` [8,12]) = error "ChaCha: nonce length should be 64 or 96 bits" | nonceLen `notElem` [8,12] = error "ChaCha: nonce length should be 64 or 96 bits"
| not (nbRounds `elem` [8,12,20]) = error "ChaCha: rounds should be 8, 12 or 20" | nbRounds `notElem` [8,12,20] = error "ChaCha: rounds should be 8, 12 or 20"
| otherwise = unsafeDoIO $ do | otherwise = unsafeDoIO $ do
stPtr <- B.alloc 132 $ \stPtr -> stPtr <- B.alloc 132 $ \stPtr ->
B.withByteArray nonce $ \noncePtr -> B.withByteArray nonce $ \noncePtr ->
B.withByteArray key $ \keyPtr -> B.withByteArray key $ \keyPtr ->
ccryptonite_chacha_init stPtr (fromIntegral nbRounds) kLen keyPtr nonceLen noncePtr ccryptonite_chacha_init stPtr nbRounds kLen keyPtr nonceLen noncePtr
return $ State stPtr return $ State stPtr
where kLen = B.length key where kLen = B.length key
nonceLen = B.length nonce nonceLen = B.length nonce
-- | Initialize simple ChaCha State -- | Initialize simple ChaCha State
initializeSimple :: ByteArray seed --
-- The seed need to be at least 40 bytes long
initializeSimple :: ByteArrayAccess seed
=> seed -- ^ a 40 bytes long seed => seed -- ^ a 40 bytes long seed
-> StateSimple -> StateSimple
initializeSimple seed initializeSimple seed
| sLen /= 40 = error "ChaCha Random: seed length should be 40 bytes" | sLen < 40 = error "ChaCha Random: seed length should be 40 bytes"
| otherwise = unsafeDoIO $ do | otherwise = unsafeDoIO $ do
stPtr <- B.alloc 64 $ \stPtr -> stPtr <- B.alloc 64 $ \stPtr ->
B.withByteArray seed $ \seedPtr -> B.withByteArray seed $ \seedPtr ->

View File

@ -30,6 +30,11 @@ import Crypto.Internal.Compat
import Crypto.Internal.Imports import Crypto.Internal.Imports
-- | The encryption state for RC4 -- | The encryption state for RC4
--
-- This type is an instance of 'ByteArrayAccess' for debugging purpose. Internal
-- layout is architecture dependent, may contain uninitialized data fragments,
-- and change in future versions. The bytearray should not be used as input to
-- cryptographic algorithms.
newtype State = State ScrubbedBytes newtype State = State ScrubbedBytes
deriving (ByteArrayAccess,NFData) deriving (ByteArrayAccess,NFData)

View File

@ -33,14 +33,14 @@ initialize :: (ByteArrayAccess key, ByteArrayAccess nonce)
-> nonce -- ^ the nonce (64 or 96 bits) -> nonce -- ^ the nonce (64 or 96 bits)
-> State -- ^ the initial Salsa state -> State -- ^ the initial Salsa state
initialize nbRounds key nonce initialize nbRounds key nonce
| not (kLen `elem` [16,32]) = error "Salsa: key length should be 128 or 256 bits" | kLen `notElem` [16,32] = error "Salsa: key length should be 128 or 256 bits"
| not (nonceLen `elem` [8,12]) = error "Salsa: nonce length should be 64 or 96 bits" | nonceLen `notElem` [8,12] = error "Salsa: nonce length should be 64 or 96 bits"
| not (nbRounds `elem` [8,12,20]) = error "Salsa: rounds should be 8, 12 or 20" | nbRounds `notElem` [8,12,20] = error "Salsa: rounds should be 8, 12 or 20"
| otherwise = unsafeDoIO $ do | otherwise = unsafeDoIO $ do
stPtr <- B.alloc 132 $ \stPtr -> stPtr <- B.alloc 132 $ \stPtr ->
B.withByteArray nonce $ \noncePtr -> B.withByteArray nonce $ \noncePtr ->
B.withByteArray key $ \keyPtr -> B.withByteArray key $ \keyPtr ->
ccryptonite_salsa_init stPtr (fromIntegral nbRounds) kLen keyPtr nonceLen noncePtr ccryptonite_salsa_init stPtr nbRounds kLen keyPtr nonceLen noncePtr
return $ State stPtr return $ State stPtr
where kLen = B.length key where kLen = B.length key
nonceLen = B.length nonce nonceLen = B.length nonce

45
Crypto/Cipher/Twofish.hs Normal file
View File

@ -0,0 +1,45 @@
module Crypto.Cipher.Twofish
( Twofish128
, Twofish192
, Twofish256
) where
import Crypto.Cipher.Twofish.Primitive
import Crypto.Cipher.Types
import Crypto.Cipher.Utils
newtype Twofish128 = Twofish128 Twofish
instance Cipher Twofish128 where
cipherName _ = "Twofish128"
cipherKeySize _ = KeySizeFixed 16
cipherInit key = Twofish128 <$> (initTwofish =<< validateKeySize (undefined :: Twofish128) key)
instance BlockCipher Twofish128 where
blockSize _ = 16
ecbEncrypt (Twofish128 key) = encrypt key
ecbDecrypt (Twofish128 key) = decrypt key
newtype Twofish192 = Twofish192 Twofish
instance Cipher Twofish192 where
cipherName _ = "Twofish192"
cipherKeySize _ = KeySizeFixed 24
cipherInit key = Twofish192 <$> (initTwofish =<< validateKeySize (undefined :: Twofish192) key)
instance BlockCipher Twofish192 where
blockSize _ = 16
ecbEncrypt (Twofish192 key) = encrypt key
ecbDecrypt (Twofish192 key) = decrypt key
newtype Twofish256 = Twofish256 Twofish
instance Cipher Twofish256 where
cipherName _ = "Twofish256"
cipherKeySize _ = KeySizeFixed 32
cipherInit key = Twofish256 <$> (initTwofish =<< validateKeySize (undefined :: Twofish256) key)
instance BlockCipher Twofish256 where
blockSize _ = 16
ecbEncrypt (Twofish256 key) = encrypt key
ecbDecrypt (Twofish256 key) = decrypt key

View File

@ -0,0 +1,311 @@
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE BangPatterns #-}
module Crypto.Cipher.Twofish.Primitive
( Twofish
, initTwofish
, encrypt
, decrypt
) where
import Crypto.Error
import Crypto.Internal.ByteArray (ByteArray)
import qualified Crypto.Internal.ByteArray as B
import Crypto.Internal.WordArray
import Data.Word
import Data.Bits
import Data.List
-- Based on the Golang referance implementation
-- https://github.com/golang/crypto/blob/master/twofish/twofish.go
-- BlockSize is the constant block size of Twofish.
blockSize :: Int
blockSize = 16
mdsPolynomial, rsPolynomial :: Word32
mdsPolynomial = 0x169 -- x^8 + x^6 + x^5 + x^3 + 1, see [TWOFISH] 4.2
rsPolynomial = 0x14d -- x^8 + x^6 + x^3 + x^2 + 1, see [TWOFISH] 4.3
data Twofish = Twofish { s :: (Array32, Array32, Array32, Array32)
, k :: Array32 }
data ByteSize = Bytes16 | Bytes24 | Bytes32 deriving (Eq)
data KeyPackage ba = KeyPackage { rawKeyBytes :: ba
, byteSize :: ByteSize }
buildPackage :: ByteArray ba => ba -> Maybe (KeyPackage ba)
buildPackage key
| B.length key == 16 = return $ KeyPackage key Bytes16
| B.length key == 24 = return $ KeyPackage key Bytes24
| B.length key == 32 = return $ KeyPackage key Bytes32
| otherwise = Nothing
-- | Initialize a 128-bit, 192-bit, or 256-bit key
--
-- Return the initialized key or a error message if the given
-- keyseed was not 16-bytes in length.
initTwofish :: ByteArray key
=> key -- ^ The key to create the twofish context
-> CryptoFailable Twofish
initTwofish key =
case buildPackage key of Nothing -> CryptoFailed CryptoError_KeySizeInvalid
Just keyPackage -> CryptoPassed Twofish { k = generatedK, s = generatedS }
where generatedK = array32 40 $ genK keyPackage
generatedS = genSboxes keyPackage $ sWords key
mapBlocks :: ByteArray ba => (ba -> ba) -> ba -> ba
mapBlocks operation input
| B.null rest = blockOutput
| otherwise = blockOutput `B.append` mapBlocks operation rest
where (block, rest) = B.splitAt blockSize input
blockOutput = operation block
-- | Encrypts the given ByteString using the given Key
encrypt :: ByteArray ba
=> Twofish -- ^ The key to use
-> ba -- ^ The data to encrypt
-> ba
encrypt cipher = mapBlocks (encryptBlock cipher)
encryptBlock :: ByteArray ba => Twofish -> ba -> ba
encryptBlock Twofish { s = (s1, s2, s3, s4), k = ks } message = store32ls ts
where (a, b, c, d) = load32ls message
a' = a `xor` arrayRead32 ks 0
b' = b `xor` arrayRead32 ks 1
c' = c `xor` arrayRead32 ks 2
d' = d `xor` arrayRead32 ks 3
(!a'', !b'', !c'', !d'') = foldl' shuffle (a', b', c', d') [0..7]
ts = (c'' `xor` arrayRead32 ks 4, d'' `xor` arrayRead32 ks 5, a'' `xor` arrayRead32 ks 6, b'' `xor` arrayRead32 ks 7)
shuffle :: (Word32, Word32, Word32, Word32) -> Int -> (Word32, Word32, Word32, Word32)
shuffle (!retA, !retB, !retC, !retD) ind = (retA', retB', retC', retD')
where [k0, k1, k2, k3] = fmap (\offset -> arrayRead32 ks $ (8 + 4 * ind) + offset) [0..3]
t2 = byteIndex s2 retB `xor` byteIndex s3 (shiftR retB 8) `xor` byteIndex s4 (shiftR retB 16) `xor` byteIndex s1 (shiftR retB 24)
t1 = (byteIndex s1 retA `xor` byteIndex s2 (shiftR retA 8) `xor` byteIndex s3 (shiftR retA 16) `xor` byteIndex s4 (shiftR retA 24)) + t2
retC' = rotateR (retC `xor` (t1 + k0)) 1
retD' = rotateL retD 1 `xor` (t1 + t2 + k1)
t2' = byteIndex s2 retD' `xor` byteIndex s3 (shiftR retD' 8) `xor` byteIndex s4 (shiftR retD' 16) `xor` byteIndex s1 (shiftR retD' 24)
t1' = (byteIndex s1 retC' `xor` byteIndex s2 (shiftR retC' 8) `xor` byteIndex s3 (shiftR retC' 16) `xor` byteIndex s4 (shiftR retC' 24)) + t2'
retA' = rotateR (retA `xor` (t1' + k2)) 1
retB' = rotateL retB 1 `xor` (t1' + t2' + k3)
-- Unsafe, no bounds checking
byteIndex :: Array32 -> Word32 -> Word32
byteIndex xs ind = arrayRead32 xs $ fromIntegral byte
where byte = ind `mod` 256
-- | Decrypts the given ByteString using the given Key
decrypt :: ByteArray ba
=> Twofish -- ^ The key to use
-> ba -- ^ The data to decrypt
-> ba
decrypt cipher = mapBlocks (decryptBlock cipher)
{- decryption for 128 bits blocks -}
decryptBlock :: ByteArray ba => Twofish -> ba -> ba
decryptBlock Twofish { s = (s1, s2, s3, s4), k = ks } message = store32ls ixs
where (a, b, c, d) = load32ls message
a' = c `xor` arrayRead32 ks 6
b' = d `xor` arrayRead32 ks 7
c' = a `xor` arrayRead32 ks 4
d' = b `xor` arrayRead32 ks 5
(!a'', !b'', !c'', !d'') = foldl' unshuffle (a', b', c', d') [8, 7..1]
ixs = (a'' `xor` arrayRead32 ks 0, b'' `xor` arrayRead32 ks 1, c'' `xor` arrayRead32 ks 2, d'' `xor` arrayRead32 ks 3)
unshuffle :: (Word32, Word32, Word32, Word32) -> Int -> (Word32, Word32, Word32, Word32)
unshuffle (!retA, !retB, !retC, !retD) ind = (retA', retB', retC', retD')
where [k0, k1, k2, k3] = fmap (\offset -> arrayRead32 ks $ (4 + 4 * ind) + offset) [0..3]
t2 = byteIndex s2 retD `xor` byteIndex s3 (shiftR retD 8) `xor` byteIndex s4 (shiftR retD 16) `xor` byteIndex s1 (shiftR retD 24)
t1 = (byteIndex s1 retC `xor` byteIndex s2 (shiftR retC 8) `xor` byteIndex s3 (shiftR retC 16) `xor` byteIndex s4 (shiftR retC 24)) + t2
retA' = rotateL retA 1 `xor` (t1 + k2)
retB' = rotateR (retB `xor` (t2 + t1 + k3)) 1
t2' = byteIndex s2 retB' `xor` byteIndex s3 (shiftR retB' 8) `xor` byteIndex s4 (shiftR retB' 16) `xor` byteIndex s1 (shiftR retB' 24)
t1' = (byteIndex s1 retA' `xor` byteIndex s2 (shiftR retA' 8) `xor` byteIndex s3 (shiftR retA' 16) `xor` byteIndex s4 (shiftR retA' 24)) + t2'
retC' = rotateL retC 1 `xor` (t1' + k0)
retD' = rotateR (retD `xor` (t2' + t1' + k1)) 1
sbox0 :: Int -> Word8
sbox0 = arrayRead8 t
where t = array8
"\xa9\x67\xb3\xe8\x04\xfd\xa3\x76\x9a\x92\x80\x78\xe4\xdd\xd1\x38\
\\x0d\xc6\x35\x98\x18\xf7\xec\x6c\x43\x75\x37\x26\xfa\x13\x94\x48\
\\xf2\xd0\x8b\x30\x84\x54\xdf\x23\x19\x5b\x3d\x59\xf3\xae\xa2\x82\
\\x63\x01\x83\x2e\xd9\x51\x9b\x7c\xa6\xeb\xa5\xbe\x16\x0c\xe3\x61\
\\xc0\x8c\x3a\xf5\x73\x2c\x25\x0b\xbb\x4e\x89\x6b\x53\x6a\xb4\xf1\
\\xe1\xe6\xbd\x45\xe2\xf4\xb6\x66\xcc\x95\x03\x56\xd4\x1c\x1e\xd7\
\\xfb\xc3\x8e\xb5\xe9\xcf\xbf\xba\xea\x77\x39\xaf\x33\xc9\x62\x71\
\\x81\x79\x09\xad\x24\xcd\xf9\xd8\xe5\xc5\xb9\x4d\x44\x08\x86\xe7\
\\xa1\x1d\xaa\xed\x06\x70\xb2\xd2\x41\x7b\xa0\x11\x31\xc2\x27\x90\
\\x20\xf6\x60\xff\x96\x5c\xb1\xab\x9e\x9c\x52\x1b\x5f\x93\x0a\xef\
\\x91\x85\x49\xee\x2d\x4f\x8f\x3b\x47\x87\x6d\x46\xd6\x3e\x69\x64\
\\x2a\xce\xcb\x2f\xfc\x97\x05\x7a\xac\x7f\xd5\x1a\x4b\x0e\xa7\x5a\
\\x28\x14\x3f\x29\x88\x3c\x4c\x02\xb8\xda\xb0\x17\x55\x1f\x8a\x7d\
\\x57\xc7\x8d\x74\xb7\xc4\x9f\x72\x7e\x15\x22\x12\x58\x07\x99\x34\
\\x6e\x50\xde\x68\x65\xbc\xdb\xf8\xc8\xa8\x2b\x40\xdc\xfe\x32\xa4\
\\xca\x10\x21\xf0\xd3\x5d\x0f\x00\x6f\x9d\x36\x42\x4a\x5e\xc1\xe0"#
sbox1 :: Int -> Word8
sbox1 = arrayRead8 t
where t = array8
"\x75\xf3\xc6\xf4\xdb\x7b\xfb\xc8\x4a\xd3\xe6\x6b\x45\x7d\xe8\x4b\
\\xd6\x32\xd8\xfd\x37\x71\xf1\xe1\x30\x0f\xf8\x1b\x87\xfa\x06\x3f\
\\x5e\xba\xae\x5b\x8a\x00\xbc\x9d\x6d\xc1\xb1\x0e\x80\x5d\xd2\xd5\
\\xa0\x84\x07\x14\xb5\x90\x2c\xa3\xb2\x73\x4c\x54\x92\x74\x36\x51\
\\x38\xb0\xbd\x5a\xfc\x60\x62\x96\x6c\x42\xf7\x10\x7c\x28\x27\x8c\
\\x13\x95\x9c\xc7\x24\x46\x3b\x70\xca\xe3\x85\xcb\x11\xd0\x93\xb8\
\\xa6\x83\x20\xff\x9f\x77\xc3\xcc\x03\x6f\x08\xbf\x40\xe7\x2b\xe2\
\\x79\x0c\xaa\x82\x41\x3a\xea\xb9\xe4\x9a\xa4\x97\x7e\xda\x7a\x17\
\\x66\x94\xa1\x1d\x3d\xf0\xde\xb3\x0b\x72\xa7\x1c\xef\xd1\x53\x3e\
\\x8f\x33\x26\x5f\xec\x76\x2a\x49\x81\x88\xee\x21\xc4\x1a\xeb\xd9\
\\xc5\x39\x99\xcd\xad\x31\x8b\x01\x18\x23\xdd\x1f\x4e\x2d\xf9\x48\
\\x4f\xf2\x65\x8e\x78\x5c\x58\x19\x8d\xe5\x98\x57\x67\x7f\x05\x64\
\\xaf\x63\xb6\xfe\xf5\xb7\x3c\xa5\xce\xe9\x68\x44\xe0\x4d\x43\x69\
\\x29\x2e\xac\x15\x59\xa8\x0a\x9e\x6e\x47\xdf\x34\x35\x6a\xcf\xdc\
\\x22\xc9\xc0\x9b\x89\xd4\xed\xab\x12\xa2\x0d\x52\xbb\x02\x2f\xa9\
\\xd7\x61\x1e\xb4\x50\x04\xf6\xc2\x16\x25\x86\x56\x55\x09\xbe\x91"#
rs :: [[Word8]]
rs = [ [0x01, 0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E]
, [0xA4, 0x56, 0x82, 0xF3, 0x1E, 0xC6, 0x68, 0xE5]
, [0x02, 0xA1, 0xFC, 0xC1, 0x47, 0xAE, 0x3D, 0x19]
, [0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E, 0x03] ]
load32ls :: ByteArray ba => ba -> (Word32, Word32, Word32, Word32)
load32ls message = (intify q1, intify q2, intify q3, intify q4)
where (half1, half2) = B.splitAt 8 message
(q1, q2) = B.splitAt 4 half1
(q3, q4) = B.splitAt 4 half2
intify :: ByteArray ba => ba -> Word32
intify bytes = foldl' (\int (!word, !ind) -> int .|. shiftL (fromIntegral word) (ind * 8) ) 0 (zip (B.unpack bytes) [0..])
store32ls :: ByteArray ba => (Word32, Word32, Word32, Word32) -> ba
store32ls (a, b, c, d) = B.pack $ concatMap splitWordl [a, b, c, d]
where splitWordl :: Word32 -> [Word8]
splitWordl w = fmap (\ind -> fromIntegral $ shiftR w (8 * ind)) [0..3]
-- Create S words
sWords :: ByteArray ba => ba -> [Word8]
sWords key = sWord
where word64Count = B.length key `div` 2
sWord = concatMap (\wordIndex ->
map (\rsRow ->
foldl' (\acc (!rsVal, !colIndex) ->
acc `xor` gfMult rsPolynomial (B.index key $ 8 * wordIndex + colIndex) rsVal
) 0 (zip rsRow [0..])
) rs
) [0..word64Count - 1]
data Column = Zero | One | Two | Three deriving (Show, Eq, Enum, Bounded)
genSboxes :: KeyPackage ba -> [Word8] -> (Array32, Array32, Array32, Array32)
genSboxes keyPackage ws = (mkArray b0', mkArray b1', mkArray b2', mkArray b3')
where range = [0..255]
mkArray = array32 256
[w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15] = take 16 ws
(b0', b1', b2', b3') = sboxBySize $ byteSize keyPackage
sboxBySize :: ByteSize -> ([Word32], [Word32], [Word32], [Word32])
sboxBySize Bytes16 = (b0, b1, b2, b3)
where !b0 = fmap mapper range
where mapper :: Int -> Word32
mapper byte = mdsColumnMult ((sbox1 . fromIntegral) ((sbox0 . fromIntegral $ sbox0 byte `xor` w0) `xor` w4)) Zero
!b1 = fmap mapper range
where mapper byte = mdsColumnMult ((sbox0 . fromIntegral) ((sbox0 . fromIntegral $ sbox1 byte `xor` w1) `xor` w5)) One
!b2 = fmap mapper range
where mapper byte = mdsColumnMult ((sbox1 . fromIntegral) ((sbox1 . fromIntegral $ sbox0 byte `xor` w2) `xor` w6)) Two
!b3 = fmap mapper range
where mapper byte = mdsColumnMult ((sbox0 . fromIntegral) ((sbox1 . fromIntegral $ sbox1 byte `xor` w3) `xor` w7)) Three
sboxBySize Bytes24 = (b0, b1, b2, b3)
where !b0 = fmap mapper range
where mapper byte = mdsColumnMult ((sbox1 . fromIntegral) ((sbox0 . fromIntegral) ((sbox0 . fromIntegral $ sbox1 byte `xor` w0) `xor` w4) `xor` w8)) Zero
!b1 = fmap mapper range
where mapper byte = mdsColumnMult ((sbox0 . fromIntegral) ((sbox0 . fromIntegral) ((sbox1 . fromIntegral $ sbox1 byte `xor` w1) `xor` w5) `xor` w9)) One
!b2 = fmap mapper range
where mapper byte = mdsColumnMult ((sbox1 . fromIntegral) ((sbox1 . fromIntegral) ((sbox0 . fromIntegral $ sbox0 byte `xor` w2) `xor` w6) `xor` w10)) Two
!b3 = fmap mapper range
where mapper byte = mdsColumnMult ((sbox0 . fromIntegral) ((sbox1 . fromIntegral) ((sbox1 . fromIntegral $ sbox0 byte `xor` w3) `xor` w7) `xor` w11)) Three
sboxBySize Bytes32 = (b0, b1, b2, b3)
where !b0 = fmap mapper range
where mapper byte = mdsColumnMult ((sbox1 . fromIntegral) ((sbox0 . fromIntegral) ((sbox0 . fromIntegral) ((sbox1 . fromIntegral $ sbox1 byte `xor` w0) `xor` w4) `xor` w8) `xor` w12)) Zero
!b1 = fmap mapper range
where mapper byte = mdsColumnMult ((sbox0 . fromIntegral) ((sbox0 . fromIntegral) ((sbox1 . fromIntegral) ((sbox1 . fromIntegral $ sbox0 byte `xor` w1) `xor` w5) `xor` w9) `xor` w13)) One
!b2 = fmap mapper range
where mapper byte = mdsColumnMult ((sbox1 . fromIntegral) ((sbox1 . fromIntegral) ((sbox0 . fromIntegral) ((sbox0 . fromIntegral $ sbox0 byte `xor` w2) `xor` w6) `xor` w10) `xor` w14)) Two
!b3 = fmap mapper range
where mapper byte = mdsColumnMult ((sbox0 . fromIntegral) ((sbox1 . fromIntegral) ((sbox1 . fromIntegral) ((sbox0 . fromIntegral $ sbox1 byte `xor` w3) `xor` w7) `xor` w11) `xor` w15)) Three
genK :: (ByteArray ba) => KeyPackage ba -> [Word32]
genK keyPackage = concatMap makeTuple [0..19]
where makeTuple :: Word8 -> [Word32]
makeTuple idx = [a + b', rotateL (2 * b' + a) 9]
where tmp1 = replicate 4 $ 2 * idx
tmp2 = fmap (+1) tmp1
a = h tmp1 keyPackage 0
b = h tmp2 keyPackage 1
b' = rotateL b 8
h :: (ByteArray ba) => [Word8] -> KeyPackage ba -> Int -> Word32
h input keyPackage offset = foldl' xorMdsColMult 0 $ zip [y0f, y1f, y2f, y3f] $ enumFrom Zero
where key = rawKeyBytes keyPackage
[y0, y1, y2, y3] = take 4 input
(!y0f, !y1f, !y2f, !y3f) = run (y0, y1, y2, y3) $ byteSize keyPackage
run :: (Word8, Word8, Word8, Word8) -> ByteSize -> (Word8, Word8, Word8, Word8)
run (!y0'', !y1'', !y2'', !y3'') Bytes32 = run (y0', y1', y2', y3') Bytes24
where y0' = sbox1 (fromIntegral y0'') `xor` B.index key (4 * (6 + offset) + 0)
y1' = sbox0 (fromIntegral y1'') `xor` B.index key (4 * (6 + offset) + 1)
y2' = sbox0 (fromIntegral y2'') `xor` B.index key (4 * (6 + offset) + 2)
y3' = sbox1 (fromIntegral y3'') `xor` B.index key (4 * (6 + offset) + 3)
run (!y0'', !y1'', !y2'', !y3'') Bytes24 = run (y0', y1', y2', y3') Bytes16
where y0' = sbox1 (fromIntegral y0'') `xor` B.index key (4 * (4 + offset) + 0)
y1' = sbox1 (fromIntegral y1'') `xor` B.index key (4 * (4 + offset) + 1)
y2' = sbox0 (fromIntegral y2'') `xor` B.index key (4 * (4 + offset) + 2)
y3' = sbox0 (fromIntegral y3'') `xor` B.index key (4 * (4 + offset) + 3)
run (!y0'', !y1'', !y2'', !y3'') Bytes16 = (y0', y1', y2', y3')
where y0' = sbox1 . fromIntegral $ (sbox0 . fromIntegral $ (sbox0 (fromIntegral y0'') `xor` B.index key (4 * (2 + offset) + 0))) `xor` B.index key (4 * (0 + offset) + 0)
y1' = sbox0 . fromIntegral $ (sbox0 . fromIntegral $ (sbox1 (fromIntegral y1'') `xor` B.index key (4 * (2 + offset) + 1))) `xor` B.index key (4 * (0 + offset) + 1)
y2' = sbox1 . fromIntegral $ (sbox1 . fromIntegral $ (sbox0 (fromIntegral y2'') `xor` B.index key (4 * (2 + offset) + 2))) `xor` B.index key (4 * (0 + offset) + 2)
y3' = sbox0 . fromIntegral $ (sbox1 . fromIntegral $ (sbox1 (fromIntegral y3'') `xor` B.index key (4 * (2 + offset) + 3))) `xor` B.index key (4 * (0 + offset) + 3)
xorMdsColMult :: Word32 -> (Word8, Column) -> Word32
xorMdsColMult acc wordAndIndex = acc `xor` uncurry mdsColumnMult wordAndIndex
mdsColumnMult :: Word8 -> Column -> Word32
mdsColumnMult !byte !col =
case col of Zero -> input .|. rotateL mul5B 8 .|. rotateL mulEF 16 .|. rotateL mulEF 24
One -> mulEF .|. rotateL mulEF 8 .|. rotateL mul5B 16 .|. rotateL input 24
Two -> mul5B .|. rotateL mulEF 8 .|. rotateL input 16 .|. rotateL mulEF 24
Three -> mul5B .|. rotateL input 8 .|. rotateL mulEF 16 .|. rotateL mul5B 24
where input = fromIntegral byte
mul5B = fromIntegral $ gfMult mdsPolynomial byte 0x5B
mulEF = fromIntegral $ gfMult mdsPolynomial byte 0xEF
tupInd :: (Bits b) => b -> (a, a) -> a
tupInd b
| testBit b 0 = snd
| otherwise = fst
gfMult :: Word32 -> Word8 -> Word8 -> Word8
gfMult p a b = fromIntegral $ run a b' p' result 0
where b' = (0, fromIntegral b)
p' = (0, p)
result = 0
run :: Word8 -> (Word32, Word32) -> (Word32, Word32) -> Word32 -> Int -> Word32
run a' b'' p'' result' count =
if count == 7
then result''
else run a'' b''' p'' result'' (count + 1)
where result'' = result' `xor` tupInd (a' .&. 1) b''
a'' = shiftR a' 1
b''' = (fst b'', tupInd (shiftR (snd b'') 7) p'' `xor` shiftL (snd b'') 1)

View File

@ -5,7 +5,7 @@
-- Stability : Stable -- Stability : Stable
-- Portability : Excellent -- Portability : Excellent
-- --
-- symmetric cipher basic types -- Symmetric cipher basic types
-- --
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
module Crypto.Cipher.Types module Crypto.Cipher.Types
@ -21,6 +21,8 @@ module Crypto.Cipher.Types
-- , cfb8Decrypt -- , cfb8Decrypt
-- * AEAD functions -- * AEAD functions
, AEADMode(..) , AEADMode(..)
, CCM_M(..)
, CCM_L(..)
, module Crypto.Cipher.Types.AEAD , module Crypto.Cipher.Types.AEAD
-- * Initial Vector type and constructor -- * Initial Vector type and constructor
, IV , IV

View File

@ -27,24 +27,24 @@ data AEADModeImpl st = AEADModeImpl
-- | Authenticated Encryption with Associated Data algorithms -- | Authenticated Encryption with Associated Data algorithms
data AEAD cipher = forall st . AEAD data AEAD cipher = forall st . AEAD
{ aeadModeImpl :: AEADModeImpl st { aeadModeImpl :: AEADModeImpl st
, aeadState :: st , aeadState :: !st
} }
-- | Append some header information to an AEAD context -- | Append some header information to an AEAD context
aeadAppendHeader :: ByteArrayAccess aad => AEAD cipher -> aad -> AEAD cipher aeadAppendHeader :: ByteArrayAccess aad => AEAD cipher -> aad -> AEAD cipher
aeadAppendHeader (AEAD impl st) aad = AEAD impl $ (aeadImplAppendHeader impl) st aad aeadAppendHeader (AEAD impl st) aad = AEAD impl $ aeadImplAppendHeader impl st aad
-- | Encrypt some data and update the AEAD context -- | Encrypt some data and update the AEAD context
aeadEncrypt :: ByteArray ba => AEAD cipher -> ba -> (ba, AEAD cipher) aeadEncrypt :: ByteArray ba => AEAD cipher -> ba -> (ba, AEAD cipher)
aeadEncrypt (AEAD impl st) ba = second (AEAD impl) $ (aeadImplEncrypt impl) st ba aeadEncrypt (AEAD impl st) ba = second (AEAD impl) $ aeadImplEncrypt impl st ba
-- | Decrypt some data and update the AEAD context -- | Decrypt some data and update the AEAD context
aeadDecrypt :: ByteArray ba => AEAD cipher -> ba -> (ba, AEAD cipher) aeadDecrypt :: ByteArray ba => AEAD cipher -> ba -> (ba, AEAD cipher)
aeadDecrypt (AEAD impl st) ba = second (AEAD impl) $ (aeadImplDecrypt impl) st ba aeadDecrypt (AEAD impl st) ba = second (AEAD impl) $ aeadImplDecrypt impl st ba
-- | Finalize the AEAD context and return the authentication tag -- | Finalize the AEAD context and return the authentication tag
aeadFinalize :: AEAD cipher -> Int -> AuthTag aeadFinalize :: AEAD cipher -> Int -> AuthTag
aeadFinalize (AEAD impl st) n = (aeadImplFinalize impl) st n aeadFinalize (AEAD impl st) = aeadImplFinalize impl st
-- | Simple AEAD encryption -- | Simple AEAD encryption
aeadSimpleEncrypt :: (ByteArrayAccess aad, ByteArray ba) aeadSimpleEncrypt :: (ByteArrayAccess aad, ByteArray ba)

View File

@ -5,7 +5,7 @@
-- Stability : Stable -- Stability : Stable
-- Portability : Excellent -- Portability : Excellent
-- --
-- symmetric cipher basic types -- Symmetric cipher basic types
-- --
{-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
@ -14,12 +14,15 @@ module Crypto.Cipher.Types.Base
, Cipher(..) , Cipher(..)
, AuthTag(..) , AuthTag(..)
, AEADMode(..) , AEADMode(..)
, CCM_M(..)
, CCM_L(..)
, DataUnitOffset , DataUnitOffset
) where ) where
import Data.Word import Data.Word
import Crypto.Internal.ByteArray (Bytes, ByteArrayAccess, ByteArray) import Crypto.Internal.ByteArray (Bytes, ByteArrayAccess, ByteArray)
import qualified Crypto.Internal.ByteArray as B import qualified Crypto.Internal.ByteArray as B
import Crypto.Internal.DeepSeq
import Crypto.Error import Crypto.Error
-- | Different specifier for key size in bytes -- | Different specifier for key size in bytes
@ -34,15 +37,18 @@ type DataUnitOffset = Word32
-- | Authentication Tag for AE cipher mode -- | Authentication Tag for AE cipher mode
newtype AuthTag = AuthTag { unAuthTag :: Bytes } newtype AuthTag = AuthTag { unAuthTag :: Bytes }
deriving (Show, ByteArrayAccess) deriving (Show, ByteArrayAccess, NFData)
instance Eq AuthTag where instance Eq AuthTag where
(AuthTag a) == (AuthTag b) = B.constEq a b (AuthTag a) == (AuthTag b) = B.constEq a b
data CCM_M = CCM_M4 | CCM_M6 | CCM_M8 | CCM_M10 | CCM_M12 | CCM_M14 | CCM_M16 deriving (Show, Eq)
data CCM_L = CCM_L2 | CCM_L3 | CCM_L4 deriving (Show, Eq)
-- | AEAD Mode -- | AEAD Mode
data AEADMode = data AEADMode =
AEAD_OCB -- OCB3 AEAD_OCB -- OCB3
| AEAD_CCM | AEAD_CCM Int CCM_M CCM_L
| AEAD_EAX | AEAD_EAX
| AEAD_CWC | AEAD_CWC
| AEAD_GCM | AEAD_GCM

View File

@ -5,7 +5,7 @@
-- Stability : Stable -- Stability : Stable
-- Portability : Excellent -- Portability : Excellent
-- --
-- block cipher basic types -- Block cipher basic types
-- --
{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE ExistentialQuantification #-}
@ -16,7 +16,7 @@ module Crypto.Cipher.Types.Block
-- * BlockCipher -- * BlockCipher
BlockCipher(..) BlockCipher(..)
, BlockCipher128(..) , BlockCipher128(..)
-- * initialization vector (IV) -- * Initialization vector (IV)
, IV(..) , IV(..)
, makeIV , makeIV
, nullIV , nullIV
@ -37,7 +37,6 @@ module Crypto.Cipher.Types.Block
) where ) where
import Data.Word import Data.Word
import Data.Monoid
import Crypto.Error import Crypto.Error
import Crypto.Cipher.Types.Base import Crypto.Cipher.Types.Base
import Crypto.Cipher.Types.GF import Crypto.Cipher.Types.GF
@ -164,27 +163,20 @@ nullIV = toIV undefined
-- | Increment an IV by a number. -- | Increment an IV by a number.
-- --
-- Assume the IV is in Big Endian format. -- Assume the IV is in Big Endian format.
ivAdd :: BlockCipher c => IV c -> Int -> IV c ivAdd :: IV c -> Int -> IV c
ivAdd (IV b) i = IV $ copy b ivAdd (IV b) i = IV $ copy b
where copy :: ByteArray bs => bs -> bs where copy :: ByteArray bs => bs -> bs
copy bs = B.copyAndFreeze bs $ \p -> do copy bs = B.copyAndFreeze bs $ loop i (B.length bs - 1)
let until0 accu = do
r <- loop accu (B.length bs - 1) p
case r of
0 -> return ()
_ -> until0 r
until0 i
loop :: Int -> Int -> Ptr Word8 -> IO Int loop :: Int -> Int -> Ptr Word8 -> IO ()
loop 0 _ _ = return 0 loop acc ofs p
loop acc ofs p = do | ofs < 0 = return ()
v <- peek (p `plusPtr` ofs) :: IO Word8 | otherwise = do
let accv = acc + fromIntegral v v <- peek (p `plusPtr` ofs) :: IO Word8
(hi,lo) = accv `divMod` 256 let accv = acc + fromIntegral v
poke (p `plusPtr` ofs) (fromIntegral lo :: Word8) (hi,lo) = accv `divMod` 256
if ofs == 0 poke (p `plusPtr` ofs) (fromIntegral lo :: Word8)
then return hi loop hi (ofs - 1) p
else loop hi (ofs - 1) p
cbcEncryptGeneric :: (ByteArray ba, BlockCipher cipher) => cipher -> IV cipher -> ba -> ba cbcEncryptGeneric :: (ByteArray ba, BlockCipher cipher) => cipher -> IV cipher -> ba -> ba
cbcEncryptGeneric cipher ivini input = mconcat $ doEnc ivini $ chunk (blockSize cipher) input cbcEncryptGeneric cipher ivini input = mconcat $ doEnc ivini $ chunk (blockSize cipher) input

View File

@ -5,7 +5,7 @@
-- Stability : Stable -- Stability : Stable
-- Portability : Excellent -- Portability : Excellent
-- --
-- stream cipher basic types -- Stream cipher basic types
-- --
module Crypto.Cipher.Types.Stream module Crypto.Cipher.Types.Stream
( StreamCipher(..) ( StreamCipher(..)

View File

@ -5,7 +5,7 @@
-- Stability : Stable -- Stability : Stable
-- Portability : Excellent -- Portability : Excellent
-- --
-- basic utility for cipher related stuff -- Basic utility for cipher related stuff
-- --
module Crypto.Cipher.Types.Utils where module Crypto.Cipher.Types.Utils where

18
Crypto/Cipher/Utils.hs Normal file
View File

@ -0,0 +1,18 @@
module Crypto.Cipher.Utils
( validateKeySize
) where
import Crypto.Error
import Crypto.Cipher.Types
import Data.ByteArray as BA
validateKeySize :: (ByteArrayAccess key, Cipher cipher) => cipher -> key -> CryptoFailable key
validateKeySize c k = if validKeyLength
then CryptoPassed k
else CryptoFailed CryptoError_KeySizeInvalid
where keyLength = BA.length k
validKeyLength = case cipherKeySize c of
KeySizeRange low high -> keyLength >= low && keyLength <= high
KeySizeEnum lengths -> keyLength `elem` lengths
KeySizeFixed s -> keyLength == s

View File

@ -12,18 +12,17 @@
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
module Crypto.Cipher.XSalsa module Crypto.Cipher.XSalsa
( initialize ( initialize
, derive
, combine , combine
, generate , generate
, State , State
) where ) where
import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, ScrubbedBytes) import Crypto.Internal.ByteArray (ByteArrayAccess)
import qualified Crypto.Internal.ByteArray as B import qualified Crypto.Internal.ByteArray as B
import Crypto.Internal.Compat import Crypto.Internal.Compat
import Crypto.Internal.Imports import Crypto.Internal.Imports
import Foreign.Ptr import Foreign.Ptr
import Foreign.Storable
import Foreign.C.Types
import Crypto.Cipher.Salsa hiding (initialize) import Crypto.Cipher.Salsa hiding (initialize)
-- | Initialize a new XSalsa context with the number of rounds, -- | Initialize a new XSalsa context with the number of rounds,
@ -36,15 +35,41 @@ initialize :: (ByteArrayAccess key, ByteArrayAccess nonce)
initialize nbRounds key nonce initialize nbRounds key nonce
| kLen /= 32 = error "XSalsa: key length should be 256 bits" | kLen /= 32 = error "XSalsa: key length should be 256 bits"
| nonceLen /= 24 = error "XSalsa: nonce length should be 192 bits" | nonceLen /= 24 = error "XSalsa: nonce length should be 192 bits"
| not (nbRounds `elem` [8,12,20]) = error "XSalsa: rounds should be 8, 12 or 20" | nbRounds `notElem` [8,12,20] = error "XSalsa: rounds should be 8, 12 or 20"
| otherwise = unsafeDoIO $ do | otherwise = unsafeDoIO $ do
stPtr <- B.alloc 132 $ \stPtr -> stPtr <- B.alloc 132 $ \stPtr ->
B.withByteArray nonce $ \noncePtr -> B.withByteArray nonce $ \noncePtr ->
B.withByteArray key $ \keyPtr -> B.withByteArray key $ \keyPtr ->
ccryptonite_xsalsa_init stPtr (fromIntegral nbRounds) kLen keyPtr nonceLen noncePtr ccryptonite_xsalsa_init stPtr nbRounds kLen keyPtr nonceLen noncePtr
return $ State stPtr return $ State stPtr
where kLen = B.length key where kLen = B.length key
nonceLen = B.length nonce nonceLen = B.length nonce
-- | Use an already initialized context and new nonce material to derive another
-- XSalsa context.
--
-- This allows a multi-level cascade where a first key @k1@ and nonce @n1@ is
-- used to get @HState(k1,n1)@, and this value is then used as key @k2@ to build
-- @XSalsa(k2,n2)@. Function 'initialize' is to be called with the first 192
-- bits of @n1|n2@, and the call to @derive@ should add the remaining 128 bits.
--
-- The output context always uses the same number of rounds as the input
-- context.
derive :: ByteArrayAccess nonce
=> State -- ^ base XSalsa state
-> nonce -- ^ the remainder nonce (128 bits)
-> State -- ^ the new XSalsa state
derive (State stPtr') nonce
| nonceLen /= 16 = error "XSalsa: nonce length should be 128 bits"
| otherwise = unsafeDoIO $ do
stPtr <- B.copy stPtr' $ \stPtr ->
B.withByteArray nonce $ \noncePtr ->
ccryptonite_xsalsa_derive stPtr nonceLen noncePtr
return $ State stPtr
where nonceLen = B.length nonce
foreign import ccall "cryptonite_xsalsa_init" foreign import ccall "cryptonite_xsalsa_init"
ccryptonite_xsalsa_init :: Ptr State -> Int -> Int -> Ptr Word8 -> Int -> Ptr Word8 -> IO () ccryptonite_xsalsa_init :: Ptr State -> Int -> Int -> Ptr Word8 -> Int -> Ptr Word8 -> IO ()
foreign import ccall "cryptonite_xsalsa_derive"
ccryptonite_xsalsa_derive :: Ptr State -> Int -> Ptr Word8 -> IO ()

View File

@ -5,7 +5,7 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- provide the hash function construction method from block cipher -- Provide the hash function construction method from block cipher
-- <https://en.wikipedia.org/wiki/One-way_compression_function> -- <https://en.wikipedia.org/wiki/One-way_compression_function>
-- --
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
@ -44,7 +44,7 @@ compute' g = MP . foldl' (step $ g) (B.replicate bsz 0) . chunks . pad (ZERO bsz
where where
(hd, tl) = B.splitAt bsz msg (hd, tl) = B.splitAt bsz msg
-- | Compute Miyaguchi-Preneel one way compress using the infered block cipher. -- | Compute Miyaguchi-Preneel one way compress using the inferred block cipher.
-- Only safe when KEY-SIZE equals to BLOCK-SIZE. -- Only safe when KEY-SIZE equals to BLOCK-SIZE.
-- --
-- Simple usage /mp' msg :: MiyaguchiPreneel AES128/ -- Simple usage /mp' msg :: MiyaguchiPreneel AES128/

View File

@ -5,7 +5,7 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- haskell implementation of the Anti-forensic information splitter -- Haskell implementation of the Anti-forensic information splitter
-- available in LUKS. <http://clemens.endorphin.org/AFsplitter> -- available in LUKS. <http://clemens.endorphin.org/AFsplitter>
-- --
-- The algorithm bloats an arbitrary secret with many bits that are necessary for -- The algorithm bloats an arbitrary secret with many bits that are necessary for
@ -77,7 +77,7 @@ split hashAlg rng expandTimes src
diffuse hashAlg lastBlock blockSize diffuse hashAlg lastBlock blockSize
fillRandomBlock g blockPtr = do fillRandomBlock g blockPtr = do
let (rand :: Bytes, g') = randomBytesGenerate blockSize g let (rand :: Bytes, g') = randomBytesGenerate blockSize g
B.withByteArray rand $ \randPtr -> memCopy blockPtr randPtr (fromIntegral blockSize) B.withByteArray rand $ \randPtr -> memCopy blockPtr randPtr blockSize
return g' return g'
-- | Merge previously diffused data back to the original data. -- | Merge previously diffused data back to the original data.

View File

@ -6,7 +6,7 @@
-- Portability : unknown -- Portability : unknown
-- --
-- Various cryptographic padding commonly used for block ciphers -- Various cryptographic padding commonly used for block ciphers
-- or assymetric systems. -- or asymmetric systems.
-- --
module Crypto.Data.Padding module Crypto.Data.Padding
( Format(..) ( Format(..)

View File

@ -7,6 +7,8 @@
-- --
-- Elliptic Curve Cryptography -- Elliptic Curve Cryptography
-- --
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ScopedTypeVariables #-}
@ -16,27 +18,33 @@ module Crypto.ECC
, Curve_P521R1(..) , Curve_P521R1(..)
, Curve_X25519(..) , Curve_X25519(..)
, Curve_X448(..) , Curve_X448(..)
, Curve_Edwards25519(..)
, EllipticCurve(..) , EllipticCurve(..)
, EllipticCurveDH(..) , EllipticCurveDH(..)
, EllipticCurveArith(..) , EllipticCurveArith(..)
, EllipticCurveBasepointArith(..)
, KeyPair(..) , KeyPair(..)
, SharedSecret(..) , SharedSecret(..)
) where ) where
import qualified Crypto.PubKey.ECC.P256 as P256 import qualified Crypto.PubKey.ECC.P256 as P256
import qualified Crypto.ECC.Edwards25519 as Edwards25519
import qualified Crypto.ECC.Simple.Types as Simple import qualified Crypto.ECC.Simple.Types as Simple
import qualified Crypto.ECC.Simple.Prim as Simple import qualified Crypto.ECC.Simple.Prim as Simple
import Crypto.Random import Crypto.Random
import Crypto.Error import Crypto.Error
import Crypto.Internal.Proxy
import Crypto.Internal.Imports import Crypto.Internal.Imports
import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess, ScrubbedBytes) import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess, ScrubbedBytes)
import qualified Crypto.Internal.ByteArray as B import qualified Crypto.Internal.ByteArray as B
import Crypto.Number.Basic (numBits)
import Crypto.Number.Serialize (i2ospOf_, os2ip) import Crypto.Number.Serialize (i2ospOf_, os2ip)
import qualified Crypto.Number.Serialize.LE as LE
import qualified Crypto.PubKey.Curve25519 as X25519 import qualified Crypto.PubKey.Curve25519 as X25519
import qualified Crypto.PubKey.Curve448 as X448 import qualified Crypto.PubKey.Curve448 as X448
import Data.Function (on)
import Data.ByteArray (convert) import Data.ByteArray (convert)
import Data.Data (Data())
import Data.Kind (Type)
import Data.Proxy
-- | An elliptic curve key pair composed of the private part (a scalar), and -- | An elliptic curve key pair composed of the private part (a scalar), and
-- the associated point. -- the associated point.
@ -46,14 +54,14 @@ data KeyPair curve = KeyPair
} }
newtype SharedSecret = SharedSecret ScrubbedBytes newtype SharedSecret = SharedSecret ScrubbedBytes
deriving (Eq, ByteArrayAccess) deriving (Eq, ByteArrayAccess, NFData)
class EllipticCurve curve where class EllipticCurve curve where
-- | Point on an Elliptic Curve -- | Point on an Elliptic Curve
type Point curve :: * type Point curve :: Type
-- | Scalar in the Elliptic Curve domain -- | Scalar in the Elliptic Curve domain
type Scalar curve :: * type Scalar curve :: Type
-- | Generate a new random scalar on the curve. -- | Generate a new random scalar on the curve.
-- The scalar will represent a number between 1 and the order of the curve non included -- The scalar will represent a number between 1 and the order of the curve non included
@ -78,22 +86,69 @@ class EllipticCurve curve => EllipticCurveDH curve where
-- is not hashed. -- is not hashed.
-- --
-- use `pointSmul` to keep the result in Point format. -- use `pointSmul` to keep the result in Point format.
ecdh :: proxy curve -> Scalar curve -> Point curve -> SharedSecret --
-- /WARNING:/ Curve implementations may return a special value or an
-- exception when the public point lies in a subgroup of small order.
-- This function is adequate when the scalar is in expected range and
-- contributory behaviour is not needed. Otherwise use 'ecdh'.
ecdhRaw :: proxy curve -> Scalar curve -> Point curve -> SharedSecret
ecdhRaw prx s = throwCryptoError . ecdh prx s
class EllipticCurve curve => EllipticCurveArith curve where -- | Generate a Diffie hellman secret value and verify that the result
-- is not the point at infinity.
--
-- This additional test avoids risks existing with function 'ecdhRaw'.
-- Implementations always return a 'CryptoError' instead of a special
-- value or an exception.
ecdh :: proxy curve -> Scalar curve -> Point curve -> CryptoFailable SharedSecret
class (EllipticCurve curve, Eq (Point curve)) => EllipticCurveArith curve where
-- | Add points on a curve -- | Add points on a curve
pointAdd :: proxy curve -> Point curve -> Point curve -> Point curve pointAdd :: proxy curve -> Point curve -> Point curve -> Point curve
-- | Negate a curve point
pointNegate :: proxy curve -> Point curve -> Point curve
-- | Scalar Multiplication on a curve -- | Scalar Multiplication on a curve
pointSmul :: proxy curve -> Scalar curve -> Point curve -> Point curve pointSmul :: proxy curve -> Scalar curve -> Point curve -> Point curve
-- -- | Scalar Inverse -- -- | Scalar Inverse
-- scalarInverse :: Scalar curve -> Scalar curve -- scalarInverse :: Scalar curve -> Scalar curve
class (EllipticCurveArith curve, Eq (Scalar curve)) => EllipticCurveBasepointArith curve where
-- | Get the curve order size in bits
curveOrderBits :: proxy curve -> Int
-- | Multiply a scalar with the curve base point
pointBaseSmul :: proxy curve -> Scalar curve -> Point curve
-- | Multiply the point @p@ with @s2@ and add a lifted to curve value @s1@
pointsSmulVarTime :: proxy curve -> Scalar curve -> Scalar curve -> Point curve -> Point curve
pointsSmulVarTime prx s1 s2 p = pointAdd prx (pointBaseSmul prx s1) (pointSmul prx s2 p)
-- | Encode an elliptic curve scalar into big-endian form
encodeScalar :: ByteArray bs => proxy curve -> Scalar curve -> bs
-- | Try to decode the big-endian form of an elliptic curve scalar
decodeScalar :: ByteArray bs => proxy curve -> bs -> CryptoFailable (Scalar curve)
-- | Convert an elliptic curve scalar to an integer
scalarToInteger :: proxy curve -> Scalar curve -> Integer
-- | Try to create an elliptic curve scalar from an integer
scalarFromInteger :: proxy curve -> Integer -> CryptoFailable (Scalar curve)
-- | Add two scalars and reduce modulo the curve order
scalarAdd :: proxy curve -> Scalar curve -> Scalar curve -> Scalar curve
-- | Multiply two scalars and reduce modulo the curve order
scalarMul :: proxy curve -> Scalar curve -> Scalar curve -> Scalar curve
-- | P256 Curve -- | P256 Curve
-- --
-- also known as P256 -- also known as P256
data Curve_P256R1 = Curve_P256R1 data Curve_P256R1 = Curve_P256R1
deriving (Show,Data)
instance EllipticCurve Curve_P256R1 where instance EllipticCurve Curve_P256R1 where
type Point Curve_P256R1 = P256.Point type Point Curve_P256R1 = P256.Point
@ -111,20 +166,34 @@ instance EllipticCurve Curve_P256R1 where
uncompressed = B.singleton 4 uncompressed = B.singleton 4
xy = P256.pointToBinary p xy = P256.pointToBinary p
decodePoint _ mxy = case B.uncons mxy of decodePoint _ mxy = case B.uncons mxy of
Nothing -> CryptoFailed $ CryptoError_PointSizeInvalid Nothing -> CryptoFailed CryptoError_PointSizeInvalid
Just (m,xy) Just (m,xy)
-- uncompressed -- uncompressed
| m == 4 -> P256.pointFromBinary xy | m == 4 -> P256.pointFromBinary xy
| otherwise -> CryptoFailed $ CryptoError_PointFormatInvalid | otherwise -> CryptoFailed CryptoError_PointFormatInvalid
instance EllipticCurveArith Curve_P256R1 where instance EllipticCurveArith Curve_P256R1 where
pointAdd _ a b = P256.pointAdd a b pointAdd _ a b = P256.pointAdd a b
pointNegate _ p = P256.pointNegate p
pointSmul _ s p = P256.pointMul s p pointSmul _ s p = P256.pointMul s p
instance EllipticCurveDH Curve_P256R1 where instance EllipticCurveDH Curve_P256R1 where
ecdh _ s p = SharedSecret $ P256.pointDh s p ecdhRaw _ s p = SharedSecret $ P256.pointDh s p
ecdh prx s p = checkNonZeroDH (ecdhRaw prx s p)
instance EllipticCurveBasepointArith Curve_P256R1 where
curveOrderBits _ = 256
pointBaseSmul _ = P256.toPoint
pointsSmulVarTime _ = P256.pointsMulVarTime
encodeScalar _ = P256.scalarToBinary
decodeScalar _ = P256.scalarFromBinary
scalarToInteger _ = P256.scalarToInteger
scalarFromInteger _ = P256.scalarFromInteger
scalarAdd _ = P256.scalarAdd
scalarMul _ = P256.scalarMul
data Curve_P384R1 = Curve_P384R1 data Curve_P384R1 = Curve_P384R1
deriving (Show,Data)
instance EllipticCurve Curve_P384R1 where instance EllipticCurve Curve_P384R1 where
type Point Curve_P384R1 = Simple.Point Simple.SEC_p384r1 type Point Curve_P384R1 = Simple.Point Simple.SEC_p384r1
@ -138,15 +207,27 @@ instance EllipticCurve Curve_P384R1 where
instance EllipticCurveArith Curve_P384R1 where instance EllipticCurveArith Curve_P384R1 where
pointAdd _ a b = Simple.pointAdd a b pointAdd _ a b = Simple.pointAdd a b
pointNegate _ p = Simple.pointNegate p
pointSmul _ s p = Simple.pointMul s p pointSmul _ s p = Simple.pointMul s p
instance EllipticCurveDH Curve_P384R1 where instance EllipticCurveDH Curve_P384R1 where
ecdh _ s p = SharedSecret $ i2ospOf_ (curveSizeBytes prx) x ecdh _ s p = encodeECShared prx (Simple.pointMul s p)
where where
prx = Proxy :: Proxy Curve_P384R1 prx = Proxy :: Proxy Simple.SEC_p384r1
Simple.Point x _ = pointSmul prx s p
instance EllipticCurveBasepointArith Curve_P384R1 where
curveOrderBits _ = 384
pointBaseSmul _ = Simple.pointBaseMul
pointsSmulVarTime _ = ecPointsMulVarTime
encodeScalar _ = ecScalarToBinary
decodeScalar _ = ecScalarFromBinary
scalarToInteger _ = ecScalarToInteger
scalarFromInteger _ = ecScalarFromInteger
scalarAdd _ = ecScalarAdd
scalarMul _ = ecScalarMul
data Curve_P521R1 = Curve_P521R1 data Curve_P521R1 = Curve_P521R1
deriving (Show,Data)
instance EllipticCurve Curve_P521R1 where instance EllipticCurve Curve_P521R1 where
type Point Curve_P521R1 = Simple.Point Simple.SEC_p521r1 type Point Curve_P521R1 = Simple.Point Simple.SEC_p521r1
@ -160,15 +241,27 @@ instance EllipticCurve Curve_P521R1 where
instance EllipticCurveArith Curve_P521R1 where instance EllipticCurveArith Curve_P521R1 where
pointAdd _ a b = Simple.pointAdd a b pointAdd _ a b = Simple.pointAdd a b
pointNegate _ p = Simple.pointNegate p
pointSmul _ s p = Simple.pointMul s p pointSmul _ s p = Simple.pointMul s p
instance EllipticCurveDH Curve_P521R1 where instance EllipticCurveDH Curve_P521R1 where
ecdh _ s p = SharedSecret $ i2ospOf_ (curveSizeBytes prx) x ecdh _ s p = encodeECShared prx (Simple.pointMul s p)
where where
prx = Proxy :: Proxy Curve_P521R1 prx = Proxy :: Proxy Simple.SEC_p521r1
Simple.Point x _ = pointSmul prx s p
instance EllipticCurveBasepointArith Curve_P521R1 where
curveOrderBits _ = 521
pointBaseSmul _ = Simple.pointBaseMul
pointsSmulVarTime _ = ecPointsMulVarTime
encodeScalar _ = ecScalarToBinary
decodeScalar _ = ecScalarFromBinary
scalarToInteger _ = ecScalarToInteger
scalarFromInteger _ = ecScalarFromInteger
scalarAdd _ = ecScalarAdd
scalarMul _ = ecScalarMul
data Curve_X25519 = Curve_X25519 data Curve_X25519 = Curve_X25519
deriving (Show,Data)
instance EllipticCurve Curve_X25519 where instance EllipticCurve Curve_X25519 where
type Point Curve_X25519 = X25519.PublicKey type Point Curve_X25519 = X25519.PublicKey
@ -182,10 +275,12 @@ instance EllipticCurve Curve_X25519 where
decodePoint _ bs = X25519.publicKey bs decodePoint _ bs = X25519.publicKey bs
instance EllipticCurveDH Curve_X25519 where instance EllipticCurveDH Curve_X25519 where
ecdh _ s p = SharedSecret $ convert secret ecdhRaw _ s p = SharedSecret $ convert secret
where secret = X25519.dh p s where secret = X25519.dh p s
ecdh prx s p = checkNonZeroDH (ecdhRaw prx s p)
data Curve_X448 = Curve_X448 data Curve_X448 = Curve_X448
deriving (Show,Data)
instance EllipticCurve Curve_X448 where instance EllipticCurve Curve_X448 where
type Point Curve_X448 = X448.PublicKey type Point Curve_X448 = X448.PublicKey
@ -199,8 +294,52 @@ instance EllipticCurve Curve_X448 where
decodePoint _ bs = X448.publicKey bs decodePoint _ bs = X448.publicKey bs
instance EllipticCurveDH Curve_X448 where instance EllipticCurveDH Curve_X448 where
ecdh _ s p = SharedSecret $ convert secret ecdhRaw _ s p = SharedSecret $ convert secret
where secret = X448.dh p s where secret = X448.dh p s
ecdh prx s p = checkNonZeroDH (ecdhRaw prx s p)
data Curve_Edwards25519 = Curve_Edwards25519
deriving (Show,Data)
instance EllipticCurve Curve_Edwards25519 where
type Point Curve_Edwards25519 = Edwards25519.Point
type Scalar Curve_Edwards25519 = Edwards25519.Scalar
curveSizeBits _ = 255
curveGenerateScalar _ = Edwards25519.scalarGenerate
curveGenerateKeyPair _ = toKeyPair <$> Edwards25519.scalarGenerate
where toKeyPair scalar = KeyPair (Edwards25519.toPoint scalar) scalar
encodePoint _ point = Edwards25519.pointEncode point
decodePoint _ bs = Edwards25519.pointDecode bs
instance EllipticCurveArith Curve_Edwards25519 where
pointAdd _ a b = Edwards25519.pointAdd a b
pointNegate _ p = Edwards25519.pointNegate p
pointSmul _ s p = Edwards25519.pointMul s p
instance EllipticCurveBasepointArith Curve_Edwards25519 where
curveOrderBits _ = 253
pointBaseSmul _ = Edwards25519.toPoint
pointsSmulVarTime _ = Edwards25519.pointsMulVarTime
encodeScalar _ = B.reverse . Edwards25519.scalarEncode
decodeScalar _ bs
| B.length bs == 32 = Edwards25519.scalarDecodeLong (B.reverse bs)
| otherwise = CryptoFailed CryptoError_SecretKeySizeInvalid
scalarToInteger _ s = LE.os2ip (Edwards25519.scalarEncode s :: B.Bytes)
scalarFromInteger _ i =
case LE.i2ospOf 32 i of
Nothing -> CryptoFailed CryptoError_SecretKeySizeInvalid
Just bs -> Edwards25519.scalarDecodeLong (bs :: B.Bytes)
scalarAdd _ = Edwards25519.scalarAdd
scalarMul _ = Edwards25519.scalarMul
checkNonZeroDH :: SharedSecret -> CryptoFailable SharedSecret
checkNonZeroDH s@(SharedSecret b)
| B.constAllZero b = CryptoFailed CryptoError_ScalarMultiplicationInvalid
| otherwise = CryptoPassed s
encodeECShared :: Simple.Curve curve => Proxy curve -> Simple.Point curve -> CryptoFailable SharedSecret
encodeECShared _ Simple.PointO = CryptoFailed CryptoError_ScalarMultiplicationInvalid
encodeECShared prx (Simple.Point x _) = CryptoPassed . SharedSecret $ i2ospOf_ (Simple.curveSizeBytes prx) x
encodeECPoint :: forall curve bs . (Simple.Curve curve, ByteArray bs) => Simple.Point curve -> bs encodeECPoint :: forall curve bs . (Simple.Curve curve, ByteArray bs) => Simple.Point curve -> bs
encodeECPoint Simple.PointO = error "encodeECPoint: cannot serialize point at infinity" encodeECPoint Simple.PointO = error "encodeECPoint: cannot serialize point at infinity"
@ -214,7 +353,7 @@ encodeECPoint (Simple.Point x y) = B.concat [uncompressed,xb,yb]
decodeECPoint :: (Simple.Curve curve, ByteArray bs) => bs -> CryptoFailable (Simple.Point curve) decodeECPoint :: (Simple.Curve curve, ByteArray bs) => bs -> CryptoFailable (Simple.Point curve)
decodeECPoint mxy = case B.uncons mxy of decodeECPoint mxy = case B.uncons mxy of
Nothing -> CryptoFailed $ CryptoError_PointSizeInvalid Nothing -> CryptoFailed CryptoError_PointSizeInvalid
Just (m,xy) Just (m,xy)
-- uncompressed -- uncompressed
| m == 4 -> | m == 4 ->
@ -223,7 +362,47 @@ decodeECPoint mxy = case B.uncons mxy of
x = os2ip xb x = os2ip xb
y = os2ip yb y = os2ip yb
in Simple.pointFromIntegers (x,y) in Simple.pointFromIntegers (x,y)
| otherwise -> CryptoFailed $ CryptoError_PointFormatInvalid | otherwise -> CryptoFailed CryptoError_PointFormatInvalid
curveSizeBytes :: EllipticCurve c => Proxy c -> Int ecPointsMulVarTime :: forall curve . Simple.Curve curve
curveSizeBytes proxy = (curveSizeBits proxy + 7) `div` 8 => Simple.Scalar curve
-> Simple.Scalar curve -> Simple.Point curve
-> Simple.Point curve
ecPointsMulVarTime n1 = Simple.pointAddTwoMuls n1 g
where g = Simple.curveEccG $ Simple.curveParameters (Proxy :: Proxy curve)
ecScalarFromBinary :: forall curve bs . (Simple.Curve curve, ByteArrayAccess bs)
=> bs -> CryptoFailable (Simple.Scalar curve)
ecScalarFromBinary ba
| B.length ba /= size = CryptoFailed CryptoError_SecretKeySizeInvalid
| otherwise = CryptoPassed (Simple.Scalar $ os2ip ba)
where size = ecCurveOrderBytes (Proxy :: Proxy curve)
ecScalarToBinary :: forall curve bs . (Simple.Curve curve, ByteArray bs)
=> Simple.Scalar curve -> bs
ecScalarToBinary (Simple.Scalar s) = i2ospOf_ size s
where size = ecCurveOrderBytes (Proxy :: Proxy curve)
ecScalarFromInteger :: forall curve . Simple.Curve curve
=> Integer -> CryptoFailable (Simple.Scalar curve)
ecScalarFromInteger s
| numBits s > nb = CryptoFailed CryptoError_SecretKeySizeInvalid
| otherwise = CryptoPassed (Simple.Scalar s)
where nb = 8 * ecCurveOrderBytes (Proxy :: Proxy curve)
ecScalarToInteger :: Simple.Scalar curve -> Integer
ecScalarToInteger (Simple.Scalar s) = s
ecCurveOrderBytes :: Simple.Curve c => proxy c -> Int
ecCurveOrderBytes prx = (numBits n + 7) `div` 8
where n = Simple.curveEccN $ Simple.curveParameters prx
ecScalarAdd :: forall curve . Simple.Curve curve
=> Simple.Scalar curve -> Simple.Scalar curve -> Simple.Scalar curve
ecScalarAdd (Simple.Scalar a) (Simple.Scalar b) = Simple.Scalar ((a + b) `mod` n)
where n = Simple.curveEccN $ Simple.curveParameters (Proxy :: Proxy curve)
ecScalarMul :: forall curve . Simple.Curve curve
=> Simple.Scalar curve -> Simple.Scalar curve -> Simple.Scalar curve
ecScalarMul (Simple.Scalar a) (Simple.Scalar b) = Simple.Scalar ((a * b) `mod` n)
where n = Simple.curveEccN $ Simple.curveParameters (Proxy :: Proxy curve)

370
Crypto/ECC/Edwards25519.hs Normal file
View File

@ -0,0 +1,370 @@
-- |
-- Module : Crypto.ECC.Edwards25519
-- License : BSD-style
-- Maintainer : Olivier Chéron <olivier.cheron@gmail.com>
-- Stability : experimental
-- Portability : unknown
--
-- Arithmetic primitives over curve edwards25519.
--
-- Twisted Edwards curves are a familly of elliptic curves allowing
-- complete addition formulas without any special case and no point at
-- infinity. Curve edwards25519 is based on prime 2^255 - 19 for
-- efficient implementation. Equation and parameters are given in
-- <https://tools.ietf.org/html/rfc7748 RFC 7748>.
--
-- This module provides types and primitive operations that are useful
-- to implement cryptographic schemes based on curve edwards25519:
--
-- - arithmetic functions for point addition, doubling, negation,
-- scalar multiplication with an arbitrary point, with the base point,
-- etc.
--
-- - arithmetic functions dealing with scalars modulo the prime order
-- L of the base point
--
-- All functions run in constant time unless noted otherwise.
--
-- Warnings:
--
-- 1. Curve edwards25519 has a cofactor h = 8 so the base point does
-- not generate the entire curve and points with order 2, 4, 8 exist.
-- When implementing cryptographic algorithms, special care must be
-- taken using one of the following methods:
--
-- - points must be checked for membership in the prime-order
-- subgroup
--
-- - or cofactor must be cleared by multiplying points by 8
--
-- Utility functions are provided to implement this. Testing
-- subgroup membership with 'pointHasPrimeOrder' is 50-time slower
-- than call 'pointMulByCofactor'.
--
-- 2. Scalar arithmetic is always reduced modulo L, allowing fixed
-- length and constant execution time, but this reduction is valid
-- only when points are in the prime-order subgroup.
--
-- 3. Because of modular reduction in this implementation it is not
-- possible to multiply points directly by scalars like 8.s or L.
-- This has to be decomposed into several steps.
--
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Crypto.ECC.Edwards25519
( Scalar
, Point
-- * Scalars
, scalarGenerate
, scalarDecodeLong
, scalarEncode
-- * Points
, pointDecode
, pointEncode
, pointHasPrimeOrder
-- * Arithmetic functions
, toPoint
, scalarAdd
, scalarMul
, pointNegate
, pointAdd
, pointDouble
, pointMul
, pointMulByCofactor
, pointsMulVarTime
) where
import Data.Word
import Foreign.C.Types
import Foreign.Ptr
import Crypto.Error
import Crypto.Internal.ByteArray (Bytes, ScrubbedBytes, withByteArray)
import qualified Crypto.Internal.ByteArray as B
import Crypto.Internal.Compat
import Crypto.Internal.Imports
import Crypto.Random
scalarArraySize :: Int
scalarArraySize = 40 -- maximum [9 * 4 {- 32 bits -}, 5 * 8 {- 64 bits -}]
-- | A scalar modulo prime order of curve edwards25519.
newtype Scalar = Scalar ScrubbedBytes
deriving (Show,NFData)
instance Eq Scalar where
(Scalar s1) == (Scalar s2) = unsafeDoIO $
withByteArray s1 $ \ps1 ->
withByteArray s2 $ \ps2 ->
fmap (/= 0) (ed25519_scalar_eq ps1 ps2)
{-# NOINLINE (==) #-}
pointArraySize :: Int
pointArraySize = 160 -- maximum [4 * 10 * 4 {- 32 bits -}, 4 * 5 * 8 {- 64 bits -}]
-- | A point on curve edwards25519.
newtype Point = Point Bytes
deriving NFData
instance Show Point where
showsPrec d p =
let bs = pointEncode p :: Bytes
in showParen (d > 10) $ showString "Point "
. shows (B.convertToBase B.Base16 bs :: Bytes)
instance Eq Point where
(Point p1) == (Point p2) = unsafeDoIO $
withByteArray p1 $ \pp1 ->
withByteArray p2 $ \pp2 ->
fmap (/= 0) (ed25519_point_eq pp1 pp2)
{-# NOINLINE (==) #-}
-- | Generate a random scalar.
scalarGenerate :: MonadRandom randomly => randomly Scalar
scalarGenerate = throwCryptoError . scalarDecodeLong <$> generate
where
-- Scalar generation is based on a fixed number of bytes so that
-- there is no timing leak. But because of modular reduction
-- distribution is not uniform. We use many more bytes than
-- necessary so the probability bias is small. With 512 bits we
-- get 22% of scalars with a higher frequency, but the relative
-- probability difference is only 2^(-260).
generate :: MonadRandom randomly => randomly ScrubbedBytes
generate = getRandomBytes 64
-- | Serialize a scalar to binary, i.e. a 32-byte little-endian
-- number.
scalarEncode :: B.ByteArray bs => Scalar -> bs
scalarEncode (Scalar s) =
B.allocAndFreeze 32 $ \out ->
withByteArray s $ \ps -> ed25519_scalar_encode out ps
-- | Deserialize a little-endian number as a scalar. Input array can
-- have any length from 0 to 64 bytes.
--
-- Note: it is not advised to put secret information in the 3 lowest
-- bits of a scalar if this scalar may be multiplied to untrusted
-- points outside the prime-order subgroup.
scalarDecodeLong :: B.ByteArrayAccess bs => bs -> CryptoFailable Scalar
scalarDecodeLong bs
| B.length bs > 64 = CryptoFailed CryptoError_EcScalarOutOfBounds
| otherwise = unsafeDoIO $ withByteArray bs initialize
where
len = fromIntegral $ B.length bs
initialize inp = do
s <- B.alloc scalarArraySize $ \ps ->
ed25519_scalar_decode_long ps inp len
return $ CryptoPassed (Scalar s)
{-# NOINLINE scalarDecodeLong #-}
-- | Add two scalars.
scalarAdd :: Scalar -> Scalar -> Scalar
scalarAdd (Scalar a) (Scalar b) =
Scalar $ B.allocAndFreeze scalarArraySize $ \out ->
withByteArray a $ \pa ->
withByteArray b $ \pb ->
ed25519_scalar_add out pa pb
-- | Multiply two scalars.
scalarMul :: Scalar -> Scalar -> Scalar
scalarMul (Scalar a) (Scalar b) =
Scalar $ B.allocAndFreeze scalarArraySize $ \out ->
withByteArray a $ \pa ->
withByteArray b $ \pb ->
ed25519_scalar_mul out pa pb
-- | Multiplies a scalar with the curve base point.
toPoint :: Scalar -> Point
toPoint (Scalar scalar) =
Point $ B.allocAndFreeze pointArraySize $ \out ->
withByteArray scalar $ \pscalar ->
ed25519_point_base_scalarmul out pscalar
-- | Serialize a point to a 32-byte array.
--
-- Format is binary compatible with 'Crypto.PubKey.Ed25519.PublicKey'
-- from module "Crypto.PubKey.Ed25519".
pointEncode :: B.ByteArray bs => Point -> bs
pointEncode (Point p) =
B.allocAndFreeze 32 $ \out ->
withByteArray p $ \pp ->
ed25519_point_encode out pp
-- | Deserialize a 32-byte array as a point, ensuring the point is
-- valid on edwards25519.
--
-- /WARNING:/ variable time
pointDecode :: B.ByteArrayAccess bs => bs -> CryptoFailable Point
pointDecode bs
| B.length bs == 32 = unsafeDoIO $ withByteArray bs initialize
| otherwise = CryptoFailed CryptoError_PointSizeInvalid
where
initialize inp = do
(res, p) <- B.allocRet pointArraySize $ \pp ->
ed25519_point_decode_vartime pp inp
if res == 0 then return $ CryptoFailed CryptoError_PointCoordinatesInvalid
else return $ CryptoPassed (Point p)
{-# NOINLINE pointDecode #-}
-- | Test whether a point belongs to the prime-order subgroup
-- generated by the base point. Result is 'True' for the identity
-- point.
--
-- @
-- pointHasPrimeOrder p = 'pointNegate' p == 'pointMul' l_minus_one p
-- @
pointHasPrimeOrder :: Point -> Bool
pointHasPrimeOrder (Point p) = unsafeDoIO $
withByteArray p $ \pp ->
fmap (/= 0) (ed25519_point_has_prime_order pp)
{-# NOINLINE pointHasPrimeOrder #-}
-- | Negate a point.
pointNegate :: Point -> Point
pointNegate (Point a) =
Point $ B.allocAndFreeze pointArraySize $ \out ->
withByteArray a $ \pa ->
ed25519_point_negate out pa
-- | Add two points.
pointAdd :: Point -> Point -> Point
pointAdd (Point a) (Point b) =
Point $ B.allocAndFreeze pointArraySize $ \out ->
withByteArray a $ \pa ->
withByteArray b $ \pb ->
ed25519_point_add out pa pb
-- | Add a point to itself.
--
-- @
-- pointDouble p = 'pointAdd' p p
-- @
pointDouble :: Point -> Point
pointDouble (Point a) =
Point $ B.allocAndFreeze pointArraySize $ \out ->
withByteArray a $ \pa ->
ed25519_point_double out pa
-- | Multiply a point by h = 8.
--
-- @
-- pointMulByCofactor p = 'pointMul' scalar_8 p
-- @
pointMulByCofactor :: Point -> Point
pointMulByCofactor (Point a) =
Point $ B.allocAndFreeze pointArraySize $ \out ->
withByteArray a $ \pa ->
ed25519_point_mul_by_cofactor out pa
-- | Scalar multiplication over curve edwards25519.
--
-- Note: when the scalar had reduction modulo L and the input point
-- has a torsion component, the output point may not be in the
-- expected subgroup.
pointMul :: Scalar -> Point -> Point
pointMul (Scalar scalar) (Point base) =
Point $ B.allocAndFreeze pointArraySize $ \out ->
withByteArray scalar $ \pscalar ->
withByteArray base $ \pbase ->
ed25519_point_scalarmul out pbase pscalar
-- | Multiply the point @p@ with @s2@ and add a lifted to curve value @s1@.
--
-- @
-- pointsMulVarTime s1 s2 p = 'pointAdd' ('toPoint' s1) ('pointMul' s2 p)
-- @
--
-- /WARNING:/ variable time
pointsMulVarTime :: Scalar -> Scalar -> Point -> Point
pointsMulVarTime (Scalar s1) (Scalar s2) (Point p) =
Point $ B.allocAndFreeze pointArraySize $ \out ->
withByteArray s1 $ \ps1 ->
withByteArray s2 $ \ps2 ->
withByteArray p $ \pp ->
ed25519_base_double_scalarmul_vartime out ps1 pp ps2
foreign import ccall unsafe "cryptonite_ed25519_scalar_eq"
ed25519_scalar_eq :: Ptr Scalar
-> Ptr Scalar
-> IO CInt
foreign import ccall unsafe "cryptonite_ed25519_scalar_encode"
ed25519_scalar_encode :: Ptr Word8
-> Ptr Scalar
-> IO ()
foreign import ccall unsafe "cryptonite_ed25519_scalar_decode_long"
ed25519_scalar_decode_long :: Ptr Scalar
-> Ptr Word8
-> CSize
-> IO ()
foreign import ccall unsafe "cryptonite_ed25519_scalar_add"
ed25519_scalar_add :: Ptr Scalar -- sum
-> Ptr Scalar -- a
-> Ptr Scalar -- b
-> IO ()
foreign import ccall unsafe "cryptonite_ed25519_scalar_mul"
ed25519_scalar_mul :: Ptr Scalar -- out
-> Ptr Scalar -- a
-> Ptr Scalar -- b
-> IO ()
foreign import ccall unsafe "cryptonite_ed25519_point_encode"
ed25519_point_encode :: Ptr Word8
-> Ptr Point
-> IO ()
foreign import ccall unsafe "cryptonite_ed25519_point_decode_vartime"
ed25519_point_decode_vartime :: Ptr Point
-> Ptr Word8
-> IO CInt
foreign import ccall unsafe "cryptonite_ed25519_point_eq"
ed25519_point_eq :: Ptr Point
-> Ptr Point
-> IO CInt
foreign import ccall "cryptonite_ed25519_point_has_prime_order"
ed25519_point_has_prime_order :: Ptr Point
-> IO CInt
foreign import ccall unsafe "cryptonite_ed25519_point_negate"
ed25519_point_negate :: Ptr Point -- minus_a
-> Ptr Point -- a
-> IO ()
foreign import ccall unsafe "cryptonite_ed25519_point_add"
ed25519_point_add :: Ptr Point -- sum
-> Ptr Point -- a
-> Ptr Point -- b
-> IO ()
foreign import ccall unsafe "cryptonite_ed25519_point_double"
ed25519_point_double :: Ptr Point -- two_a
-> Ptr Point -- a
-> IO ()
foreign import ccall unsafe "cryptonite_ed25519_point_mul_by_cofactor"
ed25519_point_mul_by_cofactor :: Ptr Point -- eight_a
-> Ptr Point -- a
-> IO ()
foreign import ccall "cryptonite_ed25519_point_base_scalarmul"
ed25519_point_base_scalarmul :: Ptr Point -- scaled
-> Ptr Scalar -- scalar
-> IO ()
foreign import ccall "cryptonite_ed25519_point_scalarmul"
ed25519_point_scalarmul :: Ptr Point -- scaled
-> Ptr Point -- base
-> Ptr Scalar -- scalar
-> IO ()
foreign import ccall "cryptonite_ed25519_base_double_scalarmul_vartime"
ed25519_base_double_scalarmul_vartime :: Ptr Point -- combo
-> Ptr Scalar -- scalar1
-> Ptr Point -- base2
-> Ptr Scalar -- scalar2
-> IO ()

View File

@ -6,6 +6,7 @@ module Crypto.ECC.Simple.Prim
( scalarGenerate ( scalarGenerate
, scalarFromInteger , scalarFromInteger
, pointAdd , pointAdd
, pointNegate
, pointDouble , pointDouble
, pointBaseMul , pointBaseMul
, pointMul , pointMul
@ -16,8 +17,7 @@ module Crypto.ECC.Simple.Prim
) where ) where
import Data.Maybe import Data.Maybe
import Crypto.Internal.Imports import Data.Proxy
import Crypto.Internal.Proxy
import Crypto.Number.ModArithmetic import Crypto.Number.ModArithmetic
import Crypto.Number.F2m import Crypto.Number.F2m
import Crypto.Number.Generate (generateBetween) import Crypto.Number.Generate (generateBetween)
@ -49,7 +49,7 @@ pointNegate :: Curve curve => Point curve -> Point curve
pointNegate PointO = PointO pointNegate PointO = PointO
pointNegate point@(Point x y) = pointNegate point@(Point x y) =
case curveType point of case curveType point of
CurvePrime {} -> Point x (-y) CurvePrime (CurvePrimeParam p) -> Point x (p - y)
CurveBinary {} -> Point x (x `addF2m` y) CurveBinary {} -> Point x (x `addF2m` y)
-- | Elliptic Curve point addition. -- | Elliptic Curve point addition.

View File

@ -1,4 +1,5 @@
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-- | -- |
-- Module : Crypto.ECC.Simple.Types -- Module : Crypto.ECC.Simple.Types
-- License : BSD-style -- License : BSD-style
@ -6,7 +7,7 @@
-- Stability : Experimental -- Stability : Experimental
-- Portability : Excellent -- Portability : Excellent
-- --
-- references: -- References:
-- <https://tools.ietf.org/html/rfc5915> -- <https://tools.ietf.org/html/rfc5915>
-- --
{-# OPTIONS_GHC -fno-warn-missing-signatures #-} {-# OPTIONS_GHC -fno-warn-missing-signatures #-}
@ -20,7 +21,7 @@ module Crypto.ECC.Simple.Types
, curveSizeBits , curveSizeBits
, curveSizeBytes , curveSizeBytes
, CurveParameters(..) , CurveParameters(..)
-- * specific curves definition -- * Specific curves definition
, SEC_p112r1(..) , SEC_p112r1(..)
, SEC_p112r2(..) , SEC_p112r2(..)
, SEC_p128r1(..) , SEC_p128r1(..)
@ -83,28 +84,28 @@ data CurveParameters curve = CurveParameters
, curveEccG :: Point curve -- ^ base point , curveEccG :: Point curve -- ^ base point
, curveEccN :: Integer -- ^ order of G , curveEccN :: Integer -- ^ order of G
, curveEccH :: Integer -- ^ cofactor , curveEccH :: Integer -- ^ cofactor
} deriving (Show,Eq,Data,Typeable) } deriving (Show,Eq,Data)
newtype CurveBinaryParam = CurveBinaryParam Integer newtype CurveBinaryParam = CurveBinaryParam Integer
deriving (Show,Read,Eq,Data,Typeable) deriving (Show,Read,Eq,Data)
newtype CurvePrimeParam = CurvePrimeParam Integer newtype CurvePrimeParam = CurvePrimeParam Integer
deriving (Show,Read,Eq,Data,Typeable) deriving (Show,Read,Eq,Data)
data CurveType = data CurveType =
CurveBinary CurveBinaryParam CurveBinary CurveBinaryParam
| CurvePrime CurvePrimeParam | CurvePrime CurvePrimeParam
deriving (Show,Read,Eq,Data,Typeable) deriving (Show,Read,Eq,Data)
-- | ECC Private Number -- | ECC Private Number
newtype Scalar curve = Scalar Integer newtype Scalar curve = Scalar Integer
deriving (Show,Read,Eq,Data,Typeable) deriving (Show,Read,Eq,Data,NFData)
-- | Define a point on a curve. -- | Define a point on a curve.
data Point curve = data Point curve =
Point Integer Integer Point Integer Integer
| PointO -- ^ Point at Infinity | PointO -- ^ Point at Infinity
deriving (Show,Read,Eq,Data,Typeable) deriving (Show,Read,Eq,Data)
instance NFData (Point curve) where instance NFData (Point curve) where
rnf (Point x y) = x `seq` y `seq` () rnf (Point x y) = x `seq` y `seq` ()

View File

@ -8,6 +8,7 @@
-- Cryptographic Error enumeration and handling -- Cryptographic Error enumeration and handling
-- --
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Error.Types module Crypto.Error.Types
( CryptoError(..) ( CryptoError(..)
, CryptoFailable(..) , CryptoFailable(..)
@ -21,13 +22,14 @@ module Crypto.Error.Types
import qualified Control.Exception as E import qualified Control.Exception as E
import Data.Data import Data.Data
import Crypto.Internal.Imports import Basement.Monad (MonadFailure(..))
-- | Enumeration of all possible errors that can be found in this library -- | Enumeration of all possible errors that can be found in this library
data CryptoError = data CryptoError =
-- symmetric cipher errors -- symmetric cipher errors
CryptoError_KeySizeInvalid CryptoError_KeySizeInvalid
| CryptoError_IvSizeInvalid | CryptoError_IvSizeInvalid
| CryptoError_SeedSizeInvalid
| CryptoError_AEADModeNotSupported | CryptoError_AEADModeNotSupported
-- public key cryptography error -- public key cryptography error
| CryptoError_SecretKeySizeInvalid | CryptoError_SecretKeySizeInvalid
@ -40,12 +42,17 @@ data CryptoError =
| CryptoError_PointFormatInvalid | CryptoError_PointFormatInvalid
| CryptoError_PointFormatUnsupported | CryptoError_PointFormatUnsupported
| CryptoError_PointCoordinatesInvalid | CryptoError_PointCoordinatesInvalid
| CryptoError_ScalarMultiplicationInvalid
-- Message authentification error -- Message authentification error
| CryptoError_MacKeyInvalid | CryptoError_MacKeyInvalid
| CryptoError_AuthenticationTagSizeInvalid | CryptoError_AuthenticationTagSizeInvalid
-- Prime generation error -- Prime generation error
| CryptoError_PrimeSizeInvalid | CryptoError_PrimeSizeInvalid
deriving (Show,Eq,Enum,Data,Typeable) -- Parameter errors
| CryptoError_SaltTooSmall
| CryptoError_OutputLengthTooSmall
| CryptoError_OutputLengthTooBig
deriving (Show,Eq,Enum,Data)
instance E.Exception CryptoError instance E.Exception CryptoError
@ -75,12 +82,16 @@ instance Applicative CryptoFailable where
pure a = CryptoPassed a pure a = CryptoPassed a
(<*>) fm m = fm >>= \p -> m >>= \r2 -> return (p r2) (<*>) fm m = fm >>= \p -> m >>= \r2 -> return (p r2)
instance Monad CryptoFailable where instance Monad CryptoFailable where
return a = CryptoPassed a return = pure
(>>=) m1 m2 = do (>>=) m1 m2 = do
case m1 of case m1 of
CryptoPassed a -> m2 a CryptoPassed a -> m2 a
CryptoFailed e -> CryptoFailed e CryptoFailed e -> CryptoFailed e
instance MonadFailure CryptoFailable where
type Failure CryptoFailable = CryptoError
mFail = CryptoFailed
-- | Throw an CryptoError as exception on CryptoFailed result, -- | Throw an CryptoError as exception on CryptoFailed result,
-- otherwise return the computed value -- otherwise return the computed value
throwCryptoErrorIO :: CryptoFailable a -> IO a throwCryptoErrorIO :: CryptoFailable a -> IO a

View File

@ -16,6 +16,8 @@
-- > hexSha3_512 :: ByteString -> String -- > hexSha3_512 :: ByteString -> String
-- > hexSha3_512 bs = show (hash bs :: Digest SHA3_512) -- > hexSha3_512 bs = show (hash bs :: Digest SHA3_512)
-- --
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE BangPatterns #-}
module Crypto.Hash module Crypto.Hash
( (
-- * Types -- * Types
@ -23,77 +25,110 @@ module Crypto.Hash
, Digest , Digest
-- * Functions -- * Functions
, digestFromByteString , digestFromByteString
-- * hash methods parametrized by algorithm -- * Hash methods parametrized by algorithm
, hashInitWith , hashInitWith
, hashWith , hashWith
-- * hash methods , hashPrefixWith
-- * Hash methods
, hashInit , hashInit
, hashUpdates , hashUpdates
, hashUpdate , hashUpdate
, hashFinalize , hashFinalize
, hashFinalizePrefix
, hashBlockSize , hashBlockSize
, hashDigestSize , hashDigestSize
, hash , hash
, hashPrefix
, hashlazy , hashlazy
, hashPutContext
, hashGetContext
-- * Hash algorithms -- * Hash algorithms
, module Crypto.Hash.Algorithms , module Crypto.Hash.Algorithms
) where ) where
import Control.Monad import Basement.Types.OffsetSize (CountOf (..))
import Basement.Block (Block, unsafeFreeze)
import Basement.Block.Mutable (copyFromPtr, new)
import Crypto.Internal.Compat (unsafeDoIO)
import Crypto.Hash.Types import Crypto.Hash.Types
import Crypto.Hash.Algorithms import Crypto.Hash.Algorithms
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr, plusPtr)
import Crypto.Internal.ByteArray (ByteArrayAccess) import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray)
import qualified Crypto.Internal.ByteArray as B import qualified Crypto.Internal.ByteArray as B
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy as L
import Data.Word (Word8)
import Data.Int (Int32)
-- | Hash a strict bytestring into a digest. -- | Hash a strict bytestring into a digest.
hash :: (ByteArrayAccess ba, HashAlgorithm a) => ba -> Digest a hash :: (ByteArrayAccess ba, HashAlgorithm a) => ba -> Digest a
hash bs = hashFinalize $ hashUpdate hashInit bs hash bs = hashFinalize $ hashUpdate hashInit bs
-- | Hash the first N bytes of a bytestring, with code path independent from N.
hashPrefix :: (ByteArrayAccess ba, HashAlgorithmPrefix a) => ba -> Int -> Digest a
hashPrefix = hashFinalizePrefix hashInit
-- | Hash a lazy bytestring into a digest. -- | Hash a lazy bytestring into a digest.
hashlazy :: HashAlgorithm a => L.ByteString -> Digest a hashlazy :: HashAlgorithm a => L.ByteString -> Digest a
hashlazy lbs = hashFinalize $ hashUpdates hashInit (L.toChunks lbs) hashlazy lbs = hashFinalize $ hashUpdates hashInit (L.toChunks lbs)
-- | Initialize a new context for this hash algorithm -- | Initialize a new context for this hash algorithm
hashInit :: HashAlgorithm a hashInit :: forall a . HashAlgorithm a => Context a
=> Context a hashInit = Context $ B.allocAndFreeze (hashInternalContextSize (undefined :: a)) $ \(ptr :: Ptr (Context a)) ->
hashInit = doInit undefined B.allocAndFreeze hashInternalInit ptr
where
doInit :: HashAlgorithm a => a -> (Int -> (Ptr (Context a) -> IO ()) -> B.Bytes) -> Context a
doInit alg alloc = Context $ alloc (hashInternalContextSize alg) hashInternalInit
{-# NOINLINE hashInit #-}
-- | run hashUpdates on one single bytestring and return the updated context. -- | run hashUpdates on one single bytestring and return the updated context.
hashUpdate :: (ByteArrayAccess ba, HashAlgorithm a) => Context a -> ba -> Context a hashUpdate :: (ByteArrayAccess ba, HashAlgorithm a) => Context a -> ba -> Context a
hashUpdate ctx b = hashUpdates ctx [b] hashUpdate ctx b
| B.null b = ctx
| otherwise = hashUpdates ctx [b]
-- | Update the context with a list of strict bytestring, -- | Update the context with a list of strict bytestring,
-- and return a new context with the updates. -- and return a new context with the updates.
hashUpdates :: (HashAlgorithm a, ByteArrayAccess ba) hashUpdates :: forall a ba . (HashAlgorithm a, ByteArrayAccess ba)
=> Context a => Context a
-> [ba] -> [ba]
-> Context a -> Context a
hashUpdates c l = doUpdates (B.copyAndFreeze c) hashUpdates c l
where doUpdates :: HashAlgorithm a => ((Ptr (Context a) -> IO ()) -> B.Bytes) -> Context a | null ls = c
doUpdates copy = Context $ copy $ \ctx -> | otherwise = Context $ B.copyAndFreeze c $ \(ctx :: Ptr (Context a)) ->
mapM_ (\b -> B.withByteArray b $ \d -> hashInternalUpdate ctx d (fromIntegral $ B.length b)) l mapM_ (\b -> B.withByteArray b (processBlocks ctx (B.length b))) ls
{-# NOINLINE hashUpdates #-} where
ls = filter (not . B.null) l
-- process the data in 2GB chunks to fit in uint32_t and Int on 32 bit systems
processBlocks ctx bytesLeft dataPtr
| bytesLeft == 0 = return ()
| otherwise = do
hashInternalUpdate ctx dataPtr (fromIntegral actuallyProcessed)
processBlocks ctx (bytesLeft - actuallyProcessed) (dataPtr `plusPtr` actuallyProcessed)
where
actuallyProcessed = min bytesLeft (fromIntegral (maxBound :: Int32))
-- | Finalize a context and return a digest. -- | Finalize a context and return a digest.
hashFinalize :: HashAlgorithm a hashFinalize :: forall a . HashAlgorithm a
=> Context a => Context a
-> Digest a -> Digest a
hashFinalize c = doFinalize undefined (B.copy c) (B.allocAndFreeze) hashFinalize !c =
where doFinalize :: HashAlgorithm alg Digest $ B.allocAndFreeze (hashDigestSize (undefined :: a)) $ \(dig :: Ptr (Digest a)) -> do
=> alg ((!_) :: B.Bytes) <- B.copy c $ \(ctx :: Ptr (Context a)) -> hashInternalFinalize ctx dig
-> ((Ptr (Context alg) -> IO ()) -> IO B.Bytes) return ()
-> (Int -> (Ptr (Digest alg) -> IO ()) -> B.Bytes)
-> Digest alg -- | Update the context with the first N bytes of a bytestring and return the
doFinalize alg copy allocDigest = -- digest. The code path is independent from N but much slower than a normal
Digest $ allocDigest (hashDigestSize alg) $ \dig -> -- 'hashUpdate'. The function can be called for the last bytes of a message, in
(void $ copy $ \ctx -> hashInternalFinalize ctx dig) -- order to exclude a variable padding, without leaking the padding length. The
{-# NOINLINE hashFinalize #-} -- begining of the message, never impacted by the padding, should preferably go
-- through 'hashUpdate' for better performance.
hashFinalizePrefix :: forall a ba . (HashAlgorithmPrefix a, ByteArrayAccess ba)
=> Context a
-> ba
-> Int
-> Digest a
hashFinalizePrefix !c b len =
Digest $ B.allocAndFreeze (hashDigestSize (undefined :: a)) $ \(dig :: Ptr (Digest a)) -> do
((!_) :: B.Bytes) <- B.copy c $ \(ctx :: Ptr (Context a)) ->
B.withByteArray b $ \d ->
hashInternalFinalizePrefix ctx d (fromIntegral $ B.length b) (fromIntegral len) dig
return ()
-- | Initialize a new context for a specified hash algorithm -- | Initialize a new context for a specified hash algorithm
hashInitWith :: HashAlgorithm alg => alg -> Context alg hashInitWith :: HashAlgorithm alg => alg -> Context alg
@ -103,14 +138,39 @@ hashInitWith _ = hashInit
hashWith :: (ByteArrayAccess ba, HashAlgorithm alg) => alg -> ba -> Digest alg hashWith :: (ByteArrayAccess ba, HashAlgorithm alg) => alg -> ba -> Digest alg
hashWith _ = hash hashWith _ = hash
-- | Run the 'hashPrefix' function but takes an explicit hash algorithm parameter
hashPrefixWith :: (ByteArrayAccess ba, HashAlgorithmPrefix alg) => alg -> ba -> Int -> Digest alg
hashPrefixWith _ = hashPrefix
-- | Try to transform a bytearray into a Digest of specific algorithm. -- | Try to transform a bytearray into a Digest of specific algorithm.
-- --
-- If the digest is not the right size for the algorithm specified, then -- If the digest is not the right size for the algorithm specified, then
-- Nothing is returned. -- Nothing is returned.
digestFromByteString :: (HashAlgorithm a, ByteArrayAccess ba) => ba -> Maybe (Digest a) digestFromByteString :: forall a ba . (HashAlgorithm a, ByteArrayAccess ba) => ba -> Maybe (Digest a)
digestFromByteString = from undefined digestFromByteString = from undefined
where where
from :: (HashAlgorithm a, ByteArrayAccess ba) => a -> ba -> Maybe (Digest a) from :: a -> ba -> Maybe (Digest a)
from alg bs from alg bs
| B.length bs == (hashDigestSize alg) = (Just $ Digest $ B.convert bs) | B.length bs == (hashDigestSize alg) = Just $ Digest $ unsafeDoIO $ copyBytes bs
| otherwise = Nothing | otherwise = Nothing
copyBytes :: ba -> IO (Block Word8)
copyBytes ba = do
muArray <- new count
B.withByteArray ba $ \ptr -> copyFromPtr ptr muArray 0 count
unsafeFreeze muArray
where
count = CountOf (B.length ba)
hashPutContext :: forall a ba. (HashAlgorithmResumable a, ByteArray ba) => Context a -> ba
hashPutContext !c = B.allocAndFreeze (hashInternalContextSize (undefined :: a)) $ \(ptr :: Ptr Word8) ->
B.withByteArray c $ \(ctx :: Ptr (Context a)) -> hashInternalPutContextBE ctx ptr
hashGetContext :: forall a ba. (HashAlgorithmResumable a, ByteArrayAccess ba) => ba -> Maybe (Context a)
hashGetContext = from undefined
where
from :: a -> ba -> Maybe (Context a)
from alg bs
| B.length bs == (hashInternalContextSize alg) = Just $ Context $ B.allocAndFreeze (B.length bs) $ \(ctx :: Ptr (Context a)) ->
B.withByteArray bs $ \ptr -> hashInternalGetContextBE ptr ctx
| otherwise = Nothing

View File

@ -1,4 +1,3 @@
{-# LANGUAGE CPP #-}
-- | -- |
-- Module : Crypto.Hash.Algorithms -- Module : Crypto.Hash.Algorithms
-- License : BSD-style -- License : BSD-style
@ -10,11 +9,18 @@
-- --
module Crypto.Hash.Algorithms module Crypto.Hash.Algorithms
( HashAlgorithm ( HashAlgorithm
-- * hash algorithms , HashAlgorithmPrefix
, HashAlgorithmResumable
-- * Hash algorithms
, Blake2s_160(..)
, Blake2s_224(..) , Blake2s_224(..)
, Blake2sp_224(..)
, Blake2s_256(..) , Blake2s_256(..)
, Blake2sp_224(..)
, Blake2sp_256(..) , Blake2sp_256(..)
, Blake2b_160(..)
, Blake2b_224(..)
, Blake2b_256(..)
, Blake2b_384(..)
, Blake2b_512(..) , Blake2b_512(..)
, Blake2bp_512(..) , Blake2bp_512(..)
, MD2(..) , MD2(..)
@ -37,6 +43,10 @@ module Crypto.Hash.Algorithms
, SHA3_256(..) , SHA3_256(..)
, SHA3_384(..) , SHA3_384(..)
, SHA3_512(..) , SHA3_512(..)
, SHAKE128(..)
, SHAKE256(..)
, Blake2b(..), Blake2bp(..)
, Blake2s(..), Blake2sp(..)
, Skein256_224(..) , Skein256_224(..)
, Skein256_256(..) , Skein256_256(..)
, Skein512_224(..) , Skein512_224(..)
@ -46,7 +56,7 @@ module Crypto.Hash.Algorithms
, Whirlpool(..) , Whirlpool(..)
) where ) where
import Crypto.Hash.Types (HashAlgorithm) import Crypto.Hash.Types (HashAlgorithm, HashAlgorithmPrefix, HashAlgorithmResumable)
import Crypto.Hash.Blake2s import Crypto.Hash.Blake2s
import Crypto.Hash.Blake2sp import Crypto.Hash.Blake2sp
import Crypto.Hash.Blake2b import Crypto.Hash.Blake2b
@ -67,3 +77,5 @@ import Crypto.Hash.Tiger
import Crypto.Hash.Skein256 import Crypto.Hash.Skein256
import Crypto.Hash.Skein512 import Crypto.Hash.Skein512
import Crypto.Hash.Whirlpool import Crypto.Hash.Whirlpool
import Crypto.Hash.SHAKE
import Crypto.Hash.Blake2

162
Crypto/Hash/Blake2.hs Normal file
View File

@ -0,0 +1,162 @@
-- |
-- Module : Crypto.Hash.Blake2
-- License : BSD-style
-- Maintainer : Nicolas Di Prima <nicolas@primetype.co.uk>
-- Stability : experimental
-- Portability : unknown
--
-- Module containing the binding functions to work with the
-- Blake2
--
-- Implementation based from [RFC7693](https://tools.ietf.org/html/rfc7693)
--
-- Please consider the following when chosing a hash:
--
-- Algorithm | Target | Collision | Digest Size |
-- Identifier | Arch | Security | in bytes |
-- ---------------+--------+-----------+-------------+
-- id-blake2b160 | 64-bit | 2**80 | 20 |
-- id-blake2b256 | 64-bit | 2**128 | 32 |
-- id-blake2b384 | 64-bit | 2**192 | 48 |
-- id-blake2b512 | 64-bit | 2**256 | 64 |
-- ---------------+--------+-----------+-------------+
-- id-blake2s128 | 32-bit | 2**64 | 16 |
-- id-blake2s160 | 32-bit | 2**80 | 20 |
-- id-blake2s224 | 32-bit | 2**112 | 28 |
-- id-blake2s256 | 32-bit | 2**128 | 32 |
-- ---------------+--------+-----------+-------------+
--
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.Blake2
( Blake2s(..)
, Blake2sp(..)
, Blake2b(..)
, Blake2bp(..)
) where
import Crypto.Hash.Types
import Foreign.Ptr (Ptr)
import Data.Data
import Data.Word (Word8, Word32)
import GHC.TypeLits (Nat, KnownNat)
import Crypto.Internal.Nat
-- | Fast and secure alternative to SHA1 and HMAC-SHA1
--
-- It is espacially known to target 32bits architectures.
--
-- Known supported digest sizes:
--
-- * Blake2s 160
-- * Blake2s 224
-- * Blake2s 256
--
data Blake2s (bitlen :: Nat) = Blake2s
deriving (Show,Data)
instance (IsDivisibleBy8 bitlen, KnownNat bitlen, IsAtLeast bitlen 8, IsAtMost bitlen 256)
=> HashAlgorithm (Blake2s bitlen)
where
type HashBlockSize (Blake2s bitlen) = 64
type HashDigestSize (Blake2s bitlen) = Div8 bitlen
type HashInternalContextSize (Blake2s bitlen) = 136
hashBlockSize _ = 64
hashDigestSize _ = byteLen (Proxy :: Proxy bitlen)
hashInternalContextSize _ = 136
hashInternalInit p = c_blake2s_init p (integralNatVal (Proxy :: Proxy bitlen))
hashInternalUpdate = c_blake2s_update
hashInternalFinalize p = c_blake2s_finalize p (integralNatVal (Proxy :: Proxy bitlen))
foreign import ccall unsafe "cryptonite_blake2s_init"
c_blake2s_init :: Ptr (Context a) -> Word32 -> IO ()
foreign import ccall "cryptonite_blake2s_update"
c_blake2s_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO ()
foreign import ccall unsafe "cryptonite_blake2s_finalize"
c_blake2s_finalize :: Ptr (Context a) -> Word32 -> Ptr (Digest a) -> IO ()
-- | Fast cryptographic hash.
--
-- It is especially known to target 64bits architectures.
--
-- Known supported digest sizes:
--
-- * Blake2b 160
-- * Blake2b 224
-- * Blake2b 256
-- * Blake2b 384
-- * Blake2b 512
--
data Blake2b (bitlen :: Nat) = Blake2b
deriving (Show,Data)
instance (IsDivisibleBy8 bitlen, KnownNat bitlen, IsAtLeast bitlen 8, IsAtMost bitlen 512)
=> HashAlgorithm (Blake2b bitlen)
where
type HashBlockSize (Blake2b bitlen) = 128
type HashDigestSize (Blake2b bitlen) = Div8 bitlen
type HashInternalContextSize (Blake2b bitlen) = 248
hashBlockSize _ = 128
hashDigestSize _ = byteLen (Proxy :: Proxy bitlen)
hashInternalContextSize _ = 248
hashInternalInit p = c_blake2b_init p (integralNatVal (Proxy :: Proxy bitlen))
hashInternalUpdate = c_blake2b_update
hashInternalFinalize p = c_blake2b_finalize p (integralNatVal (Proxy :: Proxy bitlen))
foreign import ccall unsafe "cryptonite_blake2b_init"
c_blake2b_init :: Ptr (Context a) -> Word32 -> IO ()
foreign import ccall "cryptonite_blake2b_update"
c_blake2b_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO ()
foreign import ccall unsafe "cryptonite_blake2b_finalize"
c_blake2b_finalize :: Ptr (Context a) -> Word32 -> Ptr (Digest a) -> IO ()
data Blake2sp (bitlen :: Nat) = Blake2sp
deriving (Show,Data)
instance (IsDivisibleBy8 bitlen, KnownNat bitlen, IsAtLeast bitlen 8, IsAtMost bitlen 256)
=> HashAlgorithm (Blake2sp bitlen)
where
type HashBlockSize (Blake2sp bitlen) = 64
type HashDigestSize (Blake2sp bitlen) = Div8 bitlen
type HashInternalContextSize (Blake2sp bitlen) = 2185
hashBlockSize _ = 64
hashDigestSize _ = byteLen (Proxy :: Proxy bitlen)
hashInternalContextSize _ = 2185
hashInternalInit p = c_blake2sp_init p (integralNatVal (Proxy :: Proxy bitlen))
hashInternalUpdate = c_blake2sp_update
hashInternalFinalize p = c_blake2sp_finalize p (integralNatVal (Proxy :: Proxy bitlen))
foreign import ccall unsafe "cryptonite_blake2sp_init"
c_blake2sp_init :: Ptr (Context a) -> Word32 -> IO ()
foreign import ccall "cryptonite_blake2sp_update"
c_blake2sp_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO ()
foreign import ccall unsafe "cryptonite_blake2sp_finalize"
c_blake2sp_finalize :: Ptr (Context a) -> Word32 -> Ptr (Digest a) -> IO ()
data Blake2bp (bitlen :: Nat) = Blake2bp
deriving (Show,Data)
instance (IsDivisibleBy8 bitlen, KnownNat bitlen, IsAtLeast bitlen 8, IsAtMost bitlen 512)
=> HashAlgorithm (Blake2bp bitlen)
where
type HashBlockSize (Blake2bp bitlen) = 128
type HashDigestSize (Blake2bp bitlen) = Div8 bitlen
type HashInternalContextSize (Blake2bp bitlen) = 2325
hashBlockSize _ = 128
hashDigestSize _ = byteLen (Proxy :: Proxy bitlen)
hashInternalContextSize _ = 2325
hashInternalInit p = c_blake2bp_init p (integralNatVal (Proxy :: Proxy bitlen))
hashInternalUpdate = c_blake2bp_update
hashInternalFinalize p = c_blake2bp_finalize p (integralNatVal (Proxy :: Proxy bitlen))
foreign import ccall unsafe "cryptonite_blake2bp_init"
c_blake2bp_init :: Ptr (Context a) -> Word32 -> IO ()
foreign import ccall "cryptonite_blake2bp_update"
c_blake2bp_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO ()
foreign import ccall unsafe "cryptonite_blake2bp_finalize"
c_blake2bp_finalize :: Ptr (Context a) -> Word32 -> Ptr (Digest a) -> IO ()

View File

@ -5,30 +5,94 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- Blake2b cryptographic hash. -- Blake2b cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.Blake2b module Crypto.Hash.Blake2b
( Blake2b_512 (..) ( Blake2b_160 (..), Blake2b_224 (..), Blake2b_256 (..), Blake2b_384 (..), Blake2b_512 (..)
) where ) where
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | Blake2b (160 bits) cryptographic hash algorithm
data Blake2b_160 = Blake2b_160
deriving (Show,Data)
instance HashAlgorithm Blake2b_160 where
type HashBlockSize Blake2b_160 = 128
type HashDigestSize Blake2b_160 = 20
type HashInternalContextSize Blake2b_160 = 248
hashBlockSize _ = 128
hashDigestSize _ = 20
hashInternalContextSize _ = 248
hashInternalInit p = c_blake2b_init p 160
hashInternalUpdate = c_blake2b_update
hashInternalFinalize p = c_blake2b_finalize p 160
-- | Blake2b (224 bits) cryptographic hash algorithm
data Blake2b_224 = Blake2b_224
deriving (Show,Data)
instance HashAlgorithm Blake2b_224 where
type HashBlockSize Blake2b_224 = 128
type HashDigestSize Blake2b_224 = 28
type HashInternalContextSize Blake2b_224 = 248
hashBlockSize _ = 128
hashDigestSize _ = 28
hashInternalContextSize _ = 248
hashInternalInit p = c_blake2b_init p 224
hashInternalUpdate = c_blake2b_update
hashInternalFinalize p = c_blake2b_finalize p 224
-- | Blake2b (256 bits) cryptographic hash algorithm
data Blake2b_256 = Blake2b_256
deriving (Show,Data)
instance HashAlgorithm Blake2b_256 where
type HashBlockSize Blake2b_256 = 128
type HashDigestSize Blake2b_256 = 32
type HashInternalContextSize Blake2b_256 = 248
hashBlockSize _ = 128
hashDigestSize _ = 32
hashInternalContextSize _ = 248
hashInternalInit p = c_blake2b_init p 256
hashInternalUpdate = c_blake2b_update
hashInternalFinalize p = c_blake2b_finalize p 256
-- | Blake2b (384 bits) cryptographic hash algorithm
data Blake2b_384 = Blake2b_384
deriving (Show,Data)
instance HashAlgorithm Blake2b_384 where
type HashBlockSize Blake2b_384 = 128
type HashDigestSize Blake2b_384 = 48
type HashInternalContextSize Blake2b_384 = 248
hashBlockSize _ = 128
hashDigestSize _ = 48
hashInternalContextSize _ = 248
hashInternalInit p = c_blake2b_init p 384
hashInternalUpdate = c_blake2b_update
hashInternalFinalize p = c_blake2b_finalize p 384
-- | Blake2b (512 bits) cryptographic hash algorithm -- | Blake2b (512 bits) cryptographic hash algorithm
data Blake2b_512 = Blake2b_512 data Blake2b_512 = Blake2b_512
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm Blake2b_512 where instance HashAlgorithm Blake2b_512 where
type HashBlockSize Blake2b_512 = 128
type HashDigestSize Blake2b_512 = 64
type HashInternalContextSize Blake2b_512 = 248
hashBlockSize _ = 128 hashBlockSize _ = 128
hashDigestSize _ = 64 hashDigestSize _ = 64
hashInternalContextSize _ = 361 hashInternalContextSize _ = 248
hashInternalInit p = c_blake2b_init p 512 hashInternalInit p = c_blake2b_init p 512
hashInternalUpdate = c_blake2b_update hashInternalUpdate = c_blake2b_update
hashInternalFinalize p = c_blake2b_finalize p 512 hashInternalFinalize p = c_blake2b_finalize p 512

View File

@ -5,11 +5,13 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- Blake2bp cryptographic hash. -- Blake2bp cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.Blake2bp module Crypto.Hash.Blake2bp
( Blake2bp_512 (..) ( Blake2bp_512 (..)
) where ) where
@ -17,28 +19,30 @@ module Crypto.Hash.Blake2bp
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | Blake2bp (512 bits) cryptographic hash algorithm -- | Blake2bp (512 bits) cryptographic hash algorithm
data Blake2bp_512 = Blake2bp_512 data Blake2bp_512 = Blake2bp_512
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm Blake2bp_512 where instance HashAlgorithm Blake2bp_512 where
type HashBlockSize Blake2bp_512 = 128
type HashDigestSize Blake2bp_512 = 64
type HashInternalContextSize Blake2bp_512 = 1768
hashBlockSize _ = 128 hashBlockSize _ = 128
hashDigestSize _ = 64 hashDigestSize _ = 64
hashInternalContextSize _ = 2325 hashInternalContextSize _ = 1768
hashInternalInit p = c_blake2sp_init p 512 hashInternalInit p = c_blake2bp_init p 512
hashInternalUpdate = c_blake2sp_update hashInternalUpdate = c_blake2bp_update
hashInternalFinalize p = c_blake2sp_finalize p 512 hashInternalFinalize p = c_blake2bp_finalize p 512
foreign import ccall unsafe "cryptonite_blake2sp_init" foreign import ccall unsafe "cryptonite_blake2bp_init"
c_blake2sp_init :: Ptr (Context a) -> Word32 -> IO () c_blake2bp_init :: Ptr (Context a) -> Word32 -> IO ()
foreign import ccall "cryptonite_blake2sp_update" foreign import ccall "cryptonite_blake2bp_update"
c_blake2sp_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO () c_blake2bp_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO ()
foreign import ccall unsafe "cryptonite_blake2sp_finalize" foreign import ccall unsafe "cryptonite_blake2bp_finalize"
c_blake2sp_finalize :: Ptr (Context a) -> Word32 -> Ptr (Digest a) -> IO () c_blake2bp_finalize :: Ptr (Context a) -> Word32 -> Ptr (Digest a) -> IO ()

View File

@ -5,42 +5,64 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- Blake2s cryptographic hash. -- Blake2s cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.Blake2s module Crypto.Hash.Blake2s
( Blake2s_224 (..), Blake2s_256 (..) ( Blake2s_160 (..), Blake2s_224 (..), Blake2s_256 (..)
) where ) where
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | Blake2s (160 bits) cryptographic hash algorithm
data Blake2s_160 = Blake2s_160
deriving (Show,Data)
instance HashAlgorithm Blake2s_160 where
type HashBlockSize Blake2s_160 = 64
type HashDigestSize Blake2s_160 = 20
type HashInternalContextSize Blake2s_160 = 136
hashBlockSize _ = 64
hashDigestSize _ = 20
hashInternalContextSize _ = 136
hashInternalInit p = c_blake2s_init p 160
hashInternalUpdate = c_blake2s_update
hashInternalFinalize p = c_blake2s_finalize p 160
-- | Blake2s (224 bits) cryptographic hash algorithm -- | Blake2s (224 bits) cryptographic hash algorithm
data Blake2s_224 = Blake2s_224 data Blake2s_224 = Blake2s_224
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm Blake2s_224 where instance HashAlgorithm Blake2s_224 where
type HashBlockSize Blake2s_224 = 64
type HashDigestSize Blake2s_224 = 28
type HashInternalContextSize Blake2s_224 = 136
hashBlockSize _ = 64 hashBlockSize _ = 64
hashDigestSize _ = 28 hashDigestSize _ = 28
hashInternalContextSize _ = 185 hashInternalContextSize _ = 136
hashInternalInit p = c_blake2s_init p 224 hashInternalInit p = c_blake2s_init p 224
hashInternalUpdate = c_blake2s_update hashInternalUpdate = c_blake2s_update
hashInternalFinalize p = c_blake2s_finalize p 224 hashInternalFinalize p = c_blake2s_finalize p 224
-- | Blake2s (256 bits) cryptographic hash algorithm -- | Blake2s (256 bits) cryptographic hash algorithm
data Blake2s_256 = Blake2s_256 data Blake2s_256 = Blake2s_256
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm Blake2s_256 where instance HashAlgorithm Blake2s_256 where
type HashBlockSize Blake2s_256 = 64
type HashDigestSize Blake2s_256 = 32
type HashInternalContextSize Blake2s_256 = 136
hashBlockSize _ = 64 hashBlockSize _ = 64
hashDigestSize _ = 32 hashDigestSize _ = 32
hashInternalContextSize _ = 185 hashInternalContextSize _ = 136
hashInternalInit p = c_blake2s_init p 256 hashInternalInit p = c_blake2s_init p 256
hashInternalUpdate = c_blake2s_update hashInternalUpdate = c_blake2s_update
hashInternalFinalize p = c_blake2s_finalize p 256 hashInternalFinalize p = c_blake2s_finalize p 256

View File

@ -5,11 +5,13 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- Blake2sp cryptographic hash. -- Blake2sp cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.Blake2sp module Crypto.Hash.Blake2sp
( Blake2sp_224 (..), Blake2sp_256 (..) ( Blake2sp_224 (..), Blake2sp_256 (..)
) where ) where
@ -17,30 +19,35 @@ module Crypto.Hash.Blake2sp
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | Blake2sp (224 bits) cryptographic hash algorithm -- | Blake2sp (224 bits) cryptographic hash algorithm
data Blake2sp_224 = Blake2sp_224 data Blake2sp_224 = Blake2sp_224
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm Blake2sp_224 where instance HashAlgorithm Blake2sp_224 where
type HashBlockSize Blake2sp_224 = 64
type HashDigestSize Blake2sp_224 = 28
type HashInternalContextSize Blake2sp_224 = 1752
hashBlockSize _ = 64 hashBlockSize _ = 64
hashDigestSize _ = 28 hashDigestSize _ = 28
hashInternalContextSize _ = 2185 hashInternalContextSize _ = 1752
hashInternalInit p = c_blake2sp_init p 224 hashInternalInit p = c_blake2sp_init p 224
hashInternalUpdate = c_blake2sp_update hashInternalUpdate = c_blake2sp_update
hashInternalFinalize p = c_blake2sp_finalize p 224 hashInternalFinalize p = c_blake2sp_finalize p 224
-- | Blake2sp (256 bits) cryptographic hash algorithm -- | Blake2sp (256 bits) cryptographic hash algorithm
data Blake2sp_256 = Blake2sp_256 data Blake2sp_256 = Blake2sp_256
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm Blake2sp_256 where instance HashAlgorithm Blake2sp_256 where
type HashBlockSize Blake2sp_256 = 64
type HashDigestSize Blake2sp_256 = 32
type HashInternalContextSize Blake2sp_256 = 1752
hashBlockSize _ = 64 hashBlockSize _ = 64
hashDigestSize _ = 32 hashDigestSize _ = 32
hashInternalContextSize _ = 2185 hashInternalContextSize _ = 1752
hashInternalInit p = c_blake2sp_init p 256 hashInternalInit p = c_blake2sp_init p 256
hashInternalUpdate = c_blake2sp_update hashInternalUpdate = c_blake2sp_update
hashInternalFinalize p = c_blake2sp_finalize p 256 hashInternalFinalize p = c_blake2sp_finalize p 256

View File

@ -8,6 +8,7 @@
-- Generalized impure cryptographic hash interface -- Generalized impure cryptographic hash interface
-- --
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Crypto.Hash.IO module Crypto.Hash.IO
( HashAlgorithm(..) ( HashAlgorithm(..)
, MutableContext , MutableContext
@ -23,6 +24,11 @@ import qualified Crypto.Internal.ByteArray as B
import Foreign.Ptr import Foreign.Ptr
-- | A Mutable hash context -- | A Mutable hash context
--
-- This type is an instance of 'B.ByteArrayAccess' for debugging purpose.
-- Internal layout is architecture dependent, may contain uninitialized data
-- fragments, and change in future versions. The bytearray should not be used
-- as input to cryptographic algorithms.
newtype MutableContext a = MutableContext B.Bytes newtype MutableContext a = MutableContext B.Bytes
deriving (B.ByteArrayAccess) deriving (B.ByteArrayAccess)
@ -51,18 +57,10 @@ hashMutableUpdate mc dat = doUpdate mc (B.withByteArray mc)
hashInternalUpdate ctx d (fromIntegral $ B.length dat) hashInternalUpdate ctx d (fromIntegral $ B.length dat)
-- | Finalize a mutable hash context and compute a digest -- | Finalize a mutable hash context and compute a digest
hashMutableFinalize :: HashAlgorithm a => MutableContext a -> IO (Digest a) hashMutableFinalize :: forall a . HashAlgorithm a => MutableContext a -> IO (Digest a)
hashMutableFinalize mc = doFinalize undefined (B.withByteArray mc) B.alloc hashMutableFinalize mc = do
where doFinalize :: HashAlgorithm alg b <- B.alloc (hashDigestSize (undefined :: a)) $ \dig -> B.withByteArray mc $ \(ctx :: Ptr (Context a)) -> hashInternalFinalize ctx dig
=> alg return $ Digest b
-> ((Ptr (Context alg) -> IO ()) -> IO ())
-> (Int -> (Ptr (Digest alg) -> IO ()) -> IO B.Bytes)
-> IO (Digest alg)
doFinalize alg withCtx allocDigest = do
b <- allocDigest (hashDigestSize alg) $ \dig ->
withCtx $ \ctx ->
hashInternalFinalize ctx dig
return $ Digest b
-- | Reset the mutable context to the initial state of the hash -- | Reset the mutable context to the initial state of the hash
hashMutableReset :: HashAlgorithm a => MutableContext a -> IO () hashMutableReset :: HashAlgorithm a => MutableContext a -> IO ()

View File

@ -5,11 +5,13 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- Keccak cryptographic hash. -- Keccak cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.Keccak module Crypto.Hash.Keccak
( Keccak_224 (..), Keccak_256 (..), Keccak_384 (..), Keccak_512 (..) ( Keccak_224 (..), Keccak_256 (..), Keccak_384 (..), Keccak_512 (..)
) where ) where
@ -17,15 +19,17 @@ module Crypto.Hash.Keccak
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | Keccak (224 bits) cryptographic hash algorithm -- | Keccak (224 bits) cryptographic hash algorithm
data Keccak_224 = Keccak_224 data Keccak_224 = Keccak_224
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm Keccak_224 where instance HashAlgorithm Keccak_224 where
type HashBlockSize Keccak_224 = 144
type HashDigestSize Keccak_224 = 28
type HashInternalContextSize Keccak_224 = 352
hashBlockSize _ = 144 hashBlockSize _ = 144
hashDigestSize _ = 28 hashDigestSize _ = 28
hashInternalContextSize _ = 352 hashInternalContextSize _ = 352
@ -33,11 +37,18 @@ instance HashAlgorithm Keccak_224 where
hashInternalUpdate = c_keccak_update hashInternalUpdate = c_keccak_update
hashInternalFinalize p = c_keccak_finalize p 224 hashInternalFinalize p = c_keccak_finalize p 224
instance HashAlgorithmResumable Keccak_224 where
hashInternalPutContextBE = c_sha3_ctx_to_be
hashInternalGetContextBE = c_sha3_be_to_ctx
-- | Keccak (256 bits) cryptographic hash algorithm -- | Keccak (256 bits) cryptographic hash algorithm
data Keccak_256 = Keccak_256 data Keccak_256 = Keccak_256
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm Keccak_256 where instance HashAlgorithm Keccak_256 where
type HashBlockSize Keccak_256 = 136
type HashDigestSize Keccak_256 = 32
type HashInternalContextSize Keccak_256 = 344
hashBlockSize _ = 136 hashBlockSize _ = 136
hashDigestSize _ = 32 hashDigestSize _ = 32
hashInternalContextSize _ = 344 hashInternalContextSize _ = 344
@ -45,11 +56,18 @@ instance HashAlgorithm Keccak_256 where
hashInternalUpdate = c_keccak_update hashInternalUpdate = c_keccak_update
hashInternalFinalize p = c_keccak_finalize p 256 hashInternalFinalize p = c_keccak_finalize p 256
instance HashAlgorithmResumable Keccak_256 where
hashInternalPutContextBE = c_sha3_ctx_to_be
hashInternalGetContextBE = c_sha3_be_to_ctx
-- | Keccak (384 bits) cryptographic hash algorithm -- | Keccak (384 bits) cryptographic hash algorithm
data Keccak_384 = Keccak_384 data Keccak_384 = Keccak_384
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm Keccak_384 where instance HashAlgorithm Keccak_384 where
type HashBlockSize Keccak_384 = 104
type HashDigestSize Keccak_384 = 48
type HashInternalContextSize Keccak_384 = 312
hashBlockSize _ = 104 hashBlockSize _ = 104
hashDigestSize _ = 48 hashDigestSize _ = 48
hashInternalContextSize _ = 312 hashInternalContextSize _ = 312
@ -57,11 +75,18 @@ instance HashAlgorithm Keccak_384 where
hashInternalUpdate = c_keccak_update hashInternalUpdate = c_keccak_update
hashInternalFinalize p = c_keccak_finalize p 384 hashInternalFinalize p = c_keccak_finalize p 384
instance HashAlgorithmResumable Keccak_384 where
hashInternalPutContextBE = c_sha3_ctx_to_be
hashInternalGetContextBE = c_sha3_be_to_ctx
-- | Keccak (512 bits) cryptographic hash algorithm -- | Keccak (512 bits) cryptographic hash algorithm
data Keccak_512 = Keccak_512 data Keccak_512 = Keccak_512
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm Keccak_512 where instance HashAlgorithm Keccak_512 where
type HashBlockSize Keccak_512 = 72
type HashDigestSize Keccak_512 = 64
type HashInternalContextSize Keccak_512 = 280
hashBlockSize _ = 72 hashBlockSize _ = 72
hashDigestSize _ = 64 hashDigestSize _ = 64
hashInternalContextSize _ = 280 hashInternalContextSize _ = 280
@ -69,6 +94,10 @@ instance HashAlgorithm Keccak_512 where
hashInternalUpdate = c_keccak_update hashInternalUpdate = c_keccak_update
hashInternalFinalize p = c_keccak_finalize p 512 hashInternalFinalize p = c_keccak_finalize p 512
instance HashAlgorithmResumable Keccak_512 where
hashInternalPutContextBE = c_sha3_ctx_to_be
hashInternalGetContextBE = c_sha3_be_to_ctx
foreign import ccall unsafe "cryptonite_keccak_init" foreign import ccall unsafe "cryptonite_keccak_init"
c_keccak_init :: Ptr (Context a) -> Word32 -> IO () c_keccak_init :: Ptr (Context a) -> Word32 -> IO ()
@ -78,3 +107,9 @@ foreign import ccall "cryptonite_keccak_update"
foreign import ccall unsafe "cryptonite_keccak_finalize" foreign import ccall unsafe "cryptonite_keccak_finalize"
c_keccak_finalize :: Ptr (Context a) -> Word32 -> Ptr (Digest a) -> IO () c_keccak_finalize :: Ptr (Context a) -> Word32 -> Ptr (Digest a) -> IO ()
foreign import ccall unsafe "cryptonite_sha3_ctx_to_be"
c_sha3_ctx_to_be :: Ptr (Context a) -> Ptr Word8 -> IO ()
foreign import ccall unsafe "cryptonite_sha3_be_to_ctx"
c_sha3_be_to_ctx :: Ptr Word8 -> Ptr (Context a) -> IO ()

View File

@ -5,24 +5,28 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- MD2 cryptographic hash. -- MD2 cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.MD2 ( MD2 (..) ) where module Crypto.Hash.MD2 ( MD2 (..) ) where
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | MD2 cryptographic hash algorithm -- | MD2 cryptographic hash algorithm
data MD2 = MD2 data MD2 = MD2
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm MD2 where instance HashAlgorithm MD2 where
type HashBlockSize MD2 = 16
type HashDigestSize MD2 = 16
type HashInternalContextSize MD2 = 96
hashBlockSize _ = 16 hashBlockSize _ = 16
hashDigestSize _ = 16 hashDigestSize _ = 16
hashInternalContextSize _ = 96 hashInternalContextSize _ = 96

View File

@ -5,24 +5,28 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- MD4 cryptographic hash. -- MD4 cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.MD4 ( MD4 (..) ) where module Crypto.Hash.MD4 ( MD4 (..) ) where
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | MD4 cryptographic hash algorithm -- | MD4 cryptographic hash algorithm
data MD4 = MD4 data MD4 = MD4
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm MD4 where instance HashAlgorithm MD4 where
type HashBlockSize MD4 = 64
type HashDigestSize MD4 = 16
type HashInternalContextSize MD4 = 96
hashBlockSize _ = 64 hashBlockSize _ = 64
hashDigestSize _ = 16 hashDigestSize _ = 16
hashInternalContextSize _ = 96 hashInternalContextSize _ = 96

View File

@ -5,24 +5,28 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- MD5 cryptographic hash. -- MD5 cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.MD5 ( MD5 (..) ) where module Crypto.Hash.MD5 ( MD5 (..) ) where
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | MD5 cryptographic hash algorithm -- | MD5 cryptographic hash algorithm
data MD5 = MD5 data MD5 = MD5
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm MD5 where instance HashAlgorithm MD5 where
type HashBlockSize MD5 = 64
type HashDigestSize MD5 = 16
type HashInternalContextSize MD5 = 96
hashBlockSize _ = 64 hashBlockSize _ = 64
hashDigestSize _ = 16 hashDigestSize _ = 16
hashInternalContextSize _ = 96 hashInternalContextSize _ = 96
@ -30,6 +34,9 @@ instance HashAlgorithm MD5 where
hashInternalUpdate = c_md5_update hashInternalUpdate = c_md5_update
hashInternalFinalize = c_md5_finalize hashInternalFinalize = c_md5_finalize
instance HashAlgorithmPrefix MD5 where
hashInternalFinalizePrefix = c_md5_finalize_prefix
foreign import ccall unsafe "cryptonite_md5_init" foreign import ccall unsafe "cryptonite_md5_init"
c_md5_init :: Ptr (Context a)-> IO () c_md5_init :: Ptr (Context a)-> IO ()
@ -38,3 +45,6 @@ foreign import ccall "cryptonite_md5_update"
foreign import ccall unsafe "cryptonite_md5_finalize" foreign import ccall unsafe "cryptonite_md5_finalize"
c_md5_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO () c_md5_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
foreign import ccall "cryptonite_md5_finalize_prefix"
c_md5_finalize_prefix :: Ptr (Context a) -> Ptr Word8 -> Word32 -> Word32 -> Ptr (Digest a) -> IO ()

View File

@ -5,24 +5,28 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- RIPEMD160 cryptographic hash. -- RIPEMD160 cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.RIPEMD160 ( RIPEMD160 (..) ) where module Crypto.Hash.RIPEMD160 ( RIPEMD160 (..) ) where
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | RIPEMD160 cryptographic hash algorithm -- | RIPEMD160 cryptographic hash algorithm
data RIPEMD160 = RIPEMD160 data RIPEMD160 = RIPEMD160
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm RIPEMD160 where instance HashAlgorithm RIPEMD160 where
type HashBlockSize RIPEMD160 = 64
type HashDigestSize RIPEMD160 = 20
type HashInternalContextSize RIPEMD160 = 128
hashBlockSize _ = 64 hashBlockSize _ = 64
hashDigestSize _ = 20 hashDigestSize _ = 20
hashInternalContextSize _ = 128 hashInternalContextSize _ = 128

View File

@ -5,24 +5,28 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- SHA1 cryptographic hash. -- SHA1 cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.SHA1 ( SHA1 (..) ) where module Crypto.Hash.SHA1 ( SHA1 (..) ) where
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | SHA1 cryptographic hash algorithm -- | SHA1 cryptographic hash algorithm
data SHA1 = SHA1 data SHA1 = SHA1
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm SHA1 where instance HashAlgorithm SHA1 where
type HashBlockSize SHA1 = 64
type HashDigestSize SHA1 = 20
type HashInternalContextSize SHA1 = 96
hashBlockSize _ = 64 hashBlockSize _ = 64
hashDigestSize _ = 20 hashDigestSize _ = 20
hashInternalContextSize _ = 96 hashInternalContextSize _ = 96
@ -30,6 +34,9 @@ instance HashAlgorithm SHA1 where
hashInternalUpdate = c_sha1_update hashInternalUpdate = c_sha1_update
hashInternalFinalize = c_sha1_finalize hashInternalFinalize = c_sha1_finalize
instance HashAlgorithmPrefix SHA1 where
hashInternalFinalizePrefix = c_sha1_finalize_prefix
foreign import ccall unsafe "cryptonite_sha1_init" foreign import ccall unsafe "cryptonite_sha1_init"
c_sha1_init :: Ptr (Context a)-> IO () c_sha1_init :: Ptr (Context a)-> IO ()
@ -38,3 +45,6 @@ foreign import ccall "cryptonite_sha1_update"
foreign import ccall unsafe "cryptonite_sha1_finalize" foreign import ccall unsafe "cryptonite_sha1_finalize"
c_sha1_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO () c_sha1_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
foreign import ccall "cryptonite_sha1_finalize_prefix"
c_sha1_finalize_prefix :: Ptr (Context a) -> Ptr Word8 -> Word32 -> Word32 -> Ptr (Digest a) -> IO ()

View File

@ -5,24 +5,28 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- SHA224 cryptographic hash. -- SHA224 cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.SHA224 ( SHA224 (..) ) where module Crypto.Hash.SHA224 ( SHA224 (..) ) where
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | SHA224 cryptographic hash algorithm -- | SHA224 cryptographic hash algorithm
data SHA224 = SHA224 data SHA224 = SHA224
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm SHA224 where instance HashAlgorithm SHA224 where
type HashBlockSize SHA224 = 64
type HashDigestSize SHA224 = 28
type HashInternalContextSize SHA224 = 192
hashBlockSize _ = 64 hashBlockSize _ = 64
hashDigestSize _ = 28 hashDigestSize _ = 28
hashInternalContextSize _ = 192 hashInternalContextSize _ = 192
@ -30,6 +34,9 @@ instance HashAlgorithm SHA224 where
hashInternalUpdate = c_sha224_update hashInternalUpdate = c_sha224_update
hashInternalFinalize = c_sha224_finalize hashInternalFinalize = c_sha224_finalize
instance HashAlgorithmPrefix SHA224 where
hashInternalFinalizePrefix = c_sha224_finalize_prefix
foreign import ccall unsafe "cryptonite_sha224_init" foreign import ccall unsafe "cryptonite_sha224_init"
c_sha224_init :: Ptr (Context a)-> IO () c_sha224_init :: Ptr (Context a)-> IO ()
@ -38,3 +45,6 @@ foreign import ccall "cryptonite_sha224_update"
foreign import ccall unsafe "cryptonite_sha224_finalize" foreign import ccall unsafe "cryptonite_sha224_finalize"
c_sha224_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO () c_sha224_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
foreign import ccall "cryptonite_sha224_finalize_prefix"
c_sha224_finalize_prefix :: Ptr (Context a) -> Ptr Word8 -> Word32 -> Word32 -> Ptr (Digest a) -> IO ()

View File

@ -5,24 +5,28 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- SHA256 cryptographic hash. -- SHA256 cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.SHA256 ( SHA256 (..) ) where module Crypto.Hash.SHA256 ( SHA256 (..) ) where
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | SHA256 cryptographic hash algorithm -- | SHA256 cryptographic hash algorithm
data SHA256 = SHA256 data SHA256 = SHA256
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm SHA256 where instance HashAlgorithm SHA256 where
type HashBlockSize SHA256 = 64
type HashDigestSize SHA256 = 32
type HashInternalContextSize SHA256 = 192
hashBlockSize _ = 64 hashBlockSize _ = 64
hashDigestSize _ = 32 hashDigestSize _ = 32
hashInternalContextSize _ = 192 hashInternalContextSize _ = 192
@ -30,6 +34,9 @@ instance HashAlgorithm SHA256 where
hashInternalUpdate = c_sha256_update hashInternalUpdate = c_sha256_update
hashInternalFinalize = c_sha256_finalize hashInternalFinalize = c_sha256_finalize
instance HashAlgorithmPrefix SHA256 where
hashInternalFinalizePrefix = c_sha256_finalize_prefix
foreign import ccall unsafe "cryptonite_sha256_init" foreign import ccall unsafe "cryptonite_sha256_init"
c_sha256_init :: Ptr (Context a)-> IO () c_sha256_init :: Ptr (Context a)-> IO ()
@ -38,3 +45,6 @@ foreign import ccall "cryptonite_sha256_update"
foreign import ccall unsafe "cryptonite_sha256_finalize" foreign import ccall unsafe "cryptonite_sha256_finalize"
c_sha256_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO () c_sha256_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
foreign import ccall "cryptonite_sha256_finalize_prefix"
c_sha256_finalize_prefix :: Ptr (Context a) -> Ptr Word8 -> Word32 -> Word32 -> Ptr (Digest a) -> IO ()

View File

@ -5,11 +5,13 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- SHA3 cryptographic hash. -- SHA3 cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.SHA3 module Crypto.Hash.SHA3
( SHA3_224 (..), SHA3_256 (..), SHA3_384 (..), SHA3_512 (..) ( SHA3_224 (..), SHA3_256 (..), SHA3_384 (..), SHA3_512 (..)
) where ) where
@ -17,15 +19,17 @@ module Crypto.Hash.SHA3
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | SHA3 (224 bits) cryptographic hash algorithm -- | SHA3 (224 bits) cryptographic hash algorithm
data SHA3_224 = SHA3_224 data SHA3_224 = SHA3_224
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm SHA3_224 where instance HashAlgorithm SHA3_224 where
type HashBlockSize SHA3_224 = 144
type HashDigestSize SHA3_224 = 28
type HashInternalContextSize SHA3_224 = 352
hashBlockSize _ = 144 hashBlockSize _ = 144
hashDigestSize _ = 28 hashDigestSize _ = 28
hashInternalContextSize _ = 352 hashInternalContextSize _ = 352
@ -33,11 +37,18 @@ instance HashAlgorithm SHA3_224 where
hashInternalUpdate = c_sha3_update hashInternalUpdate = c_sha3_update
hashInternalFinalize p = c_sha3_finalize p 224 hashInternalFinalize p = c_sha3_finalize p 224
instance HashAlgorithmResumable SHA3_224 where
hashInternalPutContextBE = c_sha3_ctx_to_be
hashInternalGetContextBE = c_sha3_be_to_ctx
-- | SHA3 (256 bits) cryptographic hash algorithm -- | SHA3 (256 bits) cryptographic hash algorithm
data SHA3_256 = SHA3_256 data SHA3_256 = SHA3_256
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm SHA3_256 where instance HashAlgorithm SHA3_256 where
type HashBlockSize SHA3_256 = 136
type HashDigestSize SHA3_256 = 32
type HashInternalContextSize SHA3_256 = 344
hashBlockSize _ = 136 hashBlockSize _ = 136
hashDigestSize _ = 32 hashDigestSize _ = 32
hashInternalContextSize _ = 344 hashInternalContextSize _ = 344
@ -45,11 +56,18 @@ instance HashAlgorithm SHA3_256 where
hashInternalUpdate = c_sha3_update hashInternalUpdate = c_sha3_update
hashInternalFinalize p = c_sha3_finalize p 256 hashInternalFinalize p = c_sha3_finalize p 256
instance HashAlgorithmResumable SHA3_256 where
hashInternalPutContextBE = c_sha3_ctx_to_be
hashInternalGetContextBE = c_sha3_be_to_ctx
-- | SHA3 (384 bits) cryptographic hash algorithm -- | SHA3 (384 bits) cryptographic hash algorithm
data SHA3_384 = SHA3_384 data SHA3_384 = SHA3_384
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm SHA3_384 where instance HashAlgorithm SHA3_384 where
type HashBlockSize SHA3_384 = 104
type HashDigestSize SHA3_384 = 48
type HashInternalContextSize SHA3_384 = 312
hashBlockSize _ = 104 hashBlockSize _ = 104
hashDigestSize _ = 48 hashDigestSize _ = 48
hashInternalContextSize _ = 312 hashInternalContextSize _ = 312
@ -57,11 +75,18 @@ instance HashAlgorithm SHA3_384 where
hashInternalUpdate = c_sha3_update hashInternalUpdate = c_sha3_update
hashInternalFinalize p = c_sha3_finalize p 384 hashInternalFinalize p = c_sha3_finalize p 384
instance HashAlgorithmResumable SHA3_384 where
hashInternalPutContextBE = c_sha3_ctx_to_be
hashInternalGetContextBE = c_sha3_be_to_ctx
-- | SHA3 (512 bits) cryptographic hash algorithm -- | SHA3 (512 bits) cryptographic hash algorithm
data SHA3_512 = SHA3_512 data SHA3_512 = SHA3_512
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm SHA3_512 where instance HashAlgorithm SHA3_512 where
type HashBlockSize SHA3_512 = 72
type HashDigestSize SHA3_512 = 64
type HashInternalContextSize SHA3_512 = 280
hashBlockSize _ = 72 hashBlockSize _ = 72
hashDigestSize _ = 64 hashDigestSize _ = 64
hashInternalContextSize _ = 280 hashInternalContextSize _ = 280
@ -69,6 +94,10 @@ instance HashAlgorithm SHA3_512 where
hashInternalUpdate = c_sha3_update hashInternalUpdate = c_sha3_update
hashInternalFinalize p = c_sha3_finalize p 512 hashInternalFinalize p = c_sha3_finalize p 512
instance HashAlgorithmResumable SHA3_512 where
hashInternalPutContextBE = c_sha3_ctx_to_be
hashInternalGetContextBE = c_sha3_be_to_ctx
foreign import ccall unsafe "cryptonite_sha3_init" foreign import ccall unsafe "cryptonite_sha3_init"
c_sha3_init :: Ptr (Context a) -> Word32 -> IO () c_sha3_init :: Ptr (Context a) -> Word32 -> IO ()
@ -78,3 +107,9 @@ foreign import ccall "cryptonite_sha3_update"
foreign import ccall unsafe "cryptonite_sha3_finalize" foreign import ccall unsafe "cryptonite_sha3_finalize"
c_sha3_finalize :: Ptr (Context a) -> Word32 -> Ptr (Digest a) -> IO () c_sha3_finalize :: Ptr (Context a) -> Word32 -> Ptr (Digest a) -> IO ()
foreign import ccall unsafe "cryptonite_sha3_ctx_to_be"
c_sha3_ctx_to_be :: Ptr (Context a) -> Ptr Word8 -> IO ()
foreign import ccall unsafe "cryptonite_sha3_be_to_ctx"
c_sha3_be_to_ctx :: Ptr Word8 -> Ptr (Context a) -> IO ()

View File

@ -5,24 +5,28 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- SHA384 cryptographic hash. -- SHA384 cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.SHA384 ( SHA384 (..) ) where module Crypto.Hash.SHA384 ( SHA384 (..) ) where
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | SHA384 cryptographic hash algorithm -- | SHA384 cryptographic hash algorithm
data SHA384 = SHA384 data SHA384 = SHA384
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm SHA384 where instance HashAlgorithm SHA384 where
type HashBlockSize SHA384 = 128
type HashDigestSize SHA384 = 48
type HashInternalContextSize SHA384 = 256
hashBlockSize _ = 128 hashBlockSize _ = 128
hashDigestSize _ = 48 hashDigestSize _ = 48
hashInternalContextSize _ = 256 hashInternalContextSize _ = 256
@ -30,6 +34,9 @@ instance HashAlgorithm SHA384 where
hashInternalUpdate = c_sha384_update hashInternalUpdate = c_sha384_update
hashInternalFinalize = c_sha384_finalize hashInternalFinalize = c_sha384_finalize
instance HashAlgorithmPrefix SHA384 where
hashInternalFinalizePrefix = c_sha384_finalize_prefix
foreign import ccall unsafe "cryptonite_sha384_init" foreign import ccall unsafe "cryptonite_sha384_init"
c_sha384_init :: Ptr (Context a)-> IO () c_sha384_init :: Ptr (Context a)-> IO ()
@ -38,3 +45,6 @@ foreign import ccall "cryptonite_sha384_update"
foreign import ccall unsafe "cryptonite_sha384_finalize" foreign import ccall unsafe "cryptonite_sha384_finalize"
c_sha384_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO () c_sha384_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
foreign import ccall "cryptonite_sha384_finalize_prefix"
c_sha384_finalize_prefix :: Ptr (Context a) -> Ptr Word8 -> Word32 -> Word32 -> Ptr (Digest a) -> IO ()

View File

@ -5,24 +5,28 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- SHA512 cryptographic hash. -- SHA512 cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.SHA512 ( SHA512 (..) ) where module Crypto.Hash.SHA512 ( SHA512 (..) ) where
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | SHA512 cryptographic hash algorithm -- | SHA512 cryptographic hash algorithm
data SHA512 = SHA512 data SHA512 = SHA512
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm SHA512 where instance HashAlgorithm SHA512 where
type HashBlockSize SHA512 = 128
type HashDigestSize SHA512 = 64
type HashInternalContextSize SHA512 = 256
hashBlockSize _ = 128 hashBlockSize _ = 128
hashDigestSize _ = 64 hashDigestSize _ = 64
hashInternalContextSize _ = 256 hashInternalContextSize _ = 256
@ -30,6 +34,9 @@ instance HashAlgorithm SHA512 where
hashInternalUpdate = c_sha512_update hashInternalUpdate = c_sha512_update
hashInternalFinalize = c_sha512_finalize hashInternalFinalize = c_sha512_finalize
instance HashAlgorithmPrefix SHA512 where
hashInternalFinalizePrefix = c_sha512_finalize_prefix
foreign import ccall unsafe "cryptonite_sha512_init" foreign import ccall unsafe "cryptonite_sha512_init"
c_sha512_init :: Ptr (Context a)-> IO () c_sha512_init :: Ptr (Context a)-> IO ()
@ -38,3 +45,6 @@ foreign import ccall "cryptonite_sha512_update"
foreign import ccall unsafe "cryptonite_sha512_finalize" foreign import ccall unsafe "cryptonite_sha512_finalize"
c_sha512_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO () c_sha512_finalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
foreign import ccall "cryptonite_sha512_finalize_prefix"
c_sha512_finalize_prefix :: Ptr (Context a) -> Ptr Word8 -> Word32 -> Word32 -> Ptr (Digest a) -> IO ()

View File

@ -5,11 +5,13 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- SHA512t cryptographic hash. -- SHA512t cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.SHA512t module Crypto.Hash.SHA512t
( SHA512t_224 (..), SHA512t_256 (..) ( SHA512t_224 (..), SHA512t_256 (..)
) where ) where
@ -17,15 +19,17 @@ module Crypto.Hash.SHA512t
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | SHA512t (224 bits) cryptographic hash algorithm -- | SHA512t (224 bits) cryptographic hash algorithm
data SHA512t_224 = SHA512t_224 data SHA512t_224 = SHA512t_224
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm SHA512t_224 where instance HashAlgorithm SHA512t_224 where
type HashBlockSize SHA512t_224 = 128
type HashDigestSize SHA512t_224 = 28
type HashInternalContextSize SHA512t_224 = 256
hashBlockSize _ = 128 hashBlockSize _ = 128
hashDigestSize _ = 28 hashDigestSize _ = 28
hashInternalContextSize _ = 256 hashInternalContextSize _ = 256
@ -35,9 +39,12 @@ instance HashAlgorithm SHA512t_224 where
-- | SHA512t (256 bits) cryptographic hash algorithm -- | SHA512t (256 bits) cryptographic hash algorithm
data SHA512t_256 = SHA512t_256 data SHA512t_256 = SHA512t_256
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm SHA512t_256 where instance HashAlgorithm SHA512t_256 where
type HashBlockSize SHA512t_256 = 128
type HashDigestSize SHA512t_256 = 32
type HashInternalContextSize SHA512t_256 = 256
hashBlockSize _ = 128 hashBlockSize _ = 128
hashDigestSize _ = 32 hashDigestSize _ = 32
hashInternalContextSize _ = 256 hashInternalContextSize _ = 256

145
Crypto/Hash/SHAKE.hs Normal file
View File

@ -0,0 +1,145 @@
-- |
-- Module : Crypto.Hash.SHAKE
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : unknown
--
-- Module containing the binding functions to work with the
-- SHA3 extendable output functions (SHAKE).
--
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module Crypto.Hash.SHAKE
( SHAKE128 (..), SHAKE256 (..), HashSHAKE (..)
) where
import Control.Monad (when)
import Crypto.Hash.Types
import Foreign.Ptr (Ptr, castPtr)
import Foreign.Storable (Storable(..))
import Data.Bits
import Data.Data
import Data.Word (Word8, Word32)
import GHC.TypeLits (Nat, KnownNat, type (+))
import Crypto.Internal.Nat
-- | Type class of SHAKE algorithms.
class HashAlgorithm a => HashSHAKE a where
-- | Alternate finalization needed for cSHAKE
cshakeInternalFinalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
-- | Get the digest bit length
cshakeOutputLength :: a -> Int
-- | SHAKE128 (128 bits) extendable output function. Supports an arbitrary
-- digest size, to be specified as a type parameter of kind 'Nat'.
--
-- Note: outputs from @'SHAKE128' n@ and @'SHAKE128' m@ for the same input are
-- correlated (one being a prefix of the other). Results are unrelated to
-- 'SHAKE256' results.
data SHAKE128 (bitlen :: Nat) = SHAKE128
deriving (Show, Data)
instance KnownNat bitlen => HashAlgorithm (SHAKE128 bitlen) where
type HashBlockSize (SHAKE128 bitlen) = 168
type HashDigestSize (SHAKE128 bitlen) = Div8 (bitlen + 7)
type HashInternalContextSize (SHAKE128 bitlen) = 376
hashBlockSize _ = 168
hashDigestSize _ = byteLen (Proxy :: Proxy bitlen)
hashInternalContextSize _ = 376
hashInternalInit p = c_sha3_init p 128
hashInternalUpdate = c_sha3_update
hashInternalFinalize = shakeFinalizeOutput (Proxy :: Proxy bitlen)
instance KnownNat bitlen => HashSHAKE (SHAKE128 bitlen) where
cshakeInternalFinalize = cshakeFinalizeOutput (Proxy :: Proxy bitlen)
cshakeOutputLength _ = integralNatVal (Proxy :: Proxy bitlen)
instance KnownNat bitlen => HashAlgorithmResumable (SHAKE128 bitlen) where
hashInternalPutContextBE = c_sha3_ctx_to_be
hashInternalGetContextBE = c_sha3_be_to_ctx
-- | SHAKE256 (256 bits) extendable output function. Supports an arbitrary
-- digest size, to be specified as a type parameter of kind 'Nat'.
--
-- Note: outputs from @'SHAKE256' n@ and @'SHAKE256' m@ for the same input are
-- correlated (one being a prefix of the other). Results are unrelated to
-- 'SHAKE128' results.
data SHAKE256 (bitlen :: Nat) = SHAKE256
deriving (Show, Data)
instance KnownNat bitlen => HashAlgorithm (SHAKE256 bitlen) where
type HashBlockSize (SHAKE256 bitlen) = 136
type HashDigestSize (SHAKE256 bitlen) = Div8 (bitlen + 7)
type HashInternalContextSize (SHAKE256 bitlen) = 344
hashBlockSize _ = 136
hashDigestSize _ = byteLen (Proxy :: Proxy bitlen)
hashInternalContextSize _ = 344
hashInternalInit p = c_sha3_init p 256
hashInternalUpdate = c_sha3_update
hashInternalFinalize = shakeFinalizeOutput (Proxy :: Proxy bitlen)
instance KnownNat bitlen => HashSHAKE (SHAKE256 bitlen) where
cshakeInternalFinalize = cshakeFinalizeOutput (Proxy :: Proxy bitlen)
cshakeOutputLength _ = integralNatVal (Proxy :: Proxy bitlen)
instance KnownNat bitlen => HashAlgorithmResumable (SHAKE256 bitlen) where
hashInternalPutContextBE = c_sha3_ctx_to_be
hashInternalGetContextBE = c_sha3_be_to_ctx
shakeFinalizeOutput :: KnownNat bitlen
=> proxy bitlen
-> Ptr (Context a)
-> Ptr (Digest a)
-> IO ()
shakeFinalizeOutput d ctx dig = do
c_sha3_finalize_shake ctx
c_sha3_output ctx dig (byteLen d)
shakeTruncate d (castPtr dig)
cshakeFinalizeOutput :: KnownNat bitlen
=> proxy bitlen
-> Ptr (Context a)
-> Ptr (Digest a)
-> IO ()
cshakeFinalizeOutput d ctx dig = do
c_sha3_finalize_cshake ctx
c_sha3_output ctx dig (byteLen d)
shakeTruncate d (castPtr dig)
shakeTruncate :: KnownNat bitlen => proxy bitlen -> Ptr Word8 -> IO ()
shakeTruncate d ptr =
when (bits > 0) $ do
byte <- peekElemOff ptr index
pokeElemOff ptr index (byte .&. mask)
where
mask = (1 `shiftL` bits) - 1
(index, bits) = integralNatVal d `divMod` 8
foreign import ccall unsafe "cryptonite_sha3_init"
c_sha3_init :: Ptr (Context a) -> Word32 -> IO ()
foreign import ccall "cryptonite_sha3_update"
c_sha3_update :: Ptr (Context a) -> Ptr Word8 -> Word32 -> IO ()
foreign import ccall unsafe "cryptonite_sha3_finalize_shake"
c_sha3_finalize_shake :: Ptr (Context a) -> IO ()
foreign import ccall unsafe "cryptonite_sha3_finalize_cshake"
c_sha3_finalize_cshake :: Ptr (Context a) -> IO ()
foreign import ccall unsafe "cryptonite_sha3_output"
c_sha3_output :: Ptr (Context a) -> Ptr (Digest a) -> Word32 -> IO ()
foreign import ccall unsafe "cryptonite_sha3_ctx_to_be"
c_sha3_ctx_to_be :: Ptr (Context a) -> Ptr Word8 -> IO ()
foreign import ccall unsafe "cryptonite_sha3_be_to_ctx"
c_sha3_be_to_ctx :: Ptr Word8 -> Ptr (Context a) -> IO ()

View File

@ -5,11 +5,13 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- Skein256 cryptographic hash. -- Skein256 cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.Skein256 module Crypto.Hash.Skein256
( Skein256_224 (..), Skein256_256 (..) ( Skein256_224 (..), Skein256_256 (..)
) where ) where
@ -17,15 +19,17 @@ module Crypto.Hash.Skein256
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | Skein256 (224 bits) cryptographic hash algorithm -- | Skein256 (224 bits) cryptographic hash algorithm
data Skein256_224 = Skein256_224 data Skein256_224 = Skein256_224
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm Skein256_224 where instance HashAlgorithm Skein256_224 where
type HashBlockSize Skein256_224 = 32
type HashDigestSize Skein256_224 = 28
type HashInternalContextSize Skein256_224 = 96
hashBlockSize _ = 32 hashBlockSize _ = 32
hashDigestSize _ = 28 hashDigestSize _ = 28
hashInternalContextSize _ = 96 hashInternalContextSize _ = 96
@ -35,9 +39,12 @@ instance HashAlgorithm Skein256_224 where
-- | Skein256 (256 bits) cryptographic hash algorithm -- | Skein256 (256 bits) cryptographic hash algorithm
data Skein256_256 = Skein256_256 data Skein256_256 = Skein256_256
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm Skein256_256 where instance HashAlgorithm Skein256_256 where
type HashBlockSize Skein256_256 = 32
type HashDigestSize Skein256_256 = 32
type HashInternalContextSize Skein256_256 = 96
hashBlockSize _ = 32 hashBlockSize _ = 32
hashDigestSize _ = 32 hashDigestSize _ = 32
hashInternalContextSize _ = 96 hashInternalContextSize _ = 96

View File

@ -5,11 +5,13 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- Skein512 cryptographic hash. -- Skein512 cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.Skein512 module Crypto.Hash.Skein512
( Skein512_224 (..), Skein512_256 (..), Skein512_384 (..), Skein512_512 (..) ( Skein512_224 (..), Skein512_256 (..), Skein512_384 (..), Skein512_512 (..)
) where ) where
@ -17,15 +19,17 @@ module Crypto.Hash.Skein512
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | Skein512 (224 bits) cryptographic hash algorithm -- | Skein512 (224 bits) cryptographic hash algorithm
data Skein512_224 = Skein512_224 data Skein512_224 = Skein512_224
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm Skein512_224 where instance HashAlgorithm Skein512_224 where
type HashBlockSize Skein512_224 = 64
type HashDigestSize Skein512_224 = 28
type HashInternalContextSize Skein512_224 = 160
hashBlockSize _ = 64 hashBlockSize _ = 64
hashDigestSize _ = 28 hashDigestSize _ = 28
hashInternalContextSize _ = 160 hashInternalContextSize _ = 160
@ -35,9 +39,12 @@ instance HashAlgorithm Skein512_224 where
-- | Skein512 (256 bits) cryptographic hash algorithm -- | Skein512 (256 bits) cryptographic hash algorithm
data Skein512_256 = Skein512_256 data Skein512_256 = Skein512_256
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm Skein512_256 where instance HashAlgorithm Skein512_256 where
type HashBlockSize Skein512_256 = 64
type HashDigestSize Skein512_256 = 32
type HashInternalContextSize Skein512_256 = 160
hashBlockSize _ = 64 hashBlockSize _ = 64
hashDigestSize _ = 32 hashDigestSize _ = 32
hashInternalContextSize _ = 160 hashInternalContextSize _ = 160
@ -47,9 +54,12 @@ instance HashAlgorithm Skein512_256 where
-- | Skein512 (384 bits) cryptographic hash algorithm -- | Skein512 (384 bits) cryptographic hash algorithm
data Skein512_384 = Skein512_384 data Skein512_384 = Skein512_384
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm Skein512_384 where instance HashAlgorithm Skein512_384 where
type HashBlockSize Skein512_384 = 64
type HashDigestSize Skein512_384 = 48
type HashInternalContextSize Skein512_384 = 160
hashBlockSize _ = 64 hashBlockSize _ = 64
hashDigestSize _ = 48 hashDigestSize _ = 48
hashInternalContextSize _ = 160 hashInternalContextSize _ = 160
@ -59,9 +69,12 @@ instance HashAlgorithm Skein512_384 where
-- | Skein512 (512 bits) cryptographic hash algorithm -- | Skein512 (512 bits) cryptographic hash algorithm
data Skein512_512 = Skein512_512 data Skein512_512 = Skein512_512
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm Skein512_512 where instance HashAlgorithm Skein512_512 where
type HashBlockSize Skein512_512 = 64
type HashDigestSize Skein512_512 = 64
type HashInternalContextSize Skein512_512 = 160
hashBlockSize _ = 64 hashBlockSize _ = 64
hashDigestSize _ = 64 hashDigestSize _ = 64
hashInternalContextSize _ = 160 hashInternalContextSize _ = 160

View File

@ -5,24 +5,28 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- Tiger cryptographic hash. -- Tiger cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.Tiger ( Tiger (..) ) where module Crypto.Hash.Tiger ( Tiger (..) ) where
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | Tiger cryptographic hash algorithm -- | Tiger cryptographic hash algorithm
data Tiger = Tiger data Tiger = Tiger
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm Tiger where instance HashAlgorithm Tiger where
type HashBlockSize Tiger = 64
type HashDigestSize Tiger = 24
type HashInternalContextSize Tiger = 96
hashBlockSize _ = 64 hashBlockSize _ = 64
hashDigestSize _ = 24 hashDigestSize _ = 24
hashInternalContextSize _ = 96 hashInternalContextSize _ = 96

View File

@ -8,8 +8,14 @@
-- Crypto hash types definitions -- Crypto hash types definitions
-- --
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.Types module Crypto.Hash.Types
( HashAlgorithm(..) ( HashAlgorithm(..)
, HashAlgorithmPrefix(..)
, HashAlgorithmResumable(..)
, Context(..) , Context(..)
, Digest(..) , Digest(..)
) where ) where
@ -17,7 +23,15 @@ module Crypto.Hash.Types
import Crypto.Internal.Imports import Crypto.Internal.Imports
import Crypto.Internal.ByteArray (ByteArrayAccess, Bytes) import Crypto.Internal.ByteArray (ByteArrayAccess, Bytes)
import qualified Crypto.Internal.ByteArray as B import qualified Crypto.Internal.ByteArray as B
import Control.Monad.ST
import Data.Char (digitToInt, isHexDigit)
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Basement.Block (Block, unsafeFreeze)
import Basement.Block.Mutable (MutableBlock, new, unsafeWrite)
import Basement.NormalForm (deepseq)
import Basement.Types.OffsetSize (CountOf(..), Offset(..))
import GHC.TypeLits (Nat)
import Data.Data (Data)
-- | Class representing hashing algorithms. -- | Class representing hashing algorithms.
-- --
@ -25,6 +39,13 @@ import Foreign.Ptr (Ptr)
-- and lowlevel. the Hash module takes care of -- and lowlevel. the Hash module takes care of
-- hidding the mutable interface properly. -- hidding the mutable interface properly.
class HashAlgorithm a where class HashAlgorithm a where
-- | Associated type for the block size of the hash algorithm
type HashBlockSize a :: Nat
-- | Associated type for the digest size of the hash algorithm
type HashDigestSize a :: Nat
-- | Associated type for the internal context size of the hash algorithm
type HashInternalContextSize a :: Nat
-- | Get the block size of a hash algorithm -- | Get the block size of a hash algorithm
hashBlockSize :: a -> Int hashBlockSize :: a -> Int
-- | Get the digest size of a hash algorithm -- | Get the digest size of a hash algorithm
@ -40,19 +61,67 @@ class HashAlgorithm a where
-- | Finalize the context and set the digest raw memory to the right value -- | Finalize the context and set the digest raw memory to the right value
hashInternalFinalize :: Ptr (Context a) -> Ptr (Digest a) -> IO () hashInternalFinalize :: Ptr (Context a) -> Ptr (Digest a) -> IO ()
-- | Hashing algorithms with a constant-time implementation.
class HashAlgorithm a => HashAlgorithmPrefix a where
-- | Update the context with the first N bytes of a buffer and finalize this
-- context. The code path executed is independent from N and depends only
-- on the complete buffer length.
hashInternalFinalizePrefix :: Ptr (Context a)
-> Ptr Word8 -> Word32
-> Word32
-> Ptr (Digest a)
-> IO ()
class HashAlgorithm a => HashAlgorithmResumable a where
hashInternalPutContextBE :: Ptr (Context a) -> Ptr Word8 -> IO ()
hashInternalGetContextBE :: Ptr Word8 -> Ptr (Context a) -> IO ()
{- {-
hashContextGetAlgorithm :: HashAlgorithm a => Context a -> a hashContextGetAlgorithm :: HashAlgorithm a => Context a -> a
hashContextGetAlgorithm = undefined hashContextGetAlgorithm = undefined
-} -}
-- | Represent a context for a given hash algorithm. -- | Represent a context for a given hash algorithm.
--
-- This type is an instance of 'ByteArrayAccess' for debugging purpose. Internal
-- layout is architecture dependent, may contain uninitialized data fragments,
-- and change in future versions. The bytearray should not be used as input to
-- cryptographic algorithms.
newtype Context a = Context Bytes newtype Context a = Context Bytes
deriving (ByteArrayAccess,NFData) deriving (ByteArrayAccess,NFData)
-- | Represent a digest for a given hash algorithm. -- | Represent a digest for a given hash algorithm.
newtype Digest a = Digest Bytes --
deriving (Eq,Ord,ByteArrayAccess,NFData) -- This type is an instance of 'ByteArrayAccess' from package
-- <https://hackage.haskell.org/package/memory memory>.
-- Module "Data.ByteArray" provides many primitives to work with those values
-- including conversion to other types.
--
-- Creating a digest from a bytearray is also possible with function
-- 'Crypto.Hash.digestFromByteString'.
newtype Digest a = Digest (Block Word8)
deriving (Eq,Ord,ByteArrayAccess, Data)
instance NFData (Digest a) where
rnf (Digest u) = u `deepseq` ()
instance Show (Digest a) where instance Show (Digest a) where
show (Digest bs) = map (toEnum . fromIntegral) show (Digest bs) = map (toEnum . fromIntegral)
$ B.unpack (B.convertToBase B.Base16 bs :: Bytes) $ B.unpack (B.convertToBase B.Base16 bs :: Bytes)
instance HashAlgorithm a => Read (Digest a) where
readsPrec _ str = runST $ do mut <- new (CountOf len)
loop mut len str
where
len = hashDigestSize (undefined :: a)
loop :: MutableBlock Word8 s -> Int -> String -> ST s [(Digest a, String)]
loop mut 0 cs = (\b -> [(Digest b, cs)]) <$> unsafeFreeze mut
loop _ _ [] = return []
loop _ _ [_] = return []
loop mut n (c:(d:ds))
| not (isHexDigit c) = return []
| not (isHexDigit d) = return []
| otherwise = do
let w8 = fromIntegral $ digitToInt c * 16 + digitToInt d
unsafeWrite mut (Offset $ len - n) w8
loop mut (n - 1) ds

View File

@ -5,24 +5,28 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- module containing the binding functions to work with the -- Module containing the binding functions to work with the
-- Whirlpool cryptographic hash. -- Whirlpool cryptographic hash.
-- --
{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Hash.Whirlpool ( Whirlpool (..) ) where module Crypto.Hash.Whirlpool ( Whirlpool (..) ) where
import Crypto.Hash.Types import Crypto.Hash.Types
import Foreign.Ptr (Ptr) import Foreign.Ptr (Ptr)
import Data.Data import Data.Data
import Data.Typeable
import Data.Word (Word8, Word32) import Data.Word (Word8, Word32)
-- | Whirlpool cryptographic hash algorithm -- | Whirlpool cryptographic hash algorithm
data Whirlpool = Whirlpool data Whirlpool = Whirlpool
deriving (Show,Data,Typeable) deriving (Show,Data)
instance HashAlgorithm Whirlpool where instance HashAlgorithm Whirlpool where
type HashBlockSize Whirlpool = 64
type HashDigestSize Whirlpool = 64
type HashInternalContextSize Whirlpool = 168
hashBlockSize _ = 64 hashBlockSize _ = 64
hashDigestSize _ = 64 hashDigestSize _ = 64
hashInternalContextSize _ = 168 hashInternalContextSize _ = 168

View File

@ -0,0 +1,53 @@
-- |
-- Module : Crypto.Internal.Builder
-- License : BSD-style
-- Maintainer : Olivier Chéron <olivier.cheron@gmail.com>
-- Stability : stable
-- Portability : Good
--
-- Delaying and merging ByteArray allocations. This is similar to module
-- "Data.ByteArray.Pack" except the total length is computed automatically based
-- on what is appended.
--
{-# LANGUAGE BangPatterns #-}
module Crypto.Internal.Builder
( Builder
, buildAndFreeze
, builderLength
, byte
, bytes
, zero
) where
import Data.ByteArray (ByteArray, ByteArrayAccess)
import qualified Data.ByteArray as B
import Data.Memory.PtrMethods (memSet)
import Foreign.Ptr (Ptr, plusPtr)
import Foreign.Storable (poke)
import Crypto.Internal.Imports hiding (empty)
data Builder = Builder !Int (Ptr Word8 -> IO ()) -- size and initializer
instance Semigroup Builder where
(Builder s1 f1) <> (Builder s2 f2) = Builder (s1 + s2) f
where f p = f1 p >> f2 (p `plusPtr` s1)
builderLength :: Builder -> Int
builderLength (Builder s _) = s
buildAndFreeze :: ByteArray ba => Builder -> ba
buildAndFreeze (Builder s f) = B.allocAndFreeze s f
byte :: Word8 -> Builder
byte !b = Builder 1 (`poke` b)
bytes :: ByteArrayAccess ba => ba -> Builder
bytes bs = Builder (B.length bs) (B.copyByteArrayToPtr bs)
zero :: Int -> Builder
zero s = if s > 0 then Builder s (\p -> memSet p 0 s) else empty
empty :: Builder
empty = Builder 0 (const $ return ())

View File

@ -7,13 +7,33 @@
-- --
-- Simple and efficient byte array types -- Simple and efficient byte array types
-- --
{-# LANGUAGE BangPatterns #-}
{-# OPTIONS_HADDOCK hide #-} {-# OPTIONS_HADDOCK hide #-}
module Crypto.Internal.ByteArray module Crypto.Internal.ByteArray
( module Data.ByteArray ( module Data.ByteArray
, module Data.ByteArray.Mapping , module Data.ByteArray.Mapping
, module Data.ByteArray.Encoding , module Data.ByteArray.Encoding
, constAllZero
) where ) where
import Data.ByteArray import Data.ByteArray
import Data.ByteArray.Mapping import Data.ByteArray.Mapping
import Data.ByteArray.Encoding import Data.ByteArray.Encoding
import Data.Bits ((.|.))
import Data.Word (Word8)
import Foreign.Ptr (Ptr)
import Foreign.Storable (peekByteOff)
import Crypto.Internal.Compat (unsafeDoIO)
constAllZero :: ByteArrayAccess ba => ba -> Bool
constAllZero b = unsafeDoIO $ withByteArray b $ \p -> loop p 0 0
where
loop :: Ptr b -> Int -> Word8 -> IO Bool
loop p i !acc
| i == len = return $! acc == 0
| otherwise = do
e <- peekByteOff p i
loop p (i+1) (acc .|. e)
len = Data.ByteArray.length b

View File

@ -5,8 +5,8 @@
-- Stability : stable -- Stability : stable
-- Portability : Good -- Portability : Good
-- --
-- This module try to keep all the difference between versions of base -- This module tries to keep all the difference between versions of base
-- or other needed packages, so that modules don't need to use CPP -- or other needed packages, so that modules don't need to use CPP.
-- --
{-# LANGUAGE CPP #-} {-# LANGUAGE CPP #-}
module Crypto.Internal.Compat module Crypto.Internal.Compat
@ -19,10 +19,10 @@ import System.IO.Unsafe
import Data.Word import Data.Word
import Data.Bits import Data.Bits
-- | perform io for hashes that do allocation and ffi. -- | Perform io for hashes that do allocation and FFI.
-- unsafeDupablePerformIO is used when possible as the -- 'unsafeDupablePerformIO' is used when possible as the
-- computation is pure and the output is directly linked -- computation is pure and the output is directly linked
-- to the input. we also do not modify anything after it has -- to the input. We also do not modify anything after it has
-- been returned to the user. -- been returned to the user.
unsafeDoIO :: IO a -> a unsafeDoIO :: IO a -> a
#if __GLASGOW_HASKELL__ > 704 #if __GLASGOW_HASKELL__ > 704

View File

@ -5,11 +5,11 @@
-- Stability : stable -- Stability : stable
-- Portability : Compat -- Portability : Compat
-- --
-- This module try to keep all the difference between versions of ghc primitive -- This module tries to keep all the difference between versions of ghc primitive
-- or other needed packages, so that modules don't need to use CPP. -- or other needed packages, so that modules don't need to use CPP.
-- --
-- Note that MagicHash and CPP conflicts in places, making it "more interesting" -- Note that MagicHash and CPP conflicts in places, making it "more interesting"
-- to write compat code for primitives -- to write compat code for primitives.
-- --
{-# LANGUAGE CPP #-} {-# LANGUAGE CPP #-}
{-# LANGUAGE BangPatterns #-} {-# LANGUAGE BangPatterns #-}
@ -23,15 +23,21 @@ module Crypto.Internal.CompatPrim
, convert4To32 , convert4To32
) where ) where
import GHC.Prim
#if !defined(ARCH_IS_LITTLE_ENDIAN) && !defined(ARCH_IS_BIG_ENDIAN) #if !defined(ARCH_IS_LITTLE_ENDIAN) && !defined(ARCH_IS_BIG_ENDIAN)
import Data.Memory.Endian (getSystemEndianness, Endianness(..)) import Data.Memory.Endian (getSystemEndianness, Endianness(..))
#endif #endif
-- | byteswap Word# to or from Big Endian #if __GLASGOW_HASKELL__ >= 902
import GHC.Prim
#else
import GHC.Prim hiding (Word32#)
type Word32# = Word#
#endif
-- | Byteswap Word# to or from Big Endian
-- --
-- on a big endian machine, this function is a nop. -- On a big endian machine, this function is a nop.
be32Prim :: Word# -> Word# be32Prim :: Word32# -> Word32#
#ifdef ARCH_IS_LITTLE_ENDIAN #ifdef ARCH_IS_LITTLE_ENDIAN
be32Prim = byteswap32Prim be32Prim = byteswap32Prim
#elif defined(ARCH_IS_BIG_ENDIAN) #elif defined(ARCH_IS_BIG_ENDIAN)
@ -40,10 +46,10 @@ be32Prim = id
be32Prim w = if getSystemEndianness == LittleEndian then byteswap32Prim w else w be32Prim w = if getSystemEndianness == LittleEndian then byteswap32Prim w else w
#endif #endif
-- | byteswap Word# to or from Little Endian -- | Byteswap Word# to or from Little Endian
-- --
-- on a little endian machine, this function is a nop. -- On a little endian machine, this function is a nop.
le32Prim :: Word# -> Word# le32Prim :: Word32# -> Word32#
#ifdef ARCH_IS_LITTLE_ENDIAN #ifdef ARCH_IS_LITTLE_ENDIAN
le32Prim w = w le32Prim w = w
#elif defined(ARCH_IS_BIG_ENDIAN) #elif defined(ARCH_IS_BIG_ENDIAN)
@ -54,19 +60,14 @@ le32Prim w = if getSystemEndianness == LittleEndian then w else byteswap32Prim w
-- | Simple compatibility for byteswap the lower 32 bits of a Word# -- | Simple compatibility for byteswap the lower 32 bits of a Word#
-- at the primitive level -- at the primitive level
byteswap32Prim :: Word# -> Word# byteswap32Prim :: Word32# -> Word32#
#if __GLASGOW_HASKELL__ >= 708 #if __GLASGOW_HASKELL__ >= 902
byteswap32Prim w = byteSwap32# w byteswap32Prim w = wordToWord32# (byteSwap32# (word32ToWord# w))
#else #else
byteswap32Prim w = byteswap32Prim w = byteSwap32# w
let !a = uncheckedShiftL# w 24#
!b = and# (uncheckedShiftL# w 8#) 0x00ff0000##
!c = and# (uncheckedShiftRL# w 8#) 0x0000ff00##
!d = and# (uncheckedShiftRL# w 24#) 0x000000ff##
in or# a (or# b (or# c d))
#endif #endif
-- | combine 4 word8 [a,b,c,d] to a word32 representing [a,b,c,d] -- | Combine 4 word8 [a,b,c,d] to a word32 representing [a,b,c,d]
convert4To32 :: Word# -> Word# -> Word# -> Word# convert4To32 :: Word# -> Word# -> Word# -> Word#
-> Word# -> Word#
convert4To32 a b c d = or# (or# c1 c2) (or# c3 c4) convert4To32 a b c d = or# (or# c1 c2) (or# c3 c4)

View File

@ -30,4 +30,6 @@ instance NFData Word64 where rnf w = w `seq` ()
instance NFData Bytes where rnf b = b `seq` () instance NFData Bytes where rnf b = b `seq` ()
instance NFData ScrubbedBytes where rnf b = b `seq` () instance NFData ScrubbedBytes where rnf b = b `seq` ()
instance NFData Integer where rnf i = i `seq` ()
#endif #endif

View File

@ -5,11 +5,15 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
{-# LANGUAGE CPP #-}
module Crypto.Internal.Imports module Crypto.Internal.Imports
( module X ( module X
) where ) where
import Data.Word as X import Data.Word as X
#if !(MIN_VERSION_base(4,11,0))
import Data.Semigroup as X (Semigroup(..))
#endif
import Control.Applicative as X import Control.Applicative as X
import Control.Monad as X (forM, forM_, void) import Control.Monad as X (forM, forM_, void)
import Control.Arrow as X (first, second) import Control.Arrow as X (first, second)

213
Crypto/Internal/Nat.hs Normal file
View File

@ -0,0 +1,213 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module Crypto.Internal.Nat
( type IsDivisibleBy8
, type IsAtMost, type IsAtLeast
, byteLen
, integralNatVal
, type IsDiv8
, type Div8
, type Mod8
) where
import GHC.TypeLits
byteLen :: (KnownNat bitlen, Num a) => proxy bitlen -> a
byteLen d = fromInteger ((natVal d + 7) `div` 8)
integralNatVal :: (KnownNat bitlen, Num a) => proxy bitlen -> a
integralNatVal = fromInteger . natVal
type family IsLE (bitlen :: Nat) (n :: Nat) (c :: Bool) where
IsLE _ _ 'True = 'True
#if MIN_VERSION_base(4,9,0)
IsLE bitlen n 'False = TypeError
( ('Text "bitlen " ':<>: 'ShowType bitlen ':<>: 'Text " is greater than " ':<>: 'ShowType n)
':$$: ('Text "You have tried to use an invalid Digest size. Please, refer to the documentation.")
)
#else
IsLE bitlen n 'False = 'False
#endif
-- | ensure the given `bitlen` is lesser or equal to `n`
--
type IsAtMost (bitlen :: Nat) (n :: Nat) = IsLE bitlen n (bitlen <=? n) ~ 'True
type family IsGE (bitlen :: Nat) (n :: Nat) (c :: Bool) where
IsGE _ _ 'True = 'True
#if MIN_VERSION_base(4,9,0)
IsGE bitlen n 'False = TypeError
( ('Text "bitlen " ':<>: 'ShowType bitlen ':<>: 'Text " is lesser than " ':<>: 'ShowType n)
':$$: ('Text "You have tried to use an invalid Digest size. Please, refer to the documentation.")
)
#else
IsGE bitlen n 'False = 'False
#endif
-- | ensure the given `bitlen` is greater or equal to `n`
--
type IsAtLeast (bitlen :: Nat) (n :: Nat) = IsGE bitlen n (n <=? bitlen) ~ 'True
type family Div8 (bitLen :: Nat) where
Div8 0 = 0
Div8 1 = 0
Div8 2 = 0
Div8 3 = 0
Div8 4 = 0
Div8 5 = 0
Div8 6 = 0
Div8 7 = 0
Div8 8 = 1
Div8 9 = 1
Div8 10 = 1
Div8 11 = 1
Div8 12 = 1
Div8 13 = 1
Div8 14 = 1
Div8 15 = 1
Div8 16 = 2
Div8 17 = 2
Div8 18 = 2
Div8 19 = 2
Div8 20 = 2
Div8 21 = 2
Div8 22 = 2
Div8 23 = 2
Div8 24 = 3
Div8 25 = 3
Div8 26 = 3
Div8 27 = 3
Div8 28 = 3
Div8 29 = 3
Div8 30 = 3
Div8 31 = 3
Div8 32 = 4
Div8 33 = 4
Div8 34 = 4
Div8 35 = 4
Div8 36 = 4
Div8 37 = 4
Div8 38 = 4
Div8 39 = 4
Div8 40 = 5
Div8 41 = 5
Div8 42 = 5
Div8 43 = 5
Div8 44 = 5
Div8 45 = 5
Div8 46 = 5
Div8 47 = 5
Div8 48 = 6
Div8 49 = 6
Div8 50 = 6
Div8 51 = 6
Div8 52 = 6
Div8 53 = 6
Div8 54 = 6
Div8 55 = 6
Div8 56 = 7
Div8 57 = 7
Div8 58 = 7
Div8 59 = 7
Div8 60 = 7
Div8 61 = 7
Div8 62 = 7
Div8 63 = 7
Div8 64 = 8
Div8 n = 8 + Div8 (n - 64)
type family IsDiv8 (bitLen :: Nat) (n :: Nat) where
IsDiv8 _ 0 = 'True
#if MIN_VERSION_base(4,9,0)
IsDiv8 bitLen 1 = TypeError ('Text "bitLen " ':<>: 'ShowType bitLen ':<>: 'Text " is not divisible by 8")
IsDiv8 bitLen 2 = TypeError ('Text "bitLen " ':<>: 'ShowType bitLen ':<>: 'Text " is not divisible by 8")
IsDiv8 bitLen 3 = TypeError ('Text "bitLen " ':<>: 'ShowType bitLen ':<>: 'Text " is not divisible by 8")
IsDiv8 bitLen 4 = TypeError ('Text "bitLen " ':<>: 'ShowType bitLen ':<>: 'Text " is not divisible by 8")
IsDiv8 bitLen 5 = TypeError ('Text "bitLen " ':<>: 'ShowType bitLen ':<>: 'Text " is not divisible by 8")
IsDiv8 bitLen 6 = TypeError ('Text "bitLen " ':<>: 'ShowType bitLen ':<>: 'Text " is not divisible by 8")
IsDiv8 bitLen 7 = TypeError ('Text "bitLen " ':<>: 'ShowType bitLen ':<>: 'Text " is not divisible by 8")
#else
IsDiv8 _ 1 = 'False
IsDiv8 _ 2 = 'False
IsDiv8 _ 3 = 'False
IsDiv8 _ 4 = 'False
IsDiv8 _ 5 = 'False
IsDiv8 _ 6 = 'False
IsDiv8 _ 7 = 'False
#endif
IsDiv8 _ n = IsDiv8 n (Mod8 n)
type family Mod8 (n :: Nat) where
Mod8 0 = 0
Mod8 1 = 1
Mod8 2 = 2
Mod8 3 = 3
Mod8 4 = 4
Mod8 5 = 5
Mod8 6 = 6
Mod8 7 = 7
Mod8 8 = 0
Mod8 9 = 1
Mod8 10 = 2
Mod8 11 = 3
Mod8 12 = 4
Mod8 13 = 5
Mod8 14 = 6
Mod8 15 = 7
Mod8 16 = 0
Mod8 17 = 1
Mod8 18 = 2
Mod8 19 = 3
Mod8 20 = 4
Mod8 21 = 5
Mod8 22 = 6
Mod8 23 = 7
Mod8 24 = 0
Mod8 25 = 1
Mod8 26 = 2
Mod8 27 = 3
Mod8 28 = 4
Mod8 29 = 5
Mod8 30 = 6
Mod8 31 = 7
Mod8 32 = 0
Mod8 33 = 1
Mod8 34 = 2
Mod8 35 = 3
Mod8 36 = 4
Mod8 37 = 5
Mod8 38 = 6
Mod8 39 = 7
Mod8 40 = 0
Mod8 41 = 1
Mod8 42 = 2
Mod8 43 = 3
Mod8 44 = 4
Mod8 45 = 5
Mod8 46 = 6
Mod8 47 = 7
Mod8 48 = 0
Mod8 49 = 1
Mod8 50 = 2
Mod8 51 = 3
Mod8 52 = 4
Mod8 53 = 5
Mod8 54 = 6
Mod8 55 = 7
Mod8 56 = 0
Mod8 57 = 1
Mod8 58 = 2
Mod8 59 = 3
Mod8 60 = 4
Mod8 61 = 5
Mod8 62 = 6
Mod8 63 = 7
Mod8 n = Mod8 (n - 64)
-- | ensure the given `bitlen` is divisible by 8
--
type IsDivisibleBy8 bitLen = IsDiv8 bitLen bitLen ~ 'True

View File

@ -1,13 +0,0 @@
-- |
-- Module : Crypto.Internal.Proxy
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : Good
--
module Crypto.Internal.Proxy
( Proxy(..)
) where
-- | A type witness for 'a' as phantom type
data Proxy a = Proxy

View File

@ -1,5 +1,5 @@
-- | -- |
-- Module : Crypto.Internal.Compat -- Module : Crypto.Internal.WordArray
-- License : BSD-style -- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org> -- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : stable -- Stability : stable
@ -8,7 +8,7 @@
-- Small and self contained array representation -- Small and self contained array representation
-- with limited safety for internal use. -- with limited safety for internal use.
-- --
-- the array produced should never be exposed to the user directly -- The array produced should never be exposed to the user directly.
-- --
{-# LANGUAGE BangPatterns #-} {-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-} {-# LANGUAGE MagicHash #-}
@ -20,6 +20,8 @@ module Crypto.Internal.WordArray
, MutableArray32 , MutableArray32
, array8 , array8
, array32 , array32
, array32FromAddrBE
, allocArray32AndFreeze
, mutableArray32 , mutableArray32
, array64 , array64
, arrayRead8 , arrayRead8
@ -58,21 +60,21 @@ array8 = Array8
-- | Create an Array of Word32 of specific size from a list of Word32 -- | Create an Array of Word32 of specific size from a list of Word32
array32 :: Int -> [Word32] -> Array32 array32 :: Int -> [Word32] -> Array32
array32 (I# n) l = unsafeDoIO $ IO $ \s -> array32 n l = unsafeDoIO (mutableArray32 n l >>= mutableArray32Freeze)
case newAlignedPinnedByteArray# (n *# 4#) 4# s of
(# s', mbarr #) -> loop 0# s' mbarr l
where
loop _ st mb [] = freezeArray mb st
loop i st mb ((W32# x):xs)
| booleanPrim (i ==# n) = freezeArray mb st
| otherwise =
let !st' = writeWord32Array# mb i x st
in loop (i +# 1#) st' mb xs
freezeArray mb st =
case unsafeFreezeByteArray# mb st of
(# st', b #) -> (# st', Array32 b #)
{-# NOINLINE array32 #-} {-# NOINLINE array32 #-}
-- | Create an Array of BE Word32 aliasing an Addr
array32FromAddrBE :: Int -> Addr# -> Array32
array32FromAddrBE n a =
unsafeDoIO (mutableArray32FromAddrBE n a >>= mutableArray32Freeze)
{-# NOINLINE array32FromAddrBE #-}
-- | Create an Array of Word32 using an initializer
allocArray32AndFreeze :: Int -> (MutableArray32 -> IO ()) -> Array32
allocArray32AndFreeze n f =
unsafeDoIO (mutableArray32 n [] >>= \m -> f m >> mutableArray32Freeze m)
{-# NOINLINE allocArray32AndFreeze #-}
-- | Create an Array of Word64 of specific size from a list of Word64 -- | Create an Array of Word64 of specific size from a list of Word64
array64 :: Int -> [Word64] -> Array64 array64 :: Int -> [Word64] -> Array64
array64 (I# n) l = unsafeDoIO $ IO $ \s -> array64 (I# n) l = unsafeDoIO $ IO $ \s ->

157
Crypto/KDF/Argon2.hs Normal file
View File

@ -0,0 +1,157 @@
-- |
-- Module : Crypto.KDF.Argon2
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : unknown
--
-- Argon2 hashing function (P-H-C winner)
--
-- Recommended to use this module qualified
--
-- File started from Argon2.hs, from Oliver Charles
-- at https://github.com/ocharles/argon2
--
module Crypto.KDF.Argon2
(
Options(..)
, TimeCost
, MemoryCost
, Parallelism
, Variant(..)
, Version(..)
, defaultOptions
-- * Hashing function
, hash
) where
import Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess)
import qualified Crypto.Internal.ByteArray as B
import Crypto.Error
import Control.Monad (when)
import Data.Word
import Foreign.C
import Foreign.Ptr
-- | Which variant of Argon2 to use. You should choose the variant that is most
-- applicable to your intention to hash inputs.
data Variant =
Argon2d -- ^ Argon2d is faster than Argon2i and uses data-depending memory access,
-- which makes it suitable for cryptocurrencies and applications with no
-- threats from side-channel timing attacks.
| Argon2i -- ^ Argon2i uses data-independent memory access, which is preferred
-- for password hashing and password-based key derivation. Argon2i
-- is slower as it makes more passes over the memory to protect from
-- tradeoff attacks.
| Argon2id -- ^ Argon2id is a hybrid of Argon2i and Argon2d, using a combination
-- of data-depending and data-independent memory accesses, which gives
-- some of Argon2i's resistance to side-channel cache timing attacks
-- and much of Argon2d's resistance to GPU cracking attacks
deriving (Eq,Ord,Read,Show,Enum,Bounded)
-- | Which version of Argon2 to use
data Version = Version10 | Version13
deriving (Eq,Ord,Read,Show,Enum,Bounded)
-- | The time cost, which defines the amount of computation realized and therefore the execution time, given in number of iterations.
--
-- 'FFI.ARGON2_MIN_TIME' <= 'hashIterations' <= 'FFI.ARGON2_MAX_TIME'
type TimeCost = Word32
-- | The memory cost, which defines the memory usage, given in kibibytes.
--
-- max 'FFI.ARGON2_MIN_MEMORY' (8 * 'hashParallelism') <= 'hashMemory' <= 'FFI.ARGON2_MAX_MEMORY'
type MemoryCost = Word32
-- | A parallelism degree, which defines the number of parallel threads.
--
-- 'FFI.ARGON2_MIN_LANES' <= 'hashParallelism' <= 'FFI.ARGON2_MAX_LANES' && 'FFI.ARGON_MIN_THREADS' <= 'hashParallelism' <= 'FFI.ARGON2_MAX_THREADS'
type Parallelism = Word32
-- | Parameters that can be adjusted to change the runtime performance of the
-- hashing.
data Options = Options
{ iterations :: !TimeCost
, memory :: !MemoryCost
, parallelism :: !Parallelism
, variant :: !Variant -- ^ Which variant of Argon2 to use.
, version :: !Version -- ^ Which version of Argon2 to use.
}
deriving (Eq,Ord,Read,Show)
saltMinLength :: Int
saltMinLength = 8
outputMinLength :: Int
outputMinLength = 4
-- specification allows up to 2^32-1 but this is too big for a signed Int
-- on a 32-bit architecture, so we limit tag length to 2^31-1 bytes
outputMaxLength :: Int
outputMaxLength = 0x7fffffff
defaultOptions :: Options
defaultOptions =
Options { iterations = 1
, memory = 2 ^ (17 :: Int)
, parallelism = 4
, variant = Argon2i
, version = Version13
}
hash :: (ByteArrayAccess password, ByteArrayAccess salt, ByteArray out)
=> Options
-> password
-> salt
-> Int
-> CryptoFailable out
hash options password salt outLen
| saltLen < saltMinLength = CryptoFailed CryptoError_SaltTooSmall
| outLen < outputMinLength = CryptoFailed CryptoError_OutputLengthTooSmall
| outLen > outputMaxLength = CryptoFailed CryptoError_OutputLengthTooBig
| otherwise = CryptoPassed $ B.allocAndFreeze outLen $ \out -> do
res <- B.withByteArray password $ \pPass ->
B.withByteArray salt $ \pSalt ->
argon2_hash (iterations options)
(memory options)
(parallelism options)
pPass
(csizeOfInt passwordLen)
pSalt
(csizeOfInt saltLen)
out
(csizeOfInt outLen)
(cOfVariant $ variant options)
(cOfVersion $ version options)
when (res /= 0) $ error "argon2: hash: internal error"
where
saltLen = B.length salt
passwordLen = B.length password
data Pass
data Salt
data HashOut
type CVariant = CInt -- valid value is 0 (Argon2d), 1 (Argon2i) and 2 (Argon2id)
type CVersion = CInt -- valid value is 0x10, 0x13
cOfVersion :: Version -> CVersion
cOfVersion Version10 = 0x10
cOfVersion Version13 = 0x13
cOfVariant :: Variant -> CVariant
cOfVariant Argon2d = 0
cOfVariant Argon2i = 1
cOfVariant Argon2id = 2
csizeOfInt :: Int -> CSize
csizeOfInt = fromIntegral
foreign import ccall unsafe "cryptonite_argon2_hash"
argon2_hash :: Word32 -> Word32 -> Word32
-> Ptr Pass -> CSize
-> Ptr Salt -> CSize
-> Ptr HashOut -> CSize
-> CVariant
-> CVersion
-> IO CInt

View File

@ -11,7 +11,7 @@
-- >>> validatePassword password bcryptHash -- >>> validatePassword password bcryptHash
-- >>> True -- >>> True
-- >>> let otherPassword = B.pack "otherpassword" -- >>> let otherPassword = B.pack "otherpassword"
-- >>> otherHash <- hashPassword 12 otherPasssword :: IO B.ByteString -- >>> otherHash <- hashPassword 12 otherPassword :: IO B.ByteString
-- >>> validatePassword otherPassword otherHash -- >>> validatePassword otherPassword otherHash
-- >>> True -- >>> True
-- --
@ -27,13 +27,16 @@
-- salt and hash bytes (each separately Base64 encoded. Incrementing the -- salt and hash bytes (each separately Base64 encoded. Incrementing the
-- cost parameter approximately doubles the time taken to calculate the hash. -- cost parameter approximately doubles the time taken to calculate the hash.
-- --
-- The different version numbers have evolved because of bugs in the standard -- The different version numbers evolved to account for bugs in the standard
-- C implementations. The most up to date version is @2b@ and this -- C implementations. They don't represent different versions of the algorithm
-- implementation the @2b@ version prefix, but will also attempt to validate -- itself and in most cases should produce identical results.
-- The most up to date version is @2b@ and this implementation uses the
-- @2b@ version prefix, but will also attempt to validate
-- against hashes with versions @2a@ and @2y@. Version @2@ or @2x@ will be -- against hashes with versions @2a@ and @2y@. Version @2@ or @2x@ will be
-- rejected. No attempt is made to differentiate between the different versions -- rejected. No attempt is made to differentiate between the different versions
-- when validating a password, but in practice this shouldn't cause any problems -- when validating a password, but in practice this shouldn't cause any problems
-- if passwords are UTF-8 encoded (which they should be). -- if passwords are UTF-8 encoded (which they should be) and less than 256
-- characters long.
-- --
-- The cost parameter can be between 4 and 31 inclusive, but anything less than -- The cost parameter can be between 4 and 31 inclusive, but anything less than
-- 10 is probably not strong enough. High values may be prohibitively slow -- 10 is probably not strong enough. High values may be prohibitively slow
@ -49,11 +52,16 @@ module Crypto.KDF.BCrypt
) )
where where
import Control.Monad (unless, when) import Control.Monad (forM_, unless, when)
import Crypto.Cipher.Blowfish.Primitive (eksBlowfish, encrypt) import Crypto.Cipher.Blowfish.Primitive (Context, createKeySchedule,
import Crypto.Random (MonadRandom, getRandomBytes) encrypt, expandKey,
import Data.ByteArray (ByteArrayAccess, ByteArray, Bytes) expandKeyWithSalt,
import qualified Data.ByteArray as B freezeKeySchedule)
import Crypto.Internal.Compat
import Crypto.Random (MonadRandom, getRandomBytes)
import Data.ByteArray (ByteArray, ByteArrayAccess,
Bytes)
import qualified Data.ByteArray as B
import Data.ByteArray.Encoding import Data.ByteArray.Encoding
import Data.Char import Data.Char
@ -93,7 +101,7 @@ bcrypt :: (ByteArray salt, ByteArray password, ByteArray output)
bcrypt cost salt password = B.concat [header, B.snoc costBytes dollar, b64 salt, b64 hash] bcrypt cost salt password = B.concat [header, B.snoc costBytes dollar, b64 salt, b64 hash]
where where
hash = rawHash 'b' realCost salt password hash = rawHash 'b' realCost salt password
header = B.pack [dollar, fromIntegral (ord '2'), fromIntegral (ord 'a'), dollar] header = B.pack [dollar, fromIntegral (ord '2'), fromIntegral (ord 'b'), dollar]
dollar = fromIntegral (ord '$') dollar = fromIntegral (ord '$')
zero = fromIntegral (ord '0') zero = fromIntegral (ord '0')
costBytes = B.pack [zero + fromIntegral (realCost `div` 10), zero + fromIntegral (realCost `mod` 10)] costBytes = B.pack [zero + fromIntegral (realCost `div` 10), zero + fromIntegral (realCost `mod` 10)]
@ -133,7 +141,7 @@ rawHash _ cost salt password = B.take 23 hash -- Another compatibility bug. Igno
-- Truncate the password if necessary and append a null byte for C compatibility -- Truncate the password if necessary and append a null byte for C compatibility
key = B.snoc (B.take 72 password) 0 key = B.snoc (B.take 72 password) 0
ctx = eksBlowfish cost salt key ctx = expensiveBlowfishContext key salt cost
-- The BCrypt plaintext: "OrpheanBeholderScryDoubt" -- The BCrypt plaintext: "OrpheanBeholderScryDoubt"
orpheanBeholder = B.pack [79,114,112,104,101,97,110,66,101,104,111,108,100,101,114,83,99,114,121,68,111,117,98,116] orpheanBeholder = B.pack [79,114,112,104,101,97,110,66,101,104,111,108,100,101,114,83,99,114,121,68,111,117,98,116]
@ -156,10 +164,26 @@ parseBCryptHash bc = do
costTens = fromIntegral (B.index bc 4) - zero costTens = fromIntegral (B.index bc 4) - zero
costUnits = fromIntegral (B.index bc 5) - zero costUnits = fromIntegral (B.index bc 5) - zero
version = chr (fromIntegral (B.index bc 2)) version = chr (fromIntegral (B.index bc 2))
cost = costUnits + (if costTens == 0 then 0 else 10^costTens) :: Int cost = costUnits + 10*costTens :: Int
decodeSaltHash saltHash = do decodeSaltHash saltHash = do
let (s, h) = B.splitAt 22 saltHash let (s, h) = B.splitAt 22 saltHash
salt <- convertFromBase Base64OpenBSD s salt <- convertFromBase Base64OpenBSD s
hash <- convertFromBase Base64OpenBSD h hash <- convertFromBase Base64OpenBSD h
return (salt, hash) return (salt, hash)
-- | Create a key schedule for the BCrypt "EKS" version.
--
-- Salt must be a 128-bit byte array.
-- Cost must be between 4 and 31 inclusive
-- See <https://www.usenix.org/conference/1999-usenix-annual-technical-conference/future-adaptable-password-scheme>
expensiveBlowfishContext :: (ByteArrayAccess key, ByteArrayAccess salt) => key-> salt -> Int -> Context
expensiveBlowfishContext keyBytes saltBytes cost
| B.length saltBytes /= 16 = error "bcrypt salt must be 16 bytes"
| otherwise = unsafeDoIO $ do
ks <- createKeySchedule
expandKeyWithSalt ks keyBytes saltBytes
forM_ [1..2^cost :: Int] $ \_ -> do
expandKey ks keyBytes
expandKey ks saltBytes
freezeKeySchedule ks

187
Crypto/KDF/BCryptPBKDF.hs Normal file
View File

@ -0,0 +1,187 @@
-- |
-- Module : Crypto.KDF.BCryptPBKDF
-- License : BSD-style
-- Stability : experimental
-- Portability : Good
--
-- Port of the bcrypt_pbkdf key derivation function from OpenBSD
-- as described at <http://man.openbsd.org/bcrypt_pbkdf.3>.
module Crypto.KDF.BCryptPBKDF
( Parameters (..)
, generate
, hashInternal
)
where
import Basement.Block (MutableBlock)
import qualified Basement.Block as Block
import qualified Basement.Block.Mutable as Block
import Basement.Monad (PrimState)
import Basement.Types.OffsetSize (CountOf (..), Offset (..))
import Control.Exception (finally)
import Control.Monad (when)
import qualified Crypto.Cipher.Blowfish.Box as Blowfish
import qualified Crypto.Cipher.Blowfish.Primitive as Blowfish
import Crypto.Hash.Algorithms (SHA512 (..))
import Crypto.Hash.Types (Context,
hashDigestSize,
hashInternalContextSize,
hashInternalFinalize,
hashInternalInit,
hashInternalUpdate)
import Crypto.Internal.Compat (unsafeDoIO)
import Data.Bits
import qualified Data.ByteArray as B
import Data.Foldable (forM_)
import Data.Memory.PtrMethods (memCopy, memSet, memXor)
import Data.Word
import Foreign.Ptr (Ptr, castPtr)
import Foreign.Storable (peekByteOff, pokeByteOff)
data Parameters = Parameters
{ iterCounts :: Int -- ^ The number of user-defined iterations for the algorithm
-- (must be > 0)
, outputLength :: Int -- ^ The number of bytes to generate out of BCryptPBKDF
-- (must be in 1..1024)
} deriving (Eq, Ord, Show)
-- | Derive a key of specified length using the bcrypt_pbkdf algorithm.
generate :: (B.ByteArray pass, B.ByteArray salt, B.ByteArray output)
=> Parameters
-> pass
-> salt
-> output
generate params pass salt
| iterCounts params < 1 = error "BCryptPBKDF: iterCounts must be > 0"
| keyLen < 1 || keyLen > 1024 = error "BCryptPBKDF: outputLength must be in 1..1024"
| otherwise = B.unsafeCreate keyLen deriveKey
where
outLen, tmpLen, blkLen, keyLen, passLen, saltLen, ctxLen, hashLen, blocks :: Int
outLen = 32
tmpLen = 32
blkLen = 4
passLen = B.length pass
saltLen = B.length salt
keyLen = outputLength params
ctxLen = hashInternalContextSize SHA512
hashLen = hashDigestSize SHA512 -- 64
blocks = (keyLen + outLen - 1) `div` outLen
deriveKey :: Ptr Word8 -> IO ()
deriveKey keyPtr = do
-- Allocate all necessary memory. The algorihm shall not allocate
-- any more dynamic memory after this point. Blocks need to be pinned
-- as pointers to them are passed to the SHA512 implementation.
ksClean <- Blowfish.createKeySchedule
ksDirty <- Blowfish.createKeySchedule
ctxMBlock <- Block.newPinned (CountOf ctxLen :: CountOf Word8)
outMBlock <- Block.newPinned (CountOf outLen :: CountOf Word8)
tmpMBlock <- Block.newPinned (CountOf tmpLen :: CountOf Word8)
blkMBlock <- Block.newPinned (CountOf blkLen :: CountOf Word8)
passHashMBlock <- Block.newPinned (CountOf hashLen :: CountOf Word8)
saltHashMBlock <- Block.newPinned (CountOf hashLen :: CountOf Word8)
-- Finally erase all memory areas that contain information from
-- which the derived key could be reconstructed.
-- As all MutableBlocks are pinned it shall be guaranteed that
-- no temporary trampoline buffers are allocated.
finallyErase outMBlock $ finallyErase passHashMBlock $
B.withByteArray pass $ \passPtr->
B.withByteArray salt $ \saltPtr->
Block.withMutablePtr ctxMBlock $ \ctxPtr->
Block.withMutablePtr outMBlock $ \outPtr->
Block.withMutablePtr tmpMBlock $ \tmpPtr->
Block.withMutablePtr blkMBlock $ \blkPtr->
Block.withMutablePtr passHashMBlock $ \passHashPtr->
Block.withMutablePtr saltHashMBlock $ \saltHashPtr-> do
-- Hash the password.
let shaPtr = castPtr ctxPtr :: Ptr (Context SHA512)
hashInternalInit shaPtr
hashInternalUpdate shaPtr passPtr (fromIntegral passLen)
hashInternalFinalize shaPtr (castPtr passHashPtr)
passHashBlock <- Block.unsafeFreeze passHashMBlock
forM_ [1..blocks] $ \block-> do
-- Poke the increased block counter.
Block.unsafeWrite blkMBlock 0 (fromIntegral $ block `shiftR` 24)
Block.unsafeWrite blkMBlock 1 (fromIntegral $ block `shiftR` 16)
Block.unsafeWrite blkMBlock 2 (fromIntegral $ block `shiftR` 8)
Block.unsafeWrite blkMBlock 3 (fromIntegral $ block `shiftR` 0)
-- First round (slightly different).
hashInternalInit shaPtr
hashInternalUpdate shaPtr saltPtr (fromIntegral saltLen)
hashInternalUpdate shaPtr blkPtr (fromIntegral blkLen)
hashInternalFinalize shaPtr (castPtr saltHashPtr)
Block.unsafeFreeze saltHashMBlock >>= \x-> do
Blowfish.copyKeySchedule ksDirty ksClean
hashInternalMutable ksDirty passHashBlock x tmpMBlock
memCopy outPtr tmpPtr outLen
-- Remaining rounds.
forM_ [2..iterCounts params] $ const $ do
hashInternalInit shaPtr
hashInternalUpdate shaPtr tmpPtr (fromIntegral tmpLen)
hashInternalFinalize shaPtr (castPtr saltHashPtr)
Block.unsafeFreeze saltHashMBlock >>= \x-> do
Blowfish.copyKeySchedule ksDirty ksClean
hashInternalMutable ksDirty passHashBlock x tmpMBlock
memXor outPtr outPtr tmpPtr outLen
-- Spread the current out buffer evenly over the key buffer.
-- After both loops have run every byte of the key buffer
-- will have been written to exactly once and every byte
-- of the output will have been used.
forM_ [0..outLen - 1] $ \outIdx-> do
let keyIdx = outIdx * blocks + block - 1
when (keyIdx < keyLen) $ do
w8 <- peekByteOff outPtr outIdx :: IO Word8
pokeByteOff keyPtr keyIdx w8
-- | Internal hash function used by `generate`.
--
-- Normal users should not need this.
hashInternal :: (B.ByteArrayAccess pass, B.ByteArrayAccess salt, B.ByteArray output)
=> pass
-> salt
-> output
hashInternal passHash saltHash
| B.length passHash /= 64 = error "passHash must be 512 bits"
| B.length saltHash /= 64 = error "saltHash must be 512 bits"
| otherwise = unsafeDoIO $ do
ks0 <- Blowfish.createKeySchedule
outMBlock <- Block.newPinned 32
hashInternalMutable ks0 passHash saltHash outMBlock
B.convert `fmap` Block.freeze outMBlock
hashInternalMutable :: (B.ByteArrayAccess pass, B.ByteArrayAccess salt)
=> Blowfish.KeySchedule
-> pass
-> salt
-> MutableBlock Word8 (PrimState IO)
-> IO ()
hashInternalMutable bfks passHash saltHash outMBlock = do
Blowfish.expandKeyWithSalt bfks passHash saltHash
forM_ [0..63 :: Int] $ const $ do
Blowfish.expandKey bfks saltHash
Blowfish.expandKey bfks passHash
-- "OxychromaticBlowfishSwatDynamite" represented as 4 Word64 in big-endian.
store 0 =<< cipher 64 0x4f78796368726f6d
store 8 =<< cipher 64 0x61746963426c6f77
store 16 =<< cipher 64 0x6669736853776174
store 24 =<< cipher 64 0x44796e616d697465
where
store :: Offset Word8 -> Word64 -> IO ()
store o w64 = do
Block.unsafeWrite outMBlock (o + 0) (fromIntegral $ w64 `shiftR` 32)
Block.unsafeWrite outMBlock (o + 1) (fromIntegral $ w64 `shiftR` 40)
Block.unsafeWrite outMBlock (o + 2) (fromIntegral $ w64 `shiftR` 48)
Block.unsafeWrite outMBlock (o + 3) (fromIntegral $ w64 `shiftR` 56)
Block.unsafeWrite outMBlock (o + 4) (fromIntegral $ w64 `shiftR` 0)
Block.unsafeWrite outMBlock (o + 5) (fromIntegral $ w64 `shiftR` 8)
Block.unsafeWrite outMBlock (o + 6) (fromIntegral $ w64 `shiftR` 16)
Block.unsafeWrite outMBlock (o + 7) (fromIntegral $ w64 `shiftR` 24)
cipher :: Int -> Word64 -> IO Word64
cipher 0 block = return block
cipher i block = Blowfish.cipherBlockMutable bfks block >>= cipher (i - 1)
finallyErase :: MutableBlock Word8 (PrimState IO) -> IO () -> IO ()
finallyErase mblock action =
action `finally` Block.withMutablePtr mblock (\ptr-> memSet ptr 0 len)
where
CountOf len = Block.mutableLengthBytes mblock

View File

@ -24,7 +24,7 @@ import Data.Word
import Data.Bits import Data.Bits
import Foreign.Marshal.Alloc import Foreign.Marshal.Alloc
import Foreign.Ptr (plusPtr, Ptr) import Foreign.Ptr (plusPtr, Ptr)
import Foreign.C.Types (CUInt(..), CInt(..), CSize(..)) import Foreign.C.Types (CUInt(..), CSize(..))
import Crypto.Hash (HashAlgorithm) import Crypto.Hash (HashAlgorithm)
import qualified Crypto.MAC.HMAC as HMAC import qualified Crypto.MAC.HMAC as HMAC

View File

@ -5,7 +5,7 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- provide the CMAC (Cipher based Message Authentification Code) base algorithm. -- Provide the CMAC (Cipher based Message Authentification Code) base algorithm.
-- <http://en.wikipedia.org/wiki/CMAC> -- <http://en.wikipedia.org/wiki/CMAC>
-- <http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf> -- <http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf>
-- --
@ -94,7 +94,7 @@ bxor = B.xor
cipherIPT :: BlockCipher k => k -> [Word8] cipherIPT :: BlockCipher k => k -> [Word8]
cipherIPT = expandIPT . blockSize where cipherIPT = expandIPT . blockSize
-- Data type which represents the smallest irreducibule binary polynomial -- Data type which represents the smallest irreducibule binary polynomial
-- against specified degree. -- against specified degree.

View File

@ -5,15 +5,16 @@
-- Stability : experimental -- Stability : experimental
-- Portability : unknown -- Portability : unknown
-- --
-- provide the HMAC (Hash based Message Authentification Code) base algorithm. -- Provide the HMAC (Hash based Message Authentification Code) base algorithm.
-- <http://en.wikipedia.org/wiki/HMAC> -- <http://en.wikipedia.org/wiki/HMAC>
-- --
{-# LANGUAGE BangPatterns #-} {-# LANGUAGE BangPatterns #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Crypto.MAC.HMAC module Crypto.MAC.HMAC
( hmac ( hmac
, hmacLazy
, HMAC(..) , HMAC(..)
-- * incremental -- * Incremental
, Context(..) , Context(..)
, initialize , initialize
, update , update
@ -24,28 +25,36 @@ module Crypto.MAC.HMAC
import Crypto.Hash hiding (Context) import Crypto.Hash hiding (Context)
import qualified Crypto.Hash as Hash (Context) import qualified Crypto.Hash as Hash (Context)
import Crypto.Hash.IO import Crypto.Hash.IO
import Crypto.Internal.ByteArray (ScrubbedBytes, ByteArray, ByteArrayAccess) import Crypto.Internal.ByteArray (ScrubbedBytes, ByteArrayAccess)
import qualified Crypto.Internal.ByteArray as B import qualified Crypto.Internal.ByteArray as B
import Data.Memory.PtrMethods import Data.Memory.PtrMethods
import Crypto.Internal.Compat import Crypto.Internal.Compat
import Crypto.Internal.Imports import qualified Data.ByteString.Lazy as L
-- | Represent an HMAC that is a phantom type with the hash used to produce the mac. -- | Represent an HMAC that is a phantom type with the hash used to produce the mac.
-- --
-- The Eq instance is constant time. -- The Eq instance is constant time. No Show instance is provided, to avoid
-- printing by mistake.
newtype HMAC a = HMAC { hmacGetDigest :: Digest a } newtype HMAC a = HMAC { hmacGetDigest :: Digest a }
deriving (ByteArrayAccess) deriving (ByteArrayAccess)
instance Eq (HMAC a) where instance Eq (HMAC a) where
(HMAC b1) == (HMAC b2) = B.constEq b1 b2 (HMAC b1) == (HMAC b2) = B.constEq b1 b2
-- | compute a MAC using the supplied hashing function -- | Compute a MAC using the supplied hashing function
hmac :: (ByteArrayAccess key, ByteArrayAccess message, HashAlgorithm a) hmac :: (ByteArrayAccess key, ByteArrayAccess message, HashAlgorithm a)
=> key -- ^ Secret key => key -- ^ Secret key
-> message -- ^ Message to MAC -> message -- ^ Message to MAC
-> HMAC a -> HMAC a
hmac secret msg = finalize $ updates (initialize secret) [msg] hmac secret msg = finalize $ updates (initialize secret) [msg]
-- | Compute a MAC using the supplied hashing function, for a lazy input
hmacLazy :: (ByteArrayAccess key, HashAlgorithm a)
=> key -- ^ Secret key
-> L.ByteString -- ^ Message to MAC
-> HMAC a
hmacLazy secret msg = finalize $ updates (initialize secret) (L.toChunks msg)
-- | Represent an ongoing HMAC state, that can be appended with 'update' -- | Represent an ongoing HMAC state, that can be appended with 'update'
-- and finalize to an HMAC with 'hmacFinalize' -- and finalize to an HMAC with 'hmacFinalize'
data Context hashalg = Context !(Hash.Context hashalg) !(Hash.Context hashalg) data Context hashalg = Context !(Hash.Context hashalg) !(Hash.Context hashalg)

144
Crypto/MAC/KMAC.hs Normal file
View File

@ -0,0 +1,144 @@
-- |
-- Module : Crypto.MAC.KMAC
-- License : BSD-style
-- Maintainer : Olivier Chéron <olivier.cheron@gmail.com>
-- Stability : experimental
-- Portability : unknown
--
-- Provide the KMAC (Keccak Message Authentication Code) algorithm, derived from
-- the SHA-3 base algorithm Keccak and defined in NIST SP800-185.
--
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Crypto.MAC.KMAC
( HashSHAKE
, kmac
, KMAC(..)
-- * Incremental
, Context
, initialize
, update
, updates
, finalize
) where
import qualified Crypto.Hash as H
import Crypto.Hash.SHAKE (HashSHAKE(..))
import Crypto.Hash.Types (HashAlgorithm(..), Digest(..))
import qualified Crypto.Hash.Types as H
import Crypto.Internal.Builder
import Crypto.Internal.Imports
import Foreign.Ptr (Ptr)
import Data.Bits (shiftR)
import Data.ByteArray (ByteArrayAccess)
import qualified Data.ByteArray as B
-- cSHAKE
cshakeInit :: forall a name string prefix . (HashSHAKE a, ByteArrayAccess name, ByteArrayAccess string, ByteArrayAccess prefix)
=> name -> string -> prefix -> H.Context a
cshakeInit n s p = H.Context $ B.allocAndFreeze c $ \(ptr :: Ptr (H.Context a)) -> do
hashInternalInit ptr
B.withByteArray b $ \d -> hashInternalUpdate ptr d (fromIntegral $ B.length b)
B.withByteArray p $ \d -> hashInternalUpdate ptr d (fromIntegral $ B.length p)
where
c = hashInternalContextSize (undefined :: a)
w = hashBlockSize (undefined :: a)
x = encodeString n <> encodeString s
b = buildAndFreeze (bytepad x w) :: B.Bytes
cshakeUpdate :: (HashSHAKE a, ByteArrayAccess ba)
=> H.Context a -> ba -> H.Context a
cshakeUpdate = H.hashUpdate
cshakeUpdates :: (HashSHAKE a, ByteArrayAccess ba)
=> H.Context a -> [ba] -> H.Context a
cshakeUpdates = H.hashUpdates
cshakeFinalize :: forall a suffix . (HashSHAKE a, ByteArrayAccess suffix)
=> H.Context a -> suffix -> Digest a
cshakeFinalize !c s =
Digest $ B.allocAndFreeze (hashDigestSize (undefined :: a)) $ \dig -> do
((!_) :: B.Bytes) <- B.copy c $ \(ctx :: Ptr (H.Context a)) -> do
B.withByteArray s $ \d ->
hashInternalUpdate ctx d (fromIntegral $ B.length s)
cshakeInternalFinalize ctx dig
return ()
-- KMAC
-- | Represent a KMAC that is a phantom type with the hash used to produce the
-- mac.
--
-- The Eq instance is constant time. No Show instance is provided, to avoid
-- printing by mistake.
newtype KMAC a = KMAC { kmacGetDigest :: Digest a }
deriving (ByteArrayAccess,NFData)
instance Eq (KMAC a) where
(KMAC b1) == (KMAC b2) = B.constEq b1 b2
-- | Compute a KMAC using the supplied customization string and key.
kmac :: (HashSHAKE a, ByteArrayAccess string, ByteArrayAccess key, ByteArrayAccess ba)
=> string -> key -> ba -> KMAC a
kmac str key msg = finalize $ updates (initialize str key) [msg]
-- | Represent an ongoing KMAC state, that can be appended with 'update' and
-- finalized to a 'KMAC' with 'finalize'.
newtype Context a = Context (H.Context a)
-- | Initialize a new incremental KMAC context with the supplied customization
-- string and key.
initialize :: forall a string key . (HashSHAKE a, ByteArrayAccess string, ByteArrayAccess key)
=> string -> key -> Context a
initialize str key = Context $ cshakeInit n str p
where
n = B.pack [75,77,65,67] :: B.Bytes -- "KMAC"
w = hashBlockSize (undefined :: a)
p = buildAndFreeze (bytepad (encodeString key) w) :: B.ScrubbedBytes
-- | Incrementally update a KMAC context.
update :: (HashSHAKE a, ByteArrayAccess ba) => Context a -> ba -> Context a
update (Context ctx) = Context . cshakeUpdate ctx
-- | Incrementally update a KMAC context with multiple inputs.
updates :: (HashSHAKE a, ByteArrayAccess ba) => Context a -> [ba] -> Context a
updates (Context ctx) = Context . cshakeUpdates ctx
-- | Finalize a KMAC context and return the KMAC.
finalize :: forall a . HashSHAKE a => Context a -> KMAC a
finalize (Context ctx) = KMAC $ cshakeFinalize ctx suffix
where
l = cshakeOutputLength (undefined :: a)
suffix = buildAndFreeze (rightEncode l) :: B.Bytes
-- Utilities
bytepad :: Builder -> Int -> Builder
bytepad x w = prefix <> x <> zero padLen
where
prefix = leftEncode w
padLen = (w - builderLength prefix - builderLength x) `mod` w
encodeString :: ByteArrayAccess bin => bin -> Builder
encodeString s = leftEncode (8 * B.length s) <> bytes s
leftEncode :: Int -> Builder
leftEncode x = byte len <> digits
where
digits = i2osp x
len = fromIntegral (builderLength digits)
rightEncode :: Int -> Builder
rightEncode x = digits <> byte len
where
digits = i2osp x
len = fromIntegral (builderLength digits)
i2osp :: Int -> Builder
i2osp i | i >= 256 = i2osp (shiftR i 8) <> byte (fromIntegral i)
| otherwise = byte (fromIntegral i)

View File

@ -33,6 +33,11 @@ import Crypto.Internal.DeepSeq
import Crypto.Error import Crypto.Error
-- | Poly1305 State -- | Poly1305 State
--
-- This type is an instance of 'ByteArrayAccess' for debugging purpose. Internal
-- layout is architecture dependent, may contain uninitialized data fragments,
-- and change in future versions. The bytearray should not be used as input to
-- cryptographic algorithms.
newtype State = State ScrubbedBytes newtype State = State ScrubbedBytes
deriving (ByteArrayAccess) deriving (ByteArrayAccess)

View File

@ -8,7 +8,7 @@
module Crypto.Math.Polynomial module Crypto.Math.Polynomial
( Monomial(..) ( Monomial(..)
-- * polynomial operations -- * Polynomial operations
, Polynomial , Polynomial
, toList , toList
, fromList , fromList

View File

@ -13,12 +13,15 @@ module Crypto.Number.Basic
, log2 , log2
, numBits , numBits
, numBytes , numBytes
, asPowerOf2AndOdd
) where ) where
import Data.Bits
import Crypto.Number.Compat import Crypto.Number.Compat
-- | sqrti returns two integer (l,b) so that l <= sqrt i <= b -- | @sqrti@ returns two integers @(l,b)@ so that @l <= sqrt i <= b@.
-- the implementation is quite naive, use an approximation for the first number -- The implementation is quite naive, use an approximation for the first number
-- and use a dichotomy algorithm to compute the bound relatively efficiently. -- and use a dichotomy algorithm to compute the bound relatively efficiently.
sqrti :: Integer -> (Integer, Integer) sqrti :: Integer -> (Integer, Integer)
sqrti i sqrti i
@ -49,7 +52,7 @@ sqrti i
else iter (lb+d) ub else iter (lb+d) ub
sq a = a * a sq a = a * a
-- | get the extended GCD of two integer using integer divMod -- | Get the extended GCD of two integer using integer divMod
-- --
-- gcde 'a' 'b' find (x,y,gcd(a,b)) where ax + by = d -- gcde 'a' 'b' find (x,y,gcd(a,b)) where ax + by = d
-- --
@ -63,7 +66,7 @@ gcde a b = onGmpUnsupported (gmpGcde a b) $
let (q, r) = a' `divMod` b' in let (q, r) = a' `divMod` b' in
f t (r, sa - (q * sb), ta - (q * tb)) f t (r, sa - (q * sb), ta - (q * tb))
-- | check if a list of integer are all even -- | Check if a list of integer are all even
areEven :: [Integer] -> Bool areEven :: [Integer] -> Bool
areEven = and . map even areEven = and . map even
@ -98,3 +101,16 @@ numBits n = gmpSizeInBits n `onGmpUnsupported` (if n == 0 then 1 else computeBit
-- | Compute the number of bytes for an integer -- | Compute the number of bytes for an integer
numBytes :: Integer -> Int numBytes :: Integer -> Int
numBytes n = gmpSizeInBytes n `onGmpUnsupported` ((numBits n + 7) `div` 8) numBytes n = gmpSizeInBytes n `onGmpUnsupported` ((numBits n + 7) `div` 8)
-- | Express an integer as an odd number and a power of 2
asPowerOf2AndOdd :: Integer -> (Int, Integer)
asPowerOf2AndOdd a
| a == 0 = (0, 0)
| odd a = (0, a)
| a < 0 = let (e, a1) = asPowerOf2AndOdd $ abs a in (e, -a1)
| isPowerOf2 a = (log2 a, 1)
| otherwise = loop a 0
where
isPowerOf2 n = (n /= 0) && ((n .&. (n - 1)) == 0)
loop n pw = if n `mod` 2 == 0 then loop (n `div` 2) (pw + 1)
else (pw, n)

View File

@ -22,7 +22,9 @@ module Crypto.Number.Compat
, gmpSizeInBytes , gmpSizeInBytes
, gmpSizeInBits , gmpSizeInBits
, gmpExportInteger , gmpExportInteger
, gmpExportIntegerLE
, gmpImportInteger , gmpImportInteger
, gmpImportIntegerLE
) where ) where
#ifndef MIN_VERSION_integer_gmp #ifndef MIN_VERSION_integer_gmp
@ -70,7 +72,11 @@ gmpLog2 _ = GmpUnsupported
-- | Compute the power modulus using extra security to remain constant -- | Compute the power modulus using extra security to remain constant
-- time wise through GMP -- time wise through GMP
gmpPowModSecInteger :: Integer -> Integer -> Integer -> GmpSupported Integer gmpPowModSecInteger :: Integer -> Integer -> Integer -> GmpSupported Integer
#if MIN_VERSION_integer_gmp(1,0,0) #if MIN_VERSION_integer_gmp(1,1,0)
gmpPowModSecInteger _ _ _ = GmpUnsupported
#elif MIN_VERSION_integer_gmp(1,0,2)
gmpPowModSecInteger b e m = GmpSupported (powModSecInteger b e m)
#elif MIN_VERSION_integer_gmp(1,0,0)
gmpPowModSecInteger _ _ _ = GmpUnsupported gmpPowModSecInteger _ _ _ = GmpUnsupported
#elif MIN_VERSION_integer_gmp(0,5,1) #elif MIN_VERSION_integer_gmp(0,5,1)
gmpPowModSecInteger b e m = GmpSupported (powModSecInteger b e m) gmpPowModSecInteger b e m = GmpSupported (powModSecInteger b e m)
@ -99,7 +105,9 @@ gmpInverse _ _ = GmpUnsupported
-- | Get the next prime from a specific value through GMP -- | Get the next prime from a specific value through GMP
gmpNextPrime :: Integer -> GmpSupported Integer gmpNextPrime :: Integer -> GmpSupported Integer
#if MIN_VERSION_integer_gmp(0,5,1) #if MIN_VERSION_integer_gmp(1,1,0)
gmpNextPrime _ = GmpUnsupported
#elif MIN_VERSION_integer_gmp(0,5,1)
gmpNextPrime n = GmpSupported (nextPrimeInteger n) gmpNextPrime n = GmpSupported (nextPrimeInteger n)
#else #else
gmpNextPrime _ = GmpUnsupported gmpNextPrime _ = GmpUnsupported
@ -107,7 +115,9 @@ gmpNextPrime _ = GmpUnsupported
-- | Test if a number is prime using Miller Rabin -- | Test if a number is prime using Miller Rabin
gmpTestPrimeMillerRabin :: Int -> Integer -> GmpSupported Bool gmpTestPrimeMillerRabin :: Int -> Integer -> GmpSupported Bool
#if MIN_VERSION_integer_gmp(0,5,1) #if MIN_VERSION_integer_gmp(1,1,0)
gmpTestPrimeMillerRabin _ _ = GmpUnsupported
#elif MIN_VERSION_integer_gmp(0,5,1)
gmpTestPrimeMillerRabin (I# tries) !n = GmpSupported $ gmpTestPrimeMillerRabin (I# tries) !n = GmpSupported $
case testPrimeInteger n tries of case testPrimeInteger n tries of
0# -> False 0# -> False
@ -132,7 +142,7 @@ gmpSizeInBits n = GmpSupported (I# (word2Int# (sizeInBaseInteger n 2#)))
gmpSizeInBits _ = GmpUnsupported gmpSizeInBits _ = GmpUnsupported
#endif #endif
-- | Export an integer to a memory -- | Export an integer to a memory (big-endian)
gmpExportInteger :: Integer -> Ptr Word8 -> GmpSupported (IO ()) gmpExportInteger :: Integer -> Ptr Word8 -> GmpSupported (IO ())
#if MIN_VERSION_integer_gmp(1,0,0) #if MIN_VERSION_integer_gmp(1,0,0)
gmpExportInteger n (Ptr addr) = GmpSupported $ do gmpExportInteger n (Ptr addr) = GmpSupported $ do
@ -146,7 +156,21 @@ gmpExportInteger n (Ptr addr) = GmpSupported $ IO $ \s ->
gmpExportInteger _ _ = GmpUnsupported gmpExportInteger _ _ = GmpUnsupported
#endif #endif
-- | Import an integer from a memory -- | Export an integer to a memory (little-endian)
gmpExportIntegerLE :: Integer -> Ptr Word8 -> GmpSupported (IO ())
#if MIN_VERSION_integer_gmp(1,0,0)
gmpExportIntegerLE n (Ptr addr) = GmpSupported $ do
_ <- exportIntegerToAddr n addr 0#
return ()
#elif MIN_VERSION_integer_gmp(0,5,1)
gmpExportIntegerLE n (Ptr addr) = GmpSupported $ IO $ \s ->
case exportIntegerToAddr n addr 0# s of
(# s2, _ #) -> (# s2, () #)
#else
gmpExportIntegerLE _ _ = GmpUnsupported
#endif
-- | Import an integer from a memory (big-endian)
gmpImportInteger :: Int -> Ptr Word8 -> GmpSupported (IO Integer) gmpImportInteger :: Int -> Ptr Word8 -> GmpSupported (IO Integer)
#if MIN_VERSION_integer_gmp(1,0,0) #if MIN_VERSION_integer_gmp(1,0,0)
gmpImportInteger (I# n) (Ptr addr) = GmpSupported $ gmpImportInteger (I# n) (Ptr addr) = GmpSupported $
@ -157,3 +181,15 @@ gmpImportInteger (I# n) (Ptr addr) = GmpSupported $ IO $ \s ->
#else #else
gmpImportInteger _ _ = GmpUnsupported gmpImportInteger _ _ = GmpUnsupported
#endif #endif
-- | Import an integer from a memory (little-endian)
gmpImportIntegerLE :: Int -> Ptr Word8 -> GmpSupported (IO Integer)
#if MIN_VERSION_integer_gmp(1,0,0)
gmpImportIntegerLE (I# n) (Ptr addr) = GmpSupported $
importIntegerFromAddr addr (int2Word# n) 0#
#elif MIN_VERSION_integer_gmp(0,5,1)
gmpImportIntegerLE (I# n) (Ptr addr) = GmpSupported $ IO $ \s ->
importIntegerFromAddr addr (int2Word# n) 0# s
#else
gmpImportIntegerLE _ _ = GmpUnsupported
#endif

View File

@ -16,14 +16,15 @@ module Crypto.Number.F2m
, mulF2m , mulF2m
, squareF2m' , squareF2m'
, squareF2m , squareF2m
, powF2m
, modF2m , modF2m
, sqrtF2m
, invF2m , invF2m
, divF2m , divF2m
) where ) where
import Data.Bits (xor, shift, testBit, setBit) import Data.Bits (xor, shift, testBit, setBit)
import Data.List import Data.List
import Crypto.Internal.Imports
import Crypto.Number.Basic import Crypto.Number.Basic
-- | Binary Polynomial represented by an integer -- | Binary Polynomial represented by an integer
@ -67,8 +68,8 @@ mulF2m :: BinaryPolynomial -- ^ Modulus
mulF2m fx n1 n2 mulF2m fx n1 n2
| fx < 0 | fx < 0
|| n1 < 0 || n1 < 0
|| n2 < 0 = error "mulF2m: negative number represent no binary binary polynomial" || n2 < 0 = error "mulF2m: negative number represent no binary polynomial"
| fx == 0 = error "modF2m: cannot multiply modulo zero polynomial" | fx == 0 = error "mulF2m: cannot multiply modulo zero polynomial"
| otherwise = modF2m fx $ go (if n2 `mod` 2 == 1 then n1 else 0) (log2 n2) | otherwise = modF2m fx $ go (if n2 `mod` 2 == 1 then n1 else 0) (log2 n2)
where where
go n s | s == 0 = n go n s | s == 0 = n
@ -97,10 +98,37 @@ squareF2m fx = modF2m fx . squareF2m'
squareF2m' :: Integer squareF2m' :: Integer
-> Integer -> Integer
squareF2m' n squareF2m' n
| n < 0 = error "mulF2m: negative number represent no binary binary polynomial" | n < 0 = error "mulF2m: negative number represent no binary polynomial"
| otherwise = foldl' (\acc s -> if testBit n s then setBit acc (2 * s) else acc) 0 [0 .. log2 n] | otherwise = foldl' (\acc s -> if testBit n s then setBit acc (2 * s) else acc) 0 [0 .. log2 n]
{-# INLINE squareF2m' #-} {-# INLINE squareF2m' #-}
-- | Exponentiation in F₂m by computing @a^b mod fx@.
--
-- This implements an exponentiation by squaring based solution. It inherits the
-- same restrictions as 'squareF2m'. Negative exponents are disallowed.
powF2m :: BinaryPolynomial -- ^Modulus
-> Integer -- ^a
-> Integer -- ^b
-> Integer
powF2m fx a b
| b < 0 = error "powF2m: negative exponents disallowed"
| b == 0 = if fx > 1 then 1 else 0
| even b = squareF2m fx x
| otherwise = mulF2m fx a (squareF2m' x)
where x = powF2m fx a (b `div` 2)
-- | Square rooot in F₂m.
--
-- We exploit the fact that @a^(2^m) = a@, or in particular, @a^(2^m - 1) = 1@
-- from a classical result by Lagrange. Thus the square root is simply @a^(2^(m
-- - 1))@.
sqrtF2m :: BinaryPolynomial -- ^Modulus
-> Integer -- ^a
-> Integer
sqrtF2m fx a = go (log2 fx - 1) a
where go 0 x = x
go n x = go (n - 1) (squareF2m fx x)
-- | Extended GCD algorithm for polynomials. For @a@ and @b@ returns @(g, u, v)@ such that @a * u + b * v == g@. -- | Extended GCD algorithm for polynomials. For @a@ and @b@ returns @(g, u, v)@ such that @a * u + b * v == g@.
-- --
-- Reference: https://en.wikipedia.org/wiki/Polynomial_greatest_common_divisor#B.C3.A9zout.27s_identity_and_extended_GCD_algorithm -- Reference: https://en.wikipedia.org/wiki/Polynomial_greatest_common_divisor#B.C3.A9zout.27s_identity_and_extended_GCD_algorithm

View File

@ -120,6 +120,4 @@ generateMax range
-- | generate a number between the inclusive bound [low,high]. -- | generate a number between the inclusive bound [low,high].
generateBetween :: MonadRandom m => Integer -> Integer -> m Integer generateBetween :: MonadRandom m => Integer -> Integer -> m Integer
generateBetween low high generateBetween low high = (low +) <$> generateMax (high - low + 1)
| low == 1 = generateMax high >>= \r -> if r == 0 then generateBetween low high else return r
| otherwise = (low +) <$> generateMax (high - low + 1)

View File

@ -1,5 +1,4 @@
{-# LANGUAGE BangPatterns #-} {-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveDataTypeable #-}
-- | -- |
-- Module : Crypto.Number.ModArithmetic -- Module : Crypto.Number.ModArithmetic
-- License : BSD-style -- License : BSD-style
@ -9,26 +8,29 @@
module Crypto.Number.ModArithmetic module Crypto.Number.ModArithmetic
( (
-- * exponentiation -- * Exponentiation
expSafe expSafe
, expFast , expFast
-- * inverse computing -- * Inverse computing
, inverse , inverse
, inverseCoprimes , inverseCoprimes
, inverseFermat
-- * Squares
, jacobi
, squareRoot
) where ) where
import Control.Exception (throw, Exception) import Control.Exception (throw, Exception)
import Data.Typeable
import Crypto.Number.Basic import Crypto.Number.Basic
import Crypto.Number.Compat import Crypto.Number.Compat
-- | Raised when two numbers are supposed to be coprimes but are not. -- | Raised when two numbers are supposed to be coprimes but are not.
data CoprimesAssertionError = CoprimesAssertionError data CoprimesAssertionError = CoprimesAssertionError
deriving (Show,Typeable) deriving (Show)
instance Exception CoprimesAssertionError instance Exception CoprimesAssertionError
-- | Compute the modular exponentiation of base^exponant using -- | Compute the modular exponentiation of base^exponent using
-- algorithms design to avoid side channels and timing measurement -- algorithms design to avoid side channels and timing measurement
-- --
-- Modulo need to be odd otherwise the normal fast modular exponentiation -- Modulo need to be odd otherwise the normal fast modular exponentiation
@ -38,11 +40,10 @@ instance Exception CoprimesAssertionError
-- from expFast, and thus provide the same unstudied and dubious -- from expFast, and thus provide the same unstudied and dubious
-- timing and side channels claims. -- timing and side channels claims.
-- --
-- with GHC 7.10, the powModSecInteger is missing from integer-gmp -- Before GHC 8.4.2, powModSecInteger is missing from integer-gmp,
-- (which is now integer-gmp2), so is has the same security as old -- so expSafe has the same security as expFast.
-- ghc version.
expSafe :: Integer -- ^ base expSafe :: Integer -- ^ base
-> Integer -- ^ exponant -> Integer -- ^ exponent
-> Integer -- ^ modulo -> Integer -- ^ modulo
-> Integer -- ^ result -> Integer -- ^ result
expSafe b e m expSafe b e m
@ -52,30 +53,30 @@ expSafe b e m
| otherwise = gmpPowModInteger b e m `onGmpUnsupported` | otherwise = gmpPowModInteger b e m `onGmpUnsupported`
exponentiation b e m exponentiation b e m
-- | Compute the modular exponentiation of base^exponant using -- | Compute the modular exponentiation of base^exponent using
-- the fastest algorithm without any consideration for -- the fastest algorithm without any consideration for
-- hiding parameters. -- hiding parameters.
-- --
-- Use this function when all the parameters are public, -- Use this function when all the parameters are public,
-- otherwise 'expSafe' should be prefered. -- otherwise 'expSafe' should be preferred.
expFast :: Integer -- ^ base expFast :: Integer -- ^ base
-> Integer -- ^ exponant -> Integer -- ^ exponent
-> Integer -- ^ modulo -> Integer -- ^ modulo
-> Integer -- ^ result -> Integer -- ^ result
expFast b e m = gmpPowModInteger b e m `onGmpUnsupported` exponentiation b e m expFast b e m = gmpPowModInteger b e m `onGmpUnsupported` exponentiation b e m
-- | exponentiation computes modular exponentiation as b^e mod m -- | @exponentiation@ computes modular exponentiation as /b^e mod m/
-- using repetitive squaring. -- using repetitive squaring.
exponentiation :: Integer -> Integer -> Integer -> Integer exponentiation :: Integer -> Integer -> Integer -> Integer
exponentiation b e m exponentiation b e m
| b == 1 = b | b == 1 = b
| e == 0 = 1 | e == 0 = 1
| e == 1 = b `mod` m | e == 1 = b `mod` m
| even e = let p = (exponentiation b (e `div` 2) m) `mod` m | even e = let p = exponentiation b (e `div` 2) m `mod` m
in (p^(2::Integer)) `mod` m in (p^(2::Integer)) `mod` m
| otherwise = (b * exponentiation b (e-1) m) `mod` m | otherwise = (b * exponentiation b (e-1) m) `mod` m
-- | inverse computes the modular inverse as in g^(-1) mod m -- | @inverse@ computes the modular inverse as in /g^(-1) mod m/.
inverse :: Integer -> Integer -> Maybe Integer inverse :: Integer -> Integer -> Maybe Integer
inverse g m = gmpInverse g m `onGmpUnsupported` v inverse g m = gmpInverse g m `onGmpUnsupported` v
where where
@ -84,14 +85,133 @@ inverse g m = gmpInverse g m `onGmpUnsupported` v
| otherwise = Just (x `mod` m) | otherwise = Just (x `mod` m)
(x,_,d) = gcde g m (x,_,d) = gcde g m
-- | Compute the modular inverse of 2 coprime numbers. -- | Compute the modular inverse of two coprime numbers.
-- This is equivalent to inverse except that the result -- This is equivalent to inverse except that the result
-- is known to exists. -- is known to exists.
-- --
-- if the numbers are not defined as coprime, this function -- If the numbers are not defined as coprime, this function
-- will raise a CoprimesAssertionError. -- will raise a 'CoprimesAssertionError'.
inverseCoprimes :: Integer -> Integer -> Integer inverseCoprimes :: Integer -> Integer -> Integer
inverseCoprimes g m = inverseCoprimes g m =
case inverse g m of case inverse g m of
Nothing -> throw CoprimesAssertionError Nothing -> throw CoprimesAssertionError
Just i -> i Just i -> i
-- | Computes the Jacobi symbol (a/n).
-- 0 ≤ a < n; n ≥ 3 and odd.
--
-- The Legendre and Jacobi symbols are indistinguishable exactly when the
-- lower argument is an odd prime, in which case they have the same value.
--
-- See algorithm 2.149 in "Handbook of Applied Cryptography" by Alfred J. Menezes et al.
jacobi :: Integer -> Integer -> Maybe Integer
jacobi a n
| n < 3 || even n = Nothing
| a == 0 || a == 1 = Just a
| n <= a = jacobi (a `mod` n) n
| a < 0 =
let b = if n `mod` 4 == 1 then 1 else -1
in fmap (*b) (jacobi (-a) n)
| otherwise =
let (e, a1) = asPowerOf2AndOdd a
nMod8 = n `mod` 8
nMod4 = n `mod` 4
a1Mod4 = a1 `mod` 4
s' = if even e || nMod8 == 1 || nMod8 == 7 then 1 else -1
s = if nMod4 == 3 && a1Mod4 == 3 then -s' else s'
n1 = n `mod` a1
in if a1 == 1 then Just s
else fmap (*s) (jacobi n1 a1)
-- | Modular inverse using Fermat's little theorem. This works only when
-- the modulus is prime but avoids side channels like in 'expSafe'.
inverseFermat :: Integer -> Integer -> Integer
inverseFermat g p = expSafe g (p - 2) p
-- | Raised when the assumption about the modulus is invalid.
data ModulusAssertionError = ModulusAssertionError
deriving (Show)
instance Exception ModulusAssertionError
-- | Modular square root of @g@ modulo a prime @p@.
--
-- If the modulus is found not to be prime, the function will raise a
-- 'ModulusAssertionError'.
--
-- This implementation is variable time and should be used with public
-- parameters only.
squareRoot :: Integer -> Integer -> Maybe Integer
squareRoot p
| p < 2 = throw ModulusAssertionError
| otherwise =
case p `divMod` 8 of
(v, 3) -> method1 (2 * v + 1)
(v, 7) -> method1 (2 * v + 2)
(u, 5) -> method2 u
(_, 1) -> tonelliShanks p
(0, 2) -> \a -> Just (if even a then 0 else 1)
_ -> throw ModulusAssertionError
where
x `eqMod` y = (x - y) `mod` p == 0
validate g y | (y * y) `eqMod` g = Just y
| otherwise = Nothing
-- p == 4u + 3 and u' == u + 1
method1 u' g =
let y = expFast g u' p
in validate g y
-- p == 8u + 5
method2 u g =
let gamma = expFast (2 * g) u p
g_gamma = g * gamma
i = (2 * g_gamma * gamma) `mod` p
y = (g_gamma * (i - 1)) `mod` p
in validate g y
tonelliShanks :: Integer -> Integer -> Maybe Integer
tonelliShanks p a
| aa == 0 = Just 0
| otherwise =
case expFast aa p2 p of
b | b == p1 -> Nothing
| b == 1 -> Just $ go (expFast aa ((s + 1) `div` 2) p)
(expFast aa s p)
(expFast n s p)
e
| otherwise -> throw ModulusAssertionError
where
aa = a `mod` p
p1 = p - 1
p2 = p1 `div` 2
n = findN 2
x `mul` y = (x * y) `mod` p
pow2m 0 x = x
pow2m i x = pow2m (i - 1) (x `mul` x)
(e, s) = asPowerOf2AndOdd p1
-- find a quadratic non-residue
findN i
| expFast i p2 p == p1 = i
| otherwise = findN (i + 1)
-- find m such that b^(2^m) == 1 (mod p)
findM b i
| b == 1 = i
| otherwise = findM (b `mul` b) (i + 1)
go !x b g !r
| b == 1 = x
| otherwise =
let r' = findM b 0
z = pow2m (r - r' - 1) g
x' = x `mul` z
b' = b `mul` g'
g' = z `mul` z
in go x' b' g' r'

63
Crypto/Number/Nat.hs Normal file
View File

@ -0,0 +1,63 @@
-- |
-- Module : Crypto.Number.Nat
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : Good
--
-- Numbers at type level.
--
-- This module provides extensions to "GHC.TypeLits" and "GHC.TypeNats" useful
-- to work with cryptographic algorithms parameterized with a variable bit
-- length. Constraints like @'IsDivisibleBy8' n@ ensure that the type-level
-- parameter is applicable to the algorithm.
--
-- Functions are also provided to test whether constraints are satisfied from
-- values known at runtime. The following example shows how to discharge
-- 'IsDivisibleBy8' in a computation @fn@ requiring this constraint:
--
-- > withDivisibleBy8 :: Integer
-- > -> (forall proxy n . (KnownNat n, IsDivisibleBy8 n) => proxy n -> a)
-- > -> Maybe a
-- > withDivisibleBy8 len fn = do
-- > SomeNat p <- someNatVal len
-- > Refl <- isDivisibleBy8 p
-- > pure (fn p)
--
-- Function @withDivisibleBy8@ above returns 'Nothing' when the argument @len@
-- is negative or not divisible by 8.
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
module Crypto.Number.Nat
( type IsDivisibleBy8
, type IsAtMost, type IsAtLeast
, isDivisibleBy8
, isAtMost
, isAtLeast
) where
import Data.Type.Equality
import GHC.TypeLits
import Unsafe.Coerce (unsafeCoerce)
import Crypto.Internal.Nat
-- | get a runtime proof that the constraint @'IsDivisibleBy8' n@ is satified
isDivisibleBy8 :: KnownNat n => proxy n -> Maybe (IsDiv8 n n :~: 'True)
isDivisibleBy8 n
| mod (natVal n) 8 == 0 = Just (unsafeCoerce Refl)
| otherwise = Nothing
-- | get a runtime proof that the constraint @'IsAtMost' value bound@ is
-- satified
isAtMost :: (KnownNat value, KnownNat bound)
=> proxy value -> proxy' bound -> Maybe ((value <=? bound) :~: 'True)
isAtMost x y
| natVal x <= natVal y = Just (unsafeCoerce Refl)
| otherwise = Nothing
-- | get a runtime proof that the constraint @'IsAtLeast' value bound@ is
-- satified
isAtLeast :: (KnownNat value, KnownNat bound)
=> proxy value -> proxy' bound -> Maybe ((bound <=? value) :~: 'True)
isAtLeast = flip isAtMost

View File

@ -19,8 +19,6 @@ module Crypto.Number.Prime
, isCoprime , isCoprime
) where ) where
import Crypto.Internal.Imports
import Crypto.Number.Compat import Crypto.Number.Compat
import Crypto.Number.Generate import Crypto.Number.Generate
import Crypto.Number.Basic (sqrti, gcde) import Crypto.Number.Basic (sqrti, gcde)
@ -31,10 +29,10 @@ import Crypto.Error
import Data.Bits import Data.Bits
-- | returns if the number is probably prime. -- | Returns if the number is probably prime.
-- first a list of small primes are implicitely tested for divisibility, -- First a list of small primes are implicitely tested for divisibility,
-- then a fermat primality test is used with arbitrary numbers and -- then a fermat primality test is used with arbitrary numbers and
-- then the Miller Rabin algorithm is used with an accuracy of 30 recursions -- then the Miller Rabin algorithm is used with an accuracy of 30 recursions.
isProbablyPrime :: Integer -> Bool isProbablyPrime :: Integer -> Bool
isProbablyPrime !n isProbablyPrime !n
| any (\p -> p `divides` n) (filter (< n) firstPrimes) = False | any (\p -> p `divides` n) (filter (< n) firstPrimes) = False
@ -42,14 +40,14 @@ isProbablyPrime !n
| primalityTestFermat 50 (n `div` 2) n = primalityTestMillerRabin 30 n | primalityTestFermat 50 (n `div` 2) n = primalityTestMillerRabin 30 n
| otherwise = False | otherwise = False
-- | generate a prime number of the required bitsize (i.e. in the range -- | Generate a prime number of the required bitsize (i.e. in the range
-- [2^(b-1)+2^(b-2), 2^b)). -- [2^(b-1)+2^(b-2), 2^b)).
-- --
-- May throw a CryptoError_PrimeSizeInvalid if the requested size is less -- May throw a 'CryptoError_PrimeSizeInvalid' if the requested size is less
-- than 5 bits, as the smallest prime meeting these conditions is 29. -- than 5 bits, as the smallest prime meeting these conditions is 29.
-- This function requires that the two highest bits are set, so that when -- This function requires that the two highest bits are set, so that when
-- multiplied with another prime to create a key, it is guaranteed to be of -- multiplied with another prime to create a key, it is guaranteed to be of
-- the proper size. -- the proper size.
generatePrime :: MonadRandom m => Int -> m Integer generatePrime :: MonadRandom m => Int -> m Integer
generatePrime bits = do generatePrime bits = do
if bits < 5 then if bits < 5 then
@ -61,13 +59,13 @@ generatePrime bits = do
return $ prime return $ prime
else generatePrime bits else generatePrime bits
-- | generate a prime number of the form 2p+1 where p is also prime. -- | Generate a prime number of the form 2p+1 where p is also prime.
-- it is also knowed as a Sophie Germaine prime or safe prime. -- it is also knowed as a Sophie Germaine prime or safe prime.
-- --
-- The number of safe prime is significantly smaller to the number of prime, -- The number of safe prime is significantly smaller to the number of prime,
-- as such it shouldn't be used if this number is supposed to be kept safe. -- as such it shouldn't be used if this number is supposed to be kept safe.
-- --
-- May throw a CryptoError_PrimeSizeInvalid if the requested size is less than -- May throw a 'CryptoError_PrimeSizeInvalid' if the requested size is less than
-- 6 bits, as the smallest safe prime with the two highest bits set is 59. -- 6 bits, as the smallest safe prime with the two highest bits set is 59.
generateSafePrime :: MonadRandom m => Int -> m Integer generateSafePrime :: MonadRandom m => Int -> m Integer
generateSafePrime bits = do generateSafePrime bits = do
@ -81,7 +79,7 @@ generateSafePrime bits = do
return $ val return $ val
else generateSafePrime bits else generateSafePrime bits
-- | find a prime from a starting point where the property hold. -- | Find a prime from a starting point where the property hold.
findPrimeFromWith :: (Integer -> Bool) -> Integer -> Integer findPrimeFromWith :: (Integer -> Bool) -> Integer -> Integer
findPrimeFromWith prop !n findPrimeFromWith prop !n
| even n = findPrimeFromWith prop (n+1) | even n = findPrimeFromWith prop (n+1)
@ -93,7 +91,7 @@ findPrimeFromWith prop !n
then n then n
else findPrimeFromWith prop (n+2) else findPrimeFromWith prop (n+2)
-- | find a prime from a starting point with no specific property. -- | Find a prime from a starting point with no specific property.
findPrimeFrom :: Integer -> Integer findPrimeFrom :: Integer -> Integer
findPrimeFrom n = findPrimeFrom n =
case gmpNextPrime n of case gmpNextPrime n of
@ -129,7 +127,7 @@ primalityTestMillerRabin tries !n =
factorise :: Integer -> Integer -> (Integer, Integer) factorise :: Integer -> Integer -> (Integer, Integer)
factorise !si !vi factorise !si !vi
| vi `testBit` 0 = (si, vi) | vi `testBit` 0 = (si, vi)
| otherwise = factorise (si+1) (vi `shiftR` 1) -- probably faster to not shift v continously, but just once. | otherwise = factorise (si+1) (vi `shiftR` 1) -- probably faster to not shift v continuously, but just once.
expmod = expSafe expmod = expSafe
-- when iteration reach zero, we have a probable prime -- when iteration reach zero, we have a probable prime
@ -185,7 +183,7 @@ primalityTestNaive n
isCoprime :: Integer -> Integer -> Bool isCoprime :: Integer -> Integer -> Bool
isCoprime m n = case gcde m n of (_,_,d) -> d == 1 isCoprime m n = case gcde m n of (_,_,d) -> d == 1
-- | list of the first primes till 2903.. -- | List of the first primes till 2903.
firstPrimes :: [Integer] firstPrimes :: [Integer]
firstPrimes = firstPrimes =
[ 2 , 3 , 5 , 7 , 11 , 13 , 17 , 19 , 23 , 29 [ 2 , 3 , 5 , 7 , 11 , 13 , 17 , 19 , 23 , 29

View File

@ -5,7 +5,7 @@
-- Stability : experimental -- Stability : experimental
-- Portability : Good -- Portability : Good
-- --
-- fast serialization primitives for integer -- Fast serialization primitives for integer
{-# LANGUAGE BangPatterns #-} {-# LANGUAGE BangPatterns #-}
module Crypto.Number.Serialize module Crypto.Number.Serialize
( i2osp ( i2osp
@ -19,22 +19,23 @@ import Crypto.Internal.Compat (unsafeDoIO)
import qualified Crypto.Internal.ByteArray as B import qualified Crypto.Internal.ByteArray as B
import qualified Crypto.Number.Serialize.Internal as Internal import qualified Crypto.Number.Serialize.Internal as Internal
-- | os2ip converts a byte string into a positive integer -- | @os2ip@ converts a byte string into a positive integer.
os2ip :: B.ByteArrayAccess ba => ba -> Integer os2ip :: B.ByteArrayAccess ba => ba -> Integer
os2ip bs = unsafeDoIO $ B.withByteArray bs (\p -> Internal.os2ip p (B.length bs)) os2ip bs = unsafeDoIO $ B.withByteArray bs (\p -> Internal.os2ip p (B.length bs))
-- | i2osp converts a positive integer into a byte string -- | @i2osp@ converts a positive integer into a byte string.
-- --
-- first byte is MSB (most significant byte), last byte is the LSB (least significant byte) -- The first byte is MSB (most significant byte); the last byte is the LSB (least significant byte)
i2osp :: B.ByteArray ba => Integer -> ba i2osp :: B.ByteArray ba => Integer -> ba
i2osp 0 = B.allocAndFreeze 1 (\p -> Internal.i2osp 0 p 1 >> return ()) i2osp 0 = B.allocAndFreeze 1 (\p -> Internal.i2osp 0 p 1 >> return ())
i2osp m = B.allocAndFreeze sz (\p -> Internal.i2osp m p sz >> return ()) i2osp m = B.allocAndFreeze sz (\p -> Internal.i2osp m p sz >> return ())
where where
!sz = numBytes m !sz = numBytes m
-- | just like i2osp, but take an extra parameter for size. -- | Just like 'i2osp', but takes an extra parameter for size.
-- if the number is too big to fit in @len@ bytes, 'Nothing' is returned -- If the number is too big to fit in @len@ bytes, 'Nothing' is returned
-- otherwise the number is padded with 0 to fit the @len@ required. -- otherwise the number is padded with 0 to fit the @len@ required.
{-# INLINABLE i2ospOf #-}
i2ospOf :: B.ByteArray ba => Int -> Integer -> Maybe ba i2ospOf :: B.ByteArray ba => Int -> Integer -> Maybe ba
i2ospOf len m i2ospOf len m
| len <= 0 = Nothing | len <= 0 = Nothing
@ -44,10 +45,10 @@ i2ospOf len m
where where
!sz = numBytes m !sz = numBytes m
-- | just like i2ospOf except that it doesn't expect a failure: i.e. -- | Just like 'i2ospOf' except that it doesn't expect a failure: i.e.
-- an integer larger than the number of output bytes requested -- an integer larger than the number of output bytes requested.
-- --
-- for example if you just took a modulo of the number that represent -- For example if you just took a modulo of the number that represent
-- the size (example the RSA modulo n). -- the size (example the RSA modulo n).
i2ospOf_ :: B.ByteArray ba => Int -> Integer -> ba i2ospOf_ :: B.ByteArray ba => Int -> Integer -> ba
i2ospOf_ len = maybe (error "i2ospOf_: integer is larger than expected") id . i2ospOf len i2ospOf_ len = maybe (error "i2ospOf_: integer is larger than expected") id . i2ospOf len

View File

@ -5,7 +5,7 @@
-- Stability : experimental -- Stability : experimental
-- Portability : Good -- Portability : Good
-- --
-- fast serialization primitives for integer using raw pointers -- Fast serialization primitives for integer using raw pointers
{-# LANGUAGE BangPatterns #-} {-# LANGUAGE BangPatterns #-}
module Crypto.Number.Serialize.Internal module Crypto.Number.Serialize.Internal
( i2osp ( i2osp
@ -21,12 +21,12 @@ import Data.Word (Word8)
import Foreign.Ptr import Foreign.Ptr
import Foreign.Storable import Foreign.Storable
-- | fill a pointer with the big endian binary representation of an integer -- | Fill a pointer with the big endian binary representation of an integer
-- --
-- if the room available @ptrSz is less than the number of bytes needed, -- If the room available @ptrSz@ is less than the number of bytes needed,
-- 0 is returned. Likewise if a parameter is invalid, 0 is returned. -- 0 is returned. Likewise if a parameter is invalid, 0 is returned.
-- --
-- returns the number of bytes written -- Returns the number of bytes written
i2osp :: Integer -> Ptr Word8 -> Int -> IO Int i2osp :: Integer -> Ptr Word8 -> Int -> IO Int
i2osp m ptr ptrSz i2osp m ptr ptrSz
| ptrSz <= 0 = return 0 | ptrSz <= 0 = return 0
@ -61,7 +61,7 @@ fillPtr p sz m = gmpExportInteger m p `onGmpUnsupported` export (sz-1) m
pokeByteOff p ofs (fromIntegral b :: Word8) pokeByteOff p ofs (fromIntegral b :: Word8)
export (ofs-1) i' export (ofs-1) i'
-- | transform a big endian binary integer representation pointed by a pointer and a size -- | Transform a big endian binary integer representation pointed by a pointer and a size
-- into an integer -- into an integer
os2ip :: Ptr Word8 -> Int -> IO Integer os2ip :: Ptr Word8 -> Int -> IO Integer
os2ip ptr ptrSz os2ip ptr ptrSz
@ -69,7 +69,7 @@ os2ip ptr ptrSz
| otherwise = gmpImportInteger ptrSz ptr `onGmpUnsupported` loop 0 0 ptr | otherwise = gmpImportInteger ptrSz ptr `onGmpUnsupported` loop 0 0 ptr
where where
loop :: Integer -> Int -> Ptr Word8 -> IO Integer loop :: Integer -> Int -> Ptr Word8 -> IO Integer
loop !acc i p loop !acc i !p
| i == ptrSz = return acc | i == ptrSz = return acc
| otherwise = do | otherwise = do
w <- peekByteOff p i :: IO Word8 w <- peekByteOff p i :: IO Word8

View File

@ -0,0 +1,75 @@
-- |
-- Module : Crypto.Number.Serialize.Internal.LE
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : Good
--
-- Fast serialization primitives for integer using raw pointers (little endian)
{-# LANGUAGE BangPatterns #-}
module Crypto.Number.Serialize.Internal.LE
( i2osp
, i2ospOf
, os2ip
) where
import Crypto.Number.Compat
import Crypto.Number.Basic
import Data.Bits
import Data.Memory.PtrMethods
import Data.Word (Word8)
import Foreign.Ptr
import Foreign.Storable
-- | Fill a pointer with the little endian binary representation of an integer
--
-- If the room available @ptrSz@ is less than the number of bytes needed,
-- 0 is returned. Likewise if a parameter is invalid, 0 is returned.
--
-- Returns the number of bytes written
i2osp :: Integer -> Ptr Word8 -> Int -> IO Int
i2osp m ptr ptrSz
| ptrSz <= 0 = return 0
| m < 0 = return 0
| m == 0 = pokeByteOff ptr 0 (0 :: Word8) >> return 1
| ptrSz < sz = return 0
| otherwise = fillPtr ptr sz m >> return sz
where
!sz = numBytes m
-- | Similar to 'i2osp', except it will pad any remaining space with zero.
i2ospOf :: Integer -> Ptr Word8 -> Int -> IO Int
i2ospOf m ptr ptrSz
| ptrSz <= 0 = return 0
| m < 0 = return 0
| ptrSz < sz = return 0
| otherwise = do
memSet ptr 0 ptrSz
fillPtr ptr sz m
return ptrSz
where
!sz = numBytes m
fillPtr :: Ptr Word8 -> Int -> Integer -> IO ()
fillPtr p sz m = gmpExportIntegerLE m p `onGmpUnsupported` export 0 m
where
export ofs i
| ofs >= sz = return ()
| otherwise = do
let (i', b) = i `divMod` 256
pokeByteOff p ofs (fromIntegral b :: Word8)
export (ofs+1) i'
-- | Transform a little endian binary integer representation pointed by a
-- pointer and a size into an integer
os2ip :: Ptr Word8 -> Int -> IO Integer
os2ip ptr ptrSz
| ptrSz <= 0 = return 0
| otherwise = gmpImportIntegerLE ptrSz ptr `onGmpUnsupported` loop 0 (ptrSz-1) ptr
where
loop :: Integer -> Int -> Ptr Word8 -> IO Integer
loop !acc i !p
| i < 0 = return acc
| otherwise = do
w <- peekByteOff p i :: IO Word8
loop ((acc `shiftL` 8) .|. fromIntegral w) (i-1) p

View File

@ -0,0 +1,54 @@
-- |
-- Module : Crypto.Number.Serialize.LE
-- License : BSD-style
-- Maintainer : Vincent Hanquez <vincent@snarc.org>
-- Stability : experimental
-- Portability : Good
--
-- Fast serialization primitives for integer (little endian)
{-# LANGUAGE BangPatterns #-}
module Crypto.Number.Serialize.LE
( i2osp
, os2ip
, i2ospOf
, i2ospOf_
) where
import Crypto.Number.Basic
import Crypto.Internal.Compat (unsafeDoIO)
import qualified Crypto.Internal.ByteArray as B
import qualified Crypto.Number.Serialize.Internal.LE as Internal
-- | @os2ip@ converts a byte string into a positive integer.
os2ip :: B.ByteArrayAccess ba => ba -> Integer
os2ip bs = unsafeDoIO $ B.withByteArray bs (\p -> Internal.os2ip p (B.length bs))
-- | @i2osp@ converts a positive integer into a byte string.
--
-- The first byte is LSB (least significant byte); the last byte is the MSB (most significant byte)
i2osp :: B.ByteArray ba => Integer -> ba
i2osp 0 = B.allocAndFreeze 1 (\p -> Internal.i2osp 0 p 1 >> return ())
i2osp m = B.allocAndFreeze sz (\p -> Internal.i2osp m p sz >> return ())
where
!sz = numBytes m
-- | Just like 'i2osp', but takes an extra parameter for size.
-- If the number is too big to fit in @len@ bytes, 'Nothing' is returned
-- otherwise the number is padded with 0 to fit the @len@ required.
{-# INLINABLE i2ospOf #-}
i2ospOf :: B.ByteArray ba => Int -> Integer -> Maybe ba
i2ospOf len m
| len <= 0 = Nothing
| m < 0 = Nothing
| sz > len = Nothing
| otherwise = Just $ B.unsafeCreate len (\p -> Internal.i2ospOf m p len >> return ())
where
!sz = numBytes m
-- | Just like 'i2ospOf' except that it doesn't expect a failure: i.e.
-- an integer larger than the number of output bytes requested.
--
-- For example if you just took a modulo of the number that represent
-- the size (example the RSA modulo n).
i2ospOf_ :: B.ByteArray ba => Int -> Integer -> ba
i2ospOf_ len = maybe (error "i2ospOf_: integer is larger than expected") id . i2ospOf len

View File

@ -42,15 +42,14 @@ module Crypto.OTP
) )
where where
import Data.Bits (shiftL, shiftR, (.&.), (.|.)) import Data.Bits (shiftL, (.&.), (.|.))
import Data.ByteArray.Mapping (fromW64BE) import Data.ByteArray.Mapping (fromW64BE)
import Data.List (elemIndex) import Data.List (elemIndex)
import Data.Word import Data.Word
import Foreign.Storable (poke)
import Control.Monad (unless) import Control.Monad (unless)
import Crypto.Hash (HashAlgorithm, SHA1(..)) import Crypto.Hash (HashAlgorithm, SHA1(..))
import Crypto.MAC.HMAC import Crypto.MAC.HMAC
import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, Bytes) import Crypto.Internal.ByteArray (ByteArrayAccess, Bytes)
import qualified Crypto.Internal.ByteArray as B import qualified Crypto.Internal.ByteArray as B

View File

@ -18,7 +18,7 @@ module Crypto.PubKey.Curve25519
, dhSecret , dhSecret
, publicKey , publicKey
, secretKey , secretKey
-- * methods -- * Methods
, dh , dh
, toPublic , toPublic
, generateSecretKey , generateSecretKey
@ -33,9 +33,8 @@ import GHC.Ptr
import Crypto.Error import Crypto.Error
import Crypto.Internal.Compat import Crypto.Internal.Compat
import Crypto.Internal.Imports import Crypto.Internal.Imports
import Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, ScrubbedBytes, Bytes, withByteArray) import Crypto.Internal.ByteArray (ByteArrayAccess, ScrubbedBytes, Bytes, withByteArray)
import qualified Crypto.Internal.ByteArray as B import qualified Crypto.Internal.ByteArray as B
import Crypto.Error (CryptoFailable(..))
import Crypto.Random import Crypto.Random
-- | A Curve25519 Secret key -- | A Curve25519 Secret key
@ -92,7 +91,10 @@ dhSecret bs
| B.length bs == 32 = CryptoPassed $ DhSecret $ B.copyAndFreeze bs (\_ -> return ()) | B.length bs == 32 = CryptoPassed $ DhSecret $ B.copyAndFreeze bs (\_ -> return ())
| otherwise = CryptoFailed CryptoError_SharedSecretSizeInvalid | otherwise = CryptoFailed CryptoError_SharedSecretSizeInvalid
-- | Compute the Diffie Hellman secret from a public key and a secret key -- | Compute the Diffie Hellman secret from a public key and a secret key.
--
-- This implementation may return an all-zero value as it does not check for
-- the condition.
dh :: PublicKey -> SecretKey -> DhSecret dh :: PublicKey -> SecretKey -> DhSecret
dh (PublicKey pub) (SecretKey sec) = DhSecret <$> dh (PublicKey pub) (SecretKey sec) = DhSecret <$>
B.allocAndFreeze 32 $ \result -> B.allocAndFreeze 32 $ \result ->

View File

@ -7,8 +7,11 @@
-- --
-- Curve448 support -- Curve448 support
-- --
-- Internally uses Decaf point compression to omit the cofactor
-- and implementation by Mike Hamburg. Externally API and
-- data types are compatible with the encoding specified in RFC 7748.
--
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MagicHash #-}
module Crypto.PubKey.Curve448 module Crypto.PubKey.Curve448
( SecretKey ( SecretKey
, PublicKey , PublicKey
@ -17,7 +20,7 @@ module Crypto.PubKey.Curve448
, dhSecret , dhSecret
, publicKey , publicKey
, secretKey , secretKey
-- * methods -- * Methods
, dh , dh
, toPublic , toPublic
, generateSecretKey , generateSecretKey
@ -25,7 +28,6 @@ module Crypto.PubKey.Curve448
import Data.Word import Data.Word
import Foreign.Ptr import Foreign.Ptr
import GHC.Ptr
import Crypto.Error import Crypto.Error
import Crypto.Random import Crypto.Random
@ -75,13 +77,16 @@ dhSecret bs
| B.length bs == x448_bytes = CryptoPassed $ DhSecret $ B.copyAndFreeze bs (\_ -> return ()) | B.length bs == x448_bytes = CryptoPassed $ DhSecret $ B.copyAndFreeze bs (\_ -> return ())
| otherwise = CryptoFailed CryptoError_SharedSecretSizeInvalid | otherwise = CryptoFailed CryptoError_SharedSecretSizeInvalid
-- | Compute the Diffie Hellman secret from a public key and a secret key -- | Compute the Diffie Hellman secret from a public key and a secret key.
--
-- This implementation may return an all-zero value as it does not check for
-- the condition.
dh :: PublicKey -> SecretKey -> DhSecret dh :: PublicKey -> SecretKey -> DhSecret
dh (PublicKey pub) (SecretKey sec) = DhSecret <$> dh (PublicKey pub) (SecretKey sec) = DhSecret <$>
B.allocAndFreeze x448_bytes $ \result -> B.allocAndFreeze x448_bytes $ \result ->
withByteArray sec $ \psec -> withByteArray sec $ \psec ->
withByteArray pub $ \ppub -> withByteArray pub $ \ppub ->
ccryptonite_ed448 result psec ppub decaf_x448 result ppub psec
{-# NOINLINE dh #-} {-# NOINLINE dh #-}
-- | Create a public key from a secret key -- | Create a public key from a secret key
@ -89,9 +94,7 @@ toPublic :: SecretKey -> PublicKey
toPublic (SecretKey sec) = PublicKey <$> toPublic (SecretKey sec) = PublicKey <$>
B.allocAndFreeze x448_bytes $ \result -> B.allocAndFreeze x448_bytes $ \result ->
withByteArray sec $ \psec -> withByteArray sec $ \psec ->
ccryptonite_ed448 result psec basePoint decaf_x448_derive_public_key result psec
where
basePoint = Ptr "\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"#
{-# NOINLINE toPublic #-} {-# NOINLINE toPublic #-}
-- | Generate a secret key. -- | Generate a secret key.
@ -101,8 +104,13 @@ generateSecretKey = SecretKey <$> getRandomBytes x448_bytes
x448_bytes :: Int x448_bytes :: Int
x448_bytes = 448 `quot` 8 x448_bytes = 448 `quot` 8
foreign import ccall "cryptonite_x448" foreign import ccall "cryptonite_decaf_x448"
ccryptonite_ed448 :: Ptr Word8 -- ^ public decaf_x448 :: Ptr Word8 -- ^ public
-> Ptr Word8 -- ^ secret -> Ptr Word8 -- ^ basepoint
-> Ptr Word8 -- ^ basepoint -> Ptr Word8 -- ^ secret
-> IO () -> IO ()
foreign import ccall "cryptonite_decaf_x448_derive_public_key"
decaf_x448_derive_public_key :: Ptr Word8 -- ^ public
-> Ptr Word8 -- ^ secret
-> IO ()

View File

@ -33,19 +33,22 @@ data Params = Params
{ params_p :: Integer { params_p :: Integer
, params_g :: Integer , params_g :: Integer
, params_bits :: Int , params_bits :: Int
} deriving (Show,Read,Eq,Data,Typeable) } deriving (Show,Read,Eq,Data)
instance NFData Params where
rnf (Params p g bits) = rnf p `seq` rnf g `seq` bits `seq` ()
-- | Represent Diffie Hellman public number Y. -- | Represent Diffie Hellman public number Y.
newtype PublicNumber = PublicNumber Integer newtype PublicNumber = PublicNumber Integer
deriving (Show,Read,Eq,Enum,Real,Num,Ord) deriving (Show,Read,Eq,Enum,Real,Num,Ord,NFData)
-- | Represent Diffie Hellman private number X. -- | Represent Diffie Hellman private number X.
newtype PrivateNumber = PrivateNumber Integer newtype PrivateNumber = PrivateNumber Integer
deriving (Show,Read,Eq,Enum,Real,Num,Ord) deriving (Show,Read,Eq,Enum,Real,Num,Ord,NFData)
-- | Represent Diffie Hellman shared secret. -- | Represent Diffie Hellman shared secret.
newtype SharedKey = SharedKey ScrubbedBytes newtype SharedKey = SharedKey ScrubbedBytes
deriving (Show,Eq,ByteArrayAccess) deriving (Show,Eq,ByteArrayAccess,NFData)
-- | generate params from a specific generator (2 or 5 are common values) -- | generate params from a specific generator (2 or 5 are common values)
-- we generate a safe prime (a prime number of the form 2p+1 where p is also prime) -- we generate a safe prime (a prime number of the form 2p+1 where p is also prime)

View File

@ -14,13 +14,13 @@ module Crypto.PubKey.DSA
, PrivateKey(..) , PrivateKey(..)
, PublicNumber , PublicNumber
, PrivateNumber , PrivateNumber
-- * generation -- * Generation
, generatePrivate , generatePrivate
, calculatePublic , calculatePublic
-- * signature primitive -- * Signature primitive
, sign , sign
, signWith , signWith
-- * verification primitive -- * Verification primitive
, verify , verify
-- * Key pair -- * Key pair
, KeyPair(..) , KeyPair(..)
@ -28,18 +28,17 @@ module Crypto.PubKey.DSA
, toPrivateKey , toPrivateKey
) where ) where
import Crypto.Random.Types
import Data.Bits (testBit) import Data.Data
import Data.Data import Data.Maybe
import Data.Maybe
import Crypto.Number.Basic (numBits) import Crypto.Number.ModArithmetic (expFast, expSafe, inverse)
import Crypto.Number.ModArithmetic (expFast, expSafe, inverse) import Crypto.Number.Generate
import Crypto.Number.Serialize import Crypto.Internal.ByteArray (ByteArrayAccess)
import Crypto.Number.Generate import Crypto.Internal.Imports
import Crypto.Internal.ByteArray (ByteArrayAccess(length), convert, index, dropView, takeView) import Crypto.Hash
import Crypto.Internal.Imports import Crypto.PubKey.Internal (dsaTruncHash)
import Crypto.Hash import Crypto.Random.Types
import Prelude hiding (length)
-- | DSA Public Number, usually embedded in DSA Public Key -- | DSA Public Number, usually embedded in DSA Public Key
type PublicNumber = Integer type PublicNumber = Integer
@ -52,7 +51,7 @@ data Params = Params
{ params_p :: Integer -- ^ DSA p { params_p :: Integer -- ^ DSA p
, params_g :: Integer -- ^ DSA g , params_g :: Integer -- ^ DSA g
, params_q :: Integer -- ^ DSA q , params_q :: Integer -- ^ DSA q
} deriving (Show,Read,Eq,Data,Typeable) } deriving (Show,Read,Eq,Data)
instance NFData Params where instance NFData Params where
rnf (Params p g q) = p `seq` g `seq` q `seq` () rnf (Params p g q) = p `seq` g `seq` q `seq` ()
@ -61,7 +60,7 @@ instance NFData Params where
data Signature = Signature data Signature = Signature
{ sign_r :: Integer -- ^ DSA r { sign_r :: Integer -- ^ DSA r
, sign_s :: Integer -- ^ DSA s , sign_s :: Integer -- ^ DSA s
} deriving (Show,Read,Eq,Data,Typeable) } deriving (Show,Read,Eq,Data)
instance NFData Signature where instance NFData Signature where
rnf (Signature r s) = r `seq` s `seq` () rnf (Signature r s) = r `seq` s `seq` ()
@ -70,7 +69,7 @@ instance NFData Signature where
data PublicKey = PublicKey data PublicKey = PublicKey
{ public_params :: Params -- ^ DSA parameters { public_params :: Params -- ^ DSA parameters
, public_y :: PublicNumber -- ^ DSA public Y , public_y :: PublicNumber -- ^ DSA public Y
} deriving (Show,Read,Eq,Data,Typeable) } deriving (Show,Read,Eq,Data)
instance NFData PublicKey where instance NFData PublicKey where
rnf (PublicKey params y) = y `seq` params `seq` () rnf (PublicKey params y) = y `seq` params `seq` ()
@ -82,14 +81,14 @@ instance NFData PublicKey where
data PrivateKey = PrivateKey data PrivateKey = PrivateKey
{ private_params :: Params -- ^ DSA parameters { private_params :: Params -- ^ DSA parameters
, private_x :: PrivateNumber -- ^ DSA private X , private_x :: PrivateNumber -- ^ DSA private X
} deriving (Show,Read,Eq,Data,Typeable) } deriving (Show,Read,Eq,Data)
instance NFData PrivateKey where instance NFData PrivateKey where
rnf (PrivateKey params x) = x `seq` params `seq` () rnf (PrivateKey params x) = x `seq` params `seq` ()
-- | Represent a DSA key pair -- | Represent a DSA key pair
data KeyPair = KeyPair Params PublicNumber PrivateNumber data KeyPair = KeyPair Params PublicNumber PrivateNumber
deriving (Show,Read,Eq,Data,Typeable) deriving (Show,Read,Eq,Data)
instance NFData KeyPair where instance NFData KeyPair where
rnf (KeyPair params y x) = x `seq` y `seq` params `seq` () rnf (KeyPair params y x) = x `seq` y `seq` params `seq` ()
@ -126,7 +125,7 @@ signWith k pk hashAlg msg
x = private_x pk x = private_x pk
-- compute r,s -- compute r,s
kInv = fromJust $ inverse k q kInv = fromJust $ inverse k q
hm = os2ip $ hashWith hashAlg msg hm = dsaTruncHash hashAlg msg q
r = expSafe g k p `mod` q r = expSafe g k p `mod` q
s = (kInv * (hm + x * r)) `mod` q s = (kInv * (hm + x * r)) `mod` q
@ -148,11 +147,8 @@ verify hashAlg pk (Signature r s) m
| otherwise = v == r | otherwise = v == r
where (Params p g q) = public_params pk where (Params p g q) = public_params pk
y = public_y pk y = public_y pk
hm = os2ip . truncateHash $ hashWith hashAlg m hm = dsaTruncHash hashAlg m q
w = fromJust $ inverse s q w = fromJust $ inverse s q
u1 = (hm*w) `mod` q u1 = (hm*w) `mod` q
u2 = (r*w) `mod` q u2 = (r*w) `mod` q
v = ((expFast g u1 p) * (expFast y u2 p)) `mod` p `mod` q v = ((expFast g u1 p) * (expFast y u2 p)) `mod` p `mod` q
-- if the hash is larger than the size of q, truncate it; FIXME: deal with the case of a q not evenly divisible by 8
truncateHash h = if numBits (os2ip h) > numBits q then takeView h (numBits q `div` 8) else dropView h 0

View File

@ -11,45 +11,46 @@ module Crypto.PubKey.ECC.ECDSA
, toPublicKey , toPublicKey
, toPrivateKey , toPrivateKey
, signWith , signWith
, signDigestWith
, sign , sign
, signDigest
, verify , verify
, verifyDigest
) where ) where
import Control.Monad import Control.Monad
import Crypto.Random.Types
import Data.Bits (shiftR)
import Crypto.Internal.ByteArray (ByteArrayAccess)
import Data.Data import Data.Data
import Crypto.Number.Basic (numBits)
import Crypto.Hash
import Crypto.Internal.ByteArray (ByteArrayAccess)
import Crypto.Number.ModArithmetic (inverse) import Crypto.Number.ModArithmetic (inverse)
import Crypto.Number.Serialize
import Crypto.Number.Generate import Crypto.Number.Generate
import Crypto.PubKey.ECC.Types import Crypto.PubKey.ECC.Types
import Crypto.PubKey.ECC.Prim import Crypto.PubKey.ECC.Prim
import Crypto.Hash import Crypto.PubKey.Internal (dsaTruncHashDigest)
import Crypto.Hash.Types (hashDigestSize) import Crypto.Random.Types
-- | Represent a ECDSA signature namely R and S. -- | Represent a ECDSA signature namely R and S.
data Signature = Signature data Signature = Signature
{ sign_r :: Integer -- ^ ECDSA r { sign_r :: Integer -- ^ ECDSA r
, sign_s :: Integer -- ^ ECDSA s , sign_s :: Integer -- ^ ECDSA s
} deriving (Show,Read,Eq,Data,Typeable) } deriving (Show,Read,Eq,Data)
-- | ECDSA Private Key. -- | ECDSA Private Key.
data PrivateKey = PrivateKey data PrivateKey = PrivateKey
{ private_curve :: Curve { private_curve :: Curve
, private_d :: PrivateNumber , private_d :: PrivateNumber
} deriving (Show,Read,Eq,Data,Typeable) } deriving (Show,Read,Eq,Data)
-- | ECDSA Public Key. -- | ECDSA Public Key.
data PublicKey = PublicKey data PublicKey = PublicKey
{ public_curve :: Curve { public_curve :: Curve
, public_q :: PublicPoint , public_q :: PublicPoint
} deriving (Show,Read,Eq,Data,Typeable) } deriving (Show,Read,Eq,Data)
-- | ECDSA Key Pair. -- | ECDSA Key Pair.
data KeyPair = KeyPair Curve PublicPoint PrivateNumber data KeyPair = KeyPair Curve PublicPoint PrivateNumber
deriving (Show,Read,Eq,Data,Typeable) deriving (Show,Read,Eq,Data)
-- | Public key of a ECDSA Key pair. -- | Public key of a ECDSA Key pair.
toPublicKey :: KeyPair -> PublicKey toPublicKey :: KeyPair -> PublicKey
@ -59,17 +60,16 @@ toPublicKey (KeyPair curve pub _) = PublicKey curve pub
toPrivateKey :: KeyPair -> PrivateKey toPrivateKey :: KeyPair -> PrivateKey
toPrivateKey (KeyPair curve _ priv) = PrivateKey curve priv toPrivateKey (KeyPair curve _ priv) = PrivateKey curve priv
-- | Sign message using the private key and an explicit k number. -- | Sign digest using the private key and an explicit k number.
-- --
-- /WARNING:/ Vulnerable to timing attacks. -- /WARNING:/ Vulnerable to timing attacks.
signWith :: (ByteArrayAccess msg, HashAlgorithm hash) signDigestWith :: HashAlgorithm hash
=> Integer -- ^ k random number => Integer -- ^ k random number
-> PrivateKey -- ^ private key -> PrivateKey -- ^ private key
-> hash -- ^ hash function -> Digest hash -- ^ digest to sign
-> msg -- ^ message to sign -> Maybe Signature
-> Maybe Signature signDigestWith k (PrivateKey curve d) digest = do
signWith k (PrivateKey curve d) hashAlg msg = do let z = dsaTruncHashDigest digest n
let z = tHash hashAlg msg n
CurveCommon _ _ g n _ = common_curve curve CurveCommon _ _ g n _ = common_curve curve
let point = pointMul curve k g let point = pointMul curve k g
r <- case point of r <- case point of
@ -80,26 +80,44 @@ signWith k (PrivateKey curve d) hashAlg msg = do
when (r == 0 || s == 0) Nothing when (r == 0 || s == 0) Nothing
return $ Signature r s return $ Signature r s
-- | Sign message using the private key and an explicit k number.
--
-- /WARNING:/ Vulnerable to timing attacks.
signWith :: (ByteArrayAccess msg, HashAlgorithm hash)
=> Integer -- ^ k random number
-> PrivateKey -- ^ private key
-> hash -- ^ hash function
-> msg -- ^ message to sign
-> Maybe Signature
signWith k pk hashAlg msg = signDigestWith k pk (hashWith hashAlg msg)
-- | Sign digest using the private key.
--
-- /WARNING:/ Vulnerable to timing attacks.
signDigest :: (HashAlgorithm hash, MonadRandom m)
=> PrivateKey -> Digest hash -> m Signature
signDigest pk digest = do
k <- generateBetween 1 (n - 1)
case signDigestWith k pk digest of
Nothing -> signDigest pk digest
Just sig -> return sig
where n = ecc_n . common_curve $ private_curve pk
-- | Sign message using the private key. -- | Sign message using the private key.
-- --
-- /WARNING:/ Vulnerable to timing attacks. -- /WARNING:/ Vulnerable to timing attacks.
sign :: (ByteArrayAccess msg, HashAlgorithm hash, MonadRandom m) sign :: (ByteArrayAccess msg, HashAlgorithm hash, MonadRandom m)
=> PrivateKey -> hash -> msg -> m Signature => PrivateKey -> hash -> msg -> m Signature
sign pk hashAlg msg = do sign pk hashAlg msg = signDigest pk (hashWith hashAlg msg)
k <- generateBetween 1 (n - 1)
case signWith k pk hashAlg msg of
Nothing -> sign pk hashAlg msg
Just sig -> return sig
where n = ecc_n . common_curve $ private_curve pk
-- | Verify a bytestring using the public key. -- | Verify a digest using the public key.
verify :: (ByteArrayAccess msg, HashAlgorithm hash) => hash -> PublicKey -> Signature -> msg -> Bool verifyDigest :: HashAlgorithm hash => PublicKey -> Signature -> Digest hash -> Bool
verify _ (PublicKey _ PointO) _ _ = False verifyDigest (PublicKey _ PointO) _ _ = False
verify hashAlg pk@(PublicKey curve q) (Signature r s) msg verifyDigest pk@(PublicKey curve q) (Signature r s) digest
| r < 1 || r >= n || s < 1 || s >= n = False | r < 1 || r >= n || s < 1 || s >= n = False
| otherwise = maybe False (r ==) $ do | otherwise = maybe False (r ==) $ do
w <- inverse s n w <- inverse s n
let z = tHash hashAlg msg n let z = dsaTruncHashDigest digest n
u1 = z * w `mod` n u1 = z * w `mod` n
u2 = r * w `mod` n u2 = r * w `mod` n
x = pointAddTwoMuls curve u1 g u2 q x = pointAddTwoMuls curve u1 g u2 q
@ -110,10 +128,6 @@ verify hashAlg pk@(PublicKey curve q) (Signature r s) msg
g = ecc_g cc g = ecc_g cc
cc = common_curve $ public_curve pk cc = common_curve $ public_curve pk
-- | Truncate and hash. -- | Verify a bytestring using the public key.
tHash :: (ByteArrayAccess msg, HashAlgorithm hash) => hash -> msg -> Integer -> Integer verify :: (ByteArrayAccess msg, HashAlgorithm hash) => hash -> PublicKey -> Signature -> msg -> Bool
tHash hashAlg m n verify hashAlg pk sig msg = verifyDigest pk sig (hashWith hashAlg msg)
| d > 0 = shiftR e d
| otherwise = e
where e = os2ip $ hashWith hashAlg m
d = hashDigestSize hashAlg * 8 - numBits n

View File

@ -8,31 +8,37 @@
-- P256 support -- P256 support
-- --
{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE EmptyDataDecls #-}
{-# OPTIONS_GHC -fno-warn-unused-binds #-} {-# OPTIONS_GHC -fno-warn-unused-binds #-}
module Crypto.PubKey.ECC.P256 module Crypto.PubKey.ECC.P256
( Scalar ( Scalar
, Point , Point
-- * point arithmetic -- * Point arithmetic
, pointBase , pointBase
, pointAdd , pointAdd
, pointNegate
, pointMul , pointMul
, pointDh , pointDh
, pointsMulVarTime , pointsMulVarTime
, pointIsValid , pointIsValid
, pointIsAtInfinity
, toPoint , toPoint
, pointX
, pointToIntegers , pointToIntegers
, pointFromIntegers , pointFromIntegers
, pointToBinary , pointToBinary
, pointFromBinary , pointFromBinary
-- * scalar arithmetic , unsafePointFromBinary
-- * Scalar arithmetic
, scalarGenerate , scalarGenerate
, scalarZero , scalarZero
, scalarN
, scalarIsZero , scalarIsZero
, scalarAdd , scalarAdd
, scalarSub , scalarSub
, scalarMul
, scalarInv , scalarInv
, scalarInvSafe
, scalarCmp , scalarCmp
, scalarFromBinary , scalarFromBinary
, scalarToBinary , scalarToBinary
@ -43,7 +49,6 @@ module Crypto.PubKey.ECC.P256
import Data.Word import Data.Word
import Foreign.Ptr import Foreign.Ptr
import Foreign.C.Types import Foreign.C.Types
import Control.Monad
import Crypto.Internal.Compat import Crypto.Internal.Compat
import Crypto.Internal.Imports import Crypto.Internal.Imports
@ -57,11 +62,11 @@ import qualified Crypto.Number.Serialize as S (os2ip, i2ospOf)
-- | A P256 scalar -- | A P256 scalar
newtype Scalar = Scalar ScrubbedBytes newtype Scalar = Scalar ScrubbedBytes
deriving (Show,Eq,ByteArrayAccess) deriving (Show,Eq,ByteArrayAccess,NFData)
-- | A P256 point -- | A P256 point
newtype Point = Point Bytes newtype Point = Point Bytes
deriving (Show,Eq) deriving (Show,Eq,NFData)
scalarSize :: Int scalarSize :: Int
scalarSize = 32 scalarSize = 32
@ -75,6 +80,9 @@ data P256Scalar
data P256Y data P256Y
data P256X data P256X
order :: Integer
order = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- Point methods -- Point methods
------------------------------------------------------------------------ ------------------------------------------------------------------------
@ -105,20 +113,27 @@ pointAdd a b = withNewPoint $ \dx dy ->
withPoint a $ \ax ay -> withPoint b $ \bx by -> withPoint a $ \ax ay -> withPoint b $ \bx by ->
ccryptonite_p256e_point_add ax ay bx by dx dy ccryptonite_p256e_point_add ax ay bx by dx dy
-- | Negate a point
pointNegate :: Point -> Point
pointNegate a = withNewPoint $ \dx dy ->
withPoint a $ \ax ay ->
ccryptonite_p256e_point_negate ax ay dx dy
-- | Multiply a point by a scalar -- | Multiply a point by a scalar
-- --
-- warning: variable time -- warning: variable time
pointMul :: Scalar -> Point -> Point pointMul :: Scalar -> Point -> Point
pointMul scalar p = withNewPoint $ \dx dy -> pointMul scalar p = withNewPoint $ \dx dy ->
withScalar scalar $ \n -> withPoint p $ \px py -> withScalarZero $ \nzero -> withScalar scalar $ \n -> withPoint p $ \px py ->
ccryptonite_p256_points_mul_vartime nzero n px py dx dy ccryptonite_p256e_point_mul n px py dx dy
-- | Similar to 'pointMul', serializing the x coordinate as binary -- | Similar to 'pointMul', serializing the x coordinate as binary.
-- When scalar is multiple of point order the result is all zero.
pointDh :: ByteArray binary => Scalar -> Point -> binary pointDh :: ByteArray binary => Scalar -> Point -> binary
pointDh scalar p = pointDh scalar p =
B.unsafeCreate scalarSize $ \dst -> withTempPoint $ \dx dy -> do B.unsafeCreate scalarSize $ \dst -> withTempPoint $ \dx dy -> do
withScalar scalar $ \n -> withPoint p $ \px py -> withScalarZero $ \nzero -> withScalar scalar $ \n -> withPoint p $ \px py ->
ccryptonite_p256_points_mul_vartime nzero n px py dx dy ccryptonite_p256e_point_mul n px py dx dy
ccryptonite_p256_to_bin (castPtr dx) dst ccryptonite_p256_to_bin (castPtr dx) dst
-- | multiply the point @p with @n2 and add a lifted to curve value @n1 -- | multiply the point @p with @n2 and add a lifted to curve value @n1
@ -137,6 +152,19 @@ pointIsValid p = unsafeDoIO $ withPoint p $ \px py -> do
r <- ccryptonite_p256_is_valid_point px py r <- ccryptonite_p256_is_valid_point px py
return (r /= 0) return (r /= 0)
-- | Check if a 'Point' is the point at infinity
pointIsAtInfinity :: Point -> Bool
pointIsAtInfinity (Point b) = constAllZero b
-- | Return the x coordinate as a 'Scalar' if the point is not at infinity
pointX :: Point -> Maybe Scalar
pointX p
| pointIsAtInfinity p = Nothing
| otherwise = Just $
withNewScalarFreeze $ \d ->
withPoint p $ \px _ ->
ccryptonite_p256_mod ccryptonite_SECP256r1_n (castPtr px) (castPtr d)
-- | Convert a point to (x,y) Integers -- | Convert a point to (x,y) Integers
pointToIntegers :: Point -> (Integer, Integer) pointToIntegers :: Point -> (Integer, Integer)
pointToIntegers p = unsafeDoIO $ withPoint p $ \px py -> pointToIntegers p = unsafeDoIO $ withPoint p $ \px py ->
@ -172,10 +200,19 @@ pointToBinary p = B.unsafeCreate pointSize $ \dst -> withPoint p $ \px py -> do
ccryptonite_p256_to_bin (castPtr px) dst ccryptonite_p256_to_bin (castPtr px) dst
ccryptonite_p256_to_bin (castPtr py) (dst `plusPtr` 32) ccryptonite_p256_to_bin (castPtr py) (dst `plusPtr` 32)
-- | Convert from binary to a point -- | Convert from binary to a valid point
pointFromBinary :: ByteArrayAccess ba => ba -> CryptoFailable Point pointFromBinary :: ByteArrayAccess ba => ba -> CryptoFailable Point
pointFromBinary ba pointFromBinary ba = unsafePointFromBinary ba >>= validatePoint
| B.length ba /= pointSize = CryptoFailed $ CryptoError_PublicKeySizeInvalid where
validatePoint :: Point -> CryptoFailable Point
validatePoint p
| pointIsValid p = CryptoPassed p
| otherwise = CryptoFailed CryptoError_PointCoordinatesInvalid
-- | Convert from binary to a point, possibly invalid
unsafePointFromBinary :: ByteArrayAccess ba => ba -> CryptoFailable Point
unsafePointFromBinary ba
| B.length ba /= pointSize = CryptoFailed CryptoError_PublicKeySizeInvalid
| otherwise = | otherwise =
CryptoPassed $ withNewPoint $ \px py -> B.withByteArray ba $ \src -> do CryptoPassed $ withNewPoint $ \px py -> B.withByteArray ba $ \src -> do
ccryptonite_p256_from_bin src (castPtr px) ccryptonite_p256_from_bin src (castPtr px)
@ -198,40 +235,39 @@ scalarGenerate = unwrap . scalarFromBinary . witness <$> getRandomBytes 32
scalarZero :: Scalar scalarZero :: Scalar
scalarZero = withNewScalarFreeze $ \d -> ccryptonite_p256_init d scalarZero = withNewScalarFreeze $ \d -> ccryptonite_p256_init d
-- | The scalar representing the curve order
scalarN :: Scalar
scalarN = throwCryptoError (scalarFromInteger order)
-- | Check if the scalar is 0 -- | Check if the scalar is 0
scalarIsZero :: Scalar -> Bool scalarIsZero :: Scalar -> Bool
scalarIsZero s = unsafeDoIO $ withScalar s $ \d -> do scalarIsZero s = unsafeDoIO $ withScalar s $ \d -> do
result <- ccryptonite_p256_is_zero d result <- ccryptonite_p256_is_zero d
return $ result /= 0 return $ result /= 0
scalarNeedReducing :: Ptr P256Scalar -> IO Bool
scalarNeedReducing d = do
c <- ccryptonite_p256_cmp d ccryptonite_SECP256r1_n
return (c >= 0)
-- | Perform addition between two scalars -- | Perform addition between two scalars
-- --
-- > a + b -- > a + b
scalarAdd :: Scalar -> Scalar -> Scalar scalarAdd :: Scalar -> Scalar -> Scalar
scalarAdd a b = scalarAdd a b =
withNewScalarFreeze $ \d -> withScalar a $ \pa -> withScalar b $ \pb -> do withNewScalarFreeze $ \d -> withScalar a $ \pa -> withScalar b $ \pb ->
carry <- ccryptonite_p256_add pa pb d ccryptonite_p256e_modadd ccryptonite_SECP256r1_n pa pb d
when (carry /= 0) $ void $ ccryptonite_p256_sub d ccryptonite_SECP256r1_n d
needReducing <- scalarNeedReducing d
when needReducing $ do
ccryptonite_p256_mod ccryptonite_SECP256r1_n d d
-- | Perform subtraction between two scalars -- | Perform subtraction between two scalars
-- --
-- > a - b -- > a - b
scalarSub :: Scalar -> Scalar -> Scalar scalarSub :: Scalar -> Scalar -> Scalar
scalarSub a b = scalarSub a b =
withNewScalarFreeze $ \d -> withScalar a $ \pa -> withScalar b $ \pb -> do withNewScalarFreeze $ \d -> withScalar a $ \pa -> withScalar b $ \pb ->
borrow <- ccryptonite_p256_sub pa pb d ccryptonite_p256e_modsub ccryptonite_SECP256r1_n pa pb d
when (borrow /= 0) $ void $ ccryptonite_p256_add d ccryptonite_SECP256r1_n d
--needReducing <- scalarNeedReducing d -- | Perform multiplication between two scalars
--when needReducing $ do --
-- ccryptonite_p256_mod ccryptonite_SECP256r1_n d d -- > a * b
scalarMul :: Scalar -> Scalar -> Scalar
scalarMul a b =
withNewScalarFreeze $ \d -> withScalar a $ \pa -> withScalar b $ \pb ->
ccryptonite_p256_modmul ccryptonite_SECP256r1_n pa 0 pb d
-- | Give the inverse of the scalar -- | Give the inverse of the scalar
-- --
@ -243,6 +279,14 @@ scalarInv a =
withNewScalarFreeze $ \b -> withScalar a $ \pa -> withNewScalarFreeze $ \b -> withScalar a $ \pa ->
ccryptonite_p256_modinv_vartime ccryptonite_SECP256r1_n pa b ccryptonite_p256_modinv_vartime ccryptonite_SECP256r1_n pa b
-- | Give the inverse of the scalar using safe exponentiation
--
-- > 1 / a
scalarInvSafe :: Scalar -> Scalar
scalarInvSafe a =
withNewScalarFreeze $ \b -> withScalar a $ \pa ->
ccryptonite_p256e_scalar_invert pa b
-- | Compare 2 Scalar -- | Compare 2 Scalar
scalarCmp :: Scalar -> Scalar -> Ordering scalarCmp :: Scalar -> Scalar -> Ordering
scalarCmp a b = unsafeDoIO $ scalarCmp a b = unsafeDoIO $
@ -253,7 +297,7 @@ scalarCmp a b = unsafeDoIO $
-- | convert a scalar from binary -- | convert a scalar from binary
scalarFromBinary :: ByteArrayAccess ba => ba -> CryptoFailable Scalar scalarFromBinary :: ByteArrayAccess ba => ba -> CryptoFailable Scalar
scalarFromBinary ba scalarFromBinary ba
| B.length ba /= scalarSize = CryptoFailed $ CryptoError_SecretKeySizeInvalid | B.length ba /= scalarSize = CryptoFailed CryptoError_SecretKeySizeInvalid
| otherwise = | otherwise =
CryptoPassed $ withNewScalarFreeze $ \p -> B.withByteArray ba $ \b -> CryptoPassed $ withNewScalarFreeze $ \p -> B.withByteArray ba $ \b ->
ccryptonite_p256_from_bin b p ccryptonite_p256_from_bin b p
@ -292,20 +336,11 @@ withNewScalarFreeze f = Scalar $ B.allocAndFreeze scalarSize f
{-# NOINLINE withNewScalarFreeze #-} {-# NOINLINE withNewScalarFreeze #-}
withTempPoint :: (Ptr P256X -> Ptr P256Y -> IO a) -> IO a withTempPoint :: (Ptr P256X -> Ptr P256Y -> IO a) -> IO a
withTempPoint f = allocTempScrubbed scalarSize (\p -> let px = castPtr p in f px (pxToPy px)) withTempPoint f = allocTempScrubbed pointSize (\p -> let px = castPtr p in f px (pxToPy px))
withTempScalar :: (Ptr P256Scalar -> IO a) -> IO a
withTempScalar f = allocTempScrubbed scalarSize (f . castPtr)
withScalar :: Scalar -> (Ptr P256Scalar -> IO a) -> IO a withScalar :: Scalar -> (Ptr P256Scalar -> IO a) -> IO a
withScalar (Scalar d) f = B.withByteArray d f withScalar (Scalar d) f = B.withByteArray d f
withScalarZero :: (Ptr P256Scalar -> IO a) -> IO a
withScalarZero f =
withTempScalar $ \d -> do
ccryptonite_p256_init d
f d
allocTemp :: Int -> (Ptr Word8 -> IO a) -> IO a allocTemp :: Int -> (Ptr Word8 -> IO a) -> IO a
allocTemp n f = ignoreSnd <$> B.allocRet n f allocTemp n f = ignoreSnd <$> B.allocRet n f
where where
@ -334,18 +369,20 @@ foreign import ccall "cryptonite_p256_is_zero"
ccryptonite_p256_is_zero :: Ptr P256Scalar -> IO CInt ccryptonite_p256_is_zero :: Ptr P256Scalar -> IO CInt
foreign import ccall "cryptonite_p256_clear" foreign import ccall "cryptonite_p256_clear"
ccryptonite_p256_clear :: Ptr P256Scalar -> IO () ccryptonite_p256_clear :: Ptr P256Scalar -> IO ()
foreign import ccall "cryptonite_p256_add" foreign import ccall "cryptonite_p256e_modadd"
ccryptonite_p256_add :: Ptr P256Scalar -> Ptr P256Scalar -> Ptr P256Scalar -> IO CInt ccryptonite_p256e_modadd :: Ptr P256Scalar -> Ptr P256Scalar -> Ptr P256Scalar -> Ptr P256Scalar -> IO ()
foreign import ccall "cryptonite_p256_add_d" foreign import ccall "cryptonite_p256_add_d"
ccryptonite_p256_add_d :: Ptr P256Scalar -> P256Digit -> Ptr P256Scalar -> IO CInt ccryptonite_p256_add_d :: Ptr P256Scalar -> P256Digit -> Ptr P256Scalar -> IO CInt
foreign import ccall "cryptonite_p256_sub" foreign import ccall "cryptonite_p256e_modsub"
ccryptonite_p256_sub :: Ptr P256Scalar -> Ptr P256Scalar -> Ptr P256Scalar -> IO CInt ccryptonite_p256e_modsub :: Ptr P256Scalar -> Ptr P256Scalar -> Ptr P256Scalar -> Ptr P256Scalar -> IO ()
foreign import ccall "cryptonite_p256_cmp" foreign import ccall "cryptonite_p256_cmp"
ccryptonite_p256_cmp :: Ptr P256Scalar -> Ptr P256Scalar -> IO CInt ccryptonite_p256_cmp :: Ptr P256Scalar -> Ptr P256Scalar -> IO CInt
foreign import ccall "cryptonite_p256_mod" foreign import ccall "cryptonite_p256_mod"
ccryptonite_p256_mod :: Ptr P256Scalar -> Ptr P256Scalar -> Ptr P256Scalar -> IO () ccryptonite_p256_mod :: Ptr P256Scalar -> Ptr P256Scalar -> Ptr P256Scalar -> IO ()
foreign import ccall "cryptonite_p256_modmul" foreign import ccall "cryptonite_p256_modmul"
ccryptonite_p256_modmul :: Ptr P256Scalar -> Ptr P256Scalar -> P256Digit -> Ptr P256Scalar -> Ptr P256Scalar -> IO () ccryptonite_p256_modmul :: Ptr P256Scalar -> Ptr P256Scalar -> P256Digit -> Ptr P256Scalar -> Ptr P256Scalar -> IO ()
foreign import ccall "cryptonite_p256e_scalar_invert"
ccryptonite_p256e_scalar_invert :: Ptr P256Scalar -> Ptr P256Scalar -> IO ()
--foreign import ccall "cryptonite_p256_modinv" --foreign import ccall "cryptonite_p256_modinv"
-- ccryptonite_p256_modinv :: Ptr P256Scalar -> Ptr P256Scalar -> Ptr P256Scalar -> IO () -- ccryptonite_p256_modinv :: Ptr P256Scalar -> Ptr P256Scalar -> Ptr P256Scalar -> IO ()
foreign import ccall "cryptonite_p256_modinv_vartime" foreign import ccall "cryptonite_p256_modinv_vartime"
@ -361,6 +398,18 @@ foreign import ccall "cryptonite_p256e_point_add"
-> Ptr P256X -> Ptr P256Y -> Ptr P256X -> Ptr P256Y
-> IO () -> IO ()
foreign import ccall "cryptonite_p256e_point_negate"
ccryptonite_p256e_point_negate :: Ptr P256X -> Ptr P256Y
-> Ptr P256X -> Ptr P256Y
-> IO ()
-- compute (out_x,out_y) = n * (in_x,in_y)
foreign import ccall "cryptonite_p256e_point_mul"
ccryptonite_p256e_point_mul :: Ptr P256Scalar -- n
-> Ptr P256X -> Ptr P256Y -- in_{x,y}
-> Ptr P256X -> Ptr P256Y -- out_{x,y}
-> IO ()
-- compute (out_x,out,y) = n1 * G + n2 * (in_x,in_y) -- compute (out_x,out,y) = n1 * G + n2 * (in_x,in_y)
foreign import ccall "cryptonite_p256_points_mul_vartime" foreign import ccall "cryptonite_p256_points_mul_vartime"
ccryptonite_p256_points_mul_vartime :: Ptr P256Scalar -- n1 ccryptonite_p256_points_mul_vartime :: Ptr P256Scalar -- n1

View File

@ -4,6 +4,7 @@
module Crypto.PubKey.ECC.Prim module Crypto.PubKey.ECC.Prim
( scalarGenerate ( scalarGenerate
, pointAdd , pointAdd
, pointNegate
, pointDouble , pointDouble
, pointBaseMul , pointBaseMul
, pointMul , pointMul
@ -30,9 +31,9 @@ scalarGenerate curve = generateBetween 1 (n - 1)
-- | Elliptic Curve point negation: -- | Elliptic Curve point negation:
-- @pointNegate c p@ returns point @q@ such that @pointAdd c p q == PointO@. -- @pointNegate c p@ returns point @q@ such that @pointAdd c p q == PointO@.
pointNegate :: Curve -> Point -> Point pointNegate :: Curve -> Point -> Point
pointNegate _ PointO = PointO pointNegate _ PointO = PointO
pointNegate CurveFP{} (Point x y) = Point x (-y) pointNegate (CurveFP c) (Point x y) = Point x (ecc_p c - y)
pointNegate CurveF2m{} (Point x y) = Point x (x `addF2m` y) pointNegate CurveF2m{} (Point x y) = Point x (x `addF2m` y)
-- | Elliptic Curve point addition. -- | Elliptic Curve point addition.
-- --

View File

@ -6,7 +6,7 @@
-- Stability : Experimental -- Stability : Experimental
-- Portability : Excellent -- Portability : Excellent
-- --
-- references: -- References:
-- <https://tools.ietf.org/html/rfc5915> -- <https://tools.ietf.org/html/rfc5915>
-- --
module Crypto.PubKey.ECC.Types module Crypto.PubKey.ECC.Types
@ -21,7 +21,7 @@ module Crypto.PubKey.ECC.Types
, ecc_fx , ecc_fx
, ecc_p , ecc_p
, CurveCommon(..) , CurveCommon(..)
-- * recommended curves definition -- * Recommended curves definition
, CurveName(..) , CurveName(..)
, getCurveByName , getCurveByName
) where ) where
@ -33,7 +33,7 @@ import Crypto.Number.Basic (numBits)
-- | Define either a binary curve or a prime curve. -- | Define either a binary curve or a prime curve.
data Curve = CurveF2m CurveBinary -- ^ 𝔽(2^m) data Curve = CurveF2m CurveBinary -- ^ 𝔽(2^m)
| CurveFP CurvePrime -- ^ 𝔽p | CurveFP CurvePrime -- ^ 𝔽p
deriving (Show,Read,Eq,Data,Typeable) deriving (Show,Read,Eq,Data)
-- | ECC Public Point -- | ECC Public Point
type PublicPoint = Point type PublicPoint = Point
@ -44,7 +44,7 @@ type PrivateNumber = Integer
-- | Define a point on a curve. -- | Define a point on a curve.
data Point = Point Integer Integer data Point = Point Integer Integer
| PointO -- ^ Point at Infinity | PointO -- ^ Point at Infinity
deriving (Show,Read,Eq,Data,Typeable) deriving (Show,Read,Eq,Data)
instance NFData Point where instance NFData Point where
rnf (Point x y) = x `seq` y `seq` () rnf (Point x y) = x `seq` y `seq` ()
@ -53,7 +53,7 @@ instance NFData Point where
-- | Define an elliptic curve in 𝔽(2^m). -- | Define an elliptic curve in 𝔽(2^m).
-- The firt parameter is the Integer representatioin of the irreducible polynomial f(x). -- The firt parameter is the Integer representatioin of the irreducible polynomial f(x).
data CurveBinary = CurveBinary Integer CurveCommon data CurveBinary = CurveBinary Integer CurveCommon
deriving (Show,Read,Eq,Data,Typeable) deriving (Show,Read,Eq,Data)
instance NFData CurveBinary where instance NFData CurveBinary where
rnf (CurveBinary i cc) = i `seq` cc `seq` () rnf (CurveBinary i cc) = i `seq` cc `seq` ()
@ -61,7 +61,7 @@ instance NFData CurveBinary where
-- | Define an elliptic curve in 𝔽p. -- | Define an elliptic curve in 𝔽p.
-- The first parameter is the Prime Number. -- The first parameter is the Prime Number.
data CurvePrime = CurvePrime Integer CurveCommon data CurvePrime = CurvePrime Integer CurveCommon
deriving (Show,Read,Eq,Data,Typeable) deriving (Show,Read,Eq,Data)
-- | Parameters in common between binary and prime curves. -- | Parameters in common between binary and prime curves.
common_curve :: Curve -> CurveCommon common_curve :: Curve -> CurveCommon
@ -84,7 +84,7 @@ data CurveCommon = CurveCommon
, ecc_g :: Point -- ^ base point , ecc_g :: Point -- ^ base point
, ecc_n :: Integer -- ^ order of G , ecc_n :: Integer -- ^ order of G
, ecc_h :: Integer -- ^ cofactor , ecc_h :: Integer -- ^ cofactor
} deriving (Show,Read,Eq,Data,Typeable) } deriving (Show,Read,Eq,Data)
-- | Define names for known recommended curves. -- | Define names for known recommended curves.
data CurveName = data CurveName =
@ -121,7 +121,7 @@ data CurveName =
| SEC_t409r1 | SEC_t409r1
| SEC_t571k1 | SEC_t571k1
| SEC_t571r1 | SEC_t571r1
deriving (Show,Read,Eq,Ord,Enum,Bounded,Data,Typeable) deriving (Show,Read,Eq,Ord,Enum,Bounded,Data)
{- {-
curvesOIDs :: [ (CurveName, [Integer]) ] curvesOIDs :: [ (CurveName, [Integer]) ]

Some files were not shown because too many files have changed in this diff Show More