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 +21/−0
- Setup.hs +2/−0
- crypto-simple.cabal +42/−0
- src/Crypto/Simple/CBC.hs +31/−0
- src/Crypto/Simple/CTR.hs +27/−0
- src/Crypto/Simple/Cipher.hs +44/−0
- test/Crypto/SimpleSpec.hs +55/−0
- test/Spec.hs +1/−0
+ 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 #-}