diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Risto Stevcev
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
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/crypto-simple.cabal b/crypto-simple.cabal
new file mode 100644
--- /dev/null
+++ b/crypto-simple.cabal
@@ -0,0 +1,42 @@
+name:                crypto-simple
+version:             0.1.0.0
+synopsis:            A simple high level encryption interface based on cryptonite
+description:         Please see README.md
+homepage:            https://github.com/Risto-Stevcev/haskell-crypto-simple#readme
+license:             MIT
+license-file:        LICENSE
+author:              Risto Stevcev
+maintainer:          example@example.com
+copyright:           2016 Risto Stevcev
+Stability:           experimental
+category:            Cryptography
+build-type:          Simple
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Crypto.Simple.Cipher
+                     , Crypto.Simple.CBC
+                     , Crypto.Simple.CTR
+  build-depends:       base >= 4.7 && < 5
+                     , bytestring >= 0.10 && < 1
+                     , cryptonite >= 0.19 && < 1
+  default-language:    Haskell2010
+
+test-suite crypto-simple-test
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             Spec.hs
+  build-depends:       base
+                     , crypto-simple
+                     , bytestring >= 0.10 && < 1
+                     , cryptonite >= 0.19 && < 1
+                     , hspec
+                     , QuickCheck
+  other-modules:       Crypto.SimpleSpec
+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/Risto-Stevcev/haskell-crypto-simple
diff --git a/src/Crypto/Simple/CBC.hs b/src/Crypto/Simple/CBC.hs
new file mode 100644
--- /dev/null
+++ b/src/Crypto/Simple/CBC.hs
@@ -0,0 +1,31 @@
+module Crypto.Simple.CBC where
+
+import Data.Monoid ((<>))
+import Data.ByteString (ByteString)
+import Crypto.Cipher.AES (AES256)
+import Crypto.Cipher.Types (makeIV)
+import Crypto.Random.Entropy (getEntropy)
+import Crypto.Data.Padding (pad, unpad, Format(PKCS7))
+import Crypto.Simple.Cipher (encrypt', decrypt', blockLength, CipherMode(..))
+import qualified Data.ByteString as B
+
+
+-- | The key must be less than 32 bytes in length
+encrypt :: ByteString -> ByteString -> IO ByteString
+encrypt key msg = do
+    entropy <- getEntropy blockLength :: IO ByteString
+    pure $ entropy <> (encrypt' CBCencrypt key' (makeIV entropy) msg')
+  where
+    msg' = pad (PKCS7 blockLength) msg 
+    key' = if B.length key == 16 || B.length key == 32 then key else pad (PKCS7 blockLength) key
+
+
+-- | The key must be less than 32 bytes in length
+decrypt :: ByteString -> ByteString -> IO ByteString
+decrypt key msg = do
+    entropy <- getEntropy blockLength :: IO ByteString
+    let msg'' = decrypt' CBCdecrypt key' (makeIV iv) msg'
+    pure $ maybe msg'' id (unpad (PKCS7 blockLength) msg'')
+  where
+    (iv, msg') = B.splitAt blockLength msg
+    key' = if B.length key == 16 || B.length key == 32 then key else pad (PKCS7 blockLength) key
diff --git a/src/Crypto/Simple/CTR.hs b/src/Crypto/Simple/CTR.hs
new file mode 100644
--- /dev/null
+++ b/src/Crypto/Simple/CTR.hs
@@ -0,0 +1,27 @@
+module Crypto.Simple.CTR where
+
+import Data.Monoid ((<>))
+import Data.ByteString (ByteString)
+import Crypto.Cipher.AES (AES256)
+import Crypto.Cipher.Types (makeIV)
+import Crypto.Random.Entropy (getEntropy)
+import Crypto.Data.Padding (pad, Format(PKCS7))
+import Crypto.Simple.Cipher (encrypt', decrypt', blockLength, CipherMode(..))
+import qualified Data.ByteString as B
+
+
+-- | The key must be less than 32 bytes in length
+encrypt :: ByteString -> ByteString -> IO ByteString
+encrypt key msg = do
+    entropy <- getEntropy blockLength :: IO ByteString
+    pure $ entropy <> (encrypt' CTR key' (makeIV entropy) msg)
+  where
+    key' = if B.length key == 16 || B.length key == 32 then key else pad (PKCS7 blockLength) key
+
+
+-- | The key must be less than 32 bytes in length
+decrypt :: ByteString -> ByteString -> IO ByteString
+decrypt key msg = pure $ decrypt' CTR key' (makeIV iv) msg'
+  where
+    (iv, msg') = B.splitAt blockLength msg
+    key' = if B.length key == 16 || B.length key == 32 then key else pad (PKCS7 blockLength) key
diff --git a/src/Crypto/Simple/Cipher.hs b/src/Crypto/Simple/Cipher.hs
new file mode 100644
--- /dev/null
+++ b/src/Crypto/Simple/Cipher.hs
@@ -0,0 +1,44 @@
+module Crypto.Simple.Cipher where
+
+import Data.Monoid ((<>))
+import Data.ByteString (ByteString)
+import Crypto.Cipher.AES (AES256)
+import Crypto.Random.Entropy (getEntropy)
+import Crypto.Cipher.Types (BlockCipher(..), Cipher(..), IV)
+import Crypto.Error (CryptoFailable(..))
+import qualified Data.ByteString as B
+
+
+newtype Key a = Key ByteString
+    deriving (Show,Eq)
+
+blockLength :: Int
+blockLength = 16
+
+maxKeyLength :: Int
+maxKeyLength = 32
+
+data CipherMode = CBCencrypt | CBCdecrypt | CTR
+
+
+-- | key must be 32 bytes in length
+encrypt' :: CipherMode -> ByteString -> Maybe (IV AES256) -> ByteString -> ByteString
+encrypt' mode key iv = cipherEncrypt ctx iv'
+  where
+    cipherEncrypt = case mode of
+      CBCencrypt -> cbcEncrypt
+      CBCdecrypt -> cbcDecrypt
+      CTR -> ctrCombine
+    ctx = cipherInitNoErr blockCipher
+    iv' = maybe (error $ "IV length must be " <> show blockLength <> " bytes") id iv
+    blockCipher = cipherMakeKey (undefined :: AES256) key
+    cipherInitNoErr :: BlockCipher c => Key c -> c
+    cipherInitNoErr (Key k) = case cipherInit k of
+      CryptoPassed a -> a
+      CryptoFailed e -> error (show e)
+    cipherMakeKey :: Cipher cipher => cipher -> ByteString -> Key cipher
+    cipherMakeKey _ = Key
+
+
+decrypt' :: CipherMode -> ByteString -> Maybe (IV AES256) -> ByteString -> ByteString
+decrypt' = encrypt'
diff --git a/test/Crypto/SimpleSpec.hs b/test/Crypto/SimpleSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Crypto/SimpleSpec.hs
@@ -0,0 +1,55 @@
+module Crypto.SimpleSpec (main, spec) where
+
+import Test.Hspec
+import Test.QuickCheck
+import Test.QuickCheck.Monadic
+import Data.ByteString (ByteString)
+import Data.ByteString.Char8 (pack)
+import Crypto.Simple.Cipher (blockLength, maxKeyLength)
+import Crypto.Random.Entropy (getEntropy)
+import qualified Data.ByteString as B
+import qualified Crypto.Simple.CTR as CTR
+import qualified Crypto.Simple.CBC as CBC
+
+
+propNotSameMsg :: (ByteString -> ByteString -> IO ByteString) -> Property
+propNotSameMsg encrypt =
+    forAll (arbitrary :: Gen String) $ \strMsg ->
+    forAll (suchThat (arbitrary :: Gen String) (\s -> length s <= maxKeyLength)) $ \strKey -> ioProperty $ do
+
+    let msg = pack strMsg
+        key = pack strKey
+    secretMsg <- encrypt key msg
+    pure $ secretMsg /= msg
+
+
+propIsomorphic :: (ByteString -> ByteString -> IO ByteString)
+               -> (ByteString -> ByteString -> IO ByteString) -> Property
+propIsomorphic encrypt decrypt = 
+    forAll (arbitrary :: Gen String) $ \strMsg ->
+    forAll (suchThat (arbitrary :: Gen String) (\s -> length s <= maxKeyLength)) $ \strKey -> ioProperty $ do
+
+    let msg = pack strMsg
+        key = pack strKey
+    secretMsg <- encrypt key msg
+    msg' <- decrypt key secretMsg
+    pure $ msg' == msg
+
+
+main :: IO ()
+main = hspec spec
+
+
+spec :: Spec
+spec = do
+    describe "encrypt" $ do
+        it "should not be the same as the original message (CBC)" $
+            propNotSameMsg CBC.encrypt
+        it "should not be the same as the original message (CTR)" $
+            propNotSameMsg CTR.encrypt
+
+    describe "encrypt/decrypt" $ do 
+        it "should have an isomorphic relationship (CBC)" $
+            propIsomorphic CBC.encrypt CBC.decrypt
+        it "should have an isomorphic relationship (CTR)" $
+            propIsomorphic CTR.encrypt CTR.decrypt
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
