morgon has asked for the wisdom of the Perl Monks concerning the following question:
Hi,
I have several devices (pcs, phones, tablets, routers) where I store sensitive informations (passwords, PINs etc: short textual information), some of which are even shared via some cloud, so I am looking for a way to secure this in a way that would work everywhere and the one thing I have everywhere is a perl-installation.
So what I am looking for is the best way to encrypt and decrypt short strings via perl using core-modules only that produces encrypted versions containing only printable characters.
As the built-in crypt only uses the first 8 characters (afaik) this is unfortunately not as trivial as I thought it would be...
Note that I do not want solutions that implement an known algorithm in pure perl and that I am quite happy to share my secrets with the NSA, I am simply looking for something convenient to use to protect my secrets from the average Joe that hits the sweet spot between convenience and security.
Any ideas?
Many thanks!
Re: crypto with core modules only
by stevieb (Canon) on Aug 28, 2018 at 00:57 UTC
|
Quite a few years ago, I was helping someone doing some light data manipulation stuff (obfuscation really). Premise was to obfu a string with a password, print out the result, and then to decipher it, you had to supply the same password and paste in the jumbled hex text. Here's an example of how it works, then the actual code. The code is in two files (for the convenience of the person I was helping; it could easily be merged. Also, if I were to actually use it myself, I'd add another input field for the salt as well (it's hard-coded), but I digress). This is very simple and probably far from secure, but thought I'd share anyhow.
Obfuscate a message:
perl enc.pl
Create a password: secretpw
Enter your message to be encrypted: This is an encryption test
Your encrypted message: c7cda0cc55bde684b5db9698d5d6d7b0c9a9bde2d274e1
+dba6db
Then, to decrypt:
perl denc.pl
Enter your password: secretpw
Enter your encrypted message: c7cda0cc55bde684b5db9698d5d6d7b0c9a9bde2
+d274e1dba6db
Your decrypted message: This is an encryption test
The enc.pl code:
use warnings;
use strict;
use 5.10.0;
print "\nCreate a password: ";
chomp ( my $password = <STDIN> );
my $salt = 'j4';
my $crypt_pass = crypt( $salt, $password );
print "Enter your message to be encrypted: ";
chomp ( my $message = <STDIN> );
my @hex_pass
= map { sprintf( "%x", ( ord( $_ ))) } split //, $crypt_pass;
my @hex_msg
= map { sprintf( "%x", ( ord( $_ ))) } split //, $message;
my @crypted;
my @hash;
push @hash, @hex_pass until @hash > @hex_msg;
my $i=0;
for my $letter ( @hex_msg ){
push @crypted, hex( $letter ) + hex( $hash[$i] );
$i++;
}
@crypted = map { sprintf( "%x", $_ ) } @crypted;
print "\nYour encrypted message: ";
print @crypted;
print "\n\n";
The denc.pl code:
use warnings;
use strict;
use 5.10.0;
print "\nEnter your password: ";
chomp ( my $password = <STDIN> );
my $salt = 'j4';
my $crypt_pass = crypt( $salt, $password );
my @hex_pass = map { sprintf( "%x", ( ord( $_ ) ) ) } split //, $crypt
+_pass;
print "Enter your encrypted message: ";
chomp ( my $message = <STDIN> );
my @crypt_message = ( $message =~ m/../g );
my @hash;
push @hash, @hex_pass until @hash > @crypt_message;
my @decrypted_message;
my $n = 0;
for my $letter ( @crypt_message ){
push @decrypted_message, ( hex( $letter ) - hex( $hash[$n] ) ) ;
$n++;
}
print "\nYour decrypted message: ";
print map { chr( $_ ) } @decrypted_message;
print "\n\n";
| [reply] [d/l] [select] |
|
That is very insecure. It's basically adding the same set of 13 numbers in a cycle to each 13th character of the plaintext. You can
eliminate the key from the cyphertext by calculating something along the lines of
$diff[$_] = $cyphertext[$_] - $cyphertext[$_+13] for 0..(@cyphertext
+- 13);
You then end up with this equivalence for all the chars in the plaintext, apart from the first and last 13:
$diff[$_] == $plaintext[$_] - $plaintext[$_+13];
From there it's fairly easy to deduce what @plaintext is, especially if a few chars of the plaintext are known or can be guessed.
Dave. | [reply] [d/l] [select] |
|
It's called a Vigenere cipher, and this variant is an especially weak variant because the length of the key is known to be 13 characters. It is somewhat more secure if the key length isn't known to the attacker.
If the key length is variable, for long ciphertexts, there are algorithms that can quickly yield the plaintext. For very short cipertexts, it's a lot more secure than you might think. If the key is as long as the message, it's basically a one-time pad.
| [reply] |
|
Thanks Dave,
I figured it's terribly insecure, but the original premise was helping someone do some simple obfu that could be encoded in hex and then decoded. Security wasn't really part of the deal.
It was a uni project for the person and we kind of collaborated outside of any forums. A learning exercise essentially.
| [reply] |
Re: crypto with core modules only
by zentara (Archbishop) on Aug 29, 2018 at 10:06 UTC
|
Here is a good one, which frodo72, now known as polettix showed me in perl encryptions keys vs. c. I was trying to find out how to make c's RC4 compatible with perl's RC4. Anyways, this code is pretty good for your purposes, it uses no modules, and uses a key.
#!/usr/bin/perl -0777 --
# by frodo72 of perlmonks
# $0 key infile > outfile
# symmetric works both ways
use strict;
use warnings;
my @k = map { ord($_) } split //, shift;
my ( @s, $x, $y );
$y = 0;
for ( my @t = @s = 0 .. 255 ) {
$y = ( $k[ $_ % @k ] + $s[ $x = $_ ] + $y ) % 256;
&S;
}
$x = $y = 0;
for ( unpack( 'C*', <> ) ) {
$x++;
$y = ( $s[ $x %= 256 ] + $y ) % 256;
&S;
print pack( 'C', $_ ^= $s[ ( $s[$x] + $s[$y] ) % 256 ] );
}
sub S { @s[ $x, $y ] = @s[ $y, $x ] }
| [reply] [d/l] |
Re: crypto with core modules only
by shmem (Chancellor) on Aug 28, 2018 at 17:37 UTC
|
using core-modules only
That basically amounts to including any useful perl-only encryption module verbatim (along with those it depends on) into the script you want to create.
There should be no difference between doing that and using a non-core module, except maintainance issues.
See also App::FatPacker, Module::FatPack etc.
perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
| [reply] |
Re: crypto with core modules only
by trippledubs (Deacon) on Aug 28, 2018 at 18:32 UTC
|
The hashed text from crypt can be longer than 8 characters unless you are working with ancient implementation
#!/usr/bin/env perl
use strict;
use warnings;
# a non-random salt == 'salt'
#SHA256
print crypt("secret",'$5$salt');
print "\n";
#SHA512
print crypt("secret",'$66salt');
print "\n";
# Oops, security gone, that is not what I meant
# I meant this
print crypt("secret",'$6$salt');
You also have Digest, which is core
#!/usr/bin/env perl
use strict;
use warnings;
use Digest;
my $algo = 'SHA-512';
sub hash {
my $string = shift;
my $salt;
# bless whoever wrote this
$salt .= join '',('.','/',(0..9),"a".."z","A".."Z")[rand 64] for (
+1..8);
my $hasher = Digest->new($algo);
$hasher->add($salt);
$hasher->add($string);
return $salt . $hasher->b64digest();
}
sub checkHash {
# First 8 characters are salt
my $hash = shift;
my $string = shift;
my $salt = substr($hash,0,8);
my $hasher = Digest->new($algo);
$hasher->add($salt);
$hasher->add($string);
return $hash eq $salt . $hasher->b64digest();
}
my $hash = hash('blahblah');
print "match" if checkHash($hash,'blahblah');
for encryption, you can xor, read more here Encryption using perl core functions only. | [reply] [d/l] [select] |
Re: crypto with core modules only
by zentara (Archbishop) on Aug 28, 2018 at 12:35 UTC
|
Hi, if you don't care about passwords, this will still stop the average joe from viewing.
#!/usr/bin/perl
use warnings;
use strict;
#by fokat of perlmonks
my $string = 'justanotherperlhacker';
print "$string\n";
my $obscure = pack("u",$string);
print "$obscure\n";
my $unobscure = unpack(chr(ord("a") + 19 + print ""),$obscure);
print "$unobscure\n";
| [reply] [d/l] |
Re: crypto with core modules only
by QM (Parson) on Aug 28, 2018 at 17:06 UTC
|
$x =~ y/A-Za-z/N-ZA-Mn-za-m/;
-QM
--
Quantum Mechanics: The dreams stuff is made of
| [reply] [d/l] |
Re: crypto with core modules only
by TheloniusMonk (Sexton) on Aug 30, 2018 at 14:26 UTC
|
The best (unbreakable) and simplest has to be the One-time_pad. This originally was restricted to 26 letters. To include all printables you would need to transpose "\n" to say chr(127) (unprintable just after 126 printable) to keep the printables + a token for "\n" sequential. Then you generate N random numbers between 0 and 95 (hereafter the key), one for each character in the input. The encryption is to subtract 32 from the ord of each character in the input and add it to its corresponding key value modulo 95. Add 32 to that and you have the ord of a printable except for 127 which you replace with "\n". Same for the key - add 32, chr it and transpose chr(127) to "\n" for printing it out. The key (one-time pad) is issued on encryption and is needed for decryption. Decryption is simply the inverse -- subtract 32 from the key characters and input characters, subtract each key value from the input character value modulo 95, add 32, print except that 127 is printed as "\n".
Both the key and the encrypted files are random, so without the key, the code is completely unbreakable. | [reply] |
|
my $encrypted = $message ^ $key;
my $decrypted = $encrypted ^ $key;
This will result in a ciphertext which is full of non-printable characters, but you can base64 encode it (MIME::Base64 has been in core since before Perl 5.8).
The problem with one-time pads is that the keys are very long (same length as the message) and need to have a decent amount of randomness, so cannot be committed to memory. They need to be stored somewhere.
| [reply] [d/l] [select] |
|
I considered XOR before choosing the algorithm and rejected it because XOR only changes those bits that are different = about 50% of them. Although that seems plausibly enough to have the same effect, it seemed easier to block possible security loopholes therein than to have to do days of work analysing them statistically.
And because you then have to choose something like MIME::Base64 to make it printable, this would increase the average lengths of both key and message by (95-64)/64 * 100% = 60.8%, exacerbating your own final point about lengths.
Conversely, the OP is trying to encode a small list of info, I imagine to be something like:-
pwd google p&BBw0RD
pin iphone 8642
etc.
So I chose the solution that best fits what I imagine to be the use case. Yes the user needs to note the key which is issued at encryption time, equal in length to his secret info list and although it might well be 50+ characters in length, the OP is highly suggestive of wanting to reject keys that are too short - hence I stick by my post. I feel I responded as optimally as I could within a reasonable level of
background research.
update re having to store the key somewhere - this is already consequent from the boundary conditions of the OP. And its precisely what the OTP and the OP for that matter is about - write it on the back of a business card and close the terminal window used to generate the key, so there is only one physical copy, no electronic copies reducing the weakness to one physical item to keep in your physical wallet.
more update: flipping half the bits with xor is analytically breakable for repeated use on same document where changes are small. modulo solution does not have same weakness.
| [reply] |
|
|
|
|
|
|
|
A reply falls below the community's threshold of quality. You may see it by logging in.
|
|
|
|
|
|
|
|