Perl printf line breaks - perl

Looking to add a line break after every 16 bytes of the 100 bytes printed from j. All 100 bytes are currently printed on one line at the moment.
Any assistance would be great full, thanks.
for ($j = 6; $j < 106; $j++)
{
printf("%02X ", hex(#bytes[$j]));
}
printf("\t");
Thanks all. I approached it another way. In the end the visual aspect was not a concern as I ended up printing to file anyway. This data then gets pasted in a hex editor so formatting was a forethought rather than a need be. The below is now outputting all the data I was looking for in the end rather than a predetermined length.
for ($j = 6; $j < #bytes; $j = $j + 1)
{
printf outfile ("%02X ", hex(#bytes[$j]));
}
printf("\n");

Use splice() to grab 16 elements at a time from your array.
I've also switched to using say(), join(), map() and sprintf().
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
my #bytes = map { int(rand(255)) } 0..200;
# As splice is destructive, take a copy of the array.
# Also, let's remove those first six elements and any
# after index 106.
my #data = #bytes[6 .. 105];
while (my #row = splice #data, 0, 16) {
say join ' ', map { sprintf '%02X', $_ } #row;
}
Update: A few more Perl tips for you.
Always add use strict and use warnings to the top of your Perl programs. And fix the problems they will show you.
#bytes[$j] is better written as $bytes[$j] (as it's a single value). That's one of the things use warnings will tell you about.
for ($j = 6; $j < 106; $j++) is probably better written as for my $j (6 .. 105). Less chance of "off-by-one" errors.
Actually, as you're just using $j to get the element from the array, you probably want to just iterate across the elements of the array directly - for my $elem (#bytes[6 .. 105]) (and then using $elem in place of $bytes[$j]).

You can utilize some $counter and print \n once $counter % 16 equal 0.
use strict;
use warnings;
my #bytes = map { int(rand(255)) } 0..200;
my $counter = 1;
for ( #bytes[6..106] ) {
printf "%02X ", $_;
print "\n" unless $counter++ % 16;
}
print "\n";
Output sample
C9 CA E7 66 13 F5 56 BE 08 68 E4 22 93 77 E0 14
08 4F F3 AD CC F4 66 DE 6C BB 1B E6 CE F3 13 DD
AE 6A CD 9B 5E 98 1F D4 2E C5 80 4B 3E 8E BC BF
5B 27 F9 0D 97 AB 26 C0 11 2D 1D 95 CE 26 3C D8
3C D8 A4 06 0A 48 0D 45 53 28 7E 5D D2 AD 90 5C
03 32 95 48 F6 DB 20 90 A7 62 41 3D D7 AB 7C 3B
CF 3D 0D C2 DA
Note: index from 6 to 106 gives 101 element

Short and fast:
sub hex_dump {
my $i = 0;
my $d = uc unpack 'H*', pack 'C*', #_;
$d =~ s{ ..\K(?!\z) }{ ++$i % 16 ? " " : "\n" }xseg;
return "$d\n";
}
print hex_dump(#bytes[6..105]);
There's also the very clean splice loop approach.
sub hex_dump {
my $d = '';
$d .= join(" ", map sprintf("%02X", $_), splice(#_, 0, 16)) . "\n" while #_;
return $d;
}
print hex_dump(#bytes[6..105]);
Because this approach produces a line at a time, it's great for recreating the traditional hex dump format (with offset and printable characters shown).
$ hexdump -C a.pl
00000000 75 73 65 20 73 74 72 69 63 74 3b 0a 75 73 65 20 |use strict;.use |
00000010 77 61 72 6e 69 6e 67 73 3b 0a 0a 73 75 62 20 68 |warnings;..sub h|
00000020 65 78 5f 64 75 6d 70 20 7b 0a 20 20 20 6d 79 20 |ex_dump {. my |
...
000000a0 74 65 73 20 3d 20 30 2e 2e 32 35 35 3b 0a 0a 70 |tes = 0..255;..p|
000000b0 72 69 6e 74 20 68 65 78 5f 64 75 6d 70 28 40 62 |rint hex_dump(#b|
000000c0 79 74 65 73 5b 36 2e 2e 31 30 35 5d 29 3b 0a |ytes[6..105]);.|
000000cf
You could also use a for loop. You would iterate over the indexes, and print either a space or a line feed depending on the index of the byte you're printing.
sub hex_dump {
my $d = '';
for my $i (0..$#_) {
$d .= sprintf("%02X%s", $_[$i], $i == $#_ || $i % 16 == 15 ? "\n" : " ");
}
return $d;
}
print hex_dump(#bytes[6..105]);

Related

perl: What would cause perl to not find a file that exists?

Running a perl cgi script I got the error it couldn't find the file it was trying to open. I check apache error log /var/log/apache2/error.log:
[Tue Jan 13 20:59:17 2015] [error] [client ::1] [Tue Jan 13 20:59:17 2015] submit.cgi: [Tue Jan 13 20:59:17 2015] submit.cgi:
/home/jddancks/Documents/perl/homeworks/hw13/grades4.txt: No such file or directory at /var/www/homeworks/hw13/CreateExam.pm line 48., referer: http://localhost/homeworks/hw13/test.cgi
double check:
root#debian-macbook:/var/log/apache2# ls -l /home/jddancks/Documents/perl/homeworks/hw13/grades4.txt
-rwxrwxrwx 1 jddancks jddancks 2095 Jan 7 12:25 /home/jddancks/Documents/perl/homeworks/hw13/grades4.txt
Why would this happen? This is a debian machine running apache 2.2 IDK if that helps.
There are 2 files: submit.cgi and CreateExam.pm.
submit.cgi:
use CreateExam;
...
my $path = `pwd`;
...
my $check = CreateExam->new("${path}/exam4.txt","${path}/answers4.txt","${path}/grades4.txt",$pathroot);
$check->entergrades($cookie_value,$cgi->Vars());
CreateExam.pm:
package CreateExam;
sub new {
my ($class,$file,$answers,$grades,$script) = #_;
#print "<p>in new: file: $file, grades: $grades</p>\n";
return bless {'file'=>$file,'answers'=>$answers,'gradefile'=>$grades,'script'=>$script},$class;
}
sub tooktest {
my ($self,$person) = #_;
#print "<p>in tooktest: person: $person</p>\n";
my $grades = $self->{'gradefile'};
open(ANS,"< $grades") or die "$grades: $!";
my $found = 0;
LAST: while(my $line = <ANS>) {
if($line =~ /\<test taker=$person/) { $found = 1; last LAST;}
}
return $found==1;
}
Data::Dumper:
$VAR1 = "/home/jddancks/Documents/perl/homeworks/hw13"; (in browser)
hexdump:
jddancks#debian-macbook:~/Documents/perl/homeworks/hw13$ perl -e 'print qx(pwd)' | hexdump -C
00000000 2f 68 6f 6d 65 2f 6a 64 64 61 6e 63 6b 73 2f 44 |/home/jddancks/D|
00000010 6f 63 75 6d 65 6e 74 73 2f 70 65 72 6c 2f 68 6f |ocuments/perl/ho|
00000020 6d 65 77 6f 72 6b 73 2f 68 77 31 33 0a |meworks/hw13.|
0000002d
As your hexdump shows, pwd returns the working directory followed by a newline, and that is what is you are assigning to $path. Then you try to open "/home/jddancks/Documents/perl/homeworks/hw13\n/grades4.txt" which indeed has a directory that does not exist.
Try doing:
chomp( my $path = `pwd` );
If Apache is configured to run in a chroot it does not see /home on the host system at all.

HMAC implementation failure

I hope this is the right forum; I was not sure if I should ask this in stackoverflow, cryptography or security.
So my problem is that php's hash_hmac function is only available with php >=5.1.2. Because some servers are not updated to this version I wrote my own HMAC-implementaion based on php's hash function. But the code doesn't produce the same output as hash_hmac...
So where is my mistake?
define("HASH_ALGO", "sha512");
define("HMAC_BLOCKSIZE", 64);
function computeHMAC($message, $key) {
$ikey;
$okey;
$zero = hex2bin("00");
$ipad = hex2bin("36");
$opad = hex2bin("5C");
/*
* HMAC construction scheme:
* $ikey = $key padded with zeroes to blocksize and then each byte xored with 0x36
* $okey = $key padded with zeroes to blocksize and then each byte xored with 0x5C
* hash($okey . hash($ikey . $message))
*/
//Hash key if it is larger than HMAC_BLOCKSIZE
if (strlen($key) > HMAC_BLOCKSIZE) {
$key = hash(HASH_ALGO, $key, true);
}
//Fill ikey with zeroes
for ($i = 0; $i < HMAC_BLOCKSIZE; $i++) {
$ikey[$i] = $zero;
}
//Fill ikey with the real key
for ($i = 0; $i < strlen($key); $i++) {
$ikey[$i] = $key[$i];
}
//Until they get xored both keys are equal
$okey = $ikey;
//Xor both keys
for ($i = 0; $i < HMAC_BLOCKSIZE; $i++) {
$ikey[$i] ^= $ipad;
$okey[$i] ^= $opad;
}
//Build inner hash
$innerHash = hash(HASH_ALGO, $ikey . $message, true);
//Build outer hash
$outerHash = hash(HASH_ALGO, $okey . $innerHash, true);
return $outerHash;
}
The function was tested with the following code:
echo hexDump(computeHMAC("Testolope", "Testkeyolope"));
echo hexDump(hash_hmac(HASH_ALGO, "Testolope", "Testkeyolope", true));
The output is the following:
HexDump (64 Bytes):
65 a8 81 af 49 f2 49 c5 64 7a 7a b7 a6 ac a0 4e 9e 9b 1a 3c 76 fc 48 19 13 33 e0 f8 82 be 48 52 1a 50 49 09 1e fe bf 94 63 5f 9d 36 82 3f 2f a1 43 b4 60 9f 9f e5 d1 64 c6 5b 32 22 45 07 c9 cb
HexDump (64 Bytes):
d2 e9 52 d2 ab f0 db a7 60 e0 52 b0 5c 23 5a 73 d9 8c 78 8e 9e fb 26 82 54 7e f9 c8 f1 65 df 7f 97 44 fe 2b 1e 2b 6d d5 cb a4 ba c6 73 35 06 9c 0f c8 2d 36 8c b3 9b c4 48 01 5c c2 9f ce b4 08
The problem is that you've mixed up the digest size and block size; SHA-512 has a digest size of 64, but a block size of 128.
Secondly, both $ikey and $okey are arrays and not strings, so you need to convert them both into a string first:
$innerHash = hash(HASH_ALGO, join($ikey) . $message, true);
$outerHash = hash(HASH_ALGO, join($okey) . $innerHash, true);
That said, both hash() and hash_hmac() are documented as being available since 5.1.2, so I'm not sure what this will achieve :)

Why does Perl MIME::Base64 insert CR characters before LF characters on decoding Base64-encoded strings when they aren't present in the original data?

Why does the Perl MIME::Base64 module on decoding Base64-encoded strings insert CR characters before LF characters when they are not present in the original data?
Input: a binary described by the following hex string,
14 15 6A 48 E4 15 6A 32 E5 48 46 13 A5 E3 88 43 18 A6 84 E3 51 3A 8A 0A 1A 3E E6 84 A6 1A 16 E8 46 84 A1 2E A3 5E 84 8A 4E 1A 35 E1 35 1E 84 A9 8E 46 54 44
This encodes to the Base64-encoded string:
FBVqSOQVajLlSEYTpeOIQximhONROooKGj7mhKYaFuhGhKEuo16Eik4aNeE1HoSpjkZURA==
My Perl script for decoding is
use MIME::Base64;
my $bin = decode_base64('FBVqSOQVajLlSEYTpeOIQximhONROooKGj7mhKYaFuhGhKEuo16Eik4aNeE1HoSpjkZURA==');
open FH, ">test.bin" or die $!;
print FH $bin;
close FH;
Output: the resulting file 'test.bin' has the following hex string representation,
14 15 6A 48 E4 15 6A 32 E5 48 46 13 A5 E3 88 43 18 A6 84 E3 51 3A 8A 0D 0A 1A 3E E6 84 A6 1A 16 E8 46 84 A1 2E A3 5E 84 8A 4E 1A 35 E1 35 1E 84 A9 8E 46 54 44
Note the hex digits in bold highlighting the additional '0D' character that has been inserted before '0A' where it was not present in the original data.
I'm using Perl v5.14.2 on Windows 7.
Since you're on Windows, you will need to open that filehandle in binary mode to prevent your line-endings from being munged.
open FH, ">test.bin" or die $!;
binmode FH;
You can do that all at once using IO layers, and also using a lexical filehandle which is better practice than a package symbol like FH:
open my $fh, '>:raw', 'test.bin' or die $!;
print { $fh } $bin;
For more, check out
perldoc perlio
perldoc perlopentut

Hex dump parsing in perl

I have a hex dump of a message in a file which i want to get it in an array
so i can perform the decoding logic on it.
I was wondering if that was a easier way to parse a message which looks like this.
37 39 30 35 32 34 35 34 3B 32 31 36 39 33 34 35
3B 32 31 36 39 33 34 36 00 00 01 08 40 00 00 15
6C 71 34 34 73 69 6D 31 5F 33 30 33 31 00 00 00
00 00 01 28 40 00 00 15 74 65 6C 63 6F 72 64 69
74 65 6C 63 6F 72 64 69
Note that the data can be max 16 bytes on any row. But any row can contain fewer bytes too (minimum :1 )
Is there a nice and elegant way rather than to read 2 chars at a time in perl ?
Perl has a hex operator that performs the decoding logic for you.
hex EXPR
hex
Interprets EXPR as a hex string and returns the corresponding value. (To convert strings that might start with either 0, 0x, or 0b, see oct.) If EXPR is omitted, uses $_.
print hex '0xAf'; # prints '175'
print hex 'aF'; # same
Remember that the default behavior of split chops up a string at whitespace separators, so for example
$ perl -le '$_ = "a b c"; print for split'
a
b
c
For every line of the input, separate it into hex values, convert the values to numbers, and push them onto an array for later processing.
#! /usr/bin/perl
use warnings;
use strict;
my #values;
while (<>) {
push #values => map hex($_), split;
}
# for example
my $sum = 0;
$sum += $_ for #values;
print $sum, "\n";
Sample run:
$ ./sumhex mtanish-input
4196
I would read a line at a time, strip the whitespace, and use pack 'H*' to convert it. It's hard to be more specific without knowing what kind of "decoding logic" you're trying to apply. For example, here's a version that converts each byte to decimal:
while (<>) {
s/\s+//g;
my #bytes = unpack('C*', pack('H*', $_));
print "#bytes\n";
}
Output from your sample file:
55 57 48 53 50 52 53 52 59 50 49 54 57 51 52 53
59 50 49 54 57 51 52 54 0 0 1 8 64 0 0 21
108 113 52 52 115 105 109 49 95 51 48 51 49 0 0 0
0 0 1 40 64 0 0 21 116 101 108 99 111 114 100 105
116 101 108 99 111 114 100 105
I think reading in two characters at a time is the appropriate way to parse a stream whose logical tokens are two-character units.
Is there some reason you think that's ugly?
If you're trying to extract a particular sequence, you could do that with whitespace-insensitive regular expressions.

How can I convert a 48 hex string to bytes using Perl?

I have a hex string (length 48 chars) that I want to convert to raw bytes with the pack function in order to put it in a Win32 vector of bytes.
How I can do this with Perl?
my $bytes = pack "H*", $hex;
See perlpacktut for more information.
The steps are:
Extract pairs of hexadecimal characters from the string.
Convert each pair to a decimal number.
Pack the number as a byte.
For example:
use strict;
use warnings;
my $string = 'AA55FF0102040810204080';
my #hex = ($string =~ /(..)/g);
my #dec = map { hex($_) } #hex;
my #bytes = map { pack('C', $_) } #dec;
Or, expressed more compactly:
use strict;
use warnings;
my $string = 'AA55FF0102040810204080';
my #bytes = map { pack('C', hex($_)) } ($string =~ /(..)/g);
I have the string:
"61 62 63 64 65 67 69 69 6a"
which I want to interpret as hex values, and display those as ASCII chars (those values should reproduce the character string "abcdefghij").
Typically, I try to write something quick like this:
$ echo "61 62 63 64 65 67 69 69 6a" | perl -ne 'print "$_"; print pack("H2 "x10, $_)."\n";'
61 62 63 64 65 67 69 69 6a
a
... and then I wonder, why do I get only one character back :)
First, let me note down that the string I have, can also be represented as the hex values of bytes that it takes up in memory:
$ echo -n "61 62 63 64 65 67 68 69 6a" | hexdump -C
00000000 36 31 20 36 32 20 36 33 20 36 34 20 36 35 20 36 |61 62 63 64 65 6|
00000010 37 20 36 38 20 36 39 20 36 61 |7 68 69 6a|
0000001a
_(NB: Essentially, I want to "convert" the above byte values in memory as input, to these below ones, if viewed by hexdump:
$ echo -n "abcdefghij" | hexdump -C
00000000 61 62 63 64 65 66 67 68 69 6a |abcdefghij|
0000000a
... which is how the original values for the input hex string were obtained.
)_
Well, this Pack/Unpack Tutorial (AKA How the System Stores Data) turns out is the most helpful for me, as it mentions:
The pack function accepts a template string and a list of values [...]
$rec = pack( "l i Z32 s2", time, $emp_id, $item, $quan, $urgent);
It returns a scalar containing the list of values stored according to the formats specified in the template [...]
$rec would contain the following (first line in decimal, second in hex, third as characters where applicable). Pipe characters indicate field boundaries.
Offset Contents (increasing addresses left to right)
0 160 44 19 62| 41 82 3 0| 98 111 120 101 115 32 111 102
A0 2C 13 3E| 29 52 03 00| 62 6f 78 65 73 20 6f 66
| b o x e s o f
That is, in my case, $_ is a single string variable -- whereas pack expects as input a list of several such 'single' variables (in addition to a formatting template string); and outputs again a 'single' variable (which could, however, be a sizeable chunk of memory!). In my case, if the output 'single' variable contains the ASCII code in each byte in memory, then I'm all set (I could simply print the output variable directly, then).
Thus, in order to get a list of variables from the $_ string, I can simply split it at the space sign - however, note:
$ echo "61 62 63 64 65 67 68 69 6a" | perl -ne 'print "$_"; print pack("H2", split(/ /, $_))."\n";'
61 62 63 64 65 67 68 69 6a
a
... that amount of elements to be packed must be specified (otherwise again we get only one character back); then, either of these alternatives work:
$ echo "61 62 63 64 65 67 68 69 6a" | perl -ne 'print "$_"; print pack("H2"x10, split(/ /, $_))."\n";'
61 62 63 64 65 67 68 69 6a
abcdeghij
$ echo "61 62 63 64 65 67 68 69 6a" | perl -ne 'print "$_"; print pack("(H2)*", split(/ /, $_))."\n";'
61 62 63 64 65 67 68 69 6a
abcdeghij