Omidoo
Omidoo

Reputation: 513

how to digitally sign a file in PHP

I made a user table in my DB with different columns for holding users' info. Also I have added two columns public_key and private_key. When a user registers, his info will be inserted to the table. plus I am using:

// Create the keypair
$res=openssl_pkey_new();

// Get private key
openssl_pkey_export($res, $privatekey);

// Get public key
$publickey=openssl_pkey_get_details($res);
$publickey=$publickey["key"];

to create a random key pair and give it to user so that every user has a key pair. I want my users to have digital-signature ability, so when they upload a file they sign it.

I decided to sign a sample file(msg.txt) first to see if I can and then proceed. It looks straight forward:

openssl_pkcs7_sign("msg.txt", "signed.txt", "signing_cert.pem",
array("private_key.pem", "mypassphrase"),
array()
);

The problem is: what are signing_cert.pem and private_key.pem ? I pasted my generated public key in signing_cert.pem and the private one in private_key.pem, but I see this error:

Warning: openssl_pkcs7_sign() [function.openssl-pkcs7-sign]: error getting 
private key in /home/ofathian/public_html/msc/ebook/mine/assymetric-test.php 
on line 40

Any opinion is appreciated.

Upvotes: 6

Views: 33888

Answers (2)

Omidoo
Omidoo

Reputation: 513

I came to conclusion of why not make my own digital signing function.

digital signing algorithm works like this: first the plain text is hashed then it is encypted by user's private key, then the result is concatenated with the plain text.

pseudo code:

return [input + encrypt(md5(input),private_key)]

For verifying: Input is splitted to plain text and signature. then signature is decrypted using public key. Then the result is compared to the hash of the plain text and if they are equal it means the signature is verified.

pseudo code:

explode(input) --> plain_text , signature
if( decrypt(signature,public_key) == md5(plain_text) ) then signature is trusted

Now the real PHP code which I have tested and currently using:

function sign($cleartext,$private_key)
{
    $msg_hash = md5($cleartext);
    openssl_private_encrypt($msg_hash, $sig, $private_key);
    $signed_data = $cleartext . "----SIGNATURE:----" . $sig;
    return mysql_real_escape_string($signed_data);
}

function verify($my_signed_data,$public_key)
{
    list($plain_data,$old_sig) = explode("----SIGNATURE:----", $my_signed_data);
    openssl_public_decrypt($old_sig, $decrypted_sig, $public_key);
    $data_hash = md5($plain_data);
    if($decrypted_sig == $data_hash && strlen($data_hash)>0)
        return $plain_data;
    else
        return "ERROR -- untrusted signature";
}

Upvotes: 8

StormByte
StormByte

Reputation: 1335

signing_cert.pem and private_key.pem are the certificates you use to sign that file. So if you have them stored in DB, you need to dump them to files called signing_cert.pem and private_key.pem respectivelly.

The error you are getting is that openssl tries to load those files, and since they do not exists then it claims.

If you write those files to harddisk from your DB, plase TAKE IN MIND:

  1. Do NOT store it in any public accesible folder (avoid DOCUMENT_ROOT AND temp directory). Specially for the private key to avoid security issues.
  2. Remove them when you've done.

Also, you could, instead of having those certificates in DB, have them stored in some folder for each user, to prevent dumping to a file when signing. Of course, that folder should not be accesible to anyone.

More info: PHP openssl_pkc7_sign

Upvotes: 1

Related Questions