-- CryptoCipherTypes.hs: shim for crypto-cipher-types stuff (current nettle)
-- Copyright © 2016  Clint Adams
-- This software is released under the terms of the Expat license.
-- (See the LICENSE file).
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE PackageImports #-}
{-# LANGUAGE UndecidableInstances #-}

module Codec.Encryption.OpenPGP.Internal.CryptoCipherTypes
  ( HOWrappedOldCCT(..)
  ) where

import Control.Error.Util (note)
import qualified "crypto-cipher-types" Crypto.Cipher.Types as OldCCT
import qualified "cryptonite" Crypto.Cipher.Types as CCT
import qualified Data.ByteString as B

import Codec.Encryption.OpenPGP.Internal.HOBlockCipher

newtype HOWrappedOldCCT a =
  HWOCCT a

instance OldCCT.BlockCipher cipher =>
         HOBlockCipher (HOWrappedOldCCT cipher) where
  cipherInit :: ByteString -> Either String (HOWrappedOldCCT cipher)
cipherInit =
    (cipher -> HOWrappedOldCCT cipher)
-> Either String cipher -> Either String (HOWrappedOldCCT cipher)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap cipher -> HOWrappedOldCCT cipher
forall a. a -> HOWrappedOldCCT a
HWOCCT (Either String cipher -> Either String (HOWrappedOldCCT cipher))
-> (ByteString -> Either String cipher)
-> ByteString
-> Either String (HOWrappedOldCCT cipher)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    (KeyError -> Either String cipher)
-> (Key cipher -> Either String cipher)
-> Either KeyError (Key cipher)
-> Either String cipher
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Either String cipher -> KeyError -> Either String cipher
forall a b. a -> b -> a
const (String -> Either String cipher
forall a b. a -> Either a b
Left String
"nettle invalid key")) (cipher -> Either String cipher
forall a b. b -> Either a b
Right (cipher -> Either String cipher)
-> (Key cipher -> cipher) -> Key cipher -> Either String cipher
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Key cipher -> cipher
forall cipher. Cipher cipher => Key cipher -> cipher
OldCCT.cipherInit) (Either KeyError (Key cipher) -> Either String cipher)
-> (ByteString -> Either KeyError (Key cipher))
-> ByteString
-> Either String cipher
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    ByteString -> Either KeyError (Key cipher)
forall b c.
(ToSecureMem b, Cipher c) =>
b -> Either KeyError (Key c)
OldCCT.makeKey
  cipherName :: HOWrappedOldCCT cipher -> String
cipherName (HWOCCT cipher
c) = cipher -> String
forall cipher. Cipher cipher => cipher -> String
OldCCT.cipherName cipher
c
  cipherKeySize :: HOWrappedOldCCT cipher -> KeySizeSpecifier
cipherKeySize (HWOCCT cipher
c) = KeySizeSpecifier -> KeySizeSpecifier
convertKSS (KeySizeSpecifier -> KeySizeSpecifier)
-> (cipher -> KeySizeSpecifier) -> cipher -> KeySizeSpecifier
forall b c a. (b -> c) -> (a -> b) -> a -> c
. cipher -> KeySizeSpecifier
forall cipher. Cipher cipher => cipher -> KeySizeSpecifier
OldCCT.cipherKeySize (cipher -> KeySizeSpecifier) -> cipher -> KeySizeSpecifier
forall a b. (a -> b) -> a -> b
$ cipher
c
  blockSize :: HOWrappedOldCCT cipher -> Int
blockSize (HWOCCT cipher
c) = cipher -> Int
forall cipher. BlockCipher cipher => cipher -> Int
OldCCT.blockSize cipher
c
  cfbEncrypt :: HOWrappedOldCCT cipher
-> ByteString -> ByteString -> Either String ByteString
cfbEncrypt (HWOCCT cipher
c) ByteString
iv ByteString
bs =
    ByteString -> Either String (IV cipher)
forall cipher.
BlockCipher cipher =>
ByteString -> Either String (IV cipher)
hammerIV ByteString
iv Either String (IV cipher)
-> (IV cipher -> Either String ByteString)
-> Either String ByteString
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \IV cipher
i -> ByteString -> Either String ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return (cipher -> IV cipher -> ByteString -> ByteString
forall cipher.
BlockCipher cipher =>
cipher -> IV cipher -> ByteString -> ByteString
OldCCT.cfbEncrypt cipher
c IV cipher
i ByteString
bs)
  cfbDecrypt :: HOWrappedOldCCT cipher
