File: CFB.hs

package info (click to toggle)
haskell-hopenpgp 2.10.1-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,024 kB
  • sloc: haskell: 6,478; sh: 21; makefile: 6
file content (119 lines) | stat: -rw-r--r-- 3,553 bytes parent folder | download | duplicates (3)
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
-- CFB.hs: OpenPGP (RFC4880) CFB mode
-- Copyright © 2013-2019  Clint Adams
-- Copyright © 2013  Daniel Kahn Gillmor
-- This software is released under the terms of the Expat license.
-- (See the LICENSE file).
module Codec.Encryption.OpenPGP.CFB
  ( decrypt
  , decryptPreservingNonce
  , decryptNoNonce
  , decryptOpenPGPCfb
  , encryptNoNonce
  ) where

import Codec.Encryption.OpenPGP.BlockCipher (withSymmetricCipher)
import Codec.Encryption.OpenPGP.Internal.HOBlockCipher
import Codec.Encryption.OpenPGP.Types
import qualified Data.ByteString as B

decryptOpenPGPCfb ::
     SymmetricAlgorithm
  -> B.ByteString
  -> B.ByteString
  -> Either String B.ByteString
decryptOpenPGPCfb Plaintext ciphertext _ = return ciphertext
decryptOpenPGPCfb sa ciphertext keydata =
  withSymmetricCipher sa keydata $ \bc -> do
    nonce <- decrypt1 ciphertext bc
    cleartext <- decrypt2 ciphertext bc
    if nonceCheck bc nonce
      then return cleartext
      else Left "Session key quickcheck failed"
  where
    decrypt1 ::
         HOBlockCipher cipher
      => B.ByteString
      -> cipher
      -> Either String B.ByteString
    decrypt1 ct cipher =
      paddedCfbDecrypt
        cipher
        (B.replicate (blockSize cipher) 0)
        (B.take (blockSize cipher + 2) ct)
    decrypt2 ::
         HOBlockCipher cipher
      => B.ByteString
      -> cipher
      -> Either String B.ByteString
    decrypt2 ct cipher =
      let i = B.take (blockSize cipher) (B.drop 2 ct)
       in paddedCfbDecrypt cipher i (B.drop (blockSize cipher + 2) ct)

-- should deprecate this?
decrypt ::
     SymmetricAlgorithm
  -> B.ByteString
  -> B.ByteString
  -> Either String B.ByteString
decrypt x y z = snd <$> (decryptPreservingNonce x y z)

decryptPreservingNonce ::
     SymmetricAlgorithm
  -> B.ByteString
  -> B.ByteString
  -> Either String (B.ByteString, B.ByteString)
decryptPreservingNonce Plaintext ciphertext _ = return (mempty, ciphertext)
decryptPreservingNonce sa ciphertext keydata =
  withSymmetricCipher sa keydata $ \bc -> do
    (nonce, cleartext) <-
      fmap (B.splitAt (blockSize bc + 2)) (decrypt' ciphertext bc)
    if nonceCheck bc nonce
      then return (nonce, cleartext)
      else Left "Session key quickcheck failed"
  where
    decrypt' ::
         HOBlockCipher cipher
      => B.ByteString
      -> cipher
      -> Either String B.ByteString
    decrypt' ct cipher =
      paddedCfbDecrypt cipher (B.replicate (blockSize cipher) 0) ct

decryptNoNonce ::
     SymmetricAlgorithm
  -> IV
  -> B.ByteString
  -> B.ByteString
  -> Either String B.ByteString
decryptNoNonce Plaintext _ ciphertext _ = return ciphertext
decryptNoNonce sa iv ciphertext keydata =
  withSymmetricCipher sa keydata (decrypt' ciphertext)
  where
    decrypt' ::
         HOBlockCipher cipher
      => B.ByteString
      -> cipher
      -> Either String B.ByteString
    decrypt' ct cipher = paddedCfbDecrypt cipher (unIV iv) ct

nonceCheck :: HOBlockCipher cipher => cipher -> B.ByteString -> Bool
nonceCheck bc =
  (==) <$> B.take 2 . B.drop (blockSize bc - 2) <*> B.drop (blockSize bc)

encryptNoNonce ::
     SymmetricAlgorithm
  -> S2K
  -> IV
  -> B.ByteString
  -> B.ByteString
  -> Either String B.ByteString
encryptNoNonce Plaintext _ _ payload _ = return payload
encryptNoNonce sa s2k iv payload keydata =
  withSymmetricCipher sa keydata (encrypt' payload)
  where
    encrypt' ::
         HOBlockCipher cipher
      => B.ByteString
      -> cipher
      -> Either String B.ByteString
    encrypt' ct cipher = paddedCfbEncrypt cipher (unIV iv) ct