Sunday, June 29, 2014

Passing AES keys through RSA public key encryption (PERL)

I've been interested with encryption for a while but never found a reason to actually write any code about it until recently.

Here is a sample perl script that goes through the motions of passing AES 256 key through an RSA public key encryption and then goes on to decrypt a message encrypted with the AES key.

The encrypted AES key and the encrypted message are both encoded in base64 for passing through email or other ASCII method of transfer.

I wrote this script as a learning tool to understand the AES and RSA methods. Other than that this script has no usefulness.

You may use this script in whole or part to further your understanding of cryptography methods.

I make no claims that this is the best way to accomplish passing a key to someone but it is a method.  I also make no claims that this code is correct and welcome any comments/suggestions to improve the process, especially the generation of the AES key.  I have no idea if the method I use is considered secure.

############################################################################
#!/usr/local/bin/perl

use strict;
use warnings;

use Crypt::CBC;
use MIME::Base64;
use Crypt::OpenSSL::RSA;
use Digest::SHA qw(sha1 sha1_hex sha1_base64 sha384 sha512 sha512_hex sha512_base64 sha256 sha256_hex sha256_base64 hmac_sha256 hmac_sha256_base64 hmac_sha256_hex hmac_sha512 hmac_sha512_base64);
use Bytes::Random::Secure qw(
        random_bytes random_bytes_base64 random_bytes_hex
    );

##############################################################################
#Generate the keys
##############################################################################
print "#######################################################################
# Generate the keys
#######################################################################\n\n";

my (%rsa_key_pair); #using a hash to store my private/public and other public keys. The hash itself is not encrypted but that is trivial to fix once we learn how to do it with AES

#also since this is a tutorial we generate a new set of keys each time the script is run - in the real world we'd need to dig these keys out of a key file stored on a drive
#this key file should also be encrypted with a passphrase (not discussed in this tutorial)

print "Generating RSA key pair...\n\n";

        my $rsa = Crypt::OpenSSL::RSA->generate_key(2048);

        my $keyidx = $rsa->get_public_key_string() if defined $rsa; #get the index of the key-pair

        $keyidx = sha512_hex( $keyidx, "" ); #hash the index
        $keyidx = substr( $keyidx, 0, 6 ); #shorten the hash to 6 digits

        $rsa_key_pair{$keyidx}{'pubK'}  = $rsa->get_public_key_string(); #load the hash
        $rsa_key_pair{$keyidx}{'privK'} = $rsa->get_private_key_string();
        $rsa_key_pair{$keyidx}{'Local'} = 1;

my $rsa_public_key = $rsa_key_pair{$keyidx}{'pubK'}; #set local key variables - not necessary but convenient
my $rsa_private_key = $rsa_key_pair{$keyidx}{'privK'};

#print $rsa_private_key; #print them if you want to see them
#print "\n\n";
#print $rsa_public_key;
#print "\n\n";

print "Generating AES key...\n\n";

my $random_generator = Bytes::Random::Secure->new(
    Bits        => 64,
    NonBlocking => 1,
); # Seed with 64 bits, and use /dev/urandom (or other non-blocking).

my $AES32byte_random = $random_generator->bytes(32); # A string of 32 random bytes which we'll use as the AES key

print "AES32byte_random: ";
print $AES32byte_random; 
print "\nSizeof AES32byte_random: ";
print length $AES32byte_random;
print "\n\n";
 
##############################################################################
#The encryption process
##############################################################################
print "#######################################################################
# The Encryption Process
#######################################################################\n\n";
my $RSA_en_cipher = Crypt::OpenSSL::RSA->new_public_key($rsa_public_key); #create a new public key cipher object

my $binary_encrypted_key = $RSA_en_cipher->encrypt($AES32byte_random); # encrypt the AES key

print "Binary encrypted key: \n";
print $binary_encrypted_key;
print "\n\n";

my $encoded_encrypted_key = encode_base64($binary_encrypted_key); #encode the encrypted AES key -  encrypt and encode can be combined in one line - this is a tutorial