-> ByteString -> ByteString -> Either String ByteString
cfbDecrypt (HWOCCT cipher
c) ByteString
iv ByteString
bs =
    ByteString -> Either String (IV cipher)
forall cipher.
BlockCipher cipher =>
ByteString -> Either String (IV cipher)
hammerIV ByteString
iv Either String (IV cipher)
-> (IV cipher -> Either String ByteString)
-> Either String ByteString
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \IV cipher
i -> ByteString -> Either String ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return (cipher -> IV cipher -> ByteString -> ByteString
forall cipher.
BlockCipher cipher =>
cipher -> IV cipher -> ByteString -> ByteString
OldCCT.cfbDecrypt cipher
c IV cipher
i ByteString
bs)
  paddedCfbEncrypt :: HOWrappedOldCCT cipher
-> ByteString -> ByteString -> Either String ByteString
paddedCfbEncrypt HOWrappedOldCCT cipher
_ ByteString
_ ByteString
_ =
    String -> Either String ByteString
forall a b. a -> Either a b
Left String
"padding for nettle-encryption not implemented yet"
  paddedCfbDecrypt :: HOWrappedOldCCT cipher
-> ByteString -> ByteString -> Either String ByteString
paddedCfbDecrypt (HWOCCT cipher
cipher) ByteString
iv ByteString
ciphertext =
    ByteString -> Either String (IV cipher)
forall cipher.
BlockCipher cipher =>
ByteString -> Either String (IV cipher)
hammerIV ByteString
iv Either String (IV cipher)
-> (IV cipher -> Either String ByteString)
-> Either String ByteString
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \IV cipher
i ->
      ByteString -> Either String ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> ByteString -> ByteString
B.take (ByteString -> Int
B.length ByteString
ciphertext) (cipher -> IV cipher -> ByteString -> ByteString
forall cipher.
BlockCipher cipher =>
cipher -> IV cipher -> ByteString -> ByteString
OldCCT.cfbDecrypt cipher
cipher IV cipher
i ByteString
padded))
    where
      padded :: ByteString
padded =
        ByteString
ciphertext ByteString -> ByteString -> ByteString
`B.append`
        [Word8] -> ByteString
B.pack
          (Int -> Word8 -> [Word8]
forall a. Int -> a -> [a]
replicate
             (cipher -> Int
forall cipher. BlockCipher cipher => cipher -> Int
OldCCT.blockSize cipher
cipher Int -> Int -> Int
forall a. Num a => a -> a -> a
-
              (ByteString -> Int
B.length ByteString
ciphertext Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` cipher -> Int
forall cipher. BlockCipher cipher => cipher -> Int
OldCCT.blockSize cipher
cipher))
             Word8
0)

convertKSS :: OldCCT.KeySizeSpecifier -> CCT.KeySizeSpecifier
convertKSS :: KeySizeSpecifier -> KeySizeSpecifier
convertKSS (OldCCT.KeySizeRange Int
a Int
b) = Int -> Int -> KeySizeSpecifier
CCT.KeySizeRange Int
a Int
b
convertKSS (OldCCT.KeySizeEnum [Int]
as) = [Int] -> KeySizeSpecifier
CCT.KeySizeEnum [Int]
as
convertKSS (OldCCT.KeySizeFixed Int
a) = Int -> KeySizeSpecifier
CCT.KeySizeFixed Int
a

hammerIV ::
     OldCCT.BlockCipher cipher
  => B.ByteString
  -> Either String (OldCCT.IV cipher)
hammerIV :: forall cipher.
BlockCipher cipher =>
ByteString -> Either String (IV cipher)
hammerIV = String -> Maybe (IV cipher) -> Either String (IV cipher)
forall a b. a -> Maybe b -> Either a b
note String
"nettle bad IV" (Maybe (IV cipher) -> Either String (IV cipher))
-> (ByteString -> Maybe (IV cipher))
-> ByteString
-> Either String (IV cipher)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Maybe (IV cipher)
forall b c. (Byteable b, BlockCipher c) => b -> Maybe (IV c)
OldCCT.makeIV