#!/usr/bin/perl
#
# RC4 Simple FILE Encryption/Decryption
#
# Copyright 2018 (c) Todor Donev
# <todor.donev at gmail.com>
# https://ethical-hacker.org/
# #!/usr/bin/perl
#
# RC4 Simple FILE Encryption/Decryption
#
# Copyright 2018 (c) Todor Donev
# <todor.donev at gmail.com>
# https://ethical-hacker.org/
# https://facebook.com/ethicalhackerorg
#
# Description:
# RC4 generates a pseudorandom stream of bits
# (a keystream). As with any stream cipher,
# these can be used for encryption by combining
# it with the plaintext using bit-wise exclusive-or;
# decryption is performed the same way (since
# exclusive-or with given data is an involution).
# (This is similar to the Vernam cipher except
# that generated pseudorandom bits, rather than a
# prepared stream, are used.) To generate the
# keystream, the cipher makes use of a secret
# internal state which consists of two parts:
#
# o A permutation of all 256 possible bytes
# (denoted "S" below).
#
# o Two 8-bit index-pointers (denoted "i" and "j").
#
# The permutation is initialized with a variable
# length key, typically between 40 and 2048 bits,
# using the key-scheduling algorithm (KSA). Once
# this has been completed, the stream of bits is
# generated using the pseudo-random generation
# algorithm (PRGA).
#
# [todor@paladium ~]$ perl rc4file.pl ethack test.txt test.rc4
# [ RC4 Simple FILE Encryption/Decryption
# [ =======
# [ Author: Todor Donev <todor.donev at gmail.com>
# [ https://ethical-hacker.org/
# [ https://fb.com/ethicalhackerorg
# [ =======
# [ Opening test.txt
# [ Calculation..
# [ Ready and test.rc4 file is closed.
# [todor@paladium ~]$ perl rc4file.pl ethack test.rc4 test.rc4.encoded.txt && cat test.rc4.encoded.txt
# [ RC4 Simple FILE Encryption/Decryption
# [ =======
# [ Author: Todor Donev <todor.donev at gmail.com>
# [ https://ethical-hacker.org/
# [ https://fb.com/ethicalhackerorg
# [ =======
# [ Opening test.rc4
# [ Calculation..
# [ Ready and test.rc4.encoded.txt file is closed.
# Ethical Hacker Bulgaria 2018
# International Cybersecurity Association
# [todor@paladium ~]$
#
# Disclaimer:
# This or previous programs is for Educational
# purpose ONLY. Do not use it without permission.
# The usual disclaimer applies, especially the
# fact that Todor Donev is not liable for any
# damages caused by direct or indirect use of the
# information or functionality provided by these
# programs. The author or any Internet provider
# bears NO responsibility for content or misuse
# of these programs or any derivatives thereof.
# By using these programs you accept the fact
# that any damage (dataloss, system crash,
# system compromise, etc.) caused by the use
# of these programs is not Todor Donev's
# responsibility.
#
# Use them at your own risk!

use warnings;
use strict;
use open ':std', ':encoding(UTF-8)';

print "[ RC4 Simple FILE Encryption/Decryption ";
print "[ ======= ";
print "[ Author: Todor Donev <todor.donev at gmail.com> ";
print "[ https://ethical-hacker.org/ ";
print "[ https://fb.com/ethicalhackerorg ";
print "[ ======= ";
die "[ Usage: $0 <passphrase> <input file> <output file> " if(@ARGV != 3);
our $MAX_CHUNK_SIZE = 1024 unless $MAX_CHUNK_SIZE;
my $passphrase = $ARGV[0];
print "[ Opening $ARGV[1] ";
open(IN, $ARGV[1]) or die "[ Error: Can't read $ARGV[1]: $! ";
die "[ Error: The file is empty" if (-z $ARGV[1]);
open(OUT, ">$ARGV[2]") or die "[ Error: Can't wrote $ARGV[2]: $! ";
binmode(IN);
binmode(OUT);
print "[ Calculation.. ";
my $bytes = (stat $ARGV[1])[7];
while(sysread(IN,my $in,$bytes)){
print OUT rc4($passphrase, $in);
}
print "[ Ready and $ARGV[2] file is closed. ";
close(IN);
close(OUT);

sub rc4 {
my $self;
my(@state, $x, $y);
if (ref $_[0]){
$self = shift;
@state = @{$self->{state}};
$x = $self->{x};
$y = $self->{y};
} else {
@state = init(shift);
$x = $y = 0;
}
my $message = shift;
my $num_pieces = do{
my $num = length($message) / $MAX_CHUNK_SIZE;
my $int = int $num;
$int == $num ? $int : $int+1;
};
for my $piece (0..$num_pieces-1){
my @message = unpack "C*", substr($message, $piece * $MAX_CHUNK_SIZE, $MAX_CHUNK_SIZE);
for ( @message ) {
$x = 0 if ++$x > 255;
$y -= 256 if ($y += $state[$x]) > 255;
@state[$x, $y] = @state[$y, $x];
$_ ^= $state[($state[$x]+$state[$y]) % 256];
}
substr($message, $piece * $MAX_CHUNK_SIZE, $MAX_CHUNK_SIZE) = pack "C*", @message;
}
if ($self) {
$self->{state} = @state;
$self->{x} = $x;
$self->{y} = $y;
}
$message;
}

sub init {
my @k = unpack('C*',shift);
my @state = 0..255;
my $y = 0;
for my $x (0..255){
$y = ($k[$x % @k]+$state[$x]+$y) % 256;
@state[$x, $y] = @state[$y, $x];
}
wantarray ? @state : @state;
}