print "Encoded encrypted key: \n" . $encoded_encrypted_key . "\n\n";
#at this point send the encoded encrypted key to the private key holder via email or text message etc.


#the message to encrypt - why we're doing this exercise - well one of the reasons anyway
my $cleartext = "This module is a Perl-only implementation of the cryptographic cipher block chaining mode (CBC).
In combination with a block cipher such as DES or IDEA, you can encrypt and decrypt messages of arbitrarily long length.
The encrypted messages are compatible with the encryption format used by the OpenSSL package.

To use this module, you will first create a Crypt::CBC cipher object with new().
At the time of cipher creation, you specify an encryption key to use and, optionally, a block encryption algorithm.
You will then call the start() method to initialize the encryption or decryption process,
crypt() to encrypt or decrypt one or more blocks of data, and lastly finish(), to pad and encrypt the final block.
For your convenience, you can call the encrypt() and decrypt() methods to operate on a whole data value at once.";

#create the AES encryption cipher object
my $AES_en_cryption_cipher = Crypt::CBC->new(
        {
                'key'           => $AES32byte_random,
                'cipher'        => 'Rijndael',
                'padding'       => 'standard',
             
        });
     
     
my $AES_en_crypted_message = $AES_en_cryption_cipher->encrypt($cleartext); #encrypt the message

print "Encrypted message:\n";
print $AES_en_crypted_message;
print "\n\n";


my $encoded_AES_en_crypted_message = encode_base64($AES_en_crypted_message); #encode the encrypted message to send via email etc.

print "Encoded encrypted message:\n";
print $encoded_AES_en_crypted_message;
print "\n\n";

#Now pass the message via email etc. to the other person who should now have the AES key decrypted so they can now decrypt the message


##############################################################################
#The decryption process - this happens at the private keyholder's side - this is a tutorial
##############################################################################
print "#######################################################################
# The Decryption Process
#######################################################################\n\n";


#decode
print "Decoding keys...\n";

my $encoded_decryption_key = $encoded_encrypted_key; #just to keep the variables separate - this also simulates the passing of the encrypted key via email etc.

print "Encoded decryption key: \n" . $encoded_decryption_key . "\n\n";

my $binary_decryption_key = decode_base64($encoded_decryption_key); #decode the key into binary so we can decrypt it

print "Binary decryption key: \n" . $binary_decryption_key . "\n\n";


#decrypt
print "Decrypting keys...\n";

my $RSA_de_cipher = Crypt::OpenSSL::RSA->new_private_key($rsa_private_key); # create a new decryption cipher object using the PRIVATE key

my $binary_decrypted_key = $RSA_de_cipher->decrypt($binary_decryption_key); # decrypt the AES key

print "Binary decrypted key: \n" . $binary_decrypted_key . "\n\n\n"; #this should be the binary 256bit binary AES key

#let's test that
print "Testing AES key pass through RSA public key encryption:\n\n";
print $AES32byte_random . "\n\n - should equal - \n\n" . $binary_decrypted_key . "\n\n"; #print the two binary keys - do they line up? - visual compare


if ($AES32byte_random eq $binary_decrypted_key) #let the computer compare then too
{
        print "\nSUCCESS!\n\n";
}
        else
        {
        print "\nFAIL! Now exiting!\n\n";
        exit;
}
print "Now to decrypt the message with the passed AES key...\n\n";

#create a new AES encryption cipher object
my $AES_de_cryption_cipher = Crypt::CBC->new(
        {
                'key'           => $binary_decrypted_key, #uses the binary AES key we just decoded and decrypted
                'cipher'        => 'Rijndael', #aka AES
                'padding'       => 'standard', #padding is a good thing so we can use this key more than once
             
        });

my $message_to_decode = $encoded_AES_en_crypted_message; #here is the simulated encrypted message send through email etc.

print "Encoded message to decrypt:\n";
print $message_to_decode;
print "\n\n";


$message_to_decode = decode_base64($message_to_decode); #decode into binary

print "Decoded message to decrypt:\n";
print $message_to_decode;
print "\n\n";

