<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">
=pod
perl -w xor-bigint.pl --debug=1 --dir='/home/guest/xor-test' --re='test/5\.txt$' --key='xyz0 % ^ &amp;88**' --rotate_key='&lt;&lt;' --area_size='10%' --area_offset='30%'
perl -w xor-bigint.pl --debug=1 --dir='/home/guest/xor-test' --re='test/5\.txt$' --key='xyz0 % ^ &amp;88**' --rotate_key='&lt;&lt;' --area_size=1000 --area_offset=4000

=cut

use strict;
use Getopt::Long;
use File::Find;
use Math::BigInt try =&gt; 'GMP';
#~ use POSIX ":sys_wait_h"; # perldoc -f waitpid
#~ use Fcntl;                          # for SEEK_SET and SEEK_CUR
# 0 to set the new position to POSITION; SEEK_SET
# 1 to set the it to the current position plus POSITION; SEEK_CUR


my %arg=(forks=&gt;1, dir=&gt;'.', area_offset=&gt;0, count=&gt;1, test=&gt;0, rotate_start_bit=&gt;1,); #
GetOptions(
	'forks=s'=&gt;\$arg{forks}, #
	'dir=s'=&gt;\$arg{dir}, # default='.' full path!!
	're=s'=&gt;\$arg{re}, # Ñ€ÐµÐ³ÑƒÐ»ÑÑ€Ð½Ð¾Ðµ Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ðµ Ð´Ð»Ñ Ð¿Ð¾Ð»Ð½Ð¾Ð³Ð¾ Ð¸Ð¼ÐµÐ½Ð¸ Ñ„Ð°Ð¹Ð»Ð° (Ð¿ÑƒÑÑ‚Ð¾ - Ð²ÑÐµ Ñ„Ð°Ð¹Ð»Ñ‹) default=undef
	'key=s'=&gt;\$arg{key}, #mandatory
	'area_offset=s'=&gt;\$arg{area_offset}, # Ð² Ð±Ð°Ð¹Ñ‚Ð°Ñ… ÑÐ¼ÐµÑÑ‚Ð¸Ñ‚ÑŒÑÑ Ð¾Ñ‚ Ð½Ð°Ñ‡Ð°Ð»Ð° Ñ„Ð°Ð¹Ð»Ð° default=0 (Ð¼Ð¾Ð¶Ð½Ð¾ Ð² %)
	'area_size=s'=&gt;\$arg{area_size}, # Ð² Ð±Ð°Ð¹Ñ‚Ð°Ñ… undef -&gt; Ð´Ð¾ ÐºÐ¾Ð½Ñ†Ð° (Ð¼Ð¾Ð¶Ð½Ð¾ Ð² %)
	# 4 ÑÐ²ÑÐ·Ð°Ð½Ð½Ñ‹Ñ… Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° Ð¿Ñ€Ð¸ Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ð¸ Ð±Ð¸Ñ‚Ð¾Ð² ÐºÐ»ÑŽÑ‡Ð°
	'rotate_key=s'=&gt;\$arg{rotate_key}, # ÐºÑƒÐ´Ð° Ð²Ñ€Ð°Ñ‰Ð°Ñ‚ÑŒ ÐºÐ»ÑŽÑ‡  &lt;&lt; Ð²Ð»ÐµÐ²Ð¾ &gt;&gt; Ð²Ð¿Ñ€Ð°Ð²Ð¾ Ð² Ñ†Ð¸ÐºÐ»Ðµ count (ÑÐ¼ Ð²Ñ‹Ð·Ð¾Ð² rot()) Ð•ÑÐ»Ð¸ Ð½Ðµ ÑƒÐºÐ°Ð°Ð·Ñ‚ÑŒ - Ð½Ðµ Ð±ÑƒÐ´ÐµÑ‚ Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ ÐºÐ»ÑŽÑ‡Ð° default=undef
	'rotate_count=i'=&gt;\$arg{rotate_count}, # ÑÐºÐ¾Ð»ÑŒÐºÐ¾ Ñ€Ð°Ð· Ð²Ñ€Ð°Ñ‰Ð°Ñ‚ÑŒ default=count bits of key
	'rotate_start_bit=i'=&gt;\$arg{rotate_start_bit},#  (ÑÐ¼ Ð²Ñ‹Ð·Ð¾Ð² rotate()) default=1
	'rotate_mask_bits=i'=&gt;\$arg{rotate_mask_bits},# ÐºÐ¾Ð»Ð¸Ñ‡ÐµÑÑ‚Ð²Ð¾ Ð±Ð¸Ñ‚Ð¾Ð² Ð² Ð¼Ð°ÑÐºÐµ (ÑÐ¼ Ð²Ñ‹Ð·Ð¾Ð² rotate()) default=count bits of key (Ð½Ðµ Ð±Ð¾Ð»ÑŒÑˆÐµ!!!)
	
	'debug=i'=&gt;\$arg{debug},# default=undef
	'test=i'=&gt;\$arg{test},# default=0
);

