Menu

pidCrypt's RSA compatibility with OpenSSL

Help
2009-03-30
2012-12-11
1 2 > >> (Page 1 of 2)
  • Jonah (pidder)

    Jonah (pidder) - 2009-03-30

    Problem:
    -----------
    Using a public and private key created in OpenSSL and putting them in the example tool allows for encrypting and decrypting on the demo page. The encrypted content (in base64) then cannot be decrypted with OpenSSL.

    The same thing is true for the other direction.

     
    • Jonah (pidder)

      Jonah (pidder) - 2009-03-30

      Answer:
      ----------
      The OpenSSL algorithm for base64 encoding inserts a line feed every 64 characters. The current pidCrypt demo page does not insert any line feeds in the base64 encoded string.

      If you insert these line feeds manually at position 64 of each line, you'll be able to decrypt the cypher text generated by pidCrypt with OpenSSL.

      The resulting decrypted text again is base64 encoded because the pidCrypt uses base64 encoding to ensure 8 bit characters prior to RSA encryption. The corresponding base64 decoding step is missing when decrpyting with OpenSSL and needs to be done manually.

      We plan to standardize input and output formats in the next version of pidCrypt to avoid this issue in the future.

      To sum up, here are the steps currently necessary to obtain interoperability between pidCrypt and OpenSSL:

      1. openssl genrsa -out test.pem 1024

      2. openssl rsa -pubout -in test.pem -out test_pub.pem

      3. Copy & paste the contents of private and public key files into the respective text areas of http://www.pidder.com/pidcrypt/?page=demo_rsa-encryption

      4. Enter text into the input field and encrypt it.

      5. Use the result to create a new file text.crypted

      6. Insert line feeds manually after position 64 of each line

      7. openssl base64 -d -in text.crypted | openssl rsautl -inkey test.pem -decrypt -out text.b64

      8. openssl base64 -d -in text.b64

      Voila, encrypted with pidCrypt, decrypted with OpenSSL.

      For the other direction, first encode your clear text with OpenSSL's base64 encoding, then rsa encrypt it, then delete the line feeds of the OpenSSL-encrypted base64-encoded text.

       
    • David S

      David S - 2009-04-01

      I am the person who commented on your blog entry about this.

      Thank you!!!!!

      What I am actually doing is trying to encrypt text in Java. That information is stored in a database. When a user views the database entry they need the private key to decrypt the information. The decryption will take place in the clients web-browser so the private key is never on the server.

      Anyways, I didn't realize that you were base64 encoding, encrypting, and then base64 encoding again. I was only doing the 2nd base64 encoding. Now that I base64 encode the message before RSA encrypting i am able to decrypt with you library.

      Again, thank you!

       
    • Jonah (pidder)

      Jonah (pidder) - 2009-04-23

      Base64 encoding of the text prior to RSA encryption (and the inverse operation) seem to make trouble in other contexts also.

      So we've decided to implement the functions encryptRaw and decryptRaw that will make no transformation of the input and output, respectively.

      Those functions will be available in Release 0.0.3. For those of you who can't wait till the next release, you can download the (backward compatible) version of rsa.js from the svn trunk repository.

       
  • jas

    jas - 2010-09-28

    I reviewed the two functions you mentioned (encryptRaw and decryptRaw). It seems that there is still a conversion taking place in regards to raw binary output to a utf-8 compatible string with the toString() function.

    I am not sure if you would know off hand but what would be the appropriate PHP function to reverse that?

     
  • Pidder

    Pidder - 2010-10-04

    When the JavaScript toString() method is used with an integer as a parameter (i.e. in radix mode), it transfers the output to a string representation using this parameter as base, e.g.

    var i = 10;
    alert(i.toString(2)); //outputs "1010"
    alert(i.toString(8)); //outputs "12"
    alert(i.toString(16)); //outputs "A"

    The line

    var h = c.toString(16);

    in the encryptRaw-function converts the RSA encryption (a big number) to a hex string.

    The inverse operation is parseInt(String, radix) in JavaScript.

     
  • jas

    jas - 2010-10-06

    My next question is how would I use this library to encrypt data on the client and then decrypt on the server using PHP's OpenSSL functions?

    I have tried it and received errors during the decryption process. My assumption is the difference between the base64 encoding taking place is not compatible with PHP's mime base64 encoding and the pidCrypt libraries.

    1. Using your library I am using remotely obtaining the public key generated with the PHP OpenSSL library.
    2. Registering the private key as a session variable to be used when data is submitted.
    3. Encrypting the data with the public key and then sending it back to the server.
    4. Using the already available private key attempting to decrypt the encrypted data with no solution.

    Any insight into this? Thanks for your time.

     
  • Jonah (pidder)

    Jonah (pidder) - 2010-10-07

    We checked our OpenSSL compatibility as described in posting #2 of this thread (which gives a step by step description of how to encrypt with pidCrypt and decrypt with the OpenSSL command line tool).

    If that procedure will not work when using PHP's OpenSSL functions, then there seems to be a difference between those and the way the OpenSSL command line works. Since we are no PHP experts this is not something we can answer offhand.

    Maybe someone with more insight into PHP's OpenSSL implementation can step up and provide an answer?

     
  • jas

    jas - 2010-10-07

    Maybe the public key format is the problem? Or perhaps the base64 encoding?

    The public key format is that of the following:
    ---BEGIN PUBLIC KEY---
    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDczq53fQyKvJkj2bK9qn281h+E
    o1au+yscXZUz+SmlnPtp5lasZ6bM//NXE1ct/8JFo7FN8wzBUYqbYTQ6v9xC3wMS
    jjkdZJAQq3ZlbNK0KfdiRde7u6DhoJj0IUGRAl4uKUoa0XqctT4KOWtxL1jjzZDU
    DHky6a5EfwNJr9BB712345AB
    ---END PUBLIC KEY---

    The base64 encoded value using pidCrypt is as follows:
    rbuERRWQtHYb8OUKC313auDgaSNwZMPlKuo/syWhRCQ3PKH9UclrvQh3dnxQgCpZ
    A3lHpBtMGy/e6KSsZadgqZLCAiLeR3cshFzyMg7+7xJ+lZEPek419e/uI3ADgczv
    7H/+tndMaxyE3xvxKvCnM2FUdZ9IOk0SZWjPMZ/bmlU=

    The PHP RFC followed for the base64_encode() function is using a MIME type. I do believe it is based on a different RFC then the library pidCrypt uses. Here is an example encoding which is slightly different.
    VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw==

    I am going to do some more testing here to see what I can do. Any more insight?

     
  • jas

    jas - 2010-10-07

    So if a private key was sent to the client using the PHP libraries only then would your library be able to parse the key and use it for encrypting.

    Are there plans to implement methods using the public key to encrypt or sign data using this library?

     
  • Jonah (pidder)

    Jonah (pidder) - 2010-10-07

    Nope, that is not what I meant.

    The public key is all that is needed for encryption, as long as it has the correct format, i.e. can be parsed with ASN.1.

    As mentioned, keypairs created with the OpenSSL command line tool are of that format. The key in your example is not.

    The private key is not needed for encryption, only for decryption.

     
  • jas

    jas - 2010-10-07

    That is what I am not understanding. What format is required? Given the example above what must I do to get it into a format that could be parsed with the ASN.1? I do appreciate your help as working with these key pairs are new to me. Symmetrical is easier but limited.

    The reason I am trying to pick this is up quickly is because I would like to write a jQuery plugin that would act as a wrapper to your library enabling asymmetrical encryption of forms from client to server using RSA key pairs.

    Thanks for your help.

     
  • Jonah (pidder)

    Jonah (pidder) - 2010-10-08

    What format is required?

    Hmm, we're in a loop here it seems ;) The format needs to be ASN.1 format,  see

    http://en.wikipedia.org/wiki/PKCS1
    http://tools.ietf.org/html/rfc3447
    http://tools.ietf.org/html/rfc3447#appendix-A

    Given the example above what must I do to get it into a format that could be parsed with the ASN.1?

    No idea, since we don't know how  this key was generated. All we can tell is that it can't be processed by the ASN.1 parser and as a consequence the public key properties that are needed for encryption are not available.

    It seems to me that the easiest approach is to create a keypair with the OpenSSL command line tool and continue from there.

     
  • jas

    jas - 2010-10-08

    The public key I used as an example was generated using PHP's OpenSSL functions.

    I read up on the ASN.1 and simply stripped out the --- BEGIN PUBLIC KEY--- and ---END PUBLIC KEY--- and used the decoder at http://lapo.it/asn1js/.

    It worked so I am assuming at this point I just need to follow the examples provided at https://www.pidder.com/pidcrypt/?page=rsa.

    IE
    var rsa = new pidCrypt.RSA();
    var asn = pidCrypt.ASN1.decode(public);

    All of the examples I could see seemed to use the private key for the parser. The example public key I posted here was a fictitious key.

    My apologies as once I generated a valid public key and stripped off the necessary comments I was able to parse it fine. I thought I would have to do something special with the private key to get an ASN.1 compatible public key which is not the case.

    Thanks.

     
  • jas

    jas - 2010-10-11

    I am sure you are getting tired of my questions. However I have run into another snag attempting to create a wrapper which would allow for an easy implementation as a jQuery plugin.

    Here is the code I am writing to implement such a plugin. The errors I receive occur when trying to create a new rsa object. My assumption is that because there are private methods being used I am not be able to create a worth while wrapper.

    (function($){
     /* Generate random public key */
     $.genKey = function(length) {
      var chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
      var key = '';
      for (x=0;x<length;x++) {
       i = Math.floor(Math.random() * 62);
       key += chars.charAt(i);
      }
      return key;
     }
     /* Store public key in specified storage mechanism */
     $.setKey = function(type, name, key) {
      switch(type) {
       case 'localStorage':
        $.setLocal(name, key);
       case 'sessionStorage':
        $.setSession(name, key);
       case 'cookie':
        $.setCookie(name, key);
       default:
        $.setLocal(name, key);
      }
     }
     /* Get public key from specified storage mechanism */
     $.getKey = function(type, name) {
      switch(type) {
       case 'localStorage':
        return $.getLocal(name);
       case 'sessionStorage':
        return $.getSession(name);
       case 'cookie':
        return $.getCookie(name);
       default:
        return $.getLocal(name);
      }
     }
     /* localStorage setter */
     $.setLocal = function(name, key) {
      localStorage.setItem(name+'-key', key);
     }
     /* sessionStorage setter */
     $.setSession = function(name, key) {
      sessionStorage.setItem(name+'-key', key);
     }
     /* cookie setter */
     $.setCookie = function(name, key) {
      $.cookie(name+'-key', key, {expires: 7});
     }
     /* localStorage getter */
     $.getLocal = function(name) {
      return localStorage.getItem(name+'-key');
     }
     /* sessionStorage getter */
     $.getSession = function(name) {
      return sessionStorage.getItem(name+'-key');
     }
     /* cookie getter */
     $.getCookie = function(name) {
      return $.cookie(name+'-key');
     }
     /* update status area with encrypted text */
     $.updateFormEnc = function(data) {
      $.each(data, function(k,v) {
       if ($.validateElement(k+'-enc')===true) {
        $('#'+k+'-enc').html(v);
       }
      });
     }
     /* update status area with decrypted text */
     $.updateFormDenc = function(data) {
      $.each(data, function(k,v) {
       if ($.validateElement(k+'-denc')===true) {
        $('#'+k+'-denc').html(v);
       }
      });
     }
     /* validate page element integrity */
     $.validateElement = function(element) {
      if (($('#'+element))&&($('#'+element).length>0)) {
       return true;
      } else {
       return false;
      }
     }
     /* validate string integrity */
     $.validateString = function(string) {
      if ((!string)||(string===null)||(string==='')||(string==='undefined')||(string==='false')) {
       return false;
      } else {
       return true;
      }
     }
     /* handle encryption of form elements */
     $.encryptForm = function(form, options, rsa) {
      var data = {};
      $.each($('#'+form+' :text, :password, :file, input:checkbox:checked, input:radio:checked, textarea'), function(k, v){
       if ((v.value)||(v.value!==null)||(v.value!=='')) {
        data[v.name] = (options.encode===true) ? encodeURIComponent(rsa.encrypt(v.value)) : rsa.encrypt(v.value);
        if (options.debug===true) { alert('Encrypting: '+v.name+' => '+v.value+'\nCipher-text: '+data[v.name]+'\nKey: '+options.key); }
       }
      });
      return data;
     }
     /* handle decryption of returned data */
     $.decryptData = function(data, options, rsa) {
      var denc = {};
      $.each(data, function(k, v) {
       if (options.debug===true) { alert('Decrypting: '+k+' => '+v+'\nDeciphered text: '+denc[k]+'\nKey: '+options.key); }
      });
      return denc;
     }
     /* the plug-in meat and potatoes */
     $.fn.pidCryptor = function(options) {
      /* default options */
      var defaults = {
       name:    'jQuery-pidCryptor',    // Plugin name (unique ID for local, session or cookie storage id)
       key:     '',                     // place holder for key
       length:  128,                    // key length (string length if not using RSA)
       proxy:   $(this).attr('action'), // Server side processor
       rsa:     false,                  // RSA public key from OpenSSL?  true || false
       form:    $(this).attr('id'),     // form element ID
       storage: 'localStorage',         // localStorage || sessionStorage || cookie (cookie storage requires jQuery cookie plugin)
       encode:  false,                  // encode for URI? true || false
       debug:   false                   // enable debugging output? true || false
      };
      /* merge specified options with defaults */
      var options = $.extend(defaults, options);
      /* put it in chains */
      return this.each(function() {
       /* does this user have a key? */
       options.key = $.getKey(options.storage, options.name);
       /* generate a key or get one from the server then store it locally */
       if ($.validateString(options.key)===false) {
        if (options.rsa===true) {
         $.ajax({
          global: false,
          async: false,
          data: 'ssl-key=true',
          type: 'post',
          url: options.proxy,
          success: function(response) {
           options.key = encodeURIComponent(pidCryptUtil.decodeBase64(response));
          }
         });
        } else {
         options.key = encodeURIComponent($.genKey(options.length));
        }
        $.setKey(options.storage, options.name, options.key);
       }
       /* debuging enabled? show some config values */
       if (options.debug===true) { alert('Key ID: '+options.name+'-key\nKey: '+options.key+'\nClient storage: '+options.storage); }
       /* hijack the form and process accordingly */
       $('.'+options.form).live('submit', function(e) {
        var rsa = new pidCrypt();
        $.each(rsa, function(a, b) {
         if (typeof b === 'object') {
          $.each(b, function(k, v) {
           alert(a+': '+k+' => '+v);
          });
         } else {
          alert(a+' => '+b);
         }
        });
        var asn = pidCrypt.ASN1.decode(decodeURIComponent(options.key));
        var tree = asn.toHexTree();
        rsa.setPublicKeyFromASN(tree);
        var data = $.encryptForm(options.form, options, rsa);
        $.updateFormEnc(data);
        var denc = {};
        $.ajax({
         data: data,
         type: $(this).attr('method'),
         url: options.proxy,
         dataType: 'json',
         success: function(response) {
          denc = $.decryptData(response, options, rsa);
          $.updateFormDenc(denc);
         }
        });
        return false;
       });
       return false;
      });
     };
    })(jQuery);
    

    Of course I am able to implement it as inline code by parsing the form elements and then initializing an instance of your libraries. But when I am calling ' var rsa = new pidCrypt();' I get errors.

    Any insights?

     
  • jas

    jas - 2010-10-12

    Never mind the last post. I figured it out. I also created a new project for it over at github.

    http://github.com/jas-/jQuery.pidCrypt

    Thanks for making a great encryption library that is fully compatible with using the public key generated from PHP's OpenSSL to encrypt data client side!

     
  • Jonah (pidder)

    Jonah (pidder) - 2010-10-23

    You are welcome.

    And we would like to thank you, too, for making it available to a wider public with your jquery plugin.

     
  • jas

    jas - 2010-10-23

    If you ask me this is a much needed security precaution for any of today's online shopping carts that strictly rely on signed certificates.

     
  • jas

    jas - 2010-11-04

    I do appreciate all of the assistance you have given me this far.

    My next question is in regards to the client decryption process. Using PHP's OpenSSL libraries I am able to encrypt and decrypt with the users public key. From what I know of public key encryption this is typically not the standard. The encrypting process can be either the private or public key but decryption is strictly private key only correct? I believe this may be an implementation problem on their end.

    The reason I am asking is I am trying extend the jQuery plugin to allow a configurable option to decrypt on the server or the client. I have been examining the source and it seems your library only allows decryption using the private key. Any insight? Thanks again.

     
  • Jonah (pidder)

    Jonah (pidder) - 2010-11-04

    The basic principles of asymmetric encryption are these:

    The sender encrypts the clear text with the public key of the recipient.
    The encrypted message is sent to the recipient.
    The recipient then decrypts the message with the corresponding private key.

    You cannot decrypt this message with the public key.

    If a message can be encrypted and decrypted with the same key we have symmetric encryption.
    RSA is not a symmetric encryption algorithm.

    Encrypting with a private key typically is not done either. It is possible however to "decrypt" a clear text message with your private key. That way everyone knowing your public key can use it to "encrypt" the result to arrive at the clear text message again, thus verifying that you are in fact in possession of the corresponding private key. This method is used for electronic signatures.

    So to answer your question: Yes, pidCrypt definitely needs the private key for decryption (as does any RSA implementation, quite certainly also the PHP OpenSSL implementation). If that is supposed to happen on the client side, the client needs to know the private key for the process. Obviously, the private key is something you never want to post over the internet as that would allow anyone who can intercept the transfer to be able to decrypt messages encrypted with your public key, thus compromising the whole idea of encryption.

    So you need to provide a way for the user to enter their private key for the decryption process only, while making sure at the same time that it will never be transported in a http request.

     
  • jas

    jas - 2010-11-04

    That is exactly what I thought. Since that is the case the php OpenSSL function 'OpenSSL_Public_decrypt()' seems to allow symmetric decrypting using the public key as the password. I have tested this at http://155.97.16.163/dev/.

    I double checked the php API for the above mentioned arguments and it does indeed use the public key for decrypting. I will double check the source to make sure it is using valid OpenSSL functionality. If the OpenSSL libraries do support symmetric encryption is this something that might be included in future releases of the pidcrypt libraries?

     
  • Jonah (pidder)

    Jonah (pidder) - 2010-11-04

    Well, in that case it's not RSA encryption.

    OpenSSL supports a multitude of encryption algorithms, many of which are symmetric.

    Of course you can theoretically use an RSA public key as the secret for any symmetric encryption algorithm, too, but that then has nothing to do with RSA and furthermore it is a very poor choice for a secret, since the nature of the public key is that it is indeed public, whereas a secret should be - well - secret. :)

    As for pidCrypt's support of symmetric encryption: We provide functionality for AES (CBC and CTR mode). Our AES-CBC implementation https://www.pidder.com/pidcrypt/?page=aes-cbc is fully OpenSSL compatible.

     
  • jas

    jas - 2010-11-04

    I agree. If I decide to include the client decryption using the public key feature I will have to add a security warning about it. Wrapping the connection in an SSL certificate would serve that functionality well, but then again as you said a poor choice. Thanks for the information.

     
  • jas

    jas - 2010-11-04

    Ok I have created methods for using both symmetric and rsa encryption within the plugin. I have tested it and have only come across one problem and that comes into play when the data I wish to encrypt is longer then a few words.

    The error states the data is too large for rsa. Are there limits?

    Maybe you could test the plugin to ensure my implementation is correct? Thanks again as I think something like this has been missing from common web development

     
1 2 > >> (Page 1 of 2)

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.