packages feed

tahoe-chk-0.2.0.0: src/Tahoe/CHK/Cipher.hs

{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}

module Tahoe.CHK.Cipher (
    Key (keyBytes, keyCipher),
) where

import Control.DeepSeq (NFData)
import Crypto.Cipher.Types (AEAD, BlockCipher (..), Cipher (..))
import Data.ByteArray (ScrubbedBytes)
import qualified Data.ByteArray as BA
import Data.Coerce (coerce)
import GHC.Generics (Generic)

{- | A block cipher key which can be deserialized from or serialized to a
 ByteArray.

 This is a wrapper around Crypto.Cipher.Types.Cipher which does not provide a
 way to recover the original bytes of the key.  We provide this by keeping the
 original bytes around.
-}
data Key cipher = Key {keyBytes :: ScrubbedBytes, keyCipher :: cipher}

deriving instance Generic (Key cipher)
deriving instance NFData cipher => NFData (Key cipher)

instance forall cipher. Cipher cipher => Cipher (Key cipher) where
    cipherInit bs = Key (BA.convert bs) <$> cipherInit bs
    cipherName _ = cipherName @cipher undefined
    cipherKeySize _ = cipherKeySize @cipher undefined

instance forall cipher. BlockCipher cipher => BlockCipher (Key cipher) where
    blockSize _ = blockSize @cipher undefined
    ecbEncrypt = ecbEncrypt . keyCipher
    ecbDecrypt = ecbDecrypt . keyCipher
    cbcEncrypt (Key _ cipher) iv = cbcEncrypt cipher (coerce iv)
    cbcDecrypt (Key _ cipher) iv = cbcDecrypt cipher (coerce iv)

    cfbEncrypt (Key _ cipher) iv = cfbEncrypt cipher (coerce iv)
    cfbDecrypt (Key _ cipher) iv = cfbDecrypt cipher (coerce iv)
    ctrCombine (Key _ cipher) iv = ctrCombine cipher (coerce iv)

    aeadInit mode (Key _ cipher) iv = wrap <$> aeadInit mode cipher iv
      where
        wrap = coerce @(AEAD cipher) @(AEAD (Key cipher))

instance BA.ByteArrayAccess (Key cipher) where
    length (Key ba _) = BA.length ba
    withByteArray (Key ba _) = BA.withByteArray ba