#!/usr/bin/perl ##################################################################### # # CONVERTERS 1.0 Last Update: 2023.3.15 # # This program demonstrates the use of Str2Txt(), Txt2Str(), # Str2Hex(), Hex2Str(), EncodeBase64(), DecodeBase64(), # EscapeURL(), UnescapeURL(), and simple StrXOR() encryption function. # # Str2Txt() converts any binary string to plain text that is made up # of just letters and numbers only. Txt2Str() does the opposite. # Str2Txt() stores two repeated characters as one byte, so it is # possible to end up with a plain text string that is shorter # than the input binary string. # # Written by Zsolt N Perry (also known as Zsolt Nagy Perge). # For questions, comments, feature requests, or bug reports, # write to zsnp@juno.com. # This Perl script was tested with TinyPerl 5.8 under Windows XP. # This file was downloaded from http://www.wzsn.net/perl # # THIS ENTIRE SOURCE CODE IS FREEWARE. # If you want to incorporate it or parts of it into your program, # just copy and paste whatever you need! There is no need to ask # for permission. This software is distributed "AS IS." There is # no warranty of any kind. The author will not be held liable for # any loss resulting from the use or misuse of this software. # ##################################################################### use 5.004; use strict; use warnings; $| = 1; # DO NOT MODIFY THE FOLLOWING STRING. THIS STRING CONTAINS # CHARACTER SETS AND LOOKUP TABLES FOR THE Str2Txt() CONVERTER: my $RANDOM = '47696F3164497142674F626534726153486E43636B3875456D57554E54684D767C746C70463641373220392F782E7752664479507330334C35595E0A804B3B277E860D882D60897A584A295D243A237B847D2C8B8540268E82515A216A005B5C1B223E2881833F875F2A093D252B568C8A3C04A98D8F08A71D129593A3A29A0B989F1A0E9E1C1F160F9611170119079997A69B101505A09C7F0C1E90181406139DA59194AA0302A1A492A8BDB2E3C7B7D4DFC8ADD0ACCBCDC9D7D9CAC5BCD6B4CCB9BEE0DAB8D5C0BBB5E2C1CED1ABDED3BFDBB3CFAFD8BADCAEB0C3C4C2D2C6DDE1B6B1F7F6FFFCE9E8EEEDEFF4F3E4F5E5EAFAECF2F8F0E7FBFEEBE6FDF1F95D8CA6A572959E8E766A3B7F99428388938A799F9D94878B9C8D826085789A86295B614E4C6C563F634A696D52442D2B350328360C382527152A4D3E716B626655260712311724001005493D371E1B0933592F0F1C1A6E1948395A5E5F4B3A68450E0A13040B30081D015C142218110223060D3421161F2E2C32474F205140983C64586550544167434670536F7457759BA2A97BA37A8990808F7E9297A0848196A77D7CA8A19177AA73A4CEB5B3D9D5DAE3ACD3BFC9E2AFC5C1D7C8BDABC2D1C7CBDDDBDCBCDFAEB2B8BBB6C0B7CCD4B4CDDED0B0C6BEB9D6BAC4D2D8E0CFB1C3E1CAADEFF1FCF8E9E8F2FBF4EBEAECF7FEF5EEEDF0E5E4F6FFF3F9E7FDFAE6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000263706110C0F3102072500000000000000130E3C1D011A031C050A2F172B142718152100293A302D0820320000000000001028193D0D16342E380B3912232C2A1F332236041B0924353B1E0000000000534537477449323858764A6A3465423561336C414E51664C5063467548447A705952726D7739304F62546F4D6E57684B56365A7167787331696B55794364'; my $TX = pack('H*', $RANDOM); # P R O G R A M G O E S H E R E . . . my $ORIGINAL = 'In the beginning God created the heavens & the earth!'; print "\n\nORIGINAL STRING: $ORIGINAL"; my $TEXTONLY = Str2Txt($ORIGINAL); print "\n\nSTR2TXT ENCODED: $TEXTONLY"; my $BACK_TO_ORIGINAL = Txt2Str($TEXTONLY); print "\nTXT2STR DECODED: $BACK_TO_ORIGINAL"; my $BASE64 = EncodeBase64($ORIGINAL); print "\n\nBase64:$BASE64"; my $DECODED_FROM_B64 = DecodeBase64($BASE64); print "\nBase64:$DECODED_FROM_B64"; my $ESC = EscapeURL($ORIGINAL); print "\n\n ESCAPED: $ESC"; my $UNESC = UnescapeURL($ESC); print "\nUNESCAPED: $UNESC"; my $PASSWORD = 'A3D'; my $XORd = StrXOR($ORIGINAL, $PASSWORD); print "\n\nXOR'd STRING: $XORd"; my $BACK_FROM_XOR = StrXOR($XORd, $PASSWORD); print "\nXOR'd STRING: $BACK_FROM_XOR"; my $ToHex = Str2Hex($ORIGINAL); print "\n\nHex: $ToHex"; print "\nBack to original: ", Hex2Str($ToHex); exit; ################################################## # String | v2021.2.5 # This function converts any binary string to text # format that contains nothing but letters and numbers. # # Generally, the output string will be about 20% larger # than the input string. Repeated characters will be # compressed somewhat. The output will look nothing # resembling the input string. # # HOW IT WORKS: # # According to a study at Cornell University, the most # frequently used letter in the English alphabet is the # letter E, followed by TAOINSRHDLUCMFYWGPBVKXQJZ. # This function uses the above information to encode # input text in a way that it uses less space by grouping # frequently used characters together with space, period, # forward slash, and the "|" character. All of these are # frequently used and often appear right next to each other. # In the second group, we have every other symbol along # with \0 \r \n and \xFF. In the last 3 groups, we have # all other remaining characters. # # The encoding assumes that we are starting with group 1. # If a character is encountered which is in group 2, an # escape character will be inserted before the character. # If the exact same escape character appears twice next # to each other, it signals a compressed character. # Each extra escape character stands for two characters. # The escape characters are the last 5 bytes of the # global string $TX. # # The advantage of converting data to "abc format" is # that abc data can be safely inserted into an URL # argument or HTML file, or it can be enclosed with # single or double quotes in Perl or JavaScript. # It can also be passed as an argument to a program. # # Usage: STRING = Str2Txt(STRING) # sub Str2Txt { defined $_[0] or return ''; my $L = length($_[0]); my $P; my $c = -1; my $ESC = 0; my $REPEAT = 0; my $OUT = ''; my $output_char; my $prev_char; my $prev_esc; for (my $i = 0; $i < $L; $i++) { $prev_char = $c; $c = vec($_[0], $i, 8); if ($c == $prev_char) { if (++$REPEAT < 2) { $OUT .= $output_char; } else { substr($OUT, length($OUT) - 1) = ''; $OUT .= substr($TX, $ESC + 697, 1); # ESCAPE CHARS $REPEAT = 0; } } else { $REPEAT = 0; $P = vec($TX, $c + 256, 8); # REVERSE INDEX if ($P < 0) { $ESC = $P = 0; } else { $prev_esc = $ESC; $ESC = int($P / 57); $P -= $ESC * 57; if ($ESC != $prev_esc) { $OUT .= substr($TX, $ESC + 697, 1); # ESCAPE CHARS } $output_char = substr($TX, $P + 640, 1); # OUTPUT_SET $OUT .= $output_char; } } } return $OUT; } ################################################## # String | v2021.2.4 # This is the opposite of the Str2Txt() function. # This function converts a string that contains # nothing but numbers and letters to a binary string. # This function requires a global variable named $TX # which contains character sets and index tables. # Usage: STRING = Txt2Str(STRING) # sub Txt2Str { defined $_[0] or return ''; my $L = length($_[0]); my $c; my $P; my $ESC = 0; my $OUT = ''; my $output_char = ''; my $prev_esc; for (my $i = 0; $i < $L; $i++) { $c = vec($_[0], $i, 8); $P = vec($TX, $c + 512, 8); # OUTPUT_IDX if ($P >= 57) { $prev_esc = $ESC; $ESC = $P - 57; if ($prev_esc == $ESC) { $OUT .= $output_char; $OUT .= $output_char; } } else { $P += $ESC * 57; $output_char = ($P < 256) ? substr($TX, $P, 1) : ' '; # REVERSE_SET $OUT .= $output_char; } } return $OUT; } ################################################## # String | v2022.11.4 # This function converts a Base64 encoded string # back to its original form using the standard # Base64 converter algorithm. # # The first argument should be a string. The second # argument MAY contain a custom 64-byte character set. # # Usage: STRING = DecodeBase64(STRING, [CHARSET]) # sub DecodeBase64 { defined $_[0] or return ''; my ($i, $OUT, $LUT, $CHARSET, $A, $B, $C, $D) = (0, '', '', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'); # PREPARATION: Create lookup table for decoding. vec($LUT, 255, 8) = 0; if (defined $_[1] && length($_[1]) >= 64) { $CHARSET = $_[1]; } else { vec($LUT, 45, 8) = 62; # Use '-' instead of '+' vec($LUT, 95, 8) = 63; # Use '_' instead of '/' } for (my $i = 0; $i < 64; $i++) { vec($LUT, vec($CHARSET, $i, 8), 8) = $i; } # Decode Base64 string. my $L = length($_[0]); while ($i < $L) { # Read 4 bytes. $A = vec($LUT, vec($_[0], $i++, 8), 8); $B = vec($LUT, vec($_[0], $i++, 8), 8); $C = vec($LUT, vec($_[0], $i++, 8), 8); $D = vec($LUT, vec($_[0], $i++, 8), 8); # Write 3 bytes. $OUT .= chr((($A << 2) | (($B >> 4) & 3)) & 255); $OUT .= chr((($B << 4) | ($C >> 2)) & 255); $OUT .= chr(((($C & 3) << 6) | $D) & 255); } # Set string length. my $DIFF = !$C + !$D; return substr($OUT, 0, length($OUT) - $DIFF); } ################################################## # String | v2022.11.4 # This function converts a string to base64 text # using the standard Base64 encoding algorithm. # # The first argument should be a string. # The second argument MAY contain a custom 65-byte # character set. The 65th byte will be used for padding. # # The second argument MAY also be 0 or 1: # 0 = Use standard Base64 encoding which ends with +/ (default) # 1 = Use web-safe Base64 encoding which ends with -_ # # Usage: STRING = EncodeBase64(STRING, [CHARSET]) # sub EncodeBase64 { defined $_[0] or return ''; # Prepare character set to use for encoding. my $PADDING = '='; my $BASE64 = defined $_[1] ? $_[1] : 0; if (length($BASE64) >= 64) { $PADDING = substr($BASE64, 64, 1); } else { $BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' . (($BASE64 eq '1') ? '-_' : '+/'); } my ($i, $OUT, $L) = (0, '', length($_[0])); while ($i < $L) { # Read 3 bytes. my $A = vec($_[0], $i++, 8); my $B = vec($_[0], $i++, 8); my $C = vec($_[0], $i++, 8); # Write 4 bytes. $OUT .= substr($BASE64, $A >> 2, 1); $OUT .= substr($BASE64, (($A & 3) << 4) | ($B >> 4), 1); $OUT .= substr($BASE64, (($B & 15) << 2) | (($C >> 6) & 3), 1); $OUT .= substr($BASE64, $C & 63, 1); } # Replace last couple of bytes with padding. my $DIFF = $i - $L; substr($OUT, length($OUT) - $DIFF, $DIFF) = $PADDING x $DIFF; return $OUT; } ################################################## # String | v2022.2.28 # Converts a string to a series of lowercase # hexadecimal numbers which may include a separator. # In list context, it returns a list of hexadecimal # numbers, otherwise returns a string. # # Usage: STRING = Str2Hex(STRING, [SEPARATOR]) # ARRAY = Str2Hex(STRING) # sub Str2Hex { defined $_[0] or return ''; if (wantarray) { return unpack('(H2)*', $_[0]); } my $S = defined $_[1] ? $_[1] : ''; return length($S) ? join($S, unpack('(H2)*', $_[0])) : unpack('H*', $_[0]); } ################################################## # String | v2022.10.18 # Converts a string containing a series of # hexadecimal numbers to an ASCII string. # # Usage: STRING = Hex2Str(STRING) # sub Hex2Str { my $S = defined $_[0] ? $_[0] : ''; $S =~ tr|0-9a-fA-F||cd; # Remove everything else except hexadecimal digits return length($S) ? pack('H*', $S) : ''; } ################################################## # String | v2020.6.16 # This function is similar to the escape() function # in JavaScript. It takes a string and converts the # special characters to %XX format where XX is # a hexadecimal number. # # Usage: STRING = EscapeURL(STRING) # # Example: "+Hello World!" --> "%2BHello+World%21" # sub EscapeURL { my $X = defined $_[0] ? $_[0] : ''; my $L = length($X); $L or return ''; my ($i, $j, $Z, $C) = (0, 0, ''); while ($i < $L) { $C = vec($X, $i++, 8); if ($C == 32) { $C = 43; } elsif (($C < 44 || $C > 122) || ($C > 90 && $C < 95) || ($C == 60 || $C == 62)) { $Z .= '%' . sprintf("%.02X", $C); $j += 3; next; } vec($Z, $j++, 8) = $C; } return $Z; } ################################################## # String | v2019.8.29 # This function converts an URL string to regular # binary string. It's the opposite of the EscapeURL() # function. If it encounters any invalid codes, # those characters will be included as part of the # string. If it encounters an unexpected end of # string, it will produce no warnings and no errors. # # Usage: STRING = UnescapeURL(STRING) # sub UnescapeURL { my $X = defined $_[0] ? $_[0] : ''; my $L = length($X); $L or return ''; my $HEX = '0123456789ABCDEF'; my $i = index($X, '%'); # Find first encoded character return $X if ($i < 0); # Found none? -> Return original string my $j = $i - 1; my $C = 0; my $D = 0; $X =~ tr|+| |; for (; $i < length($X); $i++) { $C = vec($X, $i, 8); if ($C == 37) { $C = substr($X, ++$i, 1); # Grab first hex digit last if (length($C) == 0); # Unexpected end of string? $C = index($HEX, uc($C)); # Expecting hex digit if ($C < 0) { $i--; next; } # Not a hex digit? $D = substr($X, ++$i, 1); # Grab second digit if (length($D)) # Got it! { $D = index($HEX, uc($D)); # Expecting hex digit if ($D < 0) { $i--; } # Not a hex digit? else { $C <<= 4; $C += $D; } # We're using 2 hex digits } } if ($j < $i) { vec($X, ++$j, 8) = $C; } } if ($j < $i) { $X = substr($X, 0, ++$j); } return $X; } ################################################## # String | v2023.3.15 # This function XORs each byte of a string using a # "password" string and returns a new string. # # This is algorithm offers a weak encryption, so don't # use it to encrypt passwords or credit card numbers # or other sensitive data. # # Usage: STRING = StrXOR(STRING, PASSWORD) # sub StrXOR { defined $_[0] or return ''; defined $_[1] && length($_[1]) or return $_[0]; my ($OUT, $j, $i) = ('', 0, length($_[0])); while ($i--) { vec($OUT, $i, 8) = vec($_[0], $i, 8) ^ vec($_[1], $j++, 8); $j < length($_[1]) or $j = 0; } return $OUT; } ##################################################