From 6c4557621c30fbd812bcba93a3bf5812dcf0c62a Mon Sep 17 00:00:00 2001 From: Vincent Hanquez Date: Mon, 6 Apr 2015 14:53:37 +0100 Subject: [PATCH] merge crypto-cipher-types --- Crypto/Cipher/Types.hs | 57 ++++++++ Crypto/Cipher/Types/AEAD.hs | 63 +++++++++ Crypto/Cipher/Types/Base.hs | 83 +++++++++++ Crypto/Cipher/Types/Block.hs | 253 ++++++++++++++++++++++++++++++++++ Crypto/Cipher/Types/GF.hs | 49 +++++++ Crypto/Cipher/Types/Stream.hs | 20 +++ Crypto/Cipher/Types/Utils.hs | 24 ++++ cryptonite.cabal | 7 + 8 files changed, 556 insertions(+) create mode 100644 Crypto/Cipher/Types/AEAD.hs create mode 100644 Crypto/Cipher/Types/Base.hs create mode 100644 Crypto/Cipher/Types/Block.hs create mode 100644 Crypto/Cipher/Types/GF.hs create mode 100644 Crypto/Cipher/Types/Stream.hs create mode 100644 Crypto/Cipher/Types/Utils.hs diff --git a/Crypto/Cipher/Types.hs b/Crypto/Cipher/Types.hs index 155b154..9a7043f 100644 --- a/Crypto/Cipher/Types.hs +++ b/Crypto/Cipher/Types.hs @@ -1,3 +1,60 @@ +-- | +-- Module : Crypto.Cipher.Types +-- License : BSD-style +-- Maintainer : Vincent Hanquez +-- Stability : Stable +-- Portability : Excellent +-- +-- symmetric cipher basic types +-- +{-# LANGUAGE DeriveDataTypeable #-} module Crypto.Cipher.Types ( + -- * Cipher classes + Cipher(..) + , BlockCipher(..) + , StreamCipher(..) + , DataUnitOffset + , KeySizeSpecifier(..) + , KeyError(..) + , AEAD(..) + , AEADState(..) + , AEADMode(..) + , AEADModeImpl(..) + , cfb8Encrypt + , cfb8Decrypt + -- * AEAD functions + , module Crypto.Cipher.Types.AEAD + -- * Key type and constructor + , Key + , makeKey + -- * Initial Vector type and constructor + , IV + , makeIV + , nullIV + , ivAdd + -- * Authentification Tag + , AuthTag(..) ) where + +import Data.SecureMem +import Data.Byteable +import Crypto.Cipher.Types.Base +import Crypto.Cipher.Types.Block +import Crypto.Cipher.Types.Stream +import Crypto.Cipher.Types.AEAD + +-- | Create a Key for a specified cipher +makeKey :: (ToSecureMem b, Cipher c) => b -> Either KeyError (Key c) +makeKey b = toKey undefined + where sm = toSecureMem b + smLen = byteableLength sm + toKey :: Cipher c => c -> Either KeyError (Key c) + toKey cipher = case cipherKeySize cipher of + KeySizeRange mi ma | smLen < mi -> Left KeyErrorTooSmall + | smLen > ma -> Left KeyErrorTooBig + | otherwise -> Right $ Key sm + KeySizeEnum l | smLen `elem` l -> Right $ Key sm + | otherwise -> Left $ KeyErrorInvalid ("valid size: " ++ show l) + KeySizeFixed v | smLen == v -> Right $ Key sm + | otherwise -> Left $ KeyErrorInvalid ("valid size: " ++ show v) diff --git a/Crypto/Cipher/Types/AEAD.hs b/Crypto/Cipher/Types/AEAD.hs new file mode 100644 index 0000000..6b3cfb7 --- /dev/null +++ b/Crypto/Cipher/Types/AEAD.hs @@ -0,0 +1,63 @@ +-- | +-- Module : Crypto.Cipher.Types.AEAD +-- License : BSD-style +-- Maintainer : Vincent Hanquez +-- Stability : Stable +-- Portability : Excellent +-- +-- AEAD cipher basic types +-- +module Crypto.Cipher.Types.AEAD where + +import Data.ByteString (ByteString) +import qualified Data.ByteString as B +import Data.Byteable +import Crypto.Cipher.Types.Base +import Crypto.Cipher.Types.Block + +-- | Append associated data into the AEAD state +aeadAppendHeader :: BlockCipher a => AEAD a -> ByteString -> AEAD a +aeadAppendHeader (AEAD cipher (AEADState state)) bs = + AEAD cipher $ AEADState (aeadStateAppendHeader cipher state bs) + +-- | Encrypt input and append into the AEAD state +aeadEncrypt :: BlockCipher a => AEAD a -> ByteString -> (ByteString, AEAD a) +aeadEncrypt (AEAD cipher (AEADState state)) input = (output, AEAD cipher (AEADState nst)) + where (output, nst) = aeadStateEncrypt cipher state input + +-- | Decrypt input and append into the AEAD state +aeadDecrypt :: BlockCipher a => AEAD a -> ByteString -> (ByteString, AEAD a) +aeadDecrypt (AEAD cipher (AEADState state)) input = (output, AEAD cipher (AEADState nst)) + where (output, nst) = aeadStateDecrypt cipher state input + +-- | Finalize the AEAD state and create an authentification tag +aeadFinalize :: BlockCipher a => AEAD a -> Int -> AuthTag +aeadFinalize (AEAD cipher (AEADState state)) len = + aeadStateFinalize cipher state len + +-- | Simple AEAD encryption +aeadSimpleEncrypt :: BlockCipher a + => AEAD a -- ^ A new AEAD Context + -> B.ByteString -- ^ Optional Authentified Header + -> B.ByteString -- ^ Optional Plaintext + -> Int -- ^ Tag length + -> (AuthTag, B.ByteString) -- ^ Authentification tag and ciphertext +aeadSimpleEncrypt aeadIni header input taglen = (tag, output) + where aead = aeadAppendHeader aeadIni header + (output, aeadFinal) = aeadEncrypt aead input + tag = aeadFinalize aeadFinal taglen + +-- | Simple AEAD decryption +aeadSimpleDecrypt :: BlockCipher a + => AEAD a -- ^ A new AEAD Context + -> B.ByteString -- ^ Optional Authentified Header + -> B.ByteString -- ^ Optional Plaintext + -> AuthTag -- ^ Tag length + -> Maybe B.ByteString -- ^ Plaintext +aeadSimpleDecrypt aeadIni header input authTag + | tag == authTag = Just output + | otherwise = Nothing + where aead = aeadAppendHeader aeadIni header + (output, aeadFinal) = aeadDecrypt aead input + tag = aeadFinalize aeadFinal (byteableLength authTag) + diff --git a/Crypto/Cipher/Types/Base.hs b/Crypto/Cipher/Types/Base.hs new file mode 100644 index 0000000..baa9827 --- /dev/null +++ b/Crypto/Cipher/Types/Base.hs @@ -0,0 +1,83 @@ +-- | +-- Module : Crypto.Cipher.Types.Base +-- License : BSD-style +-- Maintainer : Vincent Hanquez +-- Stability : Stable +-- Portability : Excellent +-- +-- symmetric cipher basic types +-- +module Crypto.Cipher.Types.Base + ( KeyError(..) + , KeySizeSpecifier(..) + , Key(..) + , IV(..) + , Cipher(..) + , AuthTag(..) + , AEADMode(..) + , DataUnitOffset + ) where + +import Data.Byteable +import Data.SecureMem +import Data.Word +import Data.ByteString (ByteString) + +-- | Possible Error that can be reported when initializating a key +data KeyError = + KeyErrorTooSmall + | KeyErrorTooBig + | KeyErrorInvalid String + deriving (Show,Eq) + +-- | Different specifier for key size in bytes +data KeySizeSpecifier = + KeySizeRange Int Int -- ^ in the range [min,max] + | KeySizeEnum [Int] -- ^ one of the specified values + | KeySizeFixed Int -- ^ a specific size + deriving (Show,Eq) + +-- | Offset inside an XTS data unit, measured in block size. +type DataUnitOffset = Word32 + +-- | a Key parametrized by the cipher +newtype Key c = Key SecureMem deriving (Eq) + +instance ToSecureMem (Key c) where + toSecureMem (Key sm) = sm +instance Byteable (Key c) where + toBytes (Key sm) = toBytes sm + +-- | an IV parametrized by the cipher +newtype IV c = IV ByteString deriving (Eq) + +instance Byteable (IV c) where + toBytes (IV sm) = sm + +-- | Authentification Tag for AE cipher mode +newtype AuthTag = AuthTag ByteString + deriving (Show) + +instance Eq AuthTag where + (AuthTag a) == (AuthTag b) = constEqBytes a b +instance Byteable AuthTag where + toBytes (AuthTag bs) = bs + +-- | AEAD Mode +data AEADMode = + AEAD_OCB -- OCB3 + | AEAD_CCM + | AEAD_EAX + | AEAD_CWC + | AEAD_GCM + deriving (Show,Eq) + +-- | Symmetric cipher class. +class Cipher cipher where + -- | Initialize a cipher context from a key + cipherInit :: Key cipher -> cipher + -- | Cipher name + cipherName :: cipher -> String + -- | return the size of the key required for this cipher. + -- Some cipher accept any size for key + cipherKeySize :: cipher -> KeySizeSpecifier diff --git a/Crypto/Cipher/Types/Block.hs b/Crypto/Cipher/Types/Block.hs new file mode 100644 index 0000000..2edc20e --- /dev/null +++ b/Crypto/Cipher/Types/Block.hs @@ -0,0 +1,253 @@ +-- | +-- Module : Crypto.Cipher.Types.Block +-- License : BSD-style +-- Maintainer : Vincent Hanquez +-- Stability : Stable +-- Portability : Excellent +-- +-- block cipher basic types +-- +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE ExistentialQuantification #-} +{-# LANGUAGE ViewPatterns #-} +module Crypto.Cipher.Types.Block + ( + -- * BlockCipher + BlockCipher(..) + -- * initialization vector (IV) + , IV + , makeIV + , nullIV + , ivAdd + -- * XTS + , XTS + -- * AEAD + , AEAD(..) + , AEADState(..) + , AEADModeImpl(..) + -- * CFB 8 bits + , cfb8Encrypt + , cfb8Decrypt + ) where + +import Data.ByteString (ByteString) +import qualified Data.ByteString as B +import qualified Data.ByteString.Internal as B (unsafeCreate) +import Data.Byteable +import Data.Word +import Data.Bits (shiftR) +import Crypto.Cipher.Types.Base +import Crypto.Cipher.Types.GF +import Crypto.Cipher.Types.Utils +import Foreign.Ptr +import Foreign.Storable + +type XTS cipher = (cipher, cipher) + -> IV cipher -- ^ Usually represent the Data Unit (e.g. disk sector) + -> DataUnitOffset -- ^ Offset in the data unit in number of blocks + -> ByteString -- ^ Data + -> ByteString -- ^ Processed Data + +-- | Symmetric block cipher class +class Cipher cipher => BlockCipher cipher where + -- | Return the size of block required for this block cipher + blockSize :: cipher -> Int + + -- | Encrypt blocks + -- + -- the input string need to be multiple of the block size + ecbEncrypt :: cipher -> ByteString -> ByteString + + -- | Decrypt blocks + -- + -- the input string need to be multiple of the block size + ecbDecrypt :: cipher -> ByteString -> ByteString + + -- | encrypt using the CBC mode. + -- + -- input need to be a multiple of the blocksize + cbcEncrypt :: cipher -> IV cipher -> ByteString -> ByteString + cbcEncrypt = cbcEncryptGeneric + -- | decrypt using the CBC mode. + -- + -- input need to be a multiple of the blocksize + cbcDecrypt :: cipher -> IV cipher -> ByteString -> ByteString + cbcDecrypt = cbcDecryptGeneric + + -- | encrypt using the CFB mode. + -- + -- input need to be a multiple of the blocksize + cfbEncrypt :: cipher -> IV cipher -> ByteString -> ByteString + cfbEncrypt = cfbEncryptGeneric + -- | decrypt using the CFB mode. + -- + -- input need to be a multiple of the blocksize + cfbDecrypt :: cipher -> IV cipher -> ByteString -> ByteString + cfbDecrypt = cfbDecryptGeneric + + -- | combine using the CTR mode. + -- + -- CTR mode produce a stream of randomized data that is combined + -- (by XOR operation) with the input stream. + -- + -- encryption and decryption are the same operation. + -- + -- input can be of any size + ctrCombine :: cipher -> IV cipher -> ByteString -> ByteString + ctrCombine = ctrCombineGeneric + + -- | encrypt using the XTS mode. + -- + -- input need to be a multiple of the blocksize, and the cipher + -- need to process 128 bits block only + xtsEncrypt :: (cipher, cipher) + -> IV cipher -- ^ Usually represent the Data Unit (e.g. disk sector) + -> DataUnitOffset -- ^ Offset in the data unit in number of blocks + -> ByteString -- ^ Plaintext + -> ByteString -- ^ Ciphertext + xtsEncrypt = xtsEncryptGeneric + + -- | decrypt using the XTS mode. + -- + -- input need to be a multiple of the blocksize, and the cipher + -- need to process 128 bits block only + xtsDecrypt :: (cipher, cipher) + -> IV cipher -- ^ Usually represent the Data Unit (e.g. disk sector) + -> DataUnitOffset -- ^ Offset in the data unit in number of blocks + -> ByteString -- ^ Ciphertext + -> ByteString -- ^ Plaintext + xtsDecrypt = xtsDecryptGeneric + + -- | Initialize a new AEAD State + -- + -- When Nothing is returns, it means the mode is not handled. + aeadInit :: Byteable iv => AEADMode -> cipher -> iv -> Maybe (AEAD cipher) + aeadInit _ _ _ = Nothing + +-- | Authenticated Encryption with Associated Data algorithms +data AEAD cipher = AEAD cipher (AEADState cipher) + +-- | Wrapper for any AEADState +data AEADState cipher = forall st . AEADModeImpl cipher st => AEADState st + +-- | Class of AEAD Mode implementation +class BlockCipher cipher => AEADModeImpl cipher state where + aeadStateAppendHeader :: cipher -> state -> ByteString -> state + aeadStateEncrypt :: cipher -> state -> ByteString -> (ByteString, state) + aeadStateDecrypt :: cipher -> state -> ByteString -> (ByteString, state) + aeadStateFinalize :: cipher -> state -> Int -> AuthTag + +-- | Create an IV for a specified block cipher +makeIV :: (Byteable b, BlockCipher c) => b -> Maybe (IV c) +makeIV b = toIV undefined + where toIV :: BlockCipher c => c -> Maybe (IV c) + toIV cipher + | byteableLength b == sz = Just (IV $ toBytes b) + | otherwise = Nothing + where sz = blockSize cipher + +-- | Create an IV that is effectively representing the number 0 +nullIV :: BlockCipher c => IV c +nullIV = toIV undefined + where toIV :: BlockCipher c => c -> IV c + toIV cipher = IV $ B.replicate (blockSize cipher) 0 + +-- | Increment an IV by a number. +-- +-- Assume the IV is in Big Endian format. +ivAdd :: BlockCipher c => IV c -> Int -> IV c +ivAdd (IV b) i = IV $ snd $ B.mapAccumR addCarry i b + where addCarry :: Int -> Word8 -> (Int, Word8) + addCarry acc w + | acc == 0 = (0, w) + | otherwise = let (hi,lo) = acc `divMod` 256 + nw = lo + (fromIntegral w) + in (hi + (nw `shiftR` 8), fromIntegral nw) + +cbcEncryptGeneric :: BlockCipher cipher => cipher -> IV cipher -> ByteString -> ByteString +cbcEncryptGeneric cipher (IV ivini) input = B.concat $ doEnc ivini $ chunk (blockSize cipher) input + where doEnc _ [] = [] + doEnc iv (i:is) = + let o = ecbEncrypt cipher $ bxor iv i + in o : doEnc o is + +cbcDecryptGeneric :: BlockCipher cipher => cipher -> IV cipher -> ByteString -> ByteString +cbcDecryptGeneric cipher (IV ivini) input = B.concat $ doDec ivini $ chunk (blockSize cipher) input + where doDec _ [] = [] + doDec iv (i:is) = + let o = bxor iv $ ecbDecrypt cipher i + in o : doDec i is + +cfbEncryptGeneric :: BlockCipher cipher => cipher -> IV cipher -> ByteString -> ByteString +cfbEncryptGeneric cipher (IV ivini) input = B.concat $ doEnc ivini $ chunk (blockSize cipher) input + where doEnc _ [] = [] + doEnc iv (i:is) = + let o = bxor i $ ecbEncrypt cipher iv + in o : doEnc o is + +cfbDecryptGeneric :: BlockCipher cipher => cipher -> IV cipher -> ByteString -> ByteString +cfbDecryptGeneric cipher (IV ivini) input = B.concat $ doDec ivini $ chunk (blockSize cipher) input + where doDec _ [] = [] + doDec iv (i:is) = + let o = bxor i $ ecbEncrypt cipher iv + in o : doDec i is + +ctrCombineGeneric :: BlockCipher cipher => cipher -> IV cipher -> ByteString -> ByteString +ctrCombineGeneric cipher ivini input = B.concat $ doCnt ivini $ chunk (blockSize cipher) input + where doCnt _ [] = [] + doCnt iv (i:is) = + let ivEnc = ecbEncrypt cipher (toBytes iv) + in bxor i ivEnc : doCnt (ivAdd iv 1) is + +xtsEncryptGeneric :: BlockCipher cipher => XTS cipher +xtsEncryptGeneric = xtsGeneric ecbEncrypt + +xtsDecryptGeneric :: BlockCipher cipher => XTS cipher +xtsDecryptGeneric = xtsGeneric ecbDecrypt + +xtsGeneric :: BlockCipher cipher + => (cipher -> B.ByteString -> B.ByteString) + -> (cipher, cipher) + -> IV cipher + -> DataUnitOffset + -> ByteString + -> ByteString +xtsGeneric f (cipher, tweakCipher) iv sPoint input + | blockSize cipher /= 16 = error "XTS mode is only available with cipher that have a block size of 128 bits" + | otherwise = B.concat $ doXts iniTweak $ chunk (blockSize cipher) input + where encTweak = ecbEncrypt tweakCipher (toBytes iv) + iniTweak = iterate xtsGFMul encTweak !! fromIntegral sPoint + doXts _ [] = [] + doXts tweak (i:is) = + let o = bxor (f cipher $ bxor i tweak) tweak + in o : doXts (xtsGFMul tweak) is + +-- | Encrypt using CFB mode in 8 bit output +-- +-- Effectively turn a Block cipher in CFB mode into a Stream cipher +cfb8Encrypt :: BlockCipher a => a -> IV a -> B.ByteString -> B.ByteString +cfb8Encrypt ctx origIv msg = B.unsafeCreate (B.length msg) $ \dst -> loop dst origIv msg + where loop d iv@(IV i) m + | B.null m = return () + | otherwise = poke d out >> loop (d `plusPtr` 1) ni (B.drop 1 m) + where m' = if B.length m < blockSize ctx + then m `B.append` B.replicate (blockSize ctx - B.length m) 0 + else B.take (blockSize ctx) m + r = cfbEncrypt ctx iv m' + out = B.head r + ni = IV (B.drop 1 i `B.snoc` out) + +-- | Decrypt using CFB mode in 8 bit output +-- +-- Effectively turn a Block cipher in CFB mode into a Stream cipher +cfb8Decrypt :: BlockCipher a => a -> IV a -> B.ByteString -> B.ByteString +cfb8Decrypt ctx origIv msg = B.unsafeCreate (B.length msg) $ \dst -> loop dst origIv msg + where loop d iv@(IV i) m + | B.null m = return () + | otherwise = poke d out >> loop (d `plusPtr` 1) ni (B.drop 1 m) + where m' = if B.length m < blockSize ctx + then m `B.append` B.replicate (blockSize ctx - B.length m) 0 + else B.take (blockSize ctx) m + r = cfbDecrypt ctx iv m' + out = B.head r + ni = IV (B.drop 1 i `B.snoc` B.head m') diff --git a/Crypto/Cipher/Types/GF.hs b/Crypto/Cipher/Types/GF.hs new file mode 100644 index 0000000..647a973 --- /dev/null +++ b/Crypto/Cipher/Types/GF.hs @@ -0,0 +1,49 @@ +-- | +-- Module : Crypto.Cipher.Types.GF +-- License : BSD-style +-- Maintainer : Vincent Hanquez +-- Stability : Stable +-- Portability : Excellent +-- +-- Slow Galois Field arithmetic for generic XTS and GCM implementation +-- +module Crypto.Cipher.Types.GF + ( + -- * XTS support + xtsGFMul + ) where + +import Control.Applicative +import Data.ByteString (ByteString) +import qualified Data.ByteString as B +import qualified Data.ByteString.Internal as B +import Data.Byteable +import Foreign.Storable +import Foreign.Ptr +import Data.Word +import Data.Bits + +-- block size need to be 128 bits. +-- +-- FIXME: add support for big endian. +xtsGFMul :: ByteString -> ByteString +xtsGFMul b + | B.length b == 16 = B.unsafeCreate (B.length b) $ \dst -> + withBytePtr b $ \src -> do + (hi,lo) <- gf <$> peek (castPtr src) <*> peek (castPtr src `plusPtr` 8) + poke (castPtr dst) lo + poke (castPtr dst `plusPtr` 8) hi + | otherwise = error "unsupported block size in GF" + where gf :: Word64 -> Word64 -> (Word64, Word64) + gf srcLo srcHi = + ((if carryLo then (.|. 1) else id) (srcHi `shiftL` 1) + ,(if carryHi then xor 0x87 else id) $ (srcLo `shiftL` 1) + ) + where carryHi = srcHi `testBit` 63 + carryLo = srcLo `testBit` 63 +{- + const uint64_t gf_mask = cpu_to_le64(0x8000000000000000ULL); + uint64_t r = ((a->q[1] & gf_mask) ? cpu_to_le64(0x87) : 0); + a->q[1] = cpu_to_le64((le64_to_cpu(a->q[1]) << 1) | (a->q[0] & gf_mask ? 1 : 0)); + a->q[0] = cpu_to_le64(le64_to_cpu(a->q[0]) << 1) ^ r; +-} diff --git a/Crypto/Cipher/Types/Stream.hs b/Crypto/Cipher/Types/Stream.hs new file mode 100644 index 0000000..177d582 --- /dev/null +++ b/Crypto/Cipher/Types/Stream.hs @@ -0,0 +1,20 @@ +-- | +-- Module : Crypto.Cipher.Types.Stream +-- License : BSD-style +-- Maintainer : Vincent Hanquez +-- Stability : Stable +-- Portability : Excellent +-- +-- stream cipher basic types +-- +module Crypto.Cipher.Types.Stream + ( StreamCipher(..) + ) where + +import Crypto.Cipher.Types.Base +import Data.ByteString (ByteString) + +-- | Symmetric stream cipher class +class Cipher cipher => StreamCipher cipher where + -- | Combine using the stream cipher + streamCombine :: cipher -> ByteString -> (ByteString, cipher) diff --git a/Crypto/Cipher/Types/Utils.hs b/Crypto/Cipher/Types/Utils.hs new file mode 100644 index 0000000..21ddf40 --- /dev/null +++ b/Crypto/Cipher/Types/Utils.hs @@ -0,0 +1,24 @@ +-- | +-- Module : Crypto.Cipher.Types.Utils +-- License : BSD-style +-- Maintainer : Vincent Hanquez +-- Stability : Stable +-- Portability : Excellent +-- +-- basic utility for cipher related stuff +-- +module Crypto.Cipher.Types.Utils where + +import Data.Bits (xor) +import Data.ByteString (ByteString) +import qualified Data.ByteString as B + +chunk :: Int -> ByteString -> [ByteString] +chunk sz bs = split bs + where split b | B.length b <= sz = [b] + | otherwise = + let (b1, b2) = B.splitAt sz b + in b1 : split b2 + +bxor :: ByteString -> ByteString -> ByteString +bxor src dst = B.pack $ B.zipWith xor src dst diff --git a/cryptonite.cabal b/cryptonite.cabal index 0fd8c40..3bdeca9 100644 --- a/cryptonite.cabal +++ b/cryptonite.cabal @@ -30,6 +30,7 @@ Library Exposed-modules: Crypto.Cipher.ChaCha Crypto.Cipher.Salsa Crypto.Cipher.RC4 + Crypto.Cipher.Types Crypto.Data.AFIS Crypto.MAC.Poly1305 Crypto.MAC.HMAC @@ -80,6 +81,12 @@ Library Crypto.Random.EntropyPool Crypto.Random.Entropy.Unsafe Other-modules: Crypto.Cipher.AES.Internal + Crypto.Cipher.Types.AEAD + Crypto.Cipher.Types.Base + Crypto.Cipher.Types.Block + Crypto.Cipher.Types.GF + Crypto.Cipher.Types.Stream + Crypto.Cipher.Types.Utils Crypto.Hash.Utils Crypto.Hash.Utils.Cpu Crypto.Hash.Types