aboutsummaryrefslogtreecommitdiff
path: root/src/Codec/Crypto/HKDF.hs
blob: 772fcf5bc5fd5b47f859e136fdf673ac67baf350 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
-- Copyright 2018 Google LLC
--
-- Licensed under the Apache License, Version 2.0 (the "License"); you may not
-- use this file except in compliance with the License. You may obtain a copy of
-- the License at
--
--     https://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- 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
  ( -- * Computing keys
    hkdf, HKDFParams(..)
  , extract, ExtractParams(..)
  , expand, ExpandParams(..)

    -- * 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

    -- * Error handling
  , Error

    -- * Legacy functions
  , md5
  ) where

import Control.Monad ((>=>))
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.Except (runExceptT)
import Data.ByteString (ByteString)
import Foreign (allocaArray)
import Foreign.Marshal.Unsafe (unsafeLocalState)

import BTLS.BoringSSL.Digest (evpMaxMDSize)
import BTLS.BoringSSL.HKDF
import BTLS.Buffer (onBufferOfMaxSize', packCUStringLen)
import BTLS.Result (Error, check)
import BTLS.Types (Algorithm(Algorithm))
import Data.Digest (md5, sha1, sha224, sha256, sha384, sha512)

-- | Computes an HKDF. It is defined as the composition of 'extract' and
-- 'expand' but may be faster than calling the two functions individually.
hkdf :: HKDFParams -> ByteString -> Either [Error] ByteString
hkdf (HKDFParams md salt info outLen) =
  extract (ExtractParams md salt) >=> expand (ExpandParams md info outLen)

data HKDFParams = HKDFParams
  { algorithm :: Algorithm
  , salt :: ByteString
  , associatedData :: ByteString
  , secretLen :: Int
  } deriving (Eq, Show)

-- | Computes an HKDF pseudorandom key (PRK).
extract :: ExtractParams -> ByteString -> Either [Error] ByteString
extract (ExtractParams (Algorithm md) salt) secret =
  unsafeLocalState $
    onBufferOfMaxSize' evpMaxMDSize $ \pOutKey pOutLen ->
      check $ hkdfExtract pOutKey pOutLen md secret salt

data ExtractParams = ExtractParams
  { extractAlgorithm :: Algorithm
  , extractSalt :: ByteString
  } deriving (Eq, Show)

-- | Computes HKDF output key material (OKM).
expand :: ExpandParams -> ByteString -> Either [Error] ByteString
expand (ExpandParams (Algorithm md) info outLen) secret =
  unsafeLocalState $
    allocaArray outLen $ \pOutKey -> runExceptT $ do
      check $ hkdfExpand pOutKey outLen md secret info
      lift $ packCUStringLen (pOutKey, outLen)

data ExpandParams = ExpandParams
  { expandAlgorithm :: Algorithm
  , expandAssociatedData :: ByteString
  , expandSecretLen :: Int
  } deriving (Eq, Show)