base64_decoding-tutorial.pl 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #!/usr/bin/perl
  2. # How does base64 works?
  3. # This short tutorial explains the basics behind the base64 decoding
  4. # Written by Trizen under the GPL.
  5. #
  6. # See also: https://en.wikipedia.org/wiki/Uuencoding
  7. # https://en.wikipedia.org/wiki/Base64
  8. my $base64 = 'SnVzdCBhbm90aGVyIFBlcmwgaGFja2VyLAo='; # base64
  9. #--------------Removing non-base64 chars--------------#
  10. # Anything that *ISN'T* A-Z, a-z, 0-9 or [+/._=] will be removed
  11. $base64 =~ tr|A-Za-z0-9+=/||cd; # remove non-base64 chars
  12. $base64 =~ s/=+$//; # remove padding (if any)
  13. #--------------Transliteration--------------#
  14. $base64 =~ tr{A-Za-z0-9+/}{ -_}; # convert to uuencoded format
  15. # same thing as:
  16. # $base64 =~ tr{ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/}
  17. # { !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_};
  18. # so: A => ' '
  19. # B => '!'
  20. # C => '"'
  21. # and so on...
  22. #--------------Decoding--------------#
  23. print unpack 'u', pack('C', 32 + int(length($1) * 3 / 4)) . $1 while $base64 =~ s/(.{60}|.+)//;
  24. # For short strings, this works just fine:
  25. # print unpack('u','M'. $base64);
  26. # unpack('u','...') unpacks this:
  27. # print unpack('u', ':2G5S="!A;F]T:&5R(%!E<FP@:&%C:V5R+ H');
  28. # Compact code 1 (with substitution)
  29. # Code from https://en.wikipedia.org/wiki/Uuencoding
  30. sub base64_decode_1 {
  31. my ($base64) = @_;
  32. $base64 =~ tr|A-Za-z0-9+=/||cd; # remove non-base64 chars
  33. $base64 =~ s/=+$//; # remove padding
  34. $base64 =~ tr|A-Za-z0-9+/| -_|; # convert to uuencoded format
  35. my $decoded;
  36. $decoded .= unpack 'u', pack('C', 32 + int(length($1) * 3 / 4)) . $1 while $base64 =~ s/(.{60}|.+)//;
  37. return $decoded;
  38. }
  39. # Without substitution
  40. # Coded by Trizen
  41. sub base64_decode_2 {
  42. my ($base64) = @_;
  43. $base64 =~ tr|A-Za-z0-9+=/||cd; # remove non-base64 chars
  44. $base64 =~ s/=+$//; # remove padding
  45. $base64 =~ tr|A-Za-z0-9+/| -_|; # convert to uuencoded format
  46. my $x = 84; # block size (default should be 60?)
  47. my $i = -$x;
  48. my $decoded;
  49. while (my $block = unpack("A$x", $base64)) {
  50. my ($base64_length, $offset) = (length($base64), $i + $x);
  51. substr($base64, $base64_length > $offset ? $offset : $base64_length, $base64_length > $x ? $x : $base64_length, '');
  52. $decoded .= chr(32 + int(length($block) * 3 / 4)) . $block;
  53. }
  54. return unpack('u', $decoded);
  55. }
  56. # May be memory expensive, but it's faster than base64_decode_2()
  57. # Coded by Trizen
  58. sub base64_decode_3 {
  59. my ($base64) = @_;
  60. $base64 =~ tr|A-Za-z0-9+=/||cd; # remove non-base64 chars
  61. $base64 =~ s/=+$//; # remove padding
  62. $base64 =~ tr|A-Za-z0-9+/| -_|; # convert to uuencoded format
  63. my $x = 84; # block size (default should be 60?)
  64. my $decoded;
  65. foreach my $block (unpack("(A$x)*", $base64)) {
  66. $decoded .= chr(32 + int(length($block) * 3 / 4)) . $block;
  67. }
  68. return unpack('u', $decoded);
  69. }
  70. # Faster still :)
  71. # Coded by Gisle Aas
  72. # https://metacpan.org/release/GAAS/MIME-Base64-Perl-1.00/source/lib/MIME/Base64/Perl.pm
  73. sub base64_decode_4 {
  74. my ($str) = @_;
  75. $str =~ tr|A-Za-z0-9+=/||cd; # remove non-base64 chars
  76. $str =~ s/=+$//; # remove padding
  77. $str =~ tr|A-Za-z0-9+/| -_|; # convert to uuencoded format
  78. my $uustr = '';
  79. my ($i, $l);
  80. $l = length($str) - 60;
  81. for ($i = 0 ; $i <= $l ; $i += 60) {
  82. $uustr .= "M" . substr($str, $i, 60);
  83. }
  84. $str = substr($str, $i);
  85. # and any leftover chars
  86. if ($str ne "") {
  87. $uustr .= chr(32 + length($str) * 3 / 4) . $str;
  88. }
  89. return unpack("u", $uustr);
  90. }
  91. # FASTEST (written in C)
  92. sub base64_decode_5 {
  93. use MIME::Base64 qw(decode_base64);
  94. return decode_base64($_[0]);
  95. }
  96. __END__
  97. # Some benchmarks
  98. my $base64_text = <<'BASE64';
  99. QmFzZTY0IGVuY29kaW5nIGNhbiBiZSBoZWxwZnVsIHdoZW4gZmFpcmx5IGxlbmd0aHkgaWRlbnRp
  100. ZnlpbmcgaW5mb3JtYXRpb24gaXMgdXNlZCBpbiBhbiBIVFRQIGVudmlyb25tZW50LiBGb3IgZXhh
  101. bXBsZSwgYSBkYXRhYmFzZSBwZXJzaXN0ZW5jZSBmcmFtZXdvcmsgZm9yIEphdmEgb2JqZWN0cyBt
  102. aWdodCB1c2UgQmFzZTY0IGVuY29kaW5nIHRvIGVuY29kZSBhIHJlbGF0aXZlbHkgbGFyZ2UgdW5p
  103. cXVlIGlkIChnZW5lcmFsbHkgMTI4LWJpdCBVVUlEcykgaW50byBhIHN0cmluZyBmb3IgdXNlIGFz
  104. IGFuIEhUVFAgcGFyYW1ldGVyIGluIEhUVFAgZm9ybXMgb3IgSFRUUCBHRVQgVVJMcy4gQWxzbywg
  105. bWFueSBhcHBsaWNhdGlvbnMgbmVlZCB0byBlbmNvZGUgYmluYXJ5IGRhdGEgaW4gYSB3YXkgdGhh
  106. dCBpcyBjb252ZW5pZW50IGZvciBpbmNsdXNpb24gaW4gVVJMcywgaW5jbHVkaW5nIGluIGhpZGRl
  107. biB3ZWIgZm9ybSBmaWVsZHMsIGFuZCBCYXNlNjQgaXMgYSBjb252ZW5pZW50IGVuY29kaW5nIHRv
  108. IHJlbmRlciB0aGVtIGluIG5vdCBvbmx5IGEgY29tcGFjdCB3YXksIGJ1dCBpbiBhIHJlbGF0aXZl
  109. bHkgdW5yZWFkYWJsZSBvbmUgd2hlbiB0cnlpbmcgdG8gb2JzY3VyZSB0aGUgbmF0dXJlIG9mIGRh
  110. dGEgZnJvbSBhIGNhc3VhbCBodW1hbiBvYnNlcnZlci4K
  111. BASE64
  112. use Benchmark qw(timethese cmpthese);
  113. my $results = timethese(
  114. 10000,
  115. {
  116. 'base64_decode_1' => sub { base64_decode_1($base64_text) },
  117. 'base64_decode_2' => sub { base64_decode_2($base64_text) },
  118. 'base64_decode_3' => sub { base64_decode_3($base64_text) },
  119. 'base64_decode_4' => sub { base64_decode_4($base64_text) },
  120. 'base64_decode_5' => sub { base64_decode_5($base64_text) },
  121. }
  122. );
  123. cmpthese($results);