How to resolve the algorithm One-time pad step by step in the Raku programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm One-time pad step by step in the Raku programming language

Table of Contents

Problem Statement

Implement a One-time pad, for encrypting and decrypting messages. To keep it simple, we will be using letters only. To support the management of pad-files:

For example, here is the data from Wikipedia:

Let's start with the solution:

Step by Step solution about How to resolve the algorithm One-time pad step by step in the Raku programming language

Source code in the raku programming language

sub MAIN {
    put "Generate data for one time pad encryption.\n" ~
        "File will have .1tp extension.";
    my $fn;
    loop {
        $fn = prompt 'Filename for one time pad data: ';
        if $fn !~~ /'.1tp' $/ { $fn ~= '.1tp' }
        if $fn.IO.e {
            my $ow = prompt "$fn aready exists, over-write? y/[n] ";
            last if $ow ~~ m:i/'y'/;
            redo;
        }
        last;
    }

    put 'Each line will contain 48 characters of encyption data.';
    my $lines = prompt 'How many lines of data to generate? [1000] ';
    $lines ||= 1000;
    generate($fn, $lines);
    say "One-time-pad data saved to: ", $fn.IO.absolute;

    sub generate ( $fn, $lines) {
        use Crypt::Random;
        $fn.IO.spurt: "# one-time-pad encryption data\n" ~
          ((sprintf(" %s %s %s %s %s %s %s %s\n",
          ((('A'..'Z')[crypt_random_uniform(26)] xx 6).join) xx 8))
          xx $lines).join;
    }
}


sub s2v ($s) { $s.uc.comb(/ <[ A..Z ]> /)».ord »-» 65 }
sub v2s (@v) { (@v »%» 26 »+» 65)».chr.join }

sub hide   ($secret, $otp) { v2s(s2v($secret) »+» s2v($otp)) }
sub reveal ($hidden, $otp) { v2s(s2v($hidden) »-» s2v($otp)) }

sub otp-data ($fn, $lines) {
    my $fh = $fn.IO.open :rw;
    my $data;
    my $count = 0;
    repeat {
        my $pos = $fh.tell;
        my $line = $fh.get;
        if $line.substr(0,1) ne '-'|'#' {
            $data ~= $line;
            $fh.seek($pos);
            $fh.put: '-' ~ $line.substr(1);
            $count++;
        }
    } until $count == $lines or $fh.eof;
    note "Insufficient lines of data remaining in $fn" if $count != $lines;
    $data;
}

sub otp-size (Str $string) { ceiling $string.uc.comb(/ <[ A..Z ]> /) / 48 }

sub otp-encrypt ( $secret, $fn ) {
    my $otp-size = otp-size $secret;
    my $otp-data = otp-data($fn, $otp-size);
    my $encrypted = hide $secret, $otp-data;
    # pad encryted text out to a full line with random text
    $encrypted ~= ('A'..'Z').roll while $encrypted.chars % 48;
    join "\n", $encrypted.comb(6).rotor(8, :partial).map:
      { sprintf "{ join ' ', "%s" xx $_ }", $_ };
}

sub otp-decrypt ( $secret, $fn ) {
    my $otp-size = otp-size $secret;
    my $otp-data = otp-data($fn, $otp-size);
    my $plain-text = reveal $secret, $otp-data;
    join "\n", $plain-text.comb(6).rotor(8, :partial).map:
      { sprintf "{ join ' ', "%s" xx $_ }", $_ };
}

my $otp-encrypt-fn = 'rosettacode.1tp';
my $otp-decrypt-fn = 'rosettacopy.1tp';

my $secret = "Beware the Jabberwock, my son! The jaws that bite, the claws that catch!";

say "Secret:\n$secret\n\nEncrypted:";
say my $encrypted =   otp-encrypt $secret,    $otp-encrypt-fn;
say "\nDecrypted:\n", otp-decrypt $encrypted, $otp-decrypt-fn;


  

You may also check:How to resolve the algorithm Variables step by step in the Go programming language
You may also check:How to resolve the algorithm Odd word problem step by step in the REXX programming language
You may also check:How to resolve the algorithm Superellipse step by step in the Delphi programming language
You may also check:How to resolve the algorithm Filter step by step in the Seed7 programming language
You may also check:How to resolve the algorithm Steffensen's method step by step in the EasyLang programming language