-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCrypto.hs
More file actions
89 lines (69 loc) · 2.4 KB
/
Crypto.hs
File metadata and controls
89 lines (69 loc) · 2.4 KB
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
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}
module Crypto (
decryptAES256CFB,
encryptAES256CFB
) where
import Data.Conduit
import Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS
import Data.ByteString.Builder
import Data.Conduit.Binary as CB
import qualified Data.Sequence as S
import Data.Foldable
import Data.List as L
import OpenSSL
import OpenSSL.EVP.Cipher
import OpenSSL.EVP.Internal
import qualified Crypto.Hash.MD5 as MD5
import System.Random
import Control.Monad
import Control.Monad.Trans
import Control.Exception
import Common
type SeqBS = S.Seq BS.ByteString
bytesToKey :: BS.ByteString -> Int -> Int -> (BS.ByteString, BS.ByteString)
bytesToKey password keyLen ivLen = (key, iv) where
loopRst = fst $ until (not . pred) loop (S.empty, 0)
ms = BS.concat $ toList loopRst
(key, rest) = BS.splitAt keyLen ms
iv = BS.take ivLen rest
pred :: (SeqBS, Int) -> Bool
pred (m, i) = (sum $ fmap BS.length m) < keyLen + ivLen
loop :: (SeqBS, Int) -> (SeqBS, Int)
loop (m, i) = (newm, newi) where
dat = if i > 0
then BS.concat [m `S.index` (i - 1), password]
else password
newm = m S.|> (MD5.hash dat)
newi = i + 1
prepareCipher :: MonadIO m
=> String
-> Password
-> ByteString
-> CryptoMode
-> m (Cipher, CipherCtx)
prepareCipher cipher key iv mode = liftIO $ withOpenSSL $ do
cipher <- getCipherByName cipher >>= \case
Just c -> return c
Nothing -> error ("No cipher for " ++ cipher)
ctx <- cipherInitBS cipher key iv mode
return (cipher, ctx)
decryptAES256CFB :: Password -> Conduit ByteString IO ByteString
decryptAES256CFB rawKey = do
iv <- fmap LBS.toStrict $ CB.take 16
let (key, _) = bytesToKey rawKey 32 16
(aesCipher, cipherContext) <- prepareCipher "AES-256-CFB" key iv Decrypt
awaitForever $ \d ->
if BS.null d
then yield ""
else (liftIO $ withOpenSSL $ cipherUpdateBS cipherContext d) >>= yield
encryptAES256CFB :: Password -> Conduit ByteString IO ByteString
encryptAES256CFB rawKey = do
rndGen <- liftIO newStdGen
let iv = pack $ L.take 16 $ randoms rndGen
(key, _) = bytesToKey rawKey 32 16
yield iv
(aesCipher, cipherContext) <- prepareCipher "AES-256-CFB" key iv Encrypt
awaitForever $ \d ->
(liftIO $ withOpenSSL $ cipherUpdateBS cipherContext d) >>= yield