{"id":635,"date":"2009-04-28T12:18:35","date_gmt":"2009-04-28T16:18:35","guid":{"rendered":"http:\/\/cd34.com\/blog\/?p=635"},"modified":"2009-04-28T12:18:36","modified_gmt":"2009-04-28T16:18:36","slug":"rsa-with-perl-php-and-python","status":"publish","type":"post","link":"https:\/\/cd34.com\/blog\/programming\/rsa-with-perl-php-and-python\/","title":{"rendered":"RSA with Perl, PHP and Python"},"content":{"rendered":"<p>Ages ago we had a system that used MySQL&#8217;s built in DES3 encryption.  It made coding applications in multiple languages easy because we could send it a string with a key and it would be encoded in the database.  It wasn&#8217;t secure if someone got hold of the code and the database, but, rather than use a hash, we could store things and get the plaintext back if we needed it.  Due to some policy issues with Debian, DES3 encryption was removed from MySQL and we were faced with converting that data to another format.  We chose RSA for the fact that it was supported in every language we were currently developing in &#8212; Perl, PHP and C, and we knew it was supported in Python even though we hadn&#8217;t started development with Python at the time.<\/p>\n<p>However, due to issues with PHP and long key lengths (at the time the code was written), our payloads had to be broken into packets smaller than the smallest key length which was 256 bytes.  Since we didn&#8217;t know if we would run into similar issues using a longer packet length even if we had a longer key, we opted to use a packet size smaller than the smallest key we could generate.  Our code initially converted data using PHP, stored the data in MySQL, and allowed a Perl script to access the data.  Getting Perl and PHP to cooperate was somewhat difficult until we dug into PHP&#8217;s source code to see just how they were handling RSA.<\/p>\n<p>PHP code:<\/p>\n<pre>\r\ndefine(\"ENCPAYLOAD_FORMAT\",'Na*');\r\n\r\nfunction cp_encrypt($hostname,$message) {\r\n  $public_key=file_get_contents(KEY_LOCATION . $hostname . '.public.key');\r\n  openssl_get_publickey($public_key);\r\n\r\n  $blockct = intval(strlen($message) \/ 245)  + 1;\r\n  $encpayload = \"\";\r\n  for ($loop=0;$loop<$blockct;$loop++) {\r\n    $blocktext = substr($message,$loop * 245, 245);\r\n    openssl_public_encrypt($blocktext,$encblocktext,$public_key);\r\n    $encpayload .= $encblocktext;\r\n  }\r\n  return(pack(ENCPAYLOAD_FORMAT,$blockct,$encpayload));\r\n}\r\n\r\nfunction cp_decrypt($hostname,$message) {\r\n  $priv_key=file_get_contents(KEY_LOCATION . $hostname . '.private.key');\r\n  openssl_get_privatekey ($priv_key);\r\n  $arr = unpack('Nblockct\/a*',$message);\r\n  $blockct = $arr['blockct'];$encpayload=$arr[1];\r\n  $decmessage = \"\";\r\n  for ($loop=0;$loop<$blockct;$loop++) {\r\n    $blocktext = substr($encpayload, $loop*256, 256);\r\n    openssl_private_decrypt($blocktext,$decblocktext,$priv_key);\r\n    $finaltext .= $decblocktext;\r\n  }\r\n\r\n  return($finaltext);\r\n}\r\n<\/pre>\n<p>Perl Code:<\/p>\n<pre>\r\nuse Crypt::OpenSSL::RSA;\r\nuse constant ENCPAYLOAD_FORMAT => 'Na*';\r\n\r\nsub cp_encrypt {\r\n  my $hostname = shift;\r\n  my $message = shift;\r\n\r\n  my $keyfile = $KEY_LOCATION . $hostname . '.public.key';\r\n  \r\n  if (-e $keyfile) {\r\n    open PUBLIC, $keyfile;\r\n    my $public_key = do{local $\/; <PUBLIC>};\r\n    close(PUBLIC);\r\n    my $rsa = Crypt::OpenSSL::RSA->new_public_key($public_key);\r\n    $rsa->use_pkcs1_padding();\r\n\r\n    my $blockct = int(length($message) \/ 245)  + 1;\r\n    my $encpayload = \"\";\r\n      for ($loop=0;$loop<$blockct;$loop++) {\r\n        $encpayload .= $rsa->encrypt(substr($message,$loop * 245, 245));\r\n      }\r\n    return(pack(ENCPAYLOAD_FORMAT,$blockct,$encpayload));\r\n  }\r\n  return(-1);\r\n}\r\n\r\nsub cp_decrypt {\r\n  my $hostname = shift;\r\n  my $message = shift;\r\n\r\n  my $keyfile = $KEY_LOCATION . $hostname . '.private.key';\r\n  if (-e $keyfile) {\r\n    open PRIVATE, $keyfile;\r\n    my $private_key = do{local $\/; <PRIVATE>};\r\n    close(PRIVATE);\r\n    my $rsa = Crypt::OpenSSL::RSA->new_private_key($private_key);\r\n    $rsa->use_pkcs1_padding();\r\n    my ($blockct,$encpayload) = unpack(ENCPAYLOAD_FORMAT,$message);\r\n    my $decmessage = \"\";\r\n    for ($loop=0;$loop<$blockct;$loop++) {\r\n      $decmessage .= $rsa->decrypt(substr($encpayload, $loop*256, 256));\r\n    }\r\n    return($decmessage);\r\n  }\r\n  return(-1);\r\n}\r\n\r\n1;\r\n<\/pre>\n<p>Python code:<\/p>\n<pre>\r\nimport M2Crypto.RSA\r\nfrom os import path\r\nfrom struct import unpack, pack, calcsize\r\n\r\nENCPAYLOAD_FORMAT = 'Na*'\r\n\r\ndef perl_unpack (perlpack, payload):\r\n    if (perlpack == 'Na*'):\r\n        count = calcsize('!L')\r\n        perlpack = '!L%ds' % (len(payload) - count)\r\n        return unpack(perlpack,payload)\r\n    return\r\n\r\ndef perl_pack (perlpack, blockcount, payload):\r\n    if (perlpack == 'Na*'):\r\n        perlpack = '!L%ds' % len(payload)\r\n        return pack(perlpack,blockcount,payload)\r\n    return\r\n\r\ndef cp_encrypt (hostname,message):\r\n  keyfile = KEY_LOCATION + hostname + '.public.key'\r\n  if (path.exists(keyfile)):\r\n    public_key = M2Crypto.RSA.load_pub_key(keyfile)\r\n\r\n    blockct = int(len(message) \/ 245)  + 1\r\n    encpayload = \"\"\r\n    for loop in range(0,blockct):\r\n      encpayload += public_key.public_encrypt(message[(loop*245):(245*(loop+1))],\r\n                    M2Crypto.RSA.pkcs1_padding)\r\n    return(perl_pack(ENCPAYLOAD_FORMAT, blockct, encpayload))\r\n  return(-1)\r\n\r\ndef cp_decrypt (hostname, message):\r\n  keyfile = KEY_LOCATION + hostname + '.private.key';\r\n  if (path.exists(keyfile)):\r\n    privatekey = M2Crypto.RSA.load_key(keyfile)\r\n    (blockct,encpayload) = perl_unpack(ENCPAYLOAD_FORMAT,message)\r\n\r\n    decmessage = \"\"\r\n    for loop in range(0,blockct):\r\n      decmessage += privatekey.private_decrypt(encpayload[(loop*256):(256*(loop+1))], M2Crypto.RSA.pkcs1_padding)\r\n    return(decmessage);\r\n  return(-1)\r\n<\/pre>\n<p>There is nothing really that restricts you from encrypting a message longer than the key size, but, if the message contains enough data, portions of the key can be discovered.  Since the key is a very large prime number, exposing a portion of that key can be vital to decrypting the data.<\/p>\n<div style=\"float:left;\">\n<div id=\"fb-root\"><\/div>\n<fb:like href=\"https:\/\/cd34.com\/blog\/programming\/rsa-with-perl-php-and-python\/\" width=\"250\" send=\"false\" show_faces=\"false\" layout=\"button_count\" action=\"recommend\"><\/fb:like>\n<\/div><div style=\"clear:both;\"><\/div>","protected":false},"excerpt":{"rendered":"<p>Ages ago we had a system that used MySQL&#8217;s built in DES3 encryption. It made coding applications in multiple languages easy because we could send it a string with a key and it would be encoded in the database. It wasn&#8217;t secure if someone got hold of the code and the database, but, rather than [&hellip;]<\/p>\n<div style=\"float:left;\">\n<div id=\"fb-root\"><\/div>\n<fb:like href=\"https:\/\/cd34.com\/blog\/programming\/rsa-with-perl-php-and-python\/\" width=\"250\" send=\"false\" show_faces=\"false\" layout=\"button_count\" action=\"recommend\"><\/fb:like>\n<\/div><div style=\"clear:both;\"><\/div>","protected":false},"author":15,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13],"tags":[17,30,299,33],"class_list":["post-635","post","type-post","status-publish","format-standard","hentry","category-programming","tag-perl","tag-php","tag-python","tag-rsa"],"_links":{"self":[{"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/posts\/635","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/comments?post=635"}],"version-history":[{"count":1,"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/posts\/635\/revisions"}],"predecessor-version":[{"id":636,"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/posts\/635\/revisions\/636"}],"wp:attachment":[{"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/media?parent=635"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/categories?post=635"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cd34.com\/blog\/wp-json\/wp\/v2\/tags?post=635"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}