问题
I am new to perl so this might be very basic, but i am finding no way around this problem. I am trying to sign my data which has to be send over https connection using my ssh private key(id_rsa)
. I am not able to do so using perl and i am at it for days. Please someone show me a possible way to do so. If any more info is needed please ask me. Thanks in advance
My code as asked is
#!/usr/bin/perl
use File::Slurp qw(read_file);
use Crypt::OpenSSL::RSA;
use MIME::Base64 qw( decode_base64 encode_base64 );
my $keystring = read_file( 'id_rsa' );
my $privatekey = Crypt::OpenSSL::RSA->new_private_key($keystring);
$privatekey->use_pkcs1_padding();
my $datatosign = "hello";
my $signature = $privatekey->sign($datatosign);
my $base64 = encode_base64($signature);
print "$base64";
The error coming on running it is RSA.xs:178: OpenSSL error: unsupported encryption at test.pl line 7.
NOTE: As discussed in the comments, I am using a passphrase protected id_rsa
.
回答1:
So, leaving out the perl, and just doing this by hand with openssl
Checking the key:
ssh-keygen -t rsa -f test_id
openssl rsa -in test_id -check
RSA key ok
So we do have a 'valid' RSA private key there, which we should be able to use for encrpyting.
Generating a comparison key
However if you use openssl to generate a key pair
openssl genrsa -out openssl_gen_rsa
openssl rsa -in openssl_gen_rsa -pubout -out openssl_gen_rsa.out
Looks like the command you need is:
openssl rsautl -inkey test_id -in test_file.txt -encrypt -out test_file.enc
(That encrypts with the private key, so you'd decrypt with the public key - that's actually pretty similar to signing - normally you wouldn't do this).
The problem is - if you compare your generated -public- keys they don't match. test_id.pub
looks like (Yes, this is the real one, and no, I did only use it for testing!)
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKfjRD+Gb5EE+SgOy7eoT0siQaAqfSY7KI2wkdrdygnJ+ccW/uMCtCVPhpz00u3EW2Gz1WI DteLKppjvUem1lKb8Tt2EWBQGyFOYKp44r3AJZgTcxLeDdqSUoiPsjWf1aUqy2Z1fBgtG+QOa7bpA8km6CbsORYX/TVg4B6vvdkkH K8WcmzBBF3rGsTCM3VXPp56bPoMCbwCsXvIjejmq+JdGHyxUmCxe1PrPyvmoYX3OUqpFBYIjeLWGDI9EXS6jA/r7viIAxdllvulPg IJ+4mdYzKN+T1ME0X0c+ZdFTMdeUnB9/TZmJr1j8Q/4SQm+3J9CiwtVXKxdkDsDObkcDp root@raspberrypi
Where my generated key file looks like:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDG8i33AuEp1wqbJgkEsnOmQim3
QT76B/oxsVGfJEDX3h4A6CD+ypBbfhhIn0GlfHanYvcGlpOJIlk3fzspbZNeoPJS
T4a0zQ0z8uJkugl8utyl9WR4tpgBRmzXZ42T/f4QSNqjDxUidRp5zPnXs9aRDtWb
XptswiGL3eVHMpbSnwIDAQAB
-----END PUBLIC KEY-----
I can use my generated pair (encrypting using public key, decrypting using private):
openssl rsautl -inkey openssl_gen_rsa.out -pubin -in test_file.txt -encrypt -out test_file.enc2
openssl rsautl -inkey openssl_gen_rsa -in test_file.enc2 -decrypt
This works.
Turning your OpenSSH private key into an RSA public key
So if we run your ssh private key through openssl:
openssl rsa -in test_id -pubout -out test_id.openssl.pub
We get:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyn40Q/hm+RBPkoDsu3qE
9LIkGgKn0mOyiNsJHa3coJyfnHFv7jArQlT4ac9NLtxFths9ViA7XiyqaY71HptZ
Sm/E7dhFgUBshTmCqeOK9wCWYE3MS3g3aklKIj7I1n9WlKstmdXwYLRvkDmu26QP
JJugm7DkWF/01YOAer73ZJByvFnJswQRd6xrEwjN1Vz6eemz6DAm8ArF7yI3o5qv
iXRh8sVJgsXtT6z8r5qGF9zlKqRQWCI3i1hgyPRF0uowP6+74iAMXZZb7pT4CCfu
JnWMyjfk9TBNF9HPmXRUzHXlJwff02Zia9Y/EP+EkJvtyfQosLVVysXZA7Azm5HA
6QIDAQAB
-----END PUBLIC KEY-----
Which isn't even a remotely similar encoding to the id_rsa.pub file - and I think therefore why you have this problem.
openssl rsautl -inkey test_id.openssl.pub -pubin -in test_file.txt -encrypt -out test_file.openssl.pub.enc
Now works, and you can decrypt it using your test_id
private key:
openssl rsautl -inkey test_id -in test_file.openssl.pub.enc -decrypt
So yes - for some reason the public key generated by ssh-keygen isn't the same format as openssl is expecting, so it's not going to work.
using an openssh key to verify
Anyway, back to your original example - using the private key to generate a signature:
openssl rsautl -sign -inkey test_id -in test_file.txt -out test_file.sig
openssl rsautl -verify -in test_file.sig -inkey test_id.openssl.pub -pubin
But the verify step won't work using the generated ssh key.
So does this answer your question as to whether it's possible
? I'm afraid I don't know how the ssh public key differs from a 'normal' rsa public key.
I suspect your code therefore doesn't even need to be as complicated as it - I don't think you need to pkcs pad your key file.
E.g.
#!/usr/bin/perl
use strict;
use warnings;
use File::Slurp qw(read_file);
use Crypt::OpenSSL::RSA;
use MIME::Base64 qw( decode_base64 encode_base64 );
my $keystring = read_file ('test_id');
my $privatekey = Crypt::OpenSSL::RSA->new_private_key($keystring);
my $datatosign = "hello";
my $signature = $privatekey->sign($datatosign);
my $base64 = encode_base64($signature);
print "Signature:\n";
print "$base64";
my $public_key_text = $privatekey-> get_public_key_string();
print "Public Key:\n";
print $public_key_text;
my $rsa_pub = Crypt::OpenSSL::RSA->new_public_key ( $public_key_text );
print "Signed correctly\n" if ($rsa_pub->verify($datatosign, decode_base64($base64)));
This seems to work. (note lack of pkcs padding line).
Encrypted private key (passphrase)
Following from comments:
If your id_rsa
has a passphrase set you'll have something like this:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,B44716076DD8B7D2B5E909BB8F70B48B
You can decrypt this by hand using openssl again:
openssl rsa -in test_id.enc
Enter pass phrase for test_id.enc:
Or:
openssl rsa -in test_id.enc -passin pass:testpass
I'm less sure how you do this using Crypt::OpenSSL::RSA
- there doesn't seem to be any option to specify a passphrase to a private key.
I think you therefore need to use Crypt::CBC
to decrypt the private key first. I can't test this, because I've got a load of dependencies to install.
A bit of googling suggests that you might be able to use Crypt::PK::RSA instead.
And as an alernative - use IPC::Open2
and start an openssl
process to do the things without using libraries at all.
e.g.
my $keystring = `openssl rsa -passin pass:testpass -in test_id.enc`;
Not very nice, but it'll work. (and test it does actually work)
来源:https://stackoverflow.com/questions/27342257/is-it-possible-to-sign-my-data-using-ssh-private-key-in-perl