my $decoded_message = $AES_de_cryption_cipher->decrypt($message_to_decode); #decode the message


print "Decrypted message:\n"; #should be the same as the $cleartext variable above
print $decoded_message;
print "\n\n";

#let's test it
print "Testing if decode was successful...\n";

if ($decoded_message eq $cleartext)
{
        print "\nMessages match - SUCCESS!\n\n";
}
        else
        {
        print "\nMessages do NOT match - FAIL! Now exiting!\n\n";
        exit;
}


exit;
###################################################################
#script run output
###################################################################
#######################################################################
# Generate the keys
#######################################################################

Generating RSA key pair...

Generating AES key...

AES32byte_random: g&ÿ}■·ºQ♂╚rF░%Y¡▀}╨;┐█¶Ñ3~Ç≡╞ª►▒
Sizeof AES32byte_random: 32

#######################################################################
# The Encryption Process
#######################################################################

Binary encrypted key:
←╖Ä     ▼╣è♥à☻;XÉzMIè√0H0Ω↨í░ônö╔≈z▓|1§⌐╚£*∙V☼ªE≡9╧'N┬N/àb╨Xjgzƒ█l4▲{═☻√■W╬p☺╢7ê
x.╪K
z5♦!Éèê¡*ä■⌠╥B╨CGPoΘ╝îσxδ╬╜;>9q]‼ε/Vτúf7îª╢ö╞Ü9┤&A«O╓
âh#╛F░-å♠▒╬╣♂∞╙┴≥`£╣≡■ó╤
BΓû║áy\ìÅ░3╢╢@à╟AF╨▄Σ╕╞;╜⌂2/ëδ§"Hîw┤║↔![╠↨3Æ>↔]cQå«{¿╦¼↕à╜┬←ôMfñ╥╕╬ú.æB∞Σ<û

Encoded encrypted key:
G7eOCR+5igOFAjtYkHpNSYr7MEgw6hehsJNulMn3erJ8MRWpyJwq+VYPpkXwOc8nTsJOL4Vi0Fhq
Z3qf22w0HnvNAvv+V85wAbY3iHgu2EsKejUEIZCKiK0qhP700kLQQ0dQb+m8jOV46869Oz45cV0T
7i9W56NmN4ymtpTGmjm0JkGuT9YKg2gjvkawLYYHBrHOuQvs08HyYJy58P6i0QokOP/ysLmx35d7
9PWhkz0vKig1DULilrqgeVyNj7AztrZAhcdBRtDc5LjGO71/Mi+J6xUiSIx3tLodIVvMFzOSPh1d
Y1GGrnuoy6wShb3CG5NNZqTSuM6jLpFC7OQ8lg==


