Encoding / encryption error when porting Python to Perl script

I have a Python script that works great. It is able to decode / decrypt the provided pwd and encode / encrypt it like below:

#!/usr/bin/python

from Crypto.Cipher import DES3
import base64

secret = base64.decodestring('tcxpLw1PsMR0CtXt/HfbIZomvJtDyE6h1Gl4vblX2W4=')
key = secret[:24]
iv = secret[24:]

# Encoded Encrypted password
EEpwd = '4TOHTKsvihUXuUd9M3TpoA=='
print "Encoded Encrypted Password : ",EEpwd

# Decoded Encrypted password
DEpwd = base64.decodestring(EEpwd)

# Decoded Decrypted password
DDpwd = DES3.new(key, DES3.MODE_CBC, iv).decrypt(DEpwd)
print "Decoded (Decrypted ( PWD ) ) : ",DDpwd

# New Decoded Encrypted password
NewDEpwd = DES3.new(key, DES3.MODE_CBC, iv).encrypt(DDpwd)

# New Encoded Encrypted password
NewEEpwd = base64.b64encode(NewDEpwd)
print "New Encoded (Encrypted (",DDpwd,") ) : ",NewEEpwd

      

... this gives me the following output:

Encoded Encrypted Password :  4TOHTKsvihUXuUd9M3TpoA==
Decoded (Decrypted ( PWD ) ) :  MYweakPW
New Encoded (Encrypted ( MYweakPW ) ) :  4TOHTKsvihUXuUd9M3TpoA==

      

Now I need to port this script to Perl, so I did:

#!/usr/bin/perl
use MIME::Base64;
use Crypt::CBC;

$secret = decode_base64('tcxpLw1PsMR0CtXt/HfbIZomvJtDyE6h1Gl4vblX2W4=');
$key = substr($secret,0,24);
$iv = substr($secret,24);

$cipher = Crypt::CBC->new(
                -cipher => 'DES_EDE3',
                -key    => $key,
                -iv     => $iv,
                -header => 'none',
                -padding => 'null',
                -literal_key => 1
                );

# Encoded Encrypted password
$EEpwd = '4TOHTKsvihUXuUd9M3TpoA==';
print "Encoded Encrypted Password : ". $EEpwd ."\n";

# Decoded Encrypted password
$DEpwd = decode_base64($EEpwd);

# Decoded Decrypted password
$DDpwd = $cipher->decrypt($DEpwd);
print "Decoded (Decrypted ( PWD ) ) : $DDpwd \n";

# New Decoded Encrypted password
$NewDEpwd = $cipher->encrypt($DDpwd);

# New Encoded Encrypted password
$NewEEpwd = encode_base64($NewDEpwd);
print "New Encoded (Encrypted ($DDpwd) ) : $NewEEpwd \n";

      

... but this comes back to me:

Encoded Encrypted Password : 4TOHTKsvihUXuUd9M3TpoA==
Decoded (Decrypted ( PWD ) ) : MYweakPW 
New Encoded (Encrypted (MYweakPW) ) : 4TOHTKsvihU=

      

Question: Why when I encrypt / encode a password in Perl, it returns an abbreviated string? What's missing to match?

RH relationships


EDIT

Since I am changing the accepted answer, let me clarify some aspects of using this code to justify some options. Of course, this is not the whole script. I removed as much personal information as possible, as well as other parts of the script that were already working, isolating the piece of code that needs attention. The general purpose of the script is to manage passwords used in some other scripts / applications when the password is changed on remote servers.

This particular piece of code that handles the password stored by Remmina in the saved sessions. Unfortunately Remmina did not provide a centralized method for replacing saved passwords, so in my case, every time I change my password on a Windows domain, all my saved Remmina sessions are outdated (and I have dozens of them!)

