packages feed

crypto-simple (empty) → 0.1.0.0

raw patch · 8 files changed

+223/−0 lines, 8 filesdep +QuickCheckdep +basedep +bytestringsetup-changed

Dependencies added: QuickCheck, base, bytestring, crypto-simple, cryptonite, hspec

Files

+ LICENSE view
@@ -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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ crypto-simple.cabal view
@@ -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
+ src/Crypto/Simple/CBC.hs view
@@ -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
+ src/Crypto/Simple/CTR.hs view
@@ -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
+ src/Crypto/Simple/Cipher.hs view
@@ -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'
+ test/Crypto/SimpleSpec.hs view
@@ -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
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}