Encrypted message:
σgò↨ⁿ¼╖báv+▒É▼¡êΦáª#gJ¼èo[ÖiV▲ª╘kÖ7v»wQa╩0g-Σ└ÖfVÖ♫╢æù8àΣ§gìºφ=æBΦCJ│äÆw■σB0¥ 2╔
æm╫>Cí▐▼Äc!3☻æY(ß╥¡ΦEôéM┌á─o?íτt▄┌█¿§Σtφ{▓¥«ε╕p☺↓Ç=3╥61≡D╡√ÜW⌡αow╒╝√Q⌡ò⌐╘(↓‼Xw♠Ä
┴Ö☻ª{ë╔Z▓ε♀]o4Éc+♥_¡α(▬"ºH♂ë\&K┌d$☺/z☼▲╙☻¼┤à)Γ╒>,▀\█♂NÅ:,└┐∙φ&L☼!7☺;m╚¬h≈┴à▼+♥│d
oYGR∙U;hÆKK╖¶Γ░♥@;çî╗E▀▒l≥╢P←é☺úIÜjg┬B▒~╧(δä5@ᬽ°╛L♫`τge‼íK%}¬fµé'     k▀ä▌∙⌐S▒
)j╨╫♂2uäü⌂ºb↨8⌡≤x╨0▒"┬♦▌ñ»♫↓╛PÖ╦;nΘ,Éû▒å,8╔â↕╡'<»≡:╜╫c╫Ü▒Φ·LΓô;µ¬☻░G■±èJδT☼╘{█É↨
xg▲zôVQ♠▼↨├)►c╢$²╓τzùvßπX♣^╜YkPà↑Θ{j¶╚½½`î0«Æ╓⌐Ä│↑.ì▬₧▌►S♥└►Ü[¿x┐6N]i╘UµtF↕_S▄↔Ä
↑¿²├L}y*┤╠═Ä╝÷┘╣1╨# üB{¬°S┌☻*'≤ñúä▌]ö§Üε,üª╬ú6▬Vu'¶Σ0╡k!╛ûúÖE*_%☺╗ö╟▄bε╜²╤{V¼╨╗√f├╖╡I▼┼≤≤∟[Θⁿ7n┤≥Ñ╠╗♫ÑÇ┬8
♦☼·Hæ▓☺#ΣìY>[µ╗`

Encoded encrypted message:
U2FsdGVkX1/gYdAOA7DFcM46bvXhGmWpamEwDYOfHLc436Fpu5OBDFXnNFsmzB+EsOGMy/G1MRMp
nPNCc0jqDlFRiJ0HycUVoBqRvOjU2l2Smnlrsh31DeVnlRf8rLdioHYrsZAfrYjooKYjZ0qsim9b
mWlWHqbUa5k3dq93UWHKMGct5MCZZlaZDraRlziF5BVnjaftBz2RQuhDSrOEknf+5UIwnQAyyb1n
mMIlDmaYNBPheHqs53hWQz+AyHQz3ZRAxSCmbQ2Rbdc+Q6HeH45jITMCkVko4dKt6EWTgk3aoMRv
P6HndNza26gV5HTte7Kdru64cAEZgD0z0jYx8ES1+5pX9eBvd9W8+1H1lanUKBkTWHcGjsGZAqZ7
iclasu4MXW/sCDSQYysDX63gKBYip0gLiVwmS9pkJAEveg8e0wKstIUp4tU+LN9c2wtOjzoswL/5
7SZMDyE3ATttyKpo98GFHysDs2RvWUdS+VU7aJJLS7cU4rADQDuHjLtF37Fs8rZQG4IBo0maamfC
QrF+zyjrhDVAoKqr+L5MDmDnZ2UToUslfapm5oInCWvfhN35qVOxKWrQ1wsydYSBf6diFzj183jQ
MLEiwgTdpK8OGb5Qmcs7bukskJaxhiw4yYMStSc8r/A6vddj15qx6PpM4pM7FAjmqgKwR/7xikrr
VA/Ue9uQF3hnHnqTVlEGHxfDKRBjtgck/dbnepd24eNYBV69WWtQhRjpe2oUyKurYIwwrpLWqY6z
GC6NFp7dEFMDwBCaW6h4vzZOXWnUVeZ0RhJfU9wdjhrVX+R73ZhoT7FMnLkoYsi8twMVshxE6xNO
GEAXgsiT38SUzD4GvBUsJ+ian36XVR1wnoKxeOjlwCn9RWVkrWazEld/B+MNGKj9w0x9eSq0zM2O
vPbZuTHQI/+BQnuq+DxmOePe+W5UyrIEoVSlE0C84aSJw73FL5px57xlWL6XMH7Z5LVXs51bI/j4
KCNeNgPqE62wHiFT2gIqJ/Oko4TdXZQVmu4sgabOozYWVnUnFOQwtWshvpajmUUqXyUBu5TH3GLu
vf3Re1as0Lv7ZsO3tUkfxfPzHFvp/DdutPKlzLsOpYDCOAQP+kiRsgEj5I1ZPlvmu2A=


#######################################################################
# The Decryption Process
#######################################################################

Decoding keys...
Encoded decryption key:
G7eOCR+5igOFAjtYkHpNSYr7MEgw6hehsJNulMn3erJ8MRWpyJwq+VYPpkXwOc8nTsJOL4Vi0Fhq
Z3qf22w0HnvNAvv+V85wAbY3iHgu2EsKejUEIZCKiK0qhP700kLQQ0dQb+m8jOV46869Oz45cV0T
7i9W56NmN4ymtpTGmjm0JkGuT9YKg2gjvkawLYYHBrHOuQvs08HyYJy58P6i0QokOP/ysLmx35d7
9PWhkz0vKig1DULilrqgeVyNj7AztrZAhcdBRtDc5LjGO71/Mi+J6xUiSIx3tLodIVvMFzOSPh1d
Y1GGrnuoy6wShb3CG5NNZqTSuM6jLpFC7OQ8lg==


Binary decryption key:
←╖Ä     ▼╣è♥à☻;XÉzMIè√0H0Ω↨í░ônö╔≈z▓|1§⌐╚£*∙V☼ªE≡9╧'N┬N/àb╨Xjgzƒ█l4▲{═☻√■W╬p☺╢7ê
x.╪K
z5♦!Éèê¡*ä■⌠╥B╨CGPoΘ╝îσxδ╬╜;>9q]‼ε/Vτúf7îª╢ö╞Ü9┤&A«O╓
âh#╛F░-å♠▒╬╣♂∞╙┴≥`£╣≡■ó╤
BΓû║áy\ìÅ░3╢╢@à╟AF╨▄Σ╕╞;╜⌂2/ëδ§"Hîw┤║↔![╠↨3Æ>↔]cQå«{¿╦¼↕à╜┬←ôMfñ╥╕╬ú.æB∞Σ<û

Decrypting keys...
Binary decrypted key:
g&ÿ}■·ºQ♂╚rF░%Y¡▀}╨;┐█¶Ñ3~Ç≡╞ª►▒


Testing AES key pass through RSA public key encryption:

g&ÿ}■·ºQ♂╚rF░%Y¡▀}╨;┐█¶Ñ3~Ç≡╞ª►▒

 - should equal -

