base64-bytestring-1.2.1.0/0000755000000000000000000000000007346545000013316 5ustar0000000000000000base64-bytestring-1.2.1.0/CHANGELOG.md0000644000000000000000000000436007346545000015132 0ustar0000000000000000See also http://pvp.haskell.org/faq # 1.2.1.0 * Bugfix for GHC 9.0.1 memory corruption bug ([#46](https://github.com/haskell/base64-bytestring/pull/46)) * Thanks to [Fraser Tweedale](https://github.com/frasertweedale) and [Andrew Lelechenko](https://github.com/bodigrim) for logging and helping with this fix. # 1.2.0.1 * Package update: support for `bytestring >=0.11` # 1.2.0.0 * Security fix: reject non-canonical base64 encoded values - ([#38](https://github.com/haskell/base64-bytestring/pull/38)) fixing issue [#24](https://github.com/haskell/base64-bytestring/issues/24). * Security fix: reject bytestrings with improper padding that can be "completed" by the unpadded-Base64url workflow, and homogenize error messages ([#33](https://github.com/haskell/base64-bytestring/pull/33)) * Test coverage expanded to 98% of the library. All critical paths covered. # 1.1.0.0 * `joinWith` has been removed ([#32](https://github.com/haskell/base64-bytestring/pull/32)) * Bugfix: `decode` formerly allowed for padding chars to be interspersed in a valid base64-encoded string. This is now not the case, and it is fully spec-compliant as of [#31](https://github.com/haskell/base64-bytestring/pull/31) * The default behavior for Base64url `decode` is now to support arbitrary padding. If you need strict padded or unpadded decode semantics, use `decodePadded` or `decodeUnpadded`. * Added strict unpadded and padded decode functions for Base64url ([#30](https://github.com/haskell/base64-bytestring/pull/30)) * Added unpadded encode for Base64url ([#26](https://github.com/haskell/base64-bytestring/pull/26)). ---- ### 1.0.0.3 * Made performance more robust ([#27](https://github.com/haskell/base64-bytestring/pull/27)). * Improved documentation ([#23](https://github.com/haskell/base64-bytestring/pull/23)). * Improved the performance of decodeLenient a bit ([#21](https://github.com/haskell/base64-bytestring/pull/21)). ### 1.0.0.2 * Fixed a write past allocated memory in joinWith (potential security issue). ## 0.1.1.0 - 1.0.0.1 * Changelog not recorded for these versions. ### 0.1.0.3 * Fixed: wrong encoding table on big-endian systems. * Fixed: too big indices in encoding table construction. ### 0.1.0.2 * Changelog not recorded up to this version. base64-bytestring-1.2.1.0/Data/ByteString/0000755000000000000000000000000007346545000016261 5ustar0000000000000000base64-bytestring-1.2.1.0/Data/ByteString/Base64.hs0000644000000000000000000000433507346545000017646 0ustar0000000000000000{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 702 {-# LANGUAGE Trustworthy #-} #endif -- | -- Module : Data.ByteString.Base64 -- Copyright : (c) 2010 Bryan O'Sullivan -- -- License : BSD-style -- Maintainer : Emily Pillmore , -- Herbert Valerio Riedel , -- Mikhail Glushenkov -- Stability : experimental -- Portability : GHC -- -- Fast and efficient encoding and decoding of base64-encoded strings. -- -- @since 0.1.0.0 module Data.ByteString.Base64 ( encode , decode , decodeLenient ) where import Data.ByteString.Base64.Internal import qualified Data.ByteString as B import Data.ByteString.Internal (ByteString(..)) import Data.Word (Word8) import Foreign.ForeignPtr (ForeignPtr) -- | Encode a string into base64 form. The result will always be a -- multiple of 4 bytes in length. encode :: ByteString -> ByteString encode s = encodeWith Padded (mkEncodeTable alphabet) s -- | Decode a base64-encoded string. This function strictly follows -- the specification in -- . -- -- (Note: this means that even @"\\n"@ and @"\\r\\n"@ as line breaks are rejected -- rather than ignored. If you are using this in the context of a -- standard that overrules RFC 4648 such as HTTP multipart mime bodies, -- consider using 'decodeLenient'.) decode :: ByteString -> Either String ByteString decode s = decodeWithTable Padded decodeFP s -- | Decode a base64-encoded string. This function is lenient in -- following the specification from -- , and will not -- generate parse errors no matter how poor its input. decodeLenient :: ByteString -> ByteString decodeLenient s = decodeLenientWithTable decodeFP s alphabet :: ByteString alphabet = B.pack $ [65..90] ++ [97..122] ++ [48..57] ++ [43,47] {-# NOINLINE alphabet #-} decodeFP :: ForeignPtr Word8 #if MIN_VERSION_bytestring(0,11,0) BS decodeFP _ = #else PS decodeFP _ _ = #endif B.pack $ replicate 43 x ++ [62,x,x,x,63] ++ [52..61] ++ [x,x,x,done,x,x,x] ++ [0..25] ++ [x,x,x,x,x,x] ++ [26..51] ++ replicate 133 x {-# NOINLINE decodeFP #-} x :: Integral a => a x = 255 {-# INLINE x #-} base64-bytestring-1.2.1.0/Data/ByteString/Base64/0000755000000000000000000000000007346545000017305 5ustar0000000000000000base64-bytestring-1.2.1.0/Data/ByteString/Base64/Internal.hs0000644000000000000000000004061507346545000021423 0ustar0000000000000000{-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-} {-# LANGUAGE DoAndIfThenElse #-} -- | -- Module : Data.ByteString.Base64.Internal -- Copyright : (c) 2010 Bryan O'Sullivan -- -- License : BSD-style -- Maintainer : bos@serpentine.com -- Stability : experimental -- Portability : GHC -- -- Fast and efficient encoding and decoding of base64-encoded strings. module Data.ByteString.Base64.Internal ( encodeWith , decodeWithTable , decodeLenientWithTable , mkEncodeTable , done , peek8, poke8, peek8_32 , reChunkIn , Padding(..) , withBS , mkBS ) where import Data.Bits ((.|.), (.&.), shiftL, shiftR) import qualified Data.ByteString as B import Data.ByteString.Internal (ByteString(..), mallocByteString) import Data.Word (Word8, Word16, Word32) import Foreign.ForeignPtr (ForeignPtr, withForeignPtr, castForeignPtr) import Foreign.Ptr (Ptr, castPtr, minusPtr, plusPtr) import Foreign.Storable (peek, peekElemOff, poke) import System.IO.Unsafe (unsafePerformIO) peek8 :: Ptr Word8 -> IO Word8 peek8 = peek poke8 :: Ptr Word8 -> Word8 -> IO () poke8 = poke peek8_32 :: Ptr Word8 -> IO Word32 peek8_32 = fmap fromIntegral . peek8 data Padding = Padded | Don'tCare | Unpadded deriving Eq -- | Encode a string into base64 form. The result will always be a multiple -- of 4 bytes in length. encodeWith :: Padding -> EncodeTable -> ByteString -> ByteString encodeWith !padding (ET alfaFP encodeTable) !bs = withBS bs go where go !sptr !slen | slen > maxBound `div` 4 = error "Data.ByteString.Base64.encode: input too long" | otherwise = do let dlen = (slen + 2) `div` 3 * 4 dfp <- mallocByteString dlen withForeignPtr alfaFP $ \aptr -> withForeignPtr encodeTable $ \ep -> do let aidx n = peek8 (aptr `plusPtr` n) sEnd = sptr `plusPtr` slen finish !n = return $ mkBS dfp n fill !dp !sp !n | sp `plusPtr` 2 >= sEnd = complete (castPtr dp) sp n | otherwise = {-# SCC "encode/fill" #-} do i <- peek8_32 sp j <- peek8_32 (sp `plusPtr` 1) k <- peek8_32 (sp `plusPtr` 2) let w = i `shiftL` 16 .|. j `shiftL` 8 .|. k enc = peekElemOff ep . fromIntegral poke dp =<< enc (w `shiftR` 12) poke (dp `plusPtr` 2) =<< enc (w .&. 0xfff) fill (dp `plusPtr` 4) (sp `plusPtr` 3) (n + 4) complete dp sp n | sp == sEnd = finish n | otherwise = {-# SCC "encode/complete" #-} do let peekSP m f = (f . fromIntegral) `fmap` peek8 (sp `plusPtr` m) twoMore = sp `plusPtr` 2 == sEnd equals = 0x3d :: Word8 doPad = padding == Padded {-# INLINE equals #-} !a <- peekSP 0 ((`shiftR` 2) . (.&. 0xfc)) !b <- peekSP 0 ((`shiftL` 4) . (.&. 0x03)) poke8 dp =<< aidx a if twoMore then do !b' <- peekSP 1 ((.|. b) . (`shiftR` 4) . (.&. 0xf0)) !c <- aidx =<< peekSP 1 ((`shiftL` 2) . (.&. 0x0f)) poke8 (dp `plusPtr` 1) =<< aidx b' poke8 (dp `plusPtr` 2) c if doPad then poke8 (dp `plusPtr` 3) equals >> finish (n + 4) else finish (n + 3) else do poke8 (dp `plusPtr` 1) =<< aidx b if doPad then do poke8 (dp `plusPtr` 2) equals poke8 (dp `plusPtr` 3) equals finish (n + 4) else finish (n + 2) withForeignPtr dfp (\dptr -> fill (castPtr dptr) sptr 0) data EncodeTable = ET !(ForeignPtr Word8) !(ForeignPtr Word16) -- The encoding table is constructed such that the expansion of a 12-bit -- block to a 16-bit block can be done by a single Word16 copy from the -- correspoding table entry to the target address. The 16-bit blocks are -- stored in big-endian order, as the indices into the table are built in -- big-endian order. mkEncodeTable :: ByteString -> EncodeTable #if MIN_VERSION_bytestring(0,11,0) mkEncodeTable alphabet@(BS afp _) = case table of BS fp _ -> ET afp (castForeignPtr fp) #else mkEncodeTable alphabet@(PS afp _ _) = case table of PS fp _ _ -> ET afp (castForeignPtr fp) #endif where ix = fromIntegral . B.index alphabet table = B.pack $ concat $ [ [ix j, ix k] | j <- [0..63], k <- [0..63] ] -- | Decode a base64-encoded string. This function strictly follows -- the specification in . -- -- This function takes the decoding table (for @base64@ or @base64url@) as -- the first parameter. -- -- For validation of padding properties, see note: $Validation -- decodeWithTable :: Padding -> ForeignPtr Word8 -> ByteString -> Either String ByteString decodeWithTable padding !decodeFP bs | B.length bs == 0 = Right B.empty | otherwise = case padding of Padded | r == 0 -> withBS bs go | r == 1 -> Left "Base64-encoded bytestring has invalid size" | otherwise -> Left "Base64-encoded bytestring is unpadded or has invalid padding" Don'tCare | r == 0 -> withBS bs go | r == 2 -> withBS (B.append bs (B.replicate 2 0x3d)) go | r == 3 -> validateLastPad bs invalidPad $ withBS (B.append bs (B.replicate 1 0x3d)) go | otherwise -> Left "Base64-encoded bytestring has invalid size" Unpadded | r == 0 -> validateLastPad bs noPad $ withBS bs go | r == 2 -> validateLastPad bs noPad $ withBS (B.append bs (B.replicate 2 0x3d)) go | r == 3 -> validateLastPad bs noPad $ withBS (B.append bs (B.replicate 1 0x3d)) go | otherwise -> Left "Base64-encoded bytestring has invalid size" where !r = B.length bs `rem` 4 noPad = "Base64-encoded bytestring required to be unpadded" invalidPad = "Base64-encoded bytestring has invalid padding" go !sptr !slen = do dfp <- mallocByteString (slen `quot` 4 * 3) withForeignPtr decodeFP (\ !decptr -> withForeignPtr dfp (\dptr -> decodeLoop decptr sptr dptr (sptr `plusPtr` slen) dfp)) decodeLoop :: Ptr Word8 -- ^ decoding table pointer -> Ptr Word8 -- ^ source pointer -> Ptr Word8 -- ^ destination pointer -> Ptr Word8 -- ^ source end pointer -> ForeignPtr Word8 -- ^ destination foreign pointer (used for finalizing string) -> IO (Either String ByteString) decodeLoop !dtable !sptr !dptr !end !dfp = go dptr sptr where err p = return . Left $ "invalid character at offset: " ++ show (p `minusPtr` sptr) padErr p = return . Left $ "invalid padding at offset: " ++ show (p `minusPtr` sptr) canonErr p = return . Left $ "non-canonical encoding detected at offset: " ++ show (p `minusPtr` sptr) look :: Ptr Word8 -> IO Word32 look !p = do !i <- peek p !v <- peekElemOff dtable (fromIntegral i) return (fromIntegral v) go !dst !src | plusPtr src 4 >= end = do !a <- look src !b <- look (src `plusPtr` 1) !c <- look (src `plusPtr` 2) !d <- look (src `plusPtr` 3) finalChunk dst src a b c d | otherwise = do !a <- look src !b <- look (src `plusPtr` 1) !c <- look (src `plusPtr` 2) !d <- look (src `plusPtr` 3) decodeChunk dst src a b c d -- | Decodes chunks of 4 bytes at a time, recombining into -- 3 bytes. Note that in the inner loop stage, no padding -- characters are admissible. -- decodeChunk !dst !src !a !b !c !d | a == 0x63 = padErr src | b == 0x63 = padErr (plusPtr src 1) | c == 0x63 = padErr (plusPtr src 2) | d == 0x63 = padErr (plusPtr src 3) | a == 0xff = err src | b == 0xff = err (plusPtr src 1) | c == 0xff = err (plusPtr src 2) | d == 0xff = err (plusPtr src 3) | otherwise = do let !w = (shiftL a 18 .|. shiftL b 12 .|. shiftL c 6 .|. d) :: Word32 poke8 dst (fromIntegral (shiftR w 16)) poke8 (plusPtr dst 1) (fromIntegral (shiftR w 8)) poke8 (plusPtr dst 2) (fromIntegral w) go (plusPtr dst 3) (plusPtr src 4) -- | Decode the final 4 bytes in the string, recombining into -- 3 bytes. Note that in this stage, we can have padding chars -- but only in the final 2 positions. -- finalChunk !dst !src a b c d | a == 0x63 = padErr src | b == 0x63 = padErr (plusPtr src 1) | c == 0x63 && d /= 0x63 = err (plusPtr src 3) -- make sure padding is coherent. | a == 0xff = err src | b == 0xff = err (plusPtr src 1) | c == 0xff = err (plusPtr src 2) | d == 0xff = err (plusPtr src 3) | otherwise = do let !w = (shiftL a 18 .|. shiftL b 12 .|. shiftL c 6 .|. d) :: Word32 poke8 dst (fromIntegral (shiftR w 16)) if c == 0x63 && d == 0x63 then if sanityCheckPos b mask_4bits then return $ Right $ mkBS dfp (1 + (dst `minusPtr` dptr)) else canonErr (plusPtr src 1) else if d == 0x63 then if sanityCheckPos c mask_2bits then do poke8 (plusPtr dst 1) (fromIntegral (shiftR w 8)) return $ Right $ mkBS dfp (2 + (dst `minusPtr` dptr)) else canonErr (plusPtr src 2) else do poke8 (plusPtr dst 1) (fromIntegral (shiftR w 8)) poke8 (plusPtr dst 2) (fromIntegral w) return $ Right $ mkBS dfp (3 + (dst `minusPtr` dptr)) -- | Decode a base64-encoded string. This function is lenient in -- following the specification from -- , and will not -- generate parse errors no matter how poor its input. This function -- takes the decoding table (for @base64@ or @base64url@) as the first -- paramert. decodeLenientWithTable :: ForeignPtr Word8 -> ByteString -> ByteString decodeLenientWithTable !decodeFP !bs = withBS bs go where go !sptr !slen | dlen <= 0 = return B.empty | otherwise = do dfp <- mallocByteString dlen withForeignPtr decodeFP $ \ !decptr -> do let finish dbytes | dbytes > 0 = return $ mkBS dfp dbytes | otherwise = return B.empty sEnd = sptr `plusPtr` slen fill !dp !sp !n | sp >= sEnd = finish n | otherwise = {-# SCC "decodeLenientWithTable/fill" #-} let look :: Bool -> Ptr Word8 -> (Ptr Word8 -> Word32 -> IO ByteString) -> IO ByteString {-# INLINE look #-} look skipPad p0 f = go' p0 where go' p | p >= sEnd = f (sEnd `plusPtr` (-1)) done | otherwise = {-# SCC "decodeLenient/look" #-} do ix <- fromIntegral `fmap` peek8 p v <- peek8 (decptr `plusPtr` ix) if v == x || v == done && skipPad then go' (p `plusPtr` 1) else f (p `plusPtr` 1) (fromIntegral v) in look True sp $ \ !aNext !aValue -> look True aNext $ \ !bNext !bValue -> if aValue == done || bValue == done then finish n else look False bNext $ \ !cNext !cValue -> look False cNext $ \ !dNext !dValue -> do let w = aValue `shiftL` 18 .|. bValue `shiftL` 12 .|. cValue `shiftL` 6 .|. dValue poke8 dp $ fromIntegral (w `shiftR` 16) if cValue == done then finish (n + 1) else do poke8 (dp `plusPtr` 1) $ fromIntegral (w `shiftR` 8) if dValue == done then finish (n + 2) else do poke8 (dp `plusPtr` 2) $ fromIntegral w fill (dp `plusPtr` 3) dNext (n+3) withForeignPtr dfp $ \dptr -> fill dptr sptr 0 where !dlen = (slen + 3) `div` 4 * 3 x :: Integral a => a x = 255 {-# INLINE x #-} done :: Integral a => a done = 99 {-# INLINE done #-} -- This takes a list of ByteStrings, and returns a list in which each -- (apart from possibly the last) has length that is a multiple of n reChunkIn :: Int -> [ByteString] -> [ByteString] reChunkIn !n = go where go [] = [] go (y : ys) = case B.length y `divMod` n of (_, 0) -> y : go ys (d, _) -> case B.splitAt (d * n) y of (prefix, suffix) -> prefix : fixup suffix ys fixup acc [] = [acc] fixup acc (z : zs) = case B.splitAt (n - B.length acc) z of (prefix, suffix) -> let acc' = acc `B.append` prefix in if B.length acc' == n then let zs' = if B.null suffix then zs else suffix : zs in acc' : go zs' else -- suffix must be null fixup acc' zs -- $Validation -- -- This function checks that the last char of a bytestring is '=' -- and, if true, fails with a message or completes some io action. -- -- This is necessary to check when decoding permissively (i.e. filling in padding chars). -- Consider the following 4 cases of a string of length l: -- -- l = 0 mod 4: No pad chars are added, since the input is assumed to be good. -- l = 1 mod 4: Never an admissible length in base64 -- l = 2 mod 4: 2 padding chars are added. If padding chars are present in the last 4 chars of the string, -- they will fail to decode as final quanta. -- l = 3 mod 4: 1 padding char is added. In this case a string is of the form + . If adding the -- pad char "completes" the string so that it is `l = 0 mod 4`, then this may possibly form corrupted data. -- This case is degenerate and should be disallowed. -- -- Hence, permissive decodes should only fill in padding chars when it makes sense to add them. That is, -- if an input is degenerate, it should never succeed when we add padding chars. We need the following invariant to hold: -- -- @ -- B64U.decodeUnpadded <|> B64U.decodePadded ~ B64U.decodePadded -- @ -- -- This means the only char we need to check is the last one, and only to disallow `l = 3 mod 4`. -- validateLastPad :: ByteString -- ^ input to validate -> String -- ^ error msg -> Either String ByteString -> Either String ByteString validateLastPad !bs err !io | B.last bs == 0x3d = Left err | otherwise = io {-# INLINE validateLastPad #-} -- | Sanity check an index against a bitmask to make sure -- it's coherent. If pos & mask == 0, we're good. If not, we should fail. -- sanityCheckPos :: Word32 -> Word8 -> Bool sanityCheckPos pos mask = fromIntegral pos .&. mask == 0 {-# INLINE sanityCheckPos #-} -- | Mask 2 bits -- mask_2bits :: Word8 mask_2bits = 3 -- (1 << 2) - 1 {-# NOINLINE mask_2bits #-} -- | Mask 4 bits -- mask_4bits :: Word8 mask_4bits = 15 -- (1 << 4) - 1 {-# NOINLINE mask_4bits #-} -- | Back-compat shim for bytestring >=0.11. Constructs a -- bytestring from a foreign ptr and a length. Offset is 0. -- mkBS :: ForeignPtr Word8 -> Int -> ByteString #if MIN_VERSION_bytestring(0,11,0) mkBS dfp n = BS dfp n #else mkBS dfp n = PS dfp 0 n #endif {-# INLINE mkBS #-} -- | Back-compat shim for bytestring >=0.11. Unwraps the foreign ptr of -- a bytestring, executing an IO action as a function of the underlying -- pointer and some starting length. -- -- Note: in `unsafePerformIO`. -- withBS :: ByteString -> (Ptr Word8 -> Int -> IO a) -> a #if MIN_VERSION_bytestring(0,11,0) withBS (BS !sfp !slen) f = unsafePerformIO $ withForeignPtr sfp $ \p -> f p slen #else withBS (PS !sfp !soff !slen) f = unsafePerformIO $ withForeignPtr sfp $ \p -> f (plusPtr p soff) slen #endif {-# INLINE withBS #-} base64-bytestring-1.2.1.0/Data/ByteString/Base64/Lazy.hs0000644000000000000000000000451607346545000020566 0ustar0000000000000000{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 702 {-# LANGUAGE Trustworthy #-} #endif -- | -- Module : Data.ByteString.Base64.Lazy -- Copyright : (c) 2012 Ian Lynagh -- -- License : BSD-style -- Maintainer : Emily Pillmore , -- Herbert Valerio Riedel , -- Mikhail Glushenkov -- Stability : experimental -- Portability : GHC -- -- Fast and efficient encoding and decoding of base64-encoded -- lazy bytestrings. -- -- @since 1.0.0.0 module Data.ByteString.Base64.Lazy ( encode , decode , decodeLenient ) where import Data.ByteString.Base64.Internal import qualified Data.ByteString.Base64 as B64 import qualified Data.ByteString as S import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy.Char8 as LC import Data.Char -- | Encode a string into base64 form. The result will always be a -- multiple of 4 bytes in length. encode :: L.ByteString -> L.ByteString encode = L.fromChunks . map B64.encode . reChunkIn 3 . L.toChunks -- | Decode a base64-encoded string. This function strictly follows -- the specification in -- . decode :: L.ByteString -> Either String L.ByteString decode b = -- Returning an Either type means that the entire result will -- need to be in memory at once anyway, so we may as well -- keep it simple and just convert to and from a strict byte -- string -- TODO: Use L.{fromStrict,toStrict} once we can rely on -- a new enough bytestring case B64.decode $ S.concat $ L.toChunks b of Left err -> Left err Right b' -> Right $ L.fromChunks [b'] -- | Decode a base64-encoded string. This function is lenient in -- following the specification from -- , and will not generate -- parse errors no matter how poor its input. decodeLenient :: L.ByteString -> L.ByteString decodeLenient = L.fromChunks . map B64.decodeLenient . reChunkIn 4 . L.toChunks . LC.filter goodChar where -- We filter out and '=' padding here, but B64.decodeLenient -- handles that goodChar c = isDigit c || isAsciiUpper c || isAsciiLower c || c == '+' || c == '/' base64-bytestring-1.2.1.0/Data/ByteString/Base64/URL.hs0000644000000000000000000000602607346545000020307 0ustar0000000000000000{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 702 {-# LANGUAGE Trustworthy #-} #endif -- | -- Module : Data.ByteString.Base64.URL -- Copyright : (c) 2012 Deian Stefan -- -- License : BSD-style -- Maintainer : Emily Pillmore , -- Herbert Valerio Riedel , -- Mikhail Glushenkov -- Stability : experimental -- Portability : GHC -- -- Fast and efficient encoding and decoding of base64url-encoded strings. -- -- @since 0.1.1.0 module Data.ByteString.Base64.URL ( encode , encodeUnpadded , decode , decodePadded , decodeUnpadded , decodeLenient ) where import Data.ByteString.Base64.Internal import qualified Data.ByteString as B import Data.ByteString.Internal (ByteString(..)) import Data.Word (Word8) import Foreign.ForeignPtr (ForeignPtr) -- | Encode a string into base64url form. The result will always be a -- multiple of 4 bytes in length. encode :: ByteString -> ByteString encode = encodeWith Padded (mkEncodeTable alphabet) -- | Encode a string into unpadded base64url form. -- -- @since 1.1.0.0 encodeUnpadded :: ByteString -> ByteString encodeUnpadded = encodeWith Unpadded (mkEncodeTable alphabet) -- | Decode a base64url-encoded string applying padding if necessary. -- This function follows the specification in -- and in decode :: ByteString -> Either String ByteString decode = decodeWithTable Don'tCare decodeFP -- | Decode a padded base64url-encoded string, failing if input is improperly padded. -- This function follows the specification in -- and in -- -- @since 1.1.0.0 decodePadded :: ByteString -> Either String ByteString decodePadded = decodeWithTable Padded decodeFP -- | Decode a unpadded base64url-encoded string, failing if input is padded. -- This function follows the specification in -- and in -- -- @since 1.1.0.0 decodeUnpadded :: ByteString -> Either String ByteString decodeUnpadded = decodeWithTable Unpadded decodeFP -- | Decode a base64url-encoded string. This function is lenient in -- following the specification from -- , and will not -- generate parse errors no matter how poor its input. decodeLenient :: ByteString -> ByteString decodeLenient = decodeLenientWithTable decodeFP alphabet :: ByteString alphabet = B.pack $ [65..90] ++ [97..122] ++ [48..57] ++ [45,95] {-# NOINLINE alphabet #-} decodeFP :: ForeignPtr Word8 #if MIN_VERSION_bytestring(0,11,0) BS decodeFP _ = #else PS decodeFP _ _ = #endif B.pack $ replicate 45 x ++ [62,x,x] ++ [52..61] ++ [x,x,x,done,x,x,x] ++ [0..25] ++ [x,x,x,x,63,x] ++ [26..51] ++ replicate 133 x {-# NOINLINE decodeFP #-} x :: Integral a => a x = 255 {-# INLINE x #-} base64-bytestring-1.2.1.0/Data/ByteString/Base64/URL/0000755000000000000000000000000007346545000017747 5ustar0000000000000000base64-bytestring-1.2.1.0/Data/ByteString/Base64/URL/Lazy.hs0000644000000000000000000000670007346545000021225 0ustar0000000000000000{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 702 {-# LANGUAGE Trustworthy #-} #endif -- | -- Module : Data.ByteString.Base64.URL.Lazy -- Copyright : (c) 2012 Ian Lynagh -- -- License : BSD-style -- Maintainer : Emily Pillmore , -- Herbert Valerio Riedel , -- Mikhail Glushenkov -- Stability : experimental -- Portability : GHC -- -- Fast and efficient encoding and decoding of base64-encoded -- lazy bytestrings. -- -- @since 1.0.0.0 module Data.ByteString.Base64.URL.Lazy ( encode , encodeUnpadded , decode , decodeUnpadded , decodePadded , decodeLenient ) where import Data.ByteString.Base64.Internal import qualified Data.ByteString.Base64.URL as B64 import qualified Data.ByteString as S import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy.Char8 as LC import Data.Char -- | Encode a string into base64 form. The result will always be a -- multiple of 4 bytes in length. encode :: L.ByteString -> L.ByteString encode = L.fromChunks . map B64.encode . reChunkIn 3 . L.toChunks -- | Encode a string into unpadded base64url form. -- -- @since 1.1.0.0 encodeUnpadded :: L.ByteString -> L.ByteString encodeUnpadded = L.fromChunks . map B64.encodeUnpadded . reChunkIn 3 . L.toChunks -- | Decode a base64-encoded string. This function strictly follows -- the specification in -- . decode :: L.ByteString -> Either String L.ByteString decode b = -- Returning an Either type means that the entire result will -- need to be in memory at once anyway, so we may as well -- keep it simple and just convert to and from a strict byte -- string -- TODO: Use L.{fromStrict,toStrict} once we can rely on -- a new enough bytestring case B64.decode $ S.concat $ L.toChunks b of Left err -> Left err Right b' -> Right $ L.fromChunks [b'] -- | Decode a unpadded base64url-encoded string, failing if input is padded. -- This function follows the specification in -- and in -- -- @since 1.1.0.0 decodeUnpadded :: L.ByteString -> Either String L.ByteString decodeUnpadded bs = case B64.decodeUnpadded $ S.concat $ L.toChunks bs of Right b -> Right $ L.fromChunks [b] Left e -> Left e -- | Decode a padded base64url-encoded string, failing if input is improperly padded. -- This function follows the specification in -- and in -- -- @since 1.1.0.0 decodePadded :: L.ByteString -> Either String L.ByteString decodePadded bs = case B64.decodePadded $ S.concat $ L.toChunks bs of Right b -> Right $ L.fromChunks [b] Left e -> Left e -- | Decode a base64-encoded string. This function is lenient in -- following the specification from -- , and will not generate -- parse errors no matter how poor its input. decodeLenient :: L.ByteString -> L.ByteString decodeLenient = L.fromChunks . map B64.decodeLenient . reChunkIn 4 . L.toChunks . LC.filter goodChar where -- We filter out and '=' padding here, but B64.decodeLenient -- handles that goodChar c = isAlphaNum c || c == '-' || c == '_' base64-bytestring-1.2.1.0/LICENSE0000644000000000000000000000271507346545000014330 0ustar0000000000000000Copyright (c) 2010 Bryan O'Sullivan All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the author nor the names of his contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. base64-bytestring-1.2.1.0/README.md0000644000000000000000000000213107346545000014572 0ustar0000000000000000# Base64 Support for ByteStrings [![Hackage version](https://img.shields.io/hackage/v/base64-bytestring.svg?label=Hackage)](https://hackage.haskell.org/package/base64-bytestring) [![Stackage version](https://www.stackage.org/package/base64-bytestring/badge/lts?label=Stackage)](https://www.stackage.org/package/base64-bytestring) [![Build Status](https://secure.travis-ci.org/haskell/base64-bytestring.svg?branch=master)](http://travis-ci.org/haskell/base64-bytestring) This package provides a Haskell library for working with base64-encoded data quickly and efficiently, using the `ByteString` type. # Get involved! Please report bugs via the [GitHub issue tracker](https://github.com/haskell/base64-bytestring). Master [Git repository](https://github.com/haskell/base64-bytestring): * `git clone git://github.com/haskell/base64-bytestring.git` # Authors This library is written by [Bryan O'Sullivan](mailto:bos@serpentine.com). It is maintained by [Herbert Valerio Riedel](mailto:hvr@gnu.org), [Mikhail Glushenkov](mailto:mikhail.glushenkov@gmail.com), and [Emily Pillmore](mailto:emilypi@cohomolo.gy). base64-bytestring-1.2.1.0/Setup.hs0000644000000000000000000000005607346545000014753 0ustar0000000000000000import Distribution.Simple main = defaultMain base64-bytestring-1.2.1.0/base64-bytestring.cabal0000644000000000000000000000453407346545000017564 0ustar0000000000000000cabal-version: 1.12 name: base64-bytestring version: 1.2.1.0 synopsis: Fast base64 encoding and decoding for ByteStrings description: This package provides support for encoding and decoding binary data according to @base64@ (see also ) for strict and lazy ByteStrings . For a fuller-featured and better-performing Base64 library, see the package. homepage: https://github.com/haskell/base64-bytestring bug-reports: https://github.com/haskell/base64-bytestring/issues license: BSD3 license-file: LICENSE author: Bryan O'Sullivan maintainer: Herbert Valerio Riedel , Mikhail Glushenkov , Emily Pillmore copyright: 2010-2020 Bryan O'Sullivan et al. category: Data build-type: Simple tested-with: GHC ==7.0.4 || ==7.2.2 || ==7.4.2 || ==7.6.3 || ==7.8.4 || ==7.10.3 || ==8.0.2 || ==8.2.2 || ==8.4.4 || ==8.6.5 || ==8.8.4 || ==8.10.5 extra-source-files: README.md CHANGELOG.md utils/Transcode.hs utils/transcode.py library exposed-modules: Data.ByteString.Base64 Data.ByteString.Base64.Lazy Data.ByteString.Base64.URL Data.ByteString.Base64.URL.Lazy other-modules: Data.ByteString.Base64.Internal build-depends: base >=4 && <5 , bytestring >=0.9 && <0.12 ghc-options: -Wall -funbox-strict-fields default-language: Haskell2010 test-suite test type: exitcode-stdio-1.0 hs-source-dirs: tests main-is: Tests.hs ghc-options: -Wall -threaded -rtsopts build-depends: base , base64-bytestring , bytestring , HUnit , QuickCheck , test-framework , test-framework-hunit , test-framework-quickcheck2 default-language: Haskell2010 benchmark benchmarks type: exitcode-stdio-1.0 hs-source-dirs: benchmarks main-is: BM.hs ghc-options: -Wall -threaded -rtsopts build-depends: base , base64-bytestring , bytestring , criterion , deepseq >=1.1 default-language: Haskell2010 source-repository head type: git location: git://github.com/haskell/base64-bytestring base64-bytestring-1.2.1.0/benchmarks/0000755000000000000000000000000007346545000015433 5ustar0000000000000000base64-bytestring-1.2.1.0/benchmarks/BM.hs0000644000000000000000000000462607346545000016275 0ustar0000000000000000{-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} module Main ( main ) where #if __GLASGOW_HASKELL__ > 702 #if !MIN_VERSION_bytestring(0,10,0) import Control.DeepSeq (NFData(rnf)) #endif import Criterion import Criterion.Main import qualified Data.ByteString as BS import qualified Data.ByteString.Base64 as B64 #endif main :: IO () main = #if __GLASGOW_HASKELL__ < 704 return () #else defaultMain [ env bs $ \ ~(bs25,bs100,bs1k,bs10k,bs100k,bs1mm) -> bgroup "encode" [ bgroup "25" [ bench "base64" $ whnf B64.encode bs25 ] , bgroup "100" [ bench "base64" $ whnf B64.encode bs100 ] , bgroup "1k" [ bench "base64" $ whnf B64.encode bs1k ] , bgroup "10k" [ bench "base64" $ whnf B64.encode bs10k ] , bgroup "100k" [ bench "base64" $ whnf B64.encode bs100k ] , bgroup "1mm" [ bench "base64" $ whnf B64.encode bs1mm ] ] , env bs' $ \ ~(bs25,bs100,bs1k,bs10k,bs100k,bs1mm) -> bgroup "decode" [ bgroup "25" [ bench "base64" $ whnf B64.decode bs25 ] , bgroup "100" [ bench "base64" $ whnf B64.decode bs100 ] , bgroup "1k" [ bench "base64" $ whnf B64.decode bs1k ] , bgroup "10k" [ bench "base64" $ whnf B64.decode bs10k ] , bgroup "100k" [ bench "base64" $ whnf B64.decode bs100k ] , bgroup "1mm" [ bench "base64" $ whnf B64.decode bs1mm ] ] ] where bss :: BS.ByteString bss = "ab%de^ghi*" bs = do let !a = BS.concat $ replicate 3 bss !b = BS.concat $ replicate 10 bss !c = BS.concat $ replicate 100 bss !d = BS.concat $ replicate 1000 bss !e = BS.concat $ replicate 10000 bss !f = BS.concat $ replicate 100000 bss return (a,b,c,d,e,f) bs' = do let !a = B64.encode (BS.concat $ replicate 3 bss) !b = B64.encode (BS.concat $ replicate 10 bss) !c = B64.encode (BS.concat $ replicate 100 bss) !d = B64.encode (BS.concat $ replicate 1000 bss) !e = B64.encode (BS.concat $ replicate 10000 bss) !f = B64.encode (BS.concat $ replicate 100000 bss) return (a,b,c,d,e,f) #if !MIN_VERSION_bytestring(0,10,0) instance NFData BS.ByteString where rnf bs = bs `seq` () #endif #endif base64-bytestring-1.2.1.0/tests/0000755000000000000000000000000007346545000014460 5ustar0000000000000000base64-bytestring-1.2.1.0/tests/Tests.hs0000644000000000000000000004525107346545000016125 0ustar0000000000000000{-# LANGUAGE DoAndIfThenElse #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Main (main) where import Test.Framework (Test, defaultMain, testGroup) import Test.Framework.Providers.QuickCheck2 (testProperty) import Test.Framework.Providers.HUnit (testCase) import Test.QuickCheck (Arbitrary(..)) import Control.Monad (liftM) import qualified Data.ByteString.Base64 as Base64 import qualified Data.ByteString.Base64.Lazy as LBase64 import qualified Data.ByteString.Base64.URL as Base64URL import qualified Data.ByteString.Base64.URL.Lazy as LBase64URL import Data.ByteString (ByteString) import qualified Data.ByteString as BS import Data.ByteString.Char8 () import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy.Char8 as L import Data.String import Test.HUnit hiding (Test) main :: IO () main = defaultMain tests data Impl bs = Impl { _label :: String , _encode :: bs -> bs , _decode :: bs -> Either String bs , _lenient :: bs -> bs } data UrlImpl bs = UrlImpl { _labelUrl :: String , _encodeUrl :: bs -> bs , _decodeUrl :: bs -> Either String bs , _encodeUrlNopad :: bs -> bs , _decodeUrlNopad :: bs -> Either String bs , _decodeUrlPad :: bs -> Either String bs , _lenientUrl :: bs -> bs } tests :: [Test] tests = [ testGroup "property tests" [ testsRegular b64impl , testsRegular lb64impl , testsURL b64uimpl , testsURL lb64uimpl ] , testGroup "unit tests" [ base64UrlUnitTests , lazyBase64UrlUnitTests ] ] where b64impl = Impl "Base64" Base64.encode Base64.decode Base64.decodeLenient lb64impl = Impl "LBase64" LBase64.encode LBase64.decode LBase64.decodeLenient b64uimpl = UrlImpl "Base64URL" Base64URL.encode Base64URL.decode Base64URL.encodeUnpadded Base64URL.decodeUnpadded Base64URL.decodePadded Base64URL.decodeLenient lb64uimpl = UrlImpl "LBase64URL" LBase64URL.encode LBase64URL.decode LBase64URL.encodeUnpadded LBase64URL.decodeUnpadded LBase64URL.decodePadded LBase64URL.decodeLenient testsRegular :: ( IsString bs , AllRepresentations bs , Show bs , Eq bs , Arbitrary bs ) => Impl bs -> Test testsRegular = testsWith base64_testData testsURL :: ( IsString bs , AllRepresentations bs , Show bs , Eq bs , Arbitrary bs ) => UrlImpl bs -> Test testsURL (UrlImpl l e d eu du dp dl) = testGroup l [ testsWith base64url_testData (Impl "Arbitrary Padding" e d dl) , testsWith base64url_testData (Impl "Required Padding" e dp dl) , testsWith base64url_testData_nopad (Impl "No padding" eu du dl) , testProperty "prop_url_pad_roundtrip" $ \bs -> Right bs == dp (e bs) , testProperty "prop_url_nopad_roundtrip" $ \bs -> Right bs == du (eu bs) , testProperty "prop_url_decode_invariant" $ \bs -> ((du (eu bs)) == (d (e bs))) || ((dp (e bs)) == d (e bs)) ] testsWith :: ( IsString bs , AllRepresentations bs , Show bs , Eq bs , Arbitrary bs ) => [(bs, bs)] -> Impl bs -> Test testsWith testData impl = testGroup label [ testProperty "decodeEncode" $ genericDecodeEncode encode decode , testProperty "decodeEncode Lenient" $ genericDecodeEncode encode (liftM Right lenient) , testGroup "base64-string tests" (string_tests testData impl) ] where label = _label impl encode = _encode impl decode = _decode impl lenient = _lenient impl instance Arbitrary ByteString where arbitrary = liftM B.pack arbitrary -- Ideally the arbitrary instance would have arbitrary chunks as well as -- arbitrary content instance Arbitrary L.ByteString where arbitrary = liftM L.pack arbitrary -- | Decoding an encoded sintrg should produce the original string. genericDecodeEncode :: (Arbitrary bs, Eq bs) => (bs -> bs) -> (bs -> Either String bs) -> bs -> Bool genericDecodeEncode enc dec x = case dec (enc x) of Left _ -> False Right x' -> x == x' -- -- Unit tests from base64-string -- Copyright (c) Ian Lynagh, 2005, 2007. -- string_tests :: forall bs . ( IsString bs , AllRepresentations bs , Show bs , Eq bs ) => [(bs, bs)] -> Impl bs -> [Test] string_tests testData (Impl _ encode decode decodeLenient) = base64_string_test encode decode testData ++ base64_string_test encode decodeLenient' testData where decodeLenient' = liftM Right decodeLenient base64_testData :: IsString bs => [(bs, bs)] base64_testData = [("", "") ,("\0", "AA==") ,("\255", "/w==") ,("E", "RQ==") ,("Ex", "RXg=") ,("Exa", "RXhh") ,("Exam", "RXhhbQ==") ,("Examp", "RXhhbXA=") ,("Exampl", "RXhhbXBs") ,("Example", "RXhhbXBsZQ==") ,("Ex\0am\254ple", "RXgAYW3+cGxl") ,("Ex\0am\255ple", "RXgAYW3/cGxl") ] base64url_testData :: IsString bs => [(bs, bs)] base64url_testData = [("", "") ,("\0", "AA==") ,("\255", "_w==") ,("E", "RQ==") ,("Ex", "RXg=") ,("Exa", "RXhh") ,("Exam", "RXhhbQ==") ,("Examp", "RXhhbXA=") ,("Exampl", "RXhhbXBs") ,("Example", "RXhhbXBsZQ==") ,("Ex\0am\254ple", "RXgAYW3-cGxl") ,("Ex\0am\255ple", "RXgAYW3_cGxl") ] base64url_testData_nopad :: IsString bs => [(bs, bs)] base64url_testData_nopad = [("", "") ,("\0", "AA") ,("\255", "_w") ,("E", "RQ") ,("Ex", "RXg") ,("Exa", "RXhh") ,("Exam", "RXhhbQ") ,("Examp", "RXhhbXA") ,("Exampl", "RXhhbXBs") ,("Example", "RXhhbXBsZQ") ,("Ex\0am\254ple", "RXgAYW3-cGxl") ,("Ex\0am\255ple", "RXgAYW3_cGxl") ] -- | Generic test given encod enad decode funstions and a -- list of (plain, encoded) pairs base64_string_test :: ( AllRepresentations bs , Eq bs , Show bs ) => (bs -> bs) -> (bs -> Either String bs) -> [(bs, bs)] -> [Test] base64_string_test enc dec testData = [ testCase ("base64-string: Encode " ++ show plain) (encoded_plain @?= rawEncoded) | (rawPlain, rawEncoded) <- testData , -- For lazy ByteStrings, we want to check not only ["foo"], but -- also ["f","oo"], ["f", "o", "o"] and ["fo", "o"]. The -- allRepresentations function gives us all representations of a -- lazy ByteString. plain <- allRepresentations rawPlain , let encoded_plain = enc plain ] ++ [ testCase ("base64-string: Decode " ++ show encoded) (decoded_encoded @?= Right rawPlain) | (rawPlain, rawEncoded) <- testData , -- Again, we need to try all representations of lazy ByteStrings. encoded <- allRepresentations rawEncoded , let decoded_encoded = dec encoded ] class AllRepresentations a where allRepresentations :: a -> [a] instance AllRepresentations ByteString where allRepresentations bs = [bs] instance AllRepresentations L.ByteString where -- TODO: Use L.toStrict instead of (B.concat . L.toChunks) once -- we can rely on a new enough bytestring allRepresentations = map L.fromChunks . allChunks . B.concat . L.toChunks where allChunks b | B.length b < 2 = [[b]] | otherwise = concat [ map (prefix :) (allChunks suffix) | let splits = zip (B.inits b) (B.tails b) -- We don't want the first split (empty prefix) -- The last split (empty suffix) gives us the -- [b] case (toChunks ignores an "" element). , (prefix, suffix) <- tail splits ] base64UrlUnitTests :: Test base64UrlUnitTests = testGroup "Base64URL unit tests" [ testGroup "URL decodePadded" [ padtest "<" "PA==" , padtest "<<" "PDw=" , padtest "<" "PDw_Pz4=" , padtest "<>" "PDw_Pz4-" ] , testGroup "URL decodeUnpadded" [ nopadtest "<" "PA" , nopadtest "<<" "PDw" , nopadtest "<" "PDw_Pz4" , nopadtest "<>" "PDw_Pz4-" ] , testGroup "Padding validity" [ testCase "Padding fails everywhere but end" $ do Base64.decode "=eAoeAo=" @=? Left "invalid padding at offset: 0" Base64.decode "e=AoeAo=" @=? Left "invalid padding at offset: 1" Base64.decode "eA=oeAo=" @=? Left "invalid padding at offset: 2" Base64.decode "eAo=eAo=" @=? Left "invalid padding at offset: 3" Base64.decode "eAoe=Ao=" @=? Left "invalid padding at offset: 4" Base64.decode "eAoeA=o=" @=? Left "invalid padding at offset: 5" ] , testGroup "Non-canonical encodings fail and canonical encodings succeed" [ testCase "roundtrip for d ~ ZA==" $ do Base64.decode "ZE==" @=? Left "non-canonical encoding detected at offset: 1" Base64.decode "ZK==" @=? Left "non-canonical encoding detected at offset: 1" Base64.decode "ZA==" @=? Right "d" , testCase "roundtrip for f` ~ ZmA=" $ do Base64.decode "ZmC=" @=? Left "non-canonical encoding detected at offset: 2" Base64.decode "ZmD=" @=? Left "non-canonical encoding detected at offset: 2" Base64.decode "ZmA=" @=? Right "f`" , testCase "roundtrip for foo` ~ Zm9vYA==" $ do Base64.decode "Zm9vYE==" @=? Left "non-canonical encoding detected at offset: 5" Base64.decode "Zm9vYK==" @=? Left "non-canonical encoding detected at offset: 5" Base64.decode "Zm9vYA==" @=? Right "foo`" , testCase "roundtrip for foob` ~ Zm9vYmA=" $ do Base64.decode "Zm9vYmC=" @=? Left "non-canonical encoding detected at offset: 6" Base64.decode "Zm9vYmD=" @=? Left "non-canonical encoding detected at offset: 6" Base64.decode "Zm9vYmA=" @=? Right "foob`" ] , testGroup "Base64URL padding case unit tests" [ testCase "stress arbitarily padded URL strings" $ do Base64URL.decode "P" @=? Left "Base64-encoded bytestring has invalid size" Base64URL.decode "PA" @=? Right "<" Base64URL.decode "PDw" @=? Right "<<" Base64URL.decode "PDw_" @=? Right "<" "PDw_Pz4=" , padtest "<>" "PDw_Pz4-" ] , testGroup "URL decodeUnpadded" [ nopadtest "<" "PA" , nopadtest "<<" "PDw" , nopadtest "<" "PDw_Pz4" , nopadtest "<>" "PDw_Pz4-" ] , testGroup "Padding validity" [ testCase "Padding fails everywhere but end" $ do LBase64.decode "=eAoeAo=" @=? Left "invalid padding at offset: 0" LBase64.decode "e=AoeAo=" @=? Left "invalid padding at offset: 1" LBase64.decode "eA=oeAo=" @=? Left "invalid padding at offset: 2" LBase64.decode "eAo=eAo=" @=? Left "invalid padding at offset: 3" LBase64.decode "eAoe=Ao=" @=? Left "invalid padding at offset: 4" LBase64.decode "eAoeA=o=" @=? Left "invalid padding at offset: 5" ] , testGroup "LBase64URL padding case unit tests" [ testCase "stress arbitarily padded URL strings" $ do LBase64URL.decode "P" @=? Left "Base64-encoded bytestring has invalid size" LBase64URL.decode "PA" @=? Right "<" LBase64URL.decode "PDw" @=? Right "<<" LBase64URL.decode "PDw_" @=? Right "< case decode bs of Left err -> putStrLn err Right p -> B.putStr p "decodeLenient" -> B.putStr (decodeLenient bs) "encode" -> B.putStr (encode bs) "read" -> B.putStr bs case files of [] -> B.getContents >>= xcode fs -> mapM_ (\f -> B.readFile f >>= xcode) fs base64-bytestring-1.2.1.0/utils/transcode.py0000644000000000000000000000036707346545000017020 0ustar0000000000000000#!/usr/bin/env python import binascii, sys funcs = { 'decode': binascii.a2b_base64, 'encode': binascii.b2a_base64, 'read': lambda x:x, } f = funcs[sys.argv[1]] for n in sys.argv[2:]: sys.stdout.write(f(open(n).read()))