2022-05-17 00:23:30 +02:00
#!/ usr / bin / env runhaskell
2024-05-19 13:23:39 +02:00
2022-05-17 00:23:30 +02:00
{- # LANGUAGE DeriveDataTypeable # -}
module Main where
import System.Console.CmdArgs
import Control.Arrow
2024-05-19 13:23:39 +02:00
import Data.ByteString.UTF8 as BSU -- from utf8-string
2022-05-17 00:23:30 +02:00
import qualified Data.ByteString.Char8 as C
2024-05-02 23:12:40 +02:00
import Text.Regex.TDFA
2024-05-19 13:23:39 +02:00
import Encoding.Base2 ( enc2 , dec2 )
import Encoding.Base8 ( enc8 , dec8 )
import Encoding.Base10 ( enc10 , dec10 )
import Encoding.Base16 ( enc16 , dec16 )
import Encoding.Base32 ( enc32 , dec32 )
import Encoding.Base58 ( enc58 , dec58 )
import Encoding.Base62 ( enc62 , dec62 )
import Encoding.Base64 ( enc64 , dec64 , enc64url , dec64url )
import Encoding.Base85 ( enc85 , dec85 )
import Encoding.Base91 ( enc91 , dec91 )
import Encoding.Url ( encurl , decurl )
import Encoding.Xx ( encxx , decxx )
import Encoding.QuotedPrintable ( encqp , decqp )
import Encoding.UnixToUnix ( encuu , decuu )
import Encoding.Yenc ( ency , decy )
2024-05-22 21:58:40 +02:00
import Encoding.Rotate ( rotate )
2024-05-19 13:23:39 +02:00
2022-05-17 00:23:30 +02:00
data Based = Decode {
b91 :: Bool ,
b85 :: Bool ,
b64 :: Bool ,
2022-05-22 22:48:44 +02:00
b64url :: Bool ,
2022-09-19 23:11:13 +02:00
url :: Bool ,
2022-05-17 00:23:30 +02:00
b62 :: Bool ,
2022-05-19 23:55:26 +02:00
b58 :: Bool ,
2022-05-17 00:23:30 +02:00
b32 :: Bool ,
2022-05-19 23:55:26 +02:00
b16 :: Bool ,
b10 :: Bool ,
2022-05-22 22:48:44 +02:00
b8 :: Bool ,
b2 :: Bool ,
2022-05-19 23:55:26 +02:00
qp :: Bool ,
uu :: Bool ,
xx :: Bool ,
2024-05-02 23:12:40 +02:00
yenc :: Bool ,
2024-05-22 21:58:40 +02:00
rot :: Maybe Int ,
2024-05-02 23:12:40 +02:00
solve :: Bool
2022-05-17 00:23:30 +02:00
}
| Encode {
b91 :: Bool ,
b85 :: Bool ,
b64 :: Bool ,
2022-05-22 22:48:44 +02:00
b64url :: Bool ,
2022-09-19 23:11:13 +02:00
url :: Bool ,
2022-05-17 00:23:30 +02:00
b62 :: Bool ,
2022-05-19 23:55:26 +02:00
b58 :: Bool ,
2022-05-17 00:23:30 +02:00
b32 :: Bool ,
2022-05-19 23:55:26 +02:00
b16 :: Bool ,
b10 :: Bool ,
2022-05-22 22:48:44 +02:00
b8 :: Bool ,
b2 :: Bool ,
2022-05-19 23:55:26 +02:00
qp :: Bool ,
uu :: Bool ,
xx :: Bool ,
2024-05-22 21:58:40 +02:00
yenc :: Bool ,
rot :: Maybe Int
}
2022-05-17 00:23:30 +02:00
deriving ( Show , Data , Typeable )
2022-05-22 22:48:44 +02:00
-- helper functions
2024-04-18 00:18:39 +02:00
2024-04-20 01:20:53 +02:00
-- convertToByteString :: String -> Either String C.ByteString
-- convertToByteString str =
-- case BSU.fromString str of
-- Just bs -> Right bs
-- Nothing -> Left "Failed to convert string to ByteString."
2024-04-18 00:18:39 +02:00
2024-04-28 23:47:31 +02:00
-- decodeFromBase91 :: String -> Either String C.ByteString
-- decodeFromBase91 decoded =
2024-04-20 01:20:53 +02:00
-- case B91.decode of
2024-04-28 23:47:31 +02:00
-- decoded | C.null decoded -> Left "Failed to decode from base91"
-- | otherwise -> Right decoded
2024-04-18 00:18:39 +02:00
2022-05-22 22:48:44 +02:00
binToInt :: [ Int ] -> Int
binToInt [] = 0
binToInt ( x : xs ) = x + 2 * binToInt xs
octToInt :: [ Int ] -> Int
octToInt [] = 0
octToInt ( x : xs ) = x + 8 * octToInt xs
-- base functions
2022-05-17 00:23:30 +02:00
-- without the show func, sequences like \n will not be shown as characters but will be executed as newline
2024-04-18 00:18:39 +02:00
2024-05-02 23:12:40 +02:00
base91Regex = " ^[!-~]*$ "
2024-05-05 00:04:19 +02:00
base85Regex = " ^[0-9A-Za-z!#$%&()*+,-;<=>?@^_`{|}~]+$ "
2024-05-02 23:12:40 +02:00
-- base85Regex = "^[A-Za-u0-9!\"#$%&((*+,-./;:<=@[]\\`]*$"
base64Regex = " ^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$ "
base58Regex = " ^[1-9A-HJ-NP-Za-km-z]+$ " -- incorrect
base32Regex = " ^(?:[A-Z2-7]{8})*(?:[A-Z2-7]{2}={6}|[A-Z2-7]{4}={4}|[A-Z2-7]{5}={3}|[A-Z2-7]{7}=)?$ "
base16Regex = " ^[0-9A-FXx]*$ "
2024-05-05 23:45:05 +02:00
base10Regex = " ^[0-9]*$ "
base8Regex = " ^[0-7]*$ "
2024-05-05 00:04:19 +02:00
base2Regex = " ^[01]*$ "
urlRegex = " ^[a-zA-Z0-9%]*$ "
2024-05-02 23:12:40 +02:00
solveEnc :: String -> String
solveEnc input =
2024-05-03 23:36:35 +02:00
let isBase91 = BSU . fromString input =~ base91Regex :: Bool
2024-05-05 00:04:19 +02:00
isBase85 = BSU . fromString input =~ base85Regex :: Bool
2024-05-03 23:36:35 +02:00
isBase64 = BSU . fromString input =~ base64Regex :: Bool
2024-05-02 23:12:40 +02:00
isBase58 = BSU . fromString input =~ base58Regex :: Bool
isBase32 = BSU . fromString input =~ base32Regex :: Bool
isBase16 = BSU . fromString input =~ base16Regex :: Bool
2024-05-05 23:45:05 +02:00
isBase10 = BSU . fromString input =~ base10Regex :: Bool
isBase8 = BSU . fromString input =~ base8Regex :: Bool
2024-05-05 00:04:19 +02:00
isBase2 = BSU . fromString input =~ base2Regex :: Bool
isURL = BSU . fromString input =~ urlRegex :: Bool
2024-05-03 23:36:35 +02:00
base91Result = if isBase91 then " \ n Trying base91: \ n " ++ dec91 input else " "
2024-05-05 00:04:19 +02:00
base85Result = if isBase85 then " \ n Trying base85: \ n " ++ dec85 input else " "
2024-05-02 23:12:40 +02:00
base64Result = if isBase64 then " \ n Trying base64: \ n " ++ dec64 input else " "
base58Result = if isBase58 then " \ n Trying base58: \ n " ++ dec58 input else " "
base32Result = if isBase64 then " \ n Trying base32: \ n " ++ dec32 input else " "
base16Result = if isBase16 then " \ n Trying base16: \ n " ++ dec16 input else " "
2024-05-05 23:45:05 +02:00
base10Result = if isBase10 then " \ n Trying base10: \ n " ++ dec10 input else " "
2024-05-05 00:04:19 +02:00
base2Result = if isBase2 then " \ n Trying base2: \ n " ++ dec2 input else " "
2024-05-05 23:45:05 +02:00
base8Result = if isBase8 then " \ n Trying base8: \ n " ++ dec8 input else " "
2024-05-05 00:04:19 +02:00
urlResult = if isURL then " \ n Trying URL decode: \ n " ++ decurl input else " "
2024-05-05 23:45:05 +02:00
results = filter ( not . null ) [ base91Result , base85Result , base64Result , base58Result , base32Result , base16Result , base10Result , base8Result , base2Result , urlResult ]
2024-05-02 23:12:40 +02:00
in
if null results
then " Not able to solve the encoding. \ n "
else unlines results
--
-- | input =~ base64Regex = dec64 input
-- | input =~ base32Regex = dec32 input
-- | otherwise = "Cannot decode: " ++ input
--
-- if BSU.fromString input =~ base64Regex :: Bool
-- then dec64 input
-- else "Not Base64.\n"
-- ++ if BSU.fromString input =~ base32Regex :: Bool
-- then dec32 input
-- else "Not able to solve the encoding.\n"
2022-05-19 23:55:26 +02:00
2024-05-19 13:23:39 +02:00
2024-05-05 23:45:05 +02:00
-- optionHandler :: EncodeOptions -> Text -> Text
2022-05-17 00:23:30 +02:00
optionHandler Decode { b91 = True } = dec91
optionHandler Encode { b91 = True } = enc91
optionHandler Decode { b85 = True } = dec85
optionHandler Encode { b85 = True } = enc85
optionHandler Decode { b64 = True } = dec64
optionHandler Encode { b64 = True } = enc64
2022-05-22 22:48:44 +02:00
optionHandler Decode { b64url = True } = dec64url
optionHandler Encode { b64url = True } = enc64url
2022-09-19 23:11:13 +02:00
optionHandler Decode { url = True } = decurl
optionHandler Encode { url = True } = encurl
2022-05-17 00:23:30 +02:00
optionHandler Decode { b62 = True } = dec62
optionHandler Encode { b62 = True } = enc62
2022-05-19 23:55:26 +02:00
optionHandler Decode { b58 = True } = dec58
optionHandler Encode { b58 = True } = enc58
2022-05-17 00:23:30 +02:00
optionHandler Decode { b32 = True } = dec32
optionHandler Encode { b32 = True } = enc32
optionHandler Decode { b16 = True } = dec16
optionHandler Encode { b16 = True } = enc16
2022-05-19 23:55:26 +02:00
optionHandler Decode { b10 = True } = dec10
optionHandler Encode { b10 = True } = enc10
2022-05-22 22:48:44 +02:00
optionHandler Decode { b8 = True } = dec8
optionHandler Encode { b8 = True } = enc8
optionHandler Decode { b2 = True } = dec2
optionHandler Encode { b2 = True } = enc2
2022-05-19 23:55:26 +02:00
optionHandler Decode { qp = True } = decqp
optionHandler Encode { qp = True } = encqp
2024-05-05 00:04:19 +02:00
optionHandler Encode { uu = True } = encuu
optionHandler Decode { uu = True } = decuu
2022-05-19 23:55:26 +02:00
optionHandler Decode { xx = True } = decxx
optionHandler Encode { xx = True } = encxx
optionHandler Decode { yenc = True } = decy
optionHandler Encode { yenc = True } = ency
2024-05-22 21:58:40 +02:00
optionHandler Encode { rot = Just n } = rotate n
optionHandler Decode { rot = Just n } = rotate n
2024-05-02 23:12:40 +02:00
optionHandler Decode { solve = True } = solveEnc
2022-05-17 00:23:30 +02:00
2023-07-25 23:17:25 +02:00
decodeMode :: Based
decodeMode = Decode {
2022-05-17 00:23:30 +02:00
b91 = def &= help " decode base91 " ,
b85 = def &= help " decode base85 " ,
b64 = def &= help " decode base64 " ,
2022-05-22 22:48:44 +02:00
b64url = def &= help " decode base64Url " ,
2022-09-19 23:11:13 +02:00
url = def &= help " decode URI " ,
2022-05-17 00:23:30 +02:00
b62 = def &= help " decode base62 " ,
2022-05-19 23:55:26 +02:00
b58 = def &= help " decode base58 " ,
2022-05-17 00:23:30 +02:00
b32 = def &= help " decode base32 " ,
2022-05-19 23:55:26 +02:00
b16 = def &= help " decode base16 " ,
2022-05-22 22:48:44 +02:00
b10 = def &= help " decode decimal from hex " ,
b8 = def &= help " decode octal from hex " ,
b2 = def &= help " decode binary from hex " ,
2022-05-19 23:55:26 +02:00
qp = def &= help " decode quoted-printable " ,
uu = def &= help " decode uu " ,
xx = def &= help " decode xx " ,
2024-05-02 23:12:40 +02:00
yenc = def &= help " decode yEncode " ,
2024-05-22 21:58:40 +02:00
rot = def &= help " rotate characters by n positions " ,
2024-05-02 23:12:40 +02:00
solve = def &= help " solve encoding "
2022-05-17 00:23:30 +02:00
} &= help " Decode chosen base " &= auto
2023-07-25 23:17:25 +02:00
encodeMode :: Based
encodeMode = Encode {
2022-05-17 00:23:30 +02:00
b91 = def &= help " encode base91 " ,
b85 = def &= help " encode base85 " ,
b64 = def &= help " encode base64 " ,
2022-05-22 22:48:44 +02:00
b64url = def &= help " encode base64Url " ,
2022-09-19 23:11:13 +02:00
url = def &= help " encode URI " ,
2022-05-17 00:23:30 +02:00
b62 = def &= help " encode base62 " ,
2022-05-19 23:55:26 +02:00
b58 = def &= help " encode base58 " ,
2022-05-17 00:23:30 +02:00
b32 = def &= help " encode base32 " ,
2022-05-19 23:55:26 +02:00
b16 = def &= help " encode base16 " ,
b10 = def &= help " encode base10 to hex " ,
2022-05-22 22:48:44 +02:00
b8 = def &= help " encode octal to hex " ,
b2 = def &= help " encode binary to hex " ,
2022-05-19 23:55:26 +02:00
qp = def &= help " encode quoted-printable " ,
uu = def &= help " encode uu " ,
xx = def &= help " encode xx " ,
2024-05-22 21:58:40 +02:00
yenc = def &= help " encode yEncode " ,
rot = def &= help " rotate characters by n positions "
2022-05-17 00:23:30 +02:00
} &= help " Encode chosen base "
2023-07-25 23:17:25 +02:00
main :: IO ()
2024-05-22 21:58:40 +02:00
main = cmdArgs ( modes [ decodeMode , encodeMode ] &= help " Based, when Cyberchef doesn't cut it. \ n To see every parameter of every mode use --help=all " &= program " based " &= summary " based v0.4 " ) >>= interact . optionHandler