-- Cryptonite.hs: shim for cryptonite
-- Copyright © 2016  Clint Adams
-- This software is released under the terms of the Expat license.
-- (See the LICENSE file).
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PackageImports #-}
{-# LANGUAGE UndecidableInstances #-}

module Codec.Encryption.OpenPGP.Internal.Cryptonite
  ( HOWrappedCCT(..)
  ) where

import Control.Error.Util (note)
import qualified "cryptonite" Crypto.Cipher.Types as CCT
import qualified Crypto.Error as CE
import Data.Bifunctor (bimap)
import qualified Data.ByteString as B

import Codec.Encryption.OpenPGP.Internal.HOBlockCipher

newtype HOWrappedCCT a =
  HWCCT a

instance CCT.BlockCipher cipher => HOBlockCipher (HOWrappedCCT cipher) where
  cipherInit :: ByteString -> Either String (HOWrappedCCT cipher)
cipherInit = (CryptoError -> String)
-> (cipher -> HOWrappedCCT cipher)
-> Either CryptoError cipher
-> Either String (HOWrappedCCT cipher)
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap CryptoError -> String
forall a. Show a => a -> String
show cipher -> HOWrappedCCT cipher
forall a. a -> HOWrappedCCT a
HWCCT (Either CryptoError cipher -> Either String (HOWrappedCCT cipher))
-> (ByteString -> Either CryptoError cipher)
-> ByteString
-> Either String (HOWrappedCCT cipher)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CryptoFailable cipher -> Either CryptoError cipher
forall a. CryptoFailable a -> Either CryptoError a
CE.eitherCryptoError (CryptoFailable cipher -> Either CryptoError cipher)
-> (ByteString -> CryptoFailable cipher)
-> ByteString
-> Either CryptoError cipher
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> CryptoFailable cipher
forall cipher key.
(Cipher cipher, ByteArray key) =>
key -> CryptoFailable cipher
CCT.cipherInit
  cipherName :: HOWrappedCCT cipher -> String
cipherName (HWCCT cipher
c) = cipher -> String
forall cipher. Cipher cipher => cipher -> String
CCT.cipherName cipher
c
  cipherKeySize :: HOWrappedCCT cipher -> KeySizeSpecifier
cipherKeySize (HWCCT cipher
c) = cipher -> KeySizeSpecifier
forall cipher. Cipher cipher => cipher -> KeySizeSpecifier
CCT.cipherKeySize cipher
c
  blockSize :: HOWrappedCCT cipher -> Int
blockSize (HWCCT cipher
c) = cipher -> Int
forall cipher. BlockCipher cipher => cipher -> Int
CCT.blockSize cipher
c
  cfbEncrypt :: HOWrappedCCT cipher
-> ByteString -> ByteString -> Either String ByteString
cfbEncrypt (HWCCT 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 ba.
(BlockCipher cipher, ByteArray ba) =>
cipher -> IV cipher -> ba -> ba
CCT.cfbEncrypt cipher
c IV cipher
i ByteString
bs)
  cfbDecrypt :: HOWrappedCCT cipher
-> ByteString -> ByteString -> Either String ByteString
cfbDecrypt (HWCCT 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 ba.
(BlockCipher cipher, ByteArray ba) =>
cipher -> IV cipher -> ba -> ba
CCT.cfbDecrypt cipher
c IV cipher
i ByteString
bs)

hammerIV ::
     CCT.BlockCipher cipher => B.ByteString -> Either String (CCT.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
"cryptonite 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. (ByteArrayAccess b, BlockCipher c) => b -> Maybe (IV c)
CCT.makeIV