S
Sam Roberts
I want to do unpadded RSA operations with openssl, but I discovered that
ossl_pkey_rsa.c hard-codes the use of PKCS#1 padding into the ruby
methods private/public_encrypt/decrypt.
What I think they should do is the same thing that OpenSSL does - accept
the padding type as an argument (and default to RSA_PKCS1_PADDING, as it
does now).
I don't know how to do this with ruby extensions, so I just hacked in
two functions that don't do the padding, just to see if it works (it
does), see the diff below.
Can unpadded RSA operations be added to the library? Thanks.
Btw, the openssl extension is systematically undocumented, I've begun
some docs locally (because my memory isn't good enough to use libraries
without docs). I'm happy to provide them as diffs to the .c source,
would anybody be interested?
Thanks,
Sam
++++++++++ beginning of OpenSSL docs ++++++++++++++++++++++++++
OpenSSL:
Key::RSA
new(bitsize, exp) -
Generate an RSA key pair, of +bitsize+, +exp+ is the public exponent, what's the default, 2^16 + 1?
These methods return the RSA key parameters:
Public:
#n = p * q, the public modulus
#e the public exponent, usually 2^16 + 1, but 3 is sometimes used for speed,
particularly when generating benchmarks that exagerate the speed of the
library.
Private:
#d = e ^ -1 mod (p-1)(q-1), the private exponent
#p prime component of d, used to speed up private key operations
#q prime component of d, used to speed up private key operations
#dmq1 = d mod (q-1), used to speed up private key operations
#dmp1 = d mod (p-1), used to speed up private key operations
#iqmp = q ^ -1 mod p, used to speed up private key operations
??
#d=
#dmp1=
#dmq1=
#e=
#iqmp=
#n=
#p=
#q=
Raw RSA operations:
Does m ^ d mod n. There are two modes, raw, and PKCS#1 padded. In raw
mode, m must be (less than or) equal in size to the public modulus, n.
In padded mode, m must be smaller than n - 11 bytes (the padding is
a least 11 bytes long) and it is padded out to size of n before raw
exponentiation is done.
FIXME - Currently, PKCS#1 padding is hard-coded.
#private_encrypt
Behaviour probably depends on padding mode. If there is no padding,
private_encrypt and private_decrypt should be the same. If there is
padding, then decrypt will strip the padding after the private
exponentiation (the inverse of the padded encrypt operation).
FIXME - Currently, PKCS#1 padding is hard-coded.
#private_decrypt
m ^ e mod n
#public_encrypt
#public_decrypt
Does it return true for private keys?
#public?
true is this is a private key.
#private?
PKCS#1v1.5 sign/verify?
#sign
#verify
??
params
??
to_pem
to_text
to_der
?? PEM
public_key
??
export
ruby -r openssl -e 'puts OpenSSL:
Key::RSA.new(512).methods-Object.methods'
++++ Diff to add unpadded rsa operations to openssl +++++++++++++
? openssl.bundle
Index: ossl_pkey_rsa.c
===================================================================
RCS file: /src/ruby/ext/openssl/ossl_pkey_rsa.c,v
retrieving revision 1.5.2.2
diff -u -r1.5.2.2 ossl_pkey_rsa.c
--- ossl_pkey_rsa.c 30 Jun 2004 18:34:59 -0000 1.5.2.2
+++ ossl_pkey_rsa.c 4 Dec 2004 18:43:56 -0000
@@ -272,6 +272,49 @@
}
static VALUE
+ossl_rsa_public_exp(VALUE self, VALUE buffer)
+{
+ EVP_PKEY *pkey;
+ int buf_len;
+ VALUE str;
+
+ GetPKeyRSA(self, pkey);
+ StringValue(buffer);
+ str = rb_str_new(0, ossl_rsa_buf_size(pkey));
+ buf_len = RSA_public_decrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr,
+ RSTRING(str)->ptr, pkey->pkey.rsa,
+ RSA_NO_PADDING);
+ if(buf_len < 0) ossl_raise(eRSAError, NULL);
+ RSTRING(str)->len = buf_len;
+ RSTRING(str)->ptr[buf_len] = 0;
+
+ return str;
+}
+
+static VALUE
+ossl_rsa_private_exp(VALUE self, VALUE buffer)
+{
+ EVP_PKEY *pkey;
+ int buf_len;
+ VALUE str;
+
+ GetPKeyRSA(self, pkey);
+ if (!RSA_PRIVATE(pkey->pkey.rsa)) {
+ ossl_raise(eRSAError, "PRIVATE key needed for this operation!");
+ }
+ StringValue(buffer);
+ str = rb_str_new(0, ossl_rsa_buf_size(pkey));
+ buf_len = RSA_private_encrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr,
+ RSTRING(str)->ptr, pkey->pkey.rsa,
+ RSA_NO_PADDING);
+ if (buf_len < 0) ossl_raise(eRSAError, NULL);
+ RSTRING(str)->len = buf_len;
+ RSTRING(str)->ptr[buf_len] = 0;
+
+ return str;
+}
+
+static VALUE
ossl_rsa_public_decrypt(VALUE self, VALUE buffer)
{
EVP_PKEY *pkey;
@@ -473,6 +516,9 @@
rb_define_method(cRSA, "public_decrypt", ossl_rsa_public_decrypt, 1);
rb_define_method(cRSA, "private_encrypt", ossl_rsa_private_encrypt, 1);
rb_define_method(cRSA, "private_decrypt", ossl_rsa_private_decrypt, 1);
+
+ rb_define_method(cRSA, "private_exp", ossl_rsa_private_exp, 1);
+ rb_define_method(cRSA, "public_exp", ossl_rsa_public_exp, 1);
DEF_OSSL_PKEY_BN(cRSA, rsa, n);
DEF_OSSL_PKEY_BN(cRSA, rsa, e);
ossl_pkey_rsa.c hard-codes the use of PKCS#1 padding into the ruby
methods private/public_encrypt/decrypt.
What I think they should do is the same thing that OpenSSL does - accept
the padding type as an argument (and default to RSA_PKCS1_PADDING, as it
does now).
I don't know how to do this with ruby extensions, so I just hacked in
two functions that don't do the padding, just to see if it works (it
does), see the diff below.
Can unpadded RSA operations be added to the library? Thanks.
Btw, the openssl extension is systematically undocumented, I've begun
some docs locally (because my memory isn't good enough to use libraries
without docs). I'm happy to provide them as diffs to the .c source,
would anybody be interested?
Thanks,
Sam
++++++++++ beginning of OpenSSL docs ++++++++++++++++++++++++++
OpenSSL:
new(bitsize, exp) -
Generate an RSA key pair, of +bitsize+, +exp+ is the public exponent, what's the default, 2^16 + 1?
These methods return the RSA key parameters:
Public:
#n = p * q, the public modulus
#e the public exponent, usually 2^16 + 1, but 3 is sometimes used for speed,
particularly when generating benchmarks that exagerate the speed of the
library.
Private:
#d = e ^ -1 mod (p-1)(q-1), the private exponent
#p prime component of d, used to speed up private key operations
#q prime component of d, used to speed up private key operations
#dmq1 = d mod (q-1), used to speed up private key operations
#dmp1 = d mod (p-1), used to speed up private key operations
#iqmp = q ^ -1 mod p, used to speed up private key operations
??
#d=
#dmp1=
#dmq1=
#e=
#iqmp=
#n=
#p=
#q=
Raw RSA operations:
Does m ^ d mod n. There are two modes, raw, and PKCS#1 padded. In raw
mode, m must be (less than or) equal in size to the public modulus, n.
In padded mode, m must be smaller than n - 11 bytes (the padding is
a least 11 bytes long) and it is padded out to size of n before raw
exponentiation is done.
FIXME - Currently, PKCS#1 padding is hard-coded.
#private_encrypt
Behaviour probably depends on padding mode. If there is no padding,
private_encrypt and private_decrypt should be the same. If there is
padding, then decrypt will strip the padding after the private
exponentiation (the inverse of the padded encrypt operation).
FIXME - Currently, PKCS#1 padding is hard-coded.
#private_decrypt
m ^ e mod n
#public_encrypt
#public_decrypt
Does it return true for private keys?
#public?
true is this is a private key.
#private?
PKCS#1v1.5 sign/verify?
#sign
#verify
??
params
??
to_pem
to_text
to_der
?? PEM
public_key
??
export
ruby -r openssl -e 'puts OpenSSL:
++++ Diff to add unpadded rsa operations to openssl +++++++++++++
? openssl.bundle
Index: ossl_pkey_rsa.c
===================================================================
RCS file: /src/ruby/ext/openssl/ossl_pkey_rsa.c,v
retrieving revision 1.5.2.2
diff -u -r1.5.2.2 ossl_pkey_rsa.c
--- ossl_pkey_rsa.c 30 Jun 2004 18:34:59 -0000 1.5.2.2
+++ ossl_pkey_rsa.c 4 Dec 2004 18:43:56 -0000
@@ -272,6 +272,49 @@
}
static VALUE
+ossl_rsa_public_exp(VALUE self, VALUE buffer)
+{
+ EVP_PKEY *pkey;
+ int buf_len;
+ VALUE str;
+
+ GetPKeyRSA(self, pkey);
+ StringValue(buffer);
+ str = rb_str_new(0, ossl_rsa_buf_size(pkey));
+ buf_len = RSA_public_decrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr,
+ RSTRING(str)->ptr, pkey->pkey.rsa,
+ RSA_NO_PADDING);
+ if(buf_len < 0) ossl_raise(eRSAError, NULL);
+ RSTRING(str)->len = buf_len;
+ RSTRING(str)->ptr[buf_len] = 0;
+
+ return str;
+}
+
+static VALUE
+ossl_rsa_private_exp(VALUE self, VALUE buffer)
+{
+ EVP_PKEY *pkey;
+ int buf_len;
+ VALUE str;
+
+ GetPKeyRSA(self, pkey);
+ if (!RSA_PRIVATE(pkey->pkey.rsa)) {
+ ossl_raise(eRSAError, "PRIVATE key needed for this operation!");
+ }
+ StringValue(buffer);
+ str = rb_str_new(0, ossl_rsa_buf_size(pkey));
+ buf_len = RSA_private_encrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr,
+ RSTRING(str)->ptr, pkey->pkey.rsa,
+ RSA_NO_PADDING);
+ if (buf_len < 0) ossl_raise(eRSAError, NULL);
+ RSTRING(str)->len = buf_len;
+ RSTRING(str)->ptr[buf_len] = 0;
+
+ return str;
+}
+
+static VALUE
ossl_rsa_public_decrypt(VALUE self, VALUE buffer)
{
EVP_PKEY *pkey;
@@ -473,6 +516,9 @@
rb_define_method(cRSA, "public_decrypt", ossl_rsa_public_decrypt, 1);
rb_define_method(cRSA, "private_encrypt", ossl_rsa_private_encrypt, 1);
rb_define_method(cRSA, "private_decrypt", ossl_rsa_private_decrypt, 1);
+
+ rb_define_method(cRSA, "private_exp", ossl_rsa_private_exp, 1);
+ rb_define_method(cRSA, "public_exp", ossl_rsa_public_exp, 1);
DEF_OSSL_PKEY_BN(cRSA, rsa, n);
DEF_OSSL_PKEY_BN(cRSA, rsa, e);