openCiphertext :: Chain
               -> Maybe ByteString
               -> ByteString
               -> Maybe (ByteString, Chain)
openCiphertext (Chain chain) hdr ct = verifyMAC
  where
    (ctxt, ctMAC) = B.splitAt (B.length ct - 16) ct
    body = maybe B.empty id hdr <> ctxt

    -- Block encryption, key derivation step two
    (chainOut, macKey2, plaintxt)
      = ( B.take 32 block
        , B.take 32 $ B.drop 32 block
        , B.drop 64 block)
      where
        block = ncipher (B.replicate 64 0x0 <> ctxt) (SecretKey chain)

    -- MAC verification
    verifyMAC :: Maybe (ByteString, Chain)
    verifyMAC =
      case Poly1305.verify (SecretKey macKey2) a body of
        True  ->
          case decode (B.take 4 plaintxt) of
            Left _  -> Nothing
            Right x -> Just $ ( B.drop (fromIntegral (x :: Word32) + 4) plaintxt
                              , Chain chainOut )
        False -> Nothing
      where a = Poly1305.Auth ctMAC
openCiphertext :: Chain
               -> Maybe ByteString
               -> ByteString
               -> Maybe (ByteString, Chain)
openCiphertext (Chain chain) hdr ct = verifyMAC
  where
    (ctxt, ctMAC) = B.splitAt (B.length ct - 16) ct
    body = maybe B.empty id hdr <> ctxt

    -- Block encryption, key derivation step two
    (chainOut, macKey2, plaintxt)
      = ( B.take 32 block
        , B.take 32 $ B.drop 32 block
        , B.drop 64 block)
      where
        block = ncipher (B.replicate 64 0x0 <> ctxt) (SecretKey chain)

    -- MAC verification
    verifyMAC :: Maybe (ByteString, Chain)
    verifyMAC =
      case Poly1305.verify (SecretKey macKey2) a body of
        True  ->
          case decode (B.take 4 plaintxt) of
            Left _  -> Nothing
            Right x -> Just $ ( B.drop (fromIntegral (x :: Word32) + 4) plaintxt
                              , Chain chainOut )
        False -> Nothing
      where a = Poly1305.Auth ctMAC
openCiphertext (Chain chain) hdr ct = verifyMAC
  where
    (ctxt, ctMAC) = B.splitAt (B.length ct - 16) ct
    body = maybe B.empty id hdr <> ctxt

    -- Block encryption, key derivation step two
    (chainOut, macKey2, plaintxt)
      = ( B.take 32 block
        , B.take 32 $ B.drop 32 block
        , B.drop 64 block)
      where
        block = ncipher (B.replicate 64 0x0 <> ctxt) (SecretKey chain)

    -- MAC verification
    verifyMAC :: Maybe (ByteString, Chain)
    verifyMAC =
      case Poly1305.verify (SecretKey macKey2) a body of
        True  ->
          case decode (B.take 4 plaintxt) of
            Left _  -> Nothing
            Right x -> Just $ ( B.drop (fromIntegral (x :: Word32) + 4) plaintxt
                              , Chain chainOut )
        False -> Nothing
      where a = Poly1305.Auth ctMAC