my $key_len = length($arg{key})
	or die "Empty --key= option";

my $key_bits = $key_len*8;
my $key_bigint = str2b($arg{key});
$arg{rotate_count} //= $key_bits;
my $mask = Math::BigInt-&gt;new('0b'.(1 x ($arg{rotate_mask_bits} || $key_bits)));# Ñ…Ð¾-Ñ…Ð¾, Ð¼Ð¾Ð¶ÐµÑ‚ Ð±Ñ‹ÑÑ‚Ñ€ÐµÐµ
#~ print "$key_len\tlen\n$key_bits\tkey_bits\n", unpack('B*', 'xz'), "\txz\n", $key_bigint-&gt;badd(1)-&gt;as_bin, "\tkey+1\n", $mask-&gt;as_bin, "\tmask\n";
# Ð³ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ ÑˆÐ¸Ñ„Ñ€Ð° Ð¸Ð· ÐºÐ»ÑŽÑ‡Ð° Ð¸ ÐµÐ³Ð¾ Ñ‚Ñ€Ð°Ð½ÑÑ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ð¸
my $cypher;
map {
	my $place = $arg{rotate_start_bit}+$_-1;
	my $rot = rotate($key_bigint, $arg{rotate_key}, $place, $mask);
	#~ print $rot-&gt;as_bin, "\trot[$arg{rotate_key} $place]\t", ($rot-&gt;is_nan &amp;&amp; ""), "\tnan\n";
	$cypher .= b2str($rot) unless $rot-&gt;is_nan;
	
} (1..($arg{rotate_count})) if $arg{rotate_key};

my $cypher_len = length($cypher);
$arg{debug} &amp;&amp; print #unpack('b*', $cypher), "\tcypher\n",
	"$cypher_len\t bit cypher len\n";
#~ exit;

my $offset_coeff = ($arg{area_offset} =~ /(\d+)/)[0]/100 if $arg{area_offset} =~ /%/;
print "Offset k=[$offset_coeff][$arg{area_offset}]\n" if $offset_coeff;
my $size_coeff = ($arg{area_size} =~ /(\d+)/)[0]/100 if $arg{area_size} &amp;&amp; $arg{area_size} =~ /%/;
print "Size k=[$size_coeff][$arg{area_size}]\n" if $size_coeff;

do {
	print "WARN!!! IT IS STRONGLY RECOMEND TO COPY/SAVE THIS COMMAND LINE FOR NEXT TIME (ok?)";
	my $ans = &lt;&gt;;
	chomp($ans);
	exit
		unless lc($ans) eq 'ok';
	print "WARN!!! STRONGLY BE SURE THAT YOU DID [\$ unset HISTFILE]. (y/n):";
	$ans = &lt;&gt;;
	chomp($ans);
	print "PLEASE DO [\$ unset HISTFILE]!\n"
		and exit
		unless lc($ans) eq 'y';
	#~ exec('bash -c "unset HISTFILE"');
};
#~ exit;

my %pids;
find({ wanted =&gt; sub {
=pod
$File::Find::dir is the current directory name,
$_ is the current filename within that directory
$File::Find::name is the complete pathname to the file.
for each directory found, it will "chdir()" into that directory and continue the search
=cut
	return if -d; # Ð¿Ñ€Ð¾Ð¿ÑƒÑÐº Ð´Ð¸Ñ€ÐµÐºÑ‚Ð¾Ñ€Ð¸Ð¹
	($arg{debug} &amp;&amp; print "Skip: [$File::Find::name]\n") || 1
		and return
		unless $File::Find::name =~ /$arg{re}/;
	
	if( scalar keys %pids == $arg{forks}) { 
		my $pid = wait();
		delete $pids{$pid};
	}
	make_child($File::Find::name);
	
} , follow =&gt; 1, # symlinks
}, $arg{dir});

waitpid $_, 0 for keys %pids;


sub make_child {
	my $fn = shift;# @find or return undef;
	my $pid = fork();
	if ($pid) {# parent
		$pids{$pid}++;
		#~ print "Ð—Ð°Ð¿ÑƒÑ‰ÐµÐ½ Ð¿Ñ€Ð¾Ñ†ÐµÑÑ [$pid] Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð° [$fn]\n";
		return 1;
	} elsif ($pid == 0) {# child
		print "Process[$$] [$File::Find::name]...";# if $arg{debug};
		process($fn);
		print " done\n";# if $arg{debug};
		exit;
	} else {
		die "ÐÐµ Ð¼Ð¾Ð¶ÐµÑ‚ fork: $!\n";
	}
}

