hOpenPGP-3.7: Codec/Encryption/OpenPGP/BlockCipher.hs
-- BlockCipher.hs: OpenPGP (RFC9580) block cipher stuff
-- Copyright © 2013-2026 Clint Adams
-- This software is released under the terms of the Expat license.
-- (See the LICENSE file).
{-# LANGUAGE RankNTypes #-}
module Codec.Encryption.OpenPGP.BlockCipher
( keySize
, supportedSymmetricAlgorithmsForCFB
, withSymmetricCipher
, withAEADCipher
) where
import qualified Crypto.Cipher.AES as AES
import qualified Crypto.Cipher.Blowfish as Blowfish
import qualified Crypto.Cipher.Camellia as Camellia
import qualified Crypto.Cipher.TripleDES as TripleDES
import qualified Crypto.Nettle.Ciphers as CNC
import qualified Data.ByteString as B
import Codec.Encryption.OpenPGP.Internal.CryptoCipherTypes
( HOWrappedOldCCT (..)
)
import Codec.Encryption.OpenPGP.Internal.Crypton
( HOWrappedCCT (..)
)
import Codec.Encryption.OpenPGP.Internal.HOBlockCipher
import Codec.Encryption.OpenPGP.Types
type HOCipher a =
forall cipher
. HOBlockCipher cipher
=> cipher -> Either CipherError a
withSymmetricCipher
:: SymmetricAlgorithm
-> B.ByteString
-> HOCipher a
-> Either CipherError a
withSymmetricCipher Plaintext _ _ = Left (CipherUnsupportedAlgorithm Plaintext)
withSymmetricCipher IDEA _ _ = Left (CipherUnsupportedAlgorithm IDEA)
withSymmetricCipher ReservedSAFER _ _ = Left (CipherUnsupportedAlgorithm ReservedSAFER)
withSymmetricCipher ReservedDES _ _ = Left (CipherUnsupportedAlgorithm ReservedDES)
withSymmetricCipher (OtherSA n) _ _ = Left (CipherUnsupportedAlgorithm (OtherSA n))
withSymmetricCipher CAST5 keyBytes f =
( cipherInit keyBytes
:: Either CipherError (HOWrappedOldCCT CNC.CAST128)
)
>>= f
withSymmetricCipher Twofish keyBytes f =
( cipherInit keyBytes
:: Either CipherError (HOWrappedOldCCT CNC.TWOFISH)
)
>>= f
withSymmetricCipher TripleDES keyBytes f =
( cipherInit keyBytes
:: Either CipherError (HOWrappedCCT TripleDES.DES_EDE3)
)
>>= f
withSymmetricCipher Blowfish keyBytes f =
( cipherInit keyBytes
:: Either CipherError (HOWrappedCCT Blowfish.Blowfish128)
)
>>= f
withSymmetricCipher AES128 keyBytes f =
( cipherInit keyBytes
:: Either CipherError (HOWrappedCCT AES.AES128)
)
>>= f
withSymmetricCipher AES192 keyBytes f =
( cipherInit keyBytes
:: Either CipherError (HOWrappedCCT AES.AES192)
)
>>= f
withSymmetricCipher AES256 keyBytes f =
( cipherInit keyBytes
:: Either CipherError (HOWrappedCCT AES.AES256)
)
>>= f
withSymmetricCipher Camellia128 keyBytes f =
( cipherInit keyBytes
:: Either CipherError (HOWrappedCCT Camellia.Camellia128)
)
>>= f
withSymmetricCipher Camellia192 keyBytes f =
( cipherInit keyBytes
:: Either CipherError (HOWrappedOldCCT CNC.Camellia192)
)
>>= f
withSymmetricCipher Camellia256 keyBytes f =
( cipherInit keyBytes
:: Either CipherError (HOWrappedOldCCT CNC.Camellia256)
)
>>= f
withAEADCipher
:: SymmetricAlgorithm
-> B.ByteString
-> HOCipher a
-> Either CipherError a
withAEADCipher symalgo keyBytes f =
case symalgo of
AES128 -> withSymmetricCipher AES128 keyBytes f
AES192 -> withSymmetricCipher AES192 keyBytes f
AES256 -> withSymmetricCipher AES256 keyBytes f
Camellia128 -> withSymmetricCipher Camellia128 keyBytes f
Twofish -> withSymmetricCipher Twofish keyBytes f
Camellia192 -> withSymmetricCipher Camellia192 keyBytes f
Camellia256 -> withSymmetricCipher Camellia256 keyBytes f
_ -> Left (CipherUnsupportedAlgorithm symalgo)
{- | Symmetric algorithms that the CFB (SEIPDv1) encryption backend can use for
new *encryption*, restricted to the RFC 9580 §9.3-permitted set.
This is the intersection of:
* algorithms 'withSymmetricCipher' can actually encrypt
(`CAST5`, `Twofish`, `TripleDES`, `Blowfish`, `AES128/192/256`,
`Camellia128/192/256`), minus
* algorithms RFC 9580 §9.3 forbids for new encryption (`IDEA`, `TripleDES`,
`CAST5`).
Decryption backward-compatibility is unaffected: 'withSymmetricCipher' still
handles all ten algorithms, including the three forbidden above.
-}
supportedSymmetricAlgorithmsForCFB :: [SymmetricAlgorithm]
supportedSymmetricAlgorithmsForCFB =
[ AES256
, AES192
, AES128
, Camellia256
, Camellia192
, Camellia128
, Twofish
, Blowfish
]
-- In octets. Keep this as an explicit OpenPGP algorithm mapping so behavior
-- stays stable across mixed backends (crypton/nettle) and includes unsupported
-- algorithms that never reach backend cipher types.
keySize :: SymmetricAlgorithm -> Either CipherError Int
keySize Plaintext = Right 0
keySize IDEA = Right 16
keySize TripleDES = Right 24
keySize CAST5 = Right 16
keySize Blowfish = Right 16
keySize ReservedSAFER = Left (CipherUnsupportedAlgorithm ReservedSAFER)
keySize ReservedDES = Left (CipherUnsupportedAlgorithm ReservedDES)
keySize AES128 = Right 16
keySize AES192 = Right 24
keySize AES256 = Right 32
keySize Twofish = Right 32
keySize Camellia128 = Right 16
keySize Camellia192 = Right 24
keySize Camellia256 = Right 32
keySize (OtherSA n) = Left (CipherUnsupportedAlgorithm (OtherSA n))