From: Sam Roberts Date: 2004-12-05T04:03:08+09:00 Subject: openssl request - don't hardcode PKCS1 padding (and some docs) 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::PKey::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::PKey::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);