Here's how Remmina stores passwords:

  • at $HOME/.remmina/remmina.pref

    is a string containing secret=*

    , encoded, with DES3 key

    andiv

  • each named session file $HOME/.remmina/*.remmina

    has a line password=*

    with your password, encoded and encrypted

However, it doesn't matter if the original encrypted / encoded password is correctly or incorrectly generated ... This is how Remmina does it and I have to deal with it: - /

Depending on the options provided on the command line, the script should be able to retrieve the saved password from files, *.remmina

or get a new one and replace it with files *.remmina

, so the point raised by @ jm666 on his EDIT2 is very pertinent, since when I get a new password from the command lines, it will not be pre-completed in any way.

For my specific scenario, I know that passwords will never be shorter than 8 bytes, but may be longer than a multiple of 8, so I tested this with new different passwords and realized that to encrypt passwords for Remmin, the corresponding padding = 'null'

  • A special case is that the password has exactly 8 bytes (or multiples of it). In this case, I had to "manually" add one null

    char to the end of the provided string to force the padding of additional null

    characters
+3


source to share


2 answers


You requested perl using padding=>'null'

. Just change:

$cipher = Crypt::CBC->new(
                -cipher => 'DES_EDE3',
                -key    => $key,
                -iv     => $iv,
                -header => 'none',
                -padding => 'null',
                -literal_key => 1
                );

      

before -padding => 'none',

and will get the same result as python .

NOTE. The above gives the desired output, but this is WRONG's answer as well as @harmic's answer too. See Board EDIT2.

Note that if you haven't entered any paddig (since you haven't used padding in your python code), for example

$cipher = Crypt::CBC->new(
                -cipher => 'DES_EDE3',
                -key    => $key,
                -iv     => $iv,
                -header => 'none',
                #-padding => 'null',   # <- commented out
                -literal_key => 1
                );

      

perl will use indentation standard

defined in PKCS#5

eg. padds with a number equal to the missing padding bytes. for example, if 2 bytes are missing, padding will be 0x02 0x02

, if 3 bytes are missing, padding will be 0x03 0x03 0x03

. (so a different python output with no specific padding will be issued)

EDIT

from the Crypt :: CBC changelog

2.31    Tue Oct 30 07:03:40 EDT 2012
    - Fixes to regular expressions to avoid rare failures to
      correctly strip padding in decoded messages.
    - Add padding type = "none".
    - Both fixes contributed by Bas van Sisseren.

      

The gasket has been none

supported for almost two years. :)

EDIT2

using none

or space

is completely wrong because:

You can never save the original 4TOHTKsvihUXuUd9M3TpoA==

string correctly ...



Try to encrypt and encode the password entered directly MYweakPW

. Regardless of the shim used, you never get the original String 4TOHTKsvihUXuUd9M3TpoA==

.

You will receive the following (depending on the add-on used):

Padding: standard               4TOHTKsvihW3UDR8tqmBIg==
Padding: space                  4TOHTKsvihU=
Padding: oneandzeroes           4TOHTKsvihUndO+JKCfmog==
Padding: rijndael_compat        4TOHTKsvihU=
Padding: null                   4TOHTKsvihU=
Padding: none                   4TOHTKsvihU=

      

MYweakPW

Hexdump plaintext password:

4d597765616b5057

      

You, after receiving decode -> decrypt

(depending on the fill method used :)

4d597765616b50570000000000000000
#or
4d597765616b5057

      

and when trying to encrypt it again, the encryption algorithm adds a new padding (or not - depending on the method used) to the string again.

All of this can be seen in the following script (basically yours, just using hex output):

use strict;
use warnings;
use MIME::Base64;
use Crypt::CBC;

my $secret = decode_base64('tcxpLw1PsMR0CtXt/HfbIZomvJtDyE6h1Gl4vblX2W4=');
my $iv = substr($secret,24);
my $key = substr($secret,0,24);

for my $padd ( qw(standard space  oneandzeroes  rijndael_compat  null  none)) {
    my $c = Crypt::CBC->new( -cipher=>'DES_EDE3', -key=>$key, -iv=>$iv,
                -header=>'none', -literal_key=>1,
                -padding=>$padd
            );
    print "== Padding: $padd=\n";
    display($c);
}

sub display {
    my $cipher = shift;

    my $EEpwd = '4TOHTKsvihUXuUd9M3TpoA==';
    p("Original (encrypted & encoded)", $EEpwd);

    my $DEpwd = decode_base64($EEpwd);
    ph("Original (decoded still encrypted)", $DEpwd);

    my $DDpwd = $cipher->decrypt($DEpwd);
    ph("Original plaintext", $DDpwd);

    my $NewDEpwd = $cipher->encrypt($DDpwd);
    ph("New from orig (encrypted)", $NewDEpwd);

    my $NewEEpwd = encode_base64($NewDEpwd);
    p( "New from orig (encrypted+encoded)", $NewEEpwd);

    my $asc = "MYweakPW";
    ph("String $asc", $asc);
    my $m1 = $cipher->encrypt($asc);
    ph("String (encrypted)", $m1);
    p("String (encrypted,encoded)", encode_base64($m1));
}

sub ph  { p($_[0] . " hex:", unpack('H*',$_[1]) ) }
sub p   { printf "%40.40s %s\n", @_; }

      

conclusion, compare yourself what hexdump you got after decryption / encryption depending on the addon used. ("Oroginal" means the strings you get from the original base64 encoding, and "String" means the value you get from the string entered directly MYweakPW

.

== Padding: standard=
          Original (encrypted & encoded) 4TOHTKsvihUXuUd9M3TpoA==
 Original (decoded still encrypted) hex: e133874cab2f8a1517b9477d3374e9a0
                 Original plaintext hex: 4d597765616b50570000000000000000
          New from orig (encrypted) hex: e133874cab2f8a1517b9477d3374e9a0a26625e0d2ebb3d4
       New from orig (encrypted+encoded) 4TOHTKsvihUXuUd9M3TpoKJmJeDS67PU

                    String MYweakPW hex: 4d597765616b5057
                 String (encrypted) hex: e133874cab2f8a15b750347cb6a98122
              String (encrypted,encoded) 4TOHTKsvihW3UDR8tqmBIg==

== Padding: space=
          Original (encrypted & encoded) 4TOHTKsvihUXuUd9M3TpoA==
 Original (decoded still encrypted) hex: e133874cab2f8a1517b9477d3374e9a0
                 Original plaintext hex: 4d597765616b50570000000000000000
          New from orig (encrypted) hex: e133874cab2f8a1517b9477d3374e9a0
       New from orig (encrypted+encoded) 4TOHTKsvihUXuUd9M3TpoA==

                    String MYweakPW hex: 4d597765616b5057
                 String (encrypted) hex: e133874cab2f8a15
              String (encrypted,encoded) 4TOHTKsvihU=

== Padding: oneandzeroes=
          Original (encrypted & encoded) 4TOHTKsvihUXuUd9M3TpoA==
 Original (decoded still encrypted) hex: e133874cab2f8a1517b9477d3374e9a0
                 Original plaintext hex: 4d597765616b50570000000000000000
          New from orig (encrypted) hex: e133874cab2f8a1517b9477d3374e9a0854bea98199fa99e
       New from orig (encrypted+encoded) 4TOHTKsvihUXuUd9M3TpoIVL6pgZn6me

                    String MYweakPW hex: 4d597765616b5057
                 String (encrypted) hex: e133874cab2f8a152774ef892827e6a2
              String (encrypted,encoded) 4TOHTKsvihUndO+JKCfmog==

== Padding: rijndael_compat=
          Original (encrypted & encoded) 4TOHTKsvihUXuUd9M3TpoA==
 Original (decoded still encrypted) hex: e133874cab2f8a1517b9477d3374e9a0
                 Original plaintext hex: 4d597765616b50570000000000000000
          New from orig (encrypted) hex: e133874cab2f8a1517b9477d3374e9a0
       New from orig (encrypted+encoded) 4TOHTKsvihUXuUd9M3TpoA==

                    String MYweakPW hex: 4d597765616b5057
                 String (encrypted) hex: e133874cab2f8a15
              String (encrypted,encoded) 4TOHTKsvihU=

== Padding: null=
          Original (encrypted & encoded) 4TOHTKsvihUXuUd9M3TpoA==
 Original (decoded still encrypted) hex: e133874cab2f8a1517b9477d3374e9a0
                 Original plaintext hex: 4d597765616b5057
          New from orig (encrypted) hex: e133874cab2f8a15
       New from orig (encrypted+encoded) 4TOHTKsvihU=

                    String MYweakPW hex: 4d597765616b5057
                 String (encrypted) hex: e133874cab2f8a15
              String (encrypted,encoded) 4TOHTKsvihU=

== Padding: none=
          Original (encrypted & encoded) 4TOHTKsvihUXuUd9M3TpoA==
 Original (decoded still encrypted) hex: e133874cab2f8a1517b9477d3374e9a0
                 Original plaintext hex: 4d597765616b50570000000000000000
          New from orig (encrypted) hex: e133874cab2f8a1517b9477d3374e9a0
       New from orig (encrypted+encoded) 4TOHTKsvihUXuUd9M3TpoA==

                    String MYweakPW hex: 4d597765616b5057
                 String (encrypted) hex: e133874cab2f8a15
              String (encrypted,encoded) 4TOHTKsvihU=

      

Result:

  • from a string string MYweakPW

    (for example, without 8 zeros at the end) you can never get the desired output regardless of padding (see results)
  • so the original string 4TOHTKsvihUXuUd9M3TpoA==

    was created INCORRECTLY (or deliberately added eight null characters to MYweakPW

    what is already added in 8 bytes).
  • you have to double-check how the original string was created (with which padding method), especially with a password that is not 8 bytes long . For example. try building a base64 encoded string with a password weak

    and you will see how it is padded.
+2


source


The padding option you choose will not be the same as the one used by the Python encryption library.



I found that by changing the -padding parameter to "space", the encrypted password was the same as the original.

+3


source







All Articles