g&ÿ}■·ºQ♂╚rF░%Y¡▀}╨;┐█¶Ñ3~Ç≡╞ª►▒


SUCCESS!

Now to decrypt the message with the passed AES key...

Encoded message to decrypt:
U2FsdGVkX1/gYdAOA7DFcM46bvXhGmWpamEwDYOfHLc436Fpu5OBDFXnNFsmzB+EsOGMy/G1MRMp
nPNCc0jqDlFRiJ0HycUVoBqRvOjU2l2Smnlrsh31DeVnlRf8rLdioHYrsZAfrYjooKYjZ0qsim9b
mWlWHqbUa5k3dq93UWHKMGct5MCZZlaZDraRlziF5BVnjaftBz2RQuhDSrOEknf+5UIwnQAyyb1n
mMIlDmaYNBPheHqs53hWQz+AyHQz3ZRAxSCmbQ2Rbdc+Q6HeH45jITMCkVko4dKt6EWTgk3aoMRv
P6HndNza26gV5HTte7Kdru64cAEZgD0z0jYx8ES1+5pX9eBvd9W8+1H1lanUKBkTWHcGjsGZAqZ7
iclasu4MXW/sCDSQYysDX63gKBYip0gLiVwmS9pkJAEveg8e0wKstIUp4tU+LN9c2wtOjzoswL/5
7SZMDyE3ATttyKpo98GFHysDs2RvWUdS+VU7aJJLS7cU4rADQDuHjLtF37Fs8rZQG4IBo0maamfC
QrF+zyjrhDVAoKqr+L5MDmDnZ2UToUslfapm5oInCWvfhN35qVOxKWrQ1wsydYSBf6diFzj183jQ
MLEiwgTdpK8OGb5Qmcs7bukskJaxhiw4yYMStSc8r/A6vddj15qx6PpM4pM7FAjmqgKwR/7xikrr
VA/Ue9uQF3hnHnqTVlEGHxfDKRBjtgck/dbnepd24eNYBV69WWtQhRjpe2oUyKurYIwwrpLWqY6z
GC6NFp7dEFMDwBCaW6h4vzZOXWnUVeZ0RhJfU9wdjhrVX+R73ZhoT7FMnLkoYsi8twMVshxE6xNO
GEAXgsiT38SUzD4GvBUsJ+ian36XVR1wnoKxeOjlwCn9RWVkrWazEld/B+MNGKj9w0x9eSq0zM2O
vPbZuTHQI/+BQnuq+DxmOePe+W5UyrIEoVSlE0C84aSJw73FL5px57xlWL6XMH7Z5LVXs51bI/j4
KCNeNgPqE62wHiFT2gIqJ/Oko4TdXZQVmu4sgabOozYWVnUnFOQwtWshvpajmUUqXyUBu5TH3GLu
vf3Re1as0Lv7ZsO3tUkfxfPzHFvp/DdutPKlzLsOpYDCOAQP+kiRsgEj5I1ZPlvmu2A=