sub process {
	#~ return;
	my $fn = shift;
	open(FH, "+&lt;", $fn)
		or warn "[$fn] opening: $!\n"
		and return;
	binmode(FH);
	my $fsize = (stat($fn))[7];
	print "\t skip size == 0"
		and (close FH
			or warn "[$fn] closing: $!")
		and return
		if $fsize == 0;

	my $foffset = defined $offset_coeff ?
		int($fsize*$offset_coeff)
		:	$arg{area_offset};
	# Ð¾Ñ‚Ð¼Ð¾Ñ‚Ð°Ñ‚ÑŒ Ð²Ð¿ÐµÑ€ÐµÐ´
	sysseek(FH, $foffset, 0)
		or warn "[$fn] forward seeking: $!" # SEEK_SET
		and (close FH
			or warn "[$fn] closing: $!")
		and return;
	
	my $count = defined $size_coeff ?# ÑƒÐ±Ñ‹Ð²Ð°ÑŽÑ‰Ð¸Ð¹ ÑÑ‡ÐµÑ‚Ñ‡Ð¸Ðº ÑÑ‡Ð¸Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ð¹
		int(($fsize-$foffset)*$size_coeff)# int((size*%/100)/len)
		:	$arg{area_size} // ($fsize-$foffset);
	my $len = $cypher_len &gt; $count ? $count : $cypher_len;
	while ($count &amp;&amp; (my $read = sysread(FH, my $buffer, $len))) {
		$count -= $read;
		$len = $cypher_len &gt; $count ? $count : $cypher_len;
		#~ push my @zero, @- while $buffer =~ /(\0)/g;
		#~ print "Found zero @zero" if @zero;
		#~ my $read = sysread(FH, my $buffer, $len);
		#~ warn "[$fn] reading whole chunk[$_] [$read] != [$len]"
			#~ and (close FH
				#~ or warn "[$fn] closing: $!")
			#~ and return
			#~ unless $read == $len;
		#~ print " after read POS: ", sysseek(FH, 0, 1) if $arg{debug};
		# Ð¾Ñ‚Ð¼Ð¾Ñ‚Ð°Ñ‚ÑŒ Ð¾Ð±Ñ€Ð°Ñ‚Ð½Ð¾
		sysseek(FH, -$read, 1) #SEEK_CUR
			or warn "[$fn] back seeking: $!"
			and (close FH
				or warn "[$fn] closing: $!")
			and return; 
		#~ print FH $BUFFER ^ $cypher ;
		print "write pos: ", sysseek(FH, 0, 1), "; " if $arg{debug};
		my $write = $buffer ^ substr($cypher, 0, $read);
		#~ substr($write, $_, 1, chr(0x00)) for @zero;
		syswrite FH, $write
			or warn "[$fn] writing: $!"
			and (close FH
				or warn "[$fn] closing: $!")
			and return;
		
	}
	close FH
		or warn "[$fn] closing: $!";
}

sub str2b {# convert string to Math::BigInt
	Math::BigInt-&gt;new("0b".unpack('B*', $_[0]));
}

sub b2str {# pack Math::BigInt to string, (is not -&gt;bstr)
	pack('B*', substr($_[0]-&gt;as_bin , 2));
}

sub rotate {# rotate($bigint, $direction, 1, $mask) - $direction(&lt;&lt;|&gt;&gt;); Ð½Ð° 1 Ð±Ð¸Ñ‚, $mask - 
	my $rev = $_[1] eq '&lt;&lt;' ? '&gt;&gt;' : '&lt;&lt;';
	my $mask_len = length(substr($_[3]-&gt;as_bin, 2));
	my $places = ($_[2] % $mask_len) || $_[2];
	my $shift1 = eval "\$_[0] $_[1] \$places";
	my $shift2 = eval "\$_[0] $rev (\$mask_len - \$places)";
	#~ my $mask = Math::BigInt-&gt;new(2) **$_[2] - 1;
	#~ my $mask = Math::BigInt-&gt;new('0b'.(1 x $_[3]));# Ñ…Ð¾-Ñ…Ð¾, Ð¼Ð¾Ð¶ÐµÑ‚ Ð±Ñ‹ÑÑ‚Ñ€ÐµÐµ
	return ($shift1 | $shift2) &amp; $_[3];
}
#~ sub rol { return ($_[0]&lt;&lt;$_[1] | $_[0]&gt;&gt;($_[2]-$_[1])) &amp; (2**$_[2]-1); }
#~ sub ror { return ($_[0]&gt;&gt;$_[1] | $_[0]&lt;&lt;($_[2]-$_[1])) &amp; (2**$_[2]-1); }

#~ substr($BUFFER ^ $cypher, 0, $read);
__END__

#~ use Math::BigInt;
use Math::BigInt try =&gt; 'GMP';
my $key = "r\0 4r";
my $up = unpack('b*', $key);
my $bits = length($up);
my $x =Math::BigInt-&gt;new("0b$up");
my $y;
print "$key key\t", length($key)," len\n",
	$x-&gt;as_bin(), " as is\t", length(bpack($x)), " len\t", "$bits bits\n",
	map {$y = rot($x, '&gt;&gt;', $_+0, $bits+0); $y-&gt;as_bin." rot[$_]\t".length(substr($y-&gt;as_bin , 2))." bits\t".length(bpack($y))." bytes\t".($x cmp $y)." cmp\t".(bpack($x) eq bpack($y))." eq\n";} (1..100);


</pre></body></html>