aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/BTLS/Result.hs1
-rw-r--r--src/BTLS/Types.hs6
-rw-r--r--src/Codec/Crypto/HKDF.hs65
-rw-r--r--src/Data/Digest.hs60
-rw-r--r--src/Data/HMAC.hs39
-rw-r--r--src/System/Random/Crypto.hs9
-rw-r--r--tests/Data/HMACTests.hs6
7 files changed, 160 insertions, 26 deletions
diff --git a/src/BTLS/Result.hs b/src/BTLS/Result.hs
index 63626bd..4f0238a 100644
--- a/src/BTLS/Result.hs
+++ b/src/BTLS/Result.hs
@@ -40,6 +40,7 @@ requireSuccess r = when (r /= 1) $ ioError (userError "BoringSSL failure")
type Result = Either [Error]
+-- | An error which occurred during processing.
data Error = Error
{ err :: Err
, file :: FilePath
diff --git a/src/BTLS/Types.hs b/src/BTLS/Types.hs
index 06b5173..44b29bc 100644
--- a/src/BTLS/Types.hs
+++ b/src/BTLS/Types.hs
@@ -31,7 +31,10 @@ newtype Algorithm = Algorithm (Ptr EVPMD)
newtype AssociatedData = AssociatedData ByteString
deriving (Eq, Ord, Show)
--- | The result of a hash operation.
+-- | The result of a hash operation. Equality comparisons on this type are
+-- variable-time.
+--
+-- The 'Show' instance for this type displays the digest as a hexadecimal string.
newtype Digest = Digest ByteString
deriving (Eq, Ord)
@@ -46,6 +49,7 @@ instance Show Digest where
newtype Salt = Salt ByteString
deriving (Eq, Ord, Show)
+-- | A special value used to request that no salt be used.
noSalt :: Salt
noSalt = Salt ByteString.empty
diff --git a/src/Codec/Crypto/HKDF.hs b/src/Codec/Crypto/HKDF.hs
index f40f707..bc1ea61 100644
--- a/src/Codec/Crypto/HKDF.hs
+++ b/src/Codec/Crypto/HKDF.hs
@@ -12,9 +12,44 @@
-- License for the specific language governing permissions and limitations under
-- the License.
+{-|
+ Module: Codec.Crypto.HKDF
+ Description: Hash-based key derivation
+ Copyright: 2018 Google LLC
+ License: Apache License, version 2.0
+
+ The hash-based key derivation function (HKDF), as specified in
+ [RFC 5869](https://tools.ietf.org/html/rfc5869).
+-}
module Codec.Crypto.HKDF
- ( AssociatedData(AssociatedData), Salt(Salt), SecretKey(SecretKey), noSalt
- , hkdf, extract, expand
+ ( -- * Computing keys
+ SecretKey(SecretKey)
+ , hkdf
+ , extract
+ , expand
+
+ -- * Cryptographic hash algorithms
+ , Algorithm
+ , sha1
+
+ -- ** SHA-2 family
+ -- | The SHA-2 family of hash functions is defined in
+ -- [FIPS 180-4](https://csrc.nist.gov/publications/detail/fips/180/4/final).
+ , sha224, sha256, sha384, sha512
+
+ -- * Salt
+
+ -- | You may salt the hash used to generate the key. If you do not wish to
+ -- do so, specify 'noSalt' as the salt.
+ , Salt(Salt), noSalt
+
+ -- * Associated data
+ -- | You may mix in arbitrary data when generating a key. If you do not wish
+ -- to do so, specify the empty string as the associated data.
+ , AssociatedData(AssociatedData)
+
+ -- * Legacy functions
+ , md5
) where
import Foreign (allocaArray)
@@ -27,12 +62,23 @@ import BTLS.Types
( Algorithm(Algorithm), AssociatedData(AssociatedData), Salt(Salt)
, SecretKey(SecretKey), noSalt
)
+import Data.Digest (md5, sha1, sha224, sha256, sha384, sha512)
--- | Computes an HKDF as specified by RFC 5869.
-hkdf :: Algorithm -> Salt -> AssociatedData -> Int -> SecretKey -> SecretKey
+-- | Computes an HKDF. It is defined by
+--
+-- prop> hkdf md salt info len = expand md info len . extract md salt
+--
+-- but may be faster than calling the two functions individually.
+hkdf ::
+ Algorithm
+ -> Salt
+ -> AssociatedData
+ -> Int -- ^ The length of the derived key, in bytes.
+ -> SecretKey
+ -> SecretKey
hkdf md salt info outLen = expand md info outLen . extract md salt
--- | Computes an HKDF pseudorandom key (PRK) as specified by RFC 5869.
+-- | Computes an HKDF pseudorandom key (PRK).
extract :: Algorithm -> Salt -> SecretKey -> SecretKey
extract (Algorithm md) (Salt salt) (SecretKey secret) =
SecretKey $
@@ -40,8 +86,13 @@ extract (Algorithm md) (Salt salt) (SecretKey secret) =
onBufferOfMaxSize evpMaxMDSize $ \pOutKey pOutLen -> do
hkdfExtract pOutKey pOutLen md secret salt
--- | Computes HKDF output key material (OKM) as specified by RFC 5869.
-expand :: Algorithm -> AssociatedData -> Int -> SecretKey -> SecretKey
+-- | Computes HKDF output key material (OKM).
+expand ::
+ Algorithm
+ -> AssociatedData
+ -> Int -- ^ The length of the OKM, in bytes.
+ -> SecretKey
+ -> SecretKey
expand (Algorithm md) (AssociatedData info) outLen (SecretKey secret) =
SecretKey $
unsafeLocalState $
diff --git a/src/Data/Digest.hs b/src/Data/Digest.hs
index 336b38d..a17c438 100644
--- a/src/Data/Digest.hs
+++ b/src/Data/Digest.hs
@@ -12,15 +12,33 @@
-- License for the specific language governing permissions and limitations under
-- the License.
+{-|
+ Module: Data.Digest
+ Description: Cryptographic hash functions
+ Copyright: 2017 Google LLC
+ License: Apache License, version 2.0
+
+ Cryptographic hash functions.
+-}
module Data.Digest
- ( Algorithm
- , Digest
+ ( -- * Computing digests
+ Digest
, hash
+
+ -- * Digest algorithms
+ , Algorithm
+
+ -- ** SHA-2 family
+ -- | The SHA-2 family of hash functions is defined in
+ -- [FIPS 180-4](https://csrc.nist.gov/publications/detail/fips/180/4/final).
+ , sha224, sha256, sha384, sha512
+
+ -- * Legacy functions
, md5
, sha1
- , sha224, sha256, sha384, sha512
) where
+import qualified Data.ByteString.Lazy as Lazy (ByteString)
import qualified Data.ByteString.Lazy as ByteString.Lazy
import Foreign (withForeignPtr)
import Foreign.Marshal.Unsafe (unsafeLocalState)
@@ -30,18 +48,44 @@ import BTLS.BoringSSL.Digest
import BTLS.Buffer (onBufferOfMaxSize)
import BTLS.Types (Algorithm(Algorithm), Digest(Digest))
-type LazyByteString = ByteString.Lazy.ByteString
+-- | Message Digest 5, a 128-bit digest defined in
+-- [RFC 1321](https://tools.ietf.org/html/rfc1321). This algorithm is
+-- cryptographically broken; do not use it except to interface with legacy
+-- applications.
+md5 :: Algorithm
+md5 = Algorithm evpMD5
+
+-- | Secure Hash Algorithm 1, a 160-bit digest defined in
+-- [FIPS 180-4](https://csrc.nist.gov/publications/detail/fips/180/4/final).
+-- Hashing with this algorithm is cryptographically broken, although
+-- constructing HMACs with it is safe.
+sha1 :: Algorithm
+sha1 = Algorithm evpSHA1
-md5, sha1, sha224, sha256, sha384, sha512 :: Algorithm
-md5 = Algorithm evpMD5
-sha1 = Algorithm evpSHA1
+-- | The SHA224 digest, a 224-bit digest and Secure Hash Algorithm 2 family
+-- member.
+sha224 :: Algorithm
sha224 = Algorithm evpSHA224
+
+-- | The SHA256 digest, a 256-bit digest and Secure Hash Algorithm 2 family
+-- member. Prefer this algorithm on 32-bit CPUs; it will run faster than
+-- 'sha384' or 'sha512'.
+sha256 :: Algorithm
sha256 = Algorithm evpSHA256
+
+-- | The SHA384 digest, a 384-bit digest and Secure Hash Algorithm 2 family
+-- member.
+sha384 :: Algorithm
sha384 = Algorithm evpSHA384
+
+-- | The SHA512 digest, a 512-bit digest and Secure Hash Algorithm 2 family
+-- member. Prefer this algorithm on 64-bit CPUs; it will run faster than
+-- 'sha224' or 'sha256'.
+sha512 :: Algorithm
sha512 = Algorithm evpSHA512
-- | Hashes according to the given 'Algorithm'.
-hash :: Algorithm -> LazyByteString -> Digest
+hash :: Algorithm -> Lazy.ByteString -> Digest
hash (Algorithm md) bytes =
unsafeLocalState $ do
ctxFP <- mallocEVPMDCtx
diff --git a/src/Data/HMAC.hs b/src/Data/HMAC.hs
index bf1bef8..fb67817 100644
--- a/src/Data/HMAC.hs
+++ b/src/Data/HMAC.hs
@@ -12,15 +12,43 @@
-- License for the specific language governing permissions and limitations under
-- the License.
+{-|
+ Module: Data.HMAC
+ Description: Hash-based message authentication codes
+ Copyright: 2018 Google LLC
+ License: Apache License, version 2.0
+
+ Hash-based message authentication codes (HMACs). An HMAC guarantees
+ authenticity but not confidentiality.
+-}
module Data.HMAC
- ( SecretKey(SecretKey)
- , HMAC, Result
+ ( -- * Computing HMACs
+ HMAC
, hmac
+
+ -- * Cryptographic hash algorithms
+ , Algorithm
+ , sha1
+
+ -- ** SHA-2 family
+ -- | The SHA-2 family of hash functions is defined in
+ -- [FIPS 180-4](https://csrc.nist.gov/publications/detail/fips/180/4/final).
+ , sha224, sha256, sha384, sha512
+
+ -- * Keys
+ , SecretKey(SecretKey)
+
+ -- * Error handling
+ , Error
+
+ -- * Legacy functions
+ , md5
) where
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.Except (runExceptT)
import Data.ByteString (ByteString)
+import qualified Data.ByteString.Lazy as Lazy (ByteString)
import qualified Data.ByteString.Lazy as ByteString.Lazy
import qualified Data.ByteString.Unsafe as ByteString
import Foreign (withForeignPtr)
@@ -31,10 +59,9 @@ import BTLS.BoringSSL.Digest (evpMaxMDSize)
import BTLS.BoringSSL.HMAC
import BTLS.BoringSSL.Mem (cryptoMemcmp)
import BTLS.Buffer (onBufferOfMaxSize)
-import BTLS.Result (Result, check)
+import BTLS.Result (Error, check)
import BTLS.Types (Algorithm(Algorithm), Digest(Digest), SecretKey(SecretKey))
-
-type LazyByteString = ByteString.Lazy.ByteString
+import Data.Digest (md5, sha1, sha224, sha256, sha384, sha512)
-- | A hash-based message authentication code. Equality comparisons on this type
-- are constant-time.
@@ -51,7 +78,7 @@ instance Show HMAC where
show (HMAC m) = show (Digest m)
-- | Creates an HMAC according to the given 'Algorithm'.
-hmac :: Algorithm -> SecretKey -> LazyByteString -> Result HMAC
+hmac :: Algorithm -> SecretKey -> Lazy.ByteString -> Either [Error] HMAC
hmac (Algorithm md) (SecretKey key) bytes =
unsafeLocalState $ do
ctxFP <- mallocHMACCtx
diff --git a/src/System/Random/Crypto.hs b/src/System/Random/Crypto.hs
index ed5706d..464555e 100644
--- a/src/System/Random/Crypto.hs
+++ b/src/System/Random/Crypto.hs
@@ -12,6 +12,12 @@
-- License for the specific language governing permissions and limitations under
-- the License.
+{-|
+ Module: System.Random.Crypto
+ Description: Cryptographically secure pseudorandom number generator
+ Copyright: 2018 Google LLC
+ License: Apache License, version 2.0
+-}
module System.Random.Crypto
( randomBytes
) where
@@ -22,7 +28,8 @@ import Foreign (allocaArray)
import BTLS.BoringSSL.Rand (randBytes)
import BTLS.Buffer (packCUStringLen)
--- | Generates a cryptographically random buffer of the specified size.
+-- | Generates a cryptographically random buffer of the specified size (in
+-- bytes).
randomBytes :: Int -> IO ByteString
randomBytes len =
allocaArray len $ \pBuf -> do
diff --git a/tests/Data/HMACTests.hs b/tests/Data/HMACTests.hs
index ea786c0..bcdd7a6 100644
--- a/tests/Data/HMACTests.hs
+++ b/tests/Data/HMACTests.hs
@@ -23,7 +23,7 @@ import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit ((@?=), testCase)
import Data.Digest (md5, sha1, sha224, sha256, sha384, sha512)
-import Data.HMAC (Result, SecretKey(SecretKey), hmac)
+import Data.HMAC (Error, SecretKey(SecretKey), hmac)
type LazyByteString = ByteString.Lazy.ByteString
@@ -35,7 +35,7 @@ tests = testGroup "Data.HMAC"
]
tableTestCase ::
- (SecretKey -> LazyByteString -> Result String)
+ (SecretKey -> LazyByteString -> Either [Error] String)
-> (SecretKey, LazyByteString, String)
-> TestTree
tableTestCase f (key, input, output) =
@@ -176,7 +176,7 @@ testRFC4231 = testGroup "RFC 4231" $
truncatedRFC4231Test =
let key = SecretKey (ByteString.replicate 20 0x0c)
input = "Test With Truncation" :: LazyByteString
- t f = take 32 <$> f key input :: Result String
+ t f = take 32 <$> f key input :: Either [Error] String
in testGroup (abbreviate input)
[ testCase "SHA-224" (t hmacSha224 @?= Right "0e2aea68a90c8d37c988bcdb9fca6fa8")
, testCase "SHA-256" (t hmacSha256 @?= Right "a3b6167473100ee06e0c796c2955552b")