Decoded message to decrypt:
σgò↨ⁿ¼╖báv+▒É▼¡êΦáª#gJ¼èo[ÖiV▲ª╘kÖ7v»wQa╩0g-Σ└ÖfVÖ♫╢æù8àΣ§gìºφ=æBΦCJ│äÆw■σB0¥ 2╔
æm╫>Cí▐▼Äc!3☻æY(ß╥¡ΦEôéM┌á─o?íτt▄┌█¿§Σtφ{▓¥«ε╕p☺↓Ç=3╥61≡D╡√ÜW⌡αow╒╝√Q⌡ò⌐╘(↓‼Xw♠Ä
┴Ö☻ª{ë╔Z▓ε♀]o4Éc+♥_¡α(▬"ºH♂ë\&K┌d$☺/z☼▲╙☻¼┤à)Γ╒>,▀\█♂NÅ:,└┐∙φ&L☼!7☺;m╚¬h≈┴à▼+♥│d
oYGR∙U;hÆKK╖¶Γ░♥@;çî╗E▀▒l≥╢P←é☺úIÜjg┬B▒~╧(δä5@ᬽ°╛L♫`τge‼íK%}¬fµé'     k▀ä▌∙⌐S▒
)j╨╫♂2uäü⌂ºb↨8⌡≤x╨0▒"┬♦▌ñ»♫↓╛PÖ╦;nΘ,Éû▒å,8╔â↕╡'<»≡:╜╫c╫Ü▒Φ·LΓô;µ¬☻░G■±èJδT☼╘{█É↨
xg▲zôVQ♠▼↨├)►c╢$²╓τzùvßπX♣^╜YkPà↑Θ{j¶╚½½`î0«Æ╓⌐Ä│↑.ì▬₧▌►S♥└►Ü[¿x┐6N]i╘UµtF↕_S▄↔Ä
↑¿²├L}y*┤╠═Ä╝÷┘╣1╨# üB{¬°S┌☻*'≤ñúä▌]ö§Üε,üª╬ú6▬Vu'¶Σ0╡k!╛ûúÖE*_%☺╗ö╟▄bε╜²╤{V¼╨╗√f├╖╡I▼┼≤≤∟[Θⁿ7n┤≥Ñ╠╗♫ÑÇ┬8
♦☼·Hæ▓☺#ΣìY>[µ╗`

Decoded message:
This module is a Perl-only implementation of the cryptographic cipher block chai
ning mode (CBC).
In combination with a block cipher such as DES or IDEA, you can encrypt and decr
ypt messages of arbitrarily long length.
The encrypted messages are compatible with the encryption format used by the Ope
nSSL package.

To use this module, you will first create a Crypt::CBC cipher object with new().

At the time of cipher creation, you specify an encryption key to use and, option
ally, a block encryption algorithm.
You will then call the start() method to initialize the encryption or decryption
 process,
crypt() to encrypt or decrypt one or more blocks of data, and lastly finish(), t
o pad and encrypt the final block.
For your convenience, you can call the encrypt() and decrypt() methods to operat
e on a whole data value at once.

Testing if decode was successful...

Messages match - SUCCESS!

Press any key to continue . . .



1 comment:

  1. Great tutorial. Very much appreciated. Only con: it took me far too long to find it :-).

    ReplyDelete