----------------------------------------------------------------------------- -- | -- Module : Codec.Encryption.Padding -- Copyright : (c) Dominic Steinitz 2003 -- License : BSD-style (see the file ReadMe.tex) -- -- Maintainer : dominic.steinitz@blueyonder.co.uk -- Stability : experimental -- Portability : portable -- -- Padding algorithms for use with block ciphers. -- -- This module currently supports: -- -- * PKCS5 padding and unpadding. -- -- * Null padding and unpadding. -- ----------------------------------------------------------------------------- module Codec.Encryption.Padding ( -- * Function types pkcs5, unPkcs5, padNulls, unPadNulls ) where import Data.Word import Data.Bits import Data.List import Codec.Utils -- | When the last block of plaintext is shorter than the block size then it -- must be padded. PKCS5 specifies that the padding octets should each -- contain the number of octets which must be stripped off. So, for example, -- with a block size of 8, \"0a0b0c\" will be padded with \"05\" resulting in -- \"0a0b0c0505050505\". If the final block is a full block of 8 octets -- then a whole block of \"0808080808080808\" is appended. pkcs5 :: (Integral a, Bits a) => [Octet] -> [a] pkcs5 s = pad p s where p n = replicate n (fromIntegral n) -- | When the last block of plaintext is shorter than the block size then it -- must be padded. Nulls padding specifies that the padding octets should each -- contain a null. So, for example, -- with a block size of 8, \"0a0b0c\" will be padded to -- \"0a0b0c0000000000\". If the final block is a full block of 8 octets -- then a whole block of \"0000000000000000\" is appended. -- NB this is only suitable for data which does not contain nulls, -- for example, ASCII. padNulls :: (Integral a, Bits a) => [Octet] -> [a] padNulls s = pad p s where p n = replicate n 0 testPad s = pad p s where p n = replicate (n-1) 0xff ++ [fromIntegral n] pad p s = blocks where octetSize = (bitSize $ head blocks) `div` 8 blocks = map (fromOctets 256) (unfoldr h $ concat $ unfoldr g s) g :: [Octet] -> Maybe ([Octet],[Octet]) g x | l == 0 = Nothing | l < octetSize = Just (t ++ (p (octetSize-l)), []) | d == [] = Just (t ++ (p octetSize), []) | otherwise = Just (t, d) where l = length t t = take octetSize x d = drop octetSize x h :: [Octet] -> Maybe ([Octet],[Octet]) h x | x == [] = Nothing | otherwise = Just (take octetSize x, drop octetSize x) -- | Take a list of blocks padded using the method described in PKCS5 -- (see <http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5>) -- and return the list of unpadded octets. NB this function does not -- currently check that the padded block is correctly formed and should -- only be used for blocks that have been padded correctly. unPkcs5 :: (Bits a, Integral a) => [a] -> [Octet] unPkcs5 s = unPad h s where h octetSize x = take (octetSize - (fromIntegral (last x))) x -- | Take a list of blocks padded with nulls -- and return the list of unpadded octets. NB if the blocks contain -- a null then the result is unpredictable. unPadNulls :: (Bits a, Integral a) => [a] -> [Octet] unPadNulls s = unPad h s where h _ x = takeWhile (/=0) x unPad p s = concat $ unfoldr g s where g :: (Integral a, Bits a) => [a] -> Maybe ([Octet],[a]) g x | t == [] = Nothing | d == [] = Just (s, []) | otherwise = Just (v, d) where t = take 1 x d = drop 1 x u = head t octetSize = (bitSize u) `div` 8 v = i2osp octetSize u s = p octetSize v