diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2015, Jiri Marsicek
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+* Neither the name of hkdf nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,20 @@
+# haskell hkdf
+Implementation of HKDF (RFC 5869)
+
+## Description
+
+This is Haskell implementation of [RFC 5869](https://tools.ietf.org/html/rfc5869) (HMAC-based Extract-and-Expand Key Derivation Function (HKDF)).
+
+Implementation is based on [cryptohash](https://hackage.haskell.org/package/cryptohash).
+
+## Installation
+
+Run either `cabal install` or `stack install`. This is library, thus there is no executable available.
+
+## Running tests
+
+Tests can be run via `stack test`.
+
+## Discalmer
+
+Any feedback is very welcomed.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/hkdf.cabal b/hkdf.cabal
new file mode 100644
--- /dev/null
+++ b/hkdf.cabal
@@ -0,0 +1,47 @@
+name:                hkdf
+version:             0.0.1.1
+synopsis:            Implementation of HKDF (RFC 5869)
+description:         Please see README.md
+homepage:            http://github.com/j1r1k/hkdf
+license:             BSD3
+license-file:        LICENSE
+author:              Jiri Marsicek <jiri.marsicek@gmail.com>
+maintainer:          Jiri Marsicek <jiri.marsicek@gmail.com>
+copyright:           Jiri Marsicek <jiri.marsicek@gmail.com>
+category:            Cryptography,Web
+build-type:          Simple
+extra-source-files:  README.md
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Crypto.HKDF
+  build-depends:       base >= 4.7 && < 5
+                     , byteable >= 0.1
+                     , bytestring >= 0.9
+                     , cryptohash >= 0.10
+  ghc-options:         -Wall
+  default-language:    Haskell2010
+
+
+test-suite hkdf-test
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             Spec.hs
+  build-depends:       base >= 4.7 && < 5
+                     , byteable >= 0.1
+                     , bytestring >= 0.9
+                     , cryptohash >= 0.10
+                     , hkdf
+                     , hspec
+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N -Wall
+  default-language:    Haskell2010
+
+source-repository this
+  type:     git
+  location: https://github.com/j1r1k/hkdf
+  tag:      0.0.1.1
+
+source-repository head
+  type:     git
+  location: https://github.com/j1r1k/hkdf
diff --git a/src/Crypto/HKDF.hs b/src/Crypto/HKDF.hs
new file mode 100644
--- /dev/null
+++ b/src/Crypto/HKDF.hs
@@ -0,0 +1,62 @@
+-- |
+-- Module: Crypto.HKDF
+-- Maintainer: Jiri Marsicek <jiri.marsicek@gmail.com>
+--
+-- This module provides implementation of HKDF function defined in
+-- RFC-5869 (<http://www.ietf.org/rfc/rfc5869.txt>),
+-- It is using "HashAlgorithm" from "cryptohash" as underlying implementation
+--
+module Crypto.HKDF
+    ( hkdfExtract
+    , hkdfExpand
+    , hkdf
+    ) where
+
+import Crypto.Hash (HashAlgorithm)
+import Crypto.MAC (HMAC, hmacAlg)
+import Data.Byteable (toBytes)
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as BS (concat, empty, length, take)
+import qualified Data.ByteString.Char8 as C8 (singleton)
+import Data.Char (chr)
+
+-- | Extract function. 
+--
+-- Synonym to 'hmacAlg'
+hkdfExtract :: (HashAlgorithm a) => a -- ^ hash algorithm
+            -> ByteString             -- ^ optional salt value (a non-secret random value)
+            -> ByteString             -- ^ input keying material
+            -> HMAC a                 -- ^ a pseudorandom key
+hkdfExtract = hmacAlg
+
+-- | Expand function.
+--
+-- "Nothing" is returned in case (length of output > 255 * hash length)
+hkdfExpand :: (HashAlgorithm a) => a -- ^ hash algorithm
+           -> ByteString             -- ^ pseudorandom key
+           -> ByteString             -- ^ info
+           -> Int                    -- ^ length of output keying material in octets
+           -> Maybe ByteString       -- ^ output keying material
+hkdfExpand alg prk info l
+  | l <= 255 * chunkSize = Just $ BS.take l $ BS.concat $ take (l `div` chunkSize + 2) hkdfChunks
+  | otherwise            = Nothing
+  where hkdfChunks = map fst $ iterate (hkdfSingle alg prk info) (BS.empty, 1)
+        chunkSize  = BS.length $ hkdfChunks !! 1
+
+type HKDFIteration = (ByteString, Int)
+
+hkdfSingle :: (HashAlgorithm a) => a -- ^ hash algorithm
+           -> ByteString             -- ^ pseudorandom key
+           -> ByteString             -- ^ info
+           -> HKDFIteration          -- ^ output of previous iteration
+           -> HKDFIteration          -- ^ output of current iteration
+hkdfSingle alg prk info (prev, n) = (toBytes $ hmacAlg alg prk $ BS.concat [prev, info, C8.singleton $ chr n], n + 1)
+
+-- | Function combining extract and expand functions.
+hkdf :: (HashAlgorithm a) => a -- ^ hash algorithm
+     -> ByteString             -- ^ optional salt value (a non-secret random value)
+     -> ByteString             -- ^ input keying material
+     -> ByteString             -- ^ info
+     -> Int                    -- ^ length of output keying material in octets
+     -> Maybe ByteString       -- ^ output keying material
+hkdf alg salt ikm = hkdfExpand alg (toBytes $ hkdfExtract alg salt ikm)
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,94 @@
+import Data.Byteable (toBytes)
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Char8 as C8
+import Data.Char (chr)
+import Data.Maybe (fromMaybe)
+import Crypto.Hash
+import Crypto.HKDF
+import Test.Hspec
+import Text.Printf
+
+hex :: BS.ByteString -> String
+hex = concatMap (printf "%02x") . BS.unpack
+
+convertOctets :: [Int] -> BS.ByteString
+convertOctets = C8.pack . map chr
+
+testCase :: (HashAlgorithm a) => a
+         -> [Int] -- ^ ikm octets
+         -> [Int] -- ^ salt octets
+         -> [Int] -- ^ info octets
+         -> Int   -- ^ L
+         -> (BS.ByteString, BS.ByteString) -- ^ (PRK, OKM)
+testCase alg ikm salt info l = (prk, okm)
+  where prk  = toBytes $ hkdfExtract alg (convertOctets salt) (convertOctets ikm)
+        okm  = fromMaybe BS.empty $ hkdfExpand alg prk (convertOctets info) l
+
+testCase1 :: (BS.ByteString, BS.ByteString)
+testCase1 = testCase SHA256
+                     (replicate 22 0x0b) 
+                     [0x00 .. 0x0c] 
+                     [0xf0 .. 0xf9] 
+                     42
+
+testCase2 :: (BS.ByteString, BS.ByteString)
+testCase2 = testCase SHA256
+                     [0x00 .. 0x4f]
+                     [0x60 .. 0xaf]
+                     [0xb0 .. 0xff]
+                     82
+
+testCase3 :: (BS.ByteString, BS.ByteString)
+testCase3 = testCase SHA256
+                     (replicate 22 0x0b)
+                     []
+                     []
+                     42
+
+testCase4 :: (BS.ByteString, BS.ByteString)
+testCase4 = testCase SHA1
+                     (replicate 11 0x0b)
+                     [0x00 .. 0x0c]
+                     [0xf0 .. 0xf9]
+                     42
+
+testCase5 :: (BS.ByteString, BS.ByteString)
+testCase5 = testCase SHA1
+                     [0x00 .. 0x4f]
+                     [0x60 .. 0xaf]
+                     [0xb0 .. 0xff]
+                     82
+
+testCase6 :: (BS.ByteString, BS.ByteString)
+testCase6 = testCase SHA1
+                     (replicate 22 0x0b)
+                     []
+                     []
+                     42
+
+testCase7 :: (BS.ByteString, BS.ByteString)
+testCase7 = testCase SHA1
+                     (replicate 22 0x0c)
+                     []
+                     []
+                     42
+
+main :: IO ()
+main = hspec $ do
+  describe "hkdf-export" $ do
+    it "should work for test case 1" $ hex (fst testCase1) `shouldBe` "077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5"
+    it "should work for test case 2" $ hex (fst testCase2) `shouldBe` "06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244"
+    it "should work for test case 3" $ hex (fst testCase3) `shouldBe` "19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04"
+    it "should work for test case 4" $ hex (fst testCase4) `shouldBe` "9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243"
+    it "should work for test case 5" $ hex (fst testCase5) `shouldBe` "8adae09a2a307059478d309b26c4115a224cfaf6"
+    it "should work for test case 6" $ hex (fst testCase6) `shouldBe` "da8c8a73c7fa77288ec6f5e7c297786aa0d32d01"
+    it "should work for test case 7" $ hex (fst testCase7) `shouldBe` "2adccada18779e7c2077ad2eb19d3f3e731385dd"
+
+  describe "hkdf-expand" $ do
+    it "should work for test case 1" $ hex (snd testCase1) `shouldBe` "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865"
+    it "should work for test case 2" $ hex (snd testCase2) `shouldBe` "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87"
+    it "should work for test case 3" $ hex (snd testCase3) `shouldBe` "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8"
+    it "should work for test case 4" $ hex (snd testCase4) `shouldBe` "085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896"
+    it "should work for test case 5" $ hex (snd testCase5) `shouldBe` "0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4"
+    it "should work for test case 6" $ hex (snd testCase6) `shouldBe` "0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918"
+    it "should work for test case 7" $ hex (snd testCase7) `shouldBe` "2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48"
