question

mohammed avatar image
mohammed asked anujc commented

CRYPTO FAILURE

I got this message :

CRYPTO FAILURE: Probably a bad swipe or damaged card. Retry swipe or use manual card entry. Contact support if this problem persists.

when sending POST to /v2/merchant/{mId}/pay.

I'm using phpseclib to encrypt the cardnumber, this is my code.

        $e = new Math_BigInteger($key->exponent);
        $m = new Math_BigInteger($key->modulus);
        $card = $key->prefix.$card_number;

        $rsa = new Crypt_RSA();

        $rsa->setHash('sha1');
        $rsa->setMGFHash('sha1');
        $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_OAEP);
        $rsa->loadKey(array('n' =>$m, 'e' => $e ));

        $ciphertext = $rsa->encrypt($card);
        $cardEncrypted =base64_encode($ciphertext);

I tested with different encryption mode (PKCS1,OAEP) and different hash (sha1,sha256,sha512).

Can you help me ?

5 comments
10 |2000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

jeremyinvoiceasap avatar image jeremyinvoiceasap commented ·

I am also having this issue. Everything works fine on the sandbox, but in production I receive "CRYPTO FAILURE".

0 Likes 0 ·
mohammed avatar image mohammed commented ·

I tested to encrypt the card number using JAVASCRIPT, also having the same message.

0 Likes 0 ·
Brian Murray avatar image Brian Murray commented ·

Note that "MGF1 with SHA-1" is not the same as "SHA1". See RFC 2437.

0 Likes 0 ·
mohammed avatar image mohammed commented ·

In the code source of RSA in phpseclib the function setMGF1 not accept sha-1 function setMGFHash($hash) { // \phpseclib\Crypt\Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example. switch ($hash) { case 'md2': case 'md5': case 'sha1': case 'sha256': case 'sha384': case 'sha512': $this->mgfHash = new Hash($hash); break; default: $this->mgfHash = new Hash('sha256'); } $this->mgfHLen = $this->mgfHas

0 Likes 0 ·
anujc avatar image anujc commented ·

Can any body provide a complete running php code?

0 Likes 0 ·
Brian Murray avatar image
Brian Murray Deactivated answered

To debug:

Generate an RSA key via OpenSSL:

$ openssl genrsa 2048 > private_key.pem

Extract the public modulus and convert it to base 10

$ MODULUS_HEX=`openssl rsa -in private_key.pem -modulus -noout | tail -c+9` && echo "ibase=16;$MODULUS_HEX"|bc 
21362630548802327432850173390331370917468565991768437256962413732729\
74927694620758772731455558074246069160345018778421520716763583527811\
99284654949543464238830655435256170070131531499917264413501242767325\
93180524495479147575313667127208962539623367822182164193271774281175\
74839282880467707931643072049690147957089537061016493223085546548971\
05810136571452774402800492487666476291215742283764054525689863925472\
97217575069367467570989868562298966121056644531970518223404577456999\
19028780012726422130463894508041184387063691312413140604341248656427\
03028243866235574675442271172802622367030953843889430255056262469806\
25917

Remove the \ and line breaks from the base 10 key and feed it into your code. Encrypt a sample credit card number and capture the result.

For this example, I encrypted it with OpenSSL:

$ echo '1234567891012'|openssl   rsautl -oaep  -encrypt -inkey    private_key.pem |base64 
fC0qltHHrBtq0zz//E9jc4dDaXsXW14opMR4ZDFs8A76mWJj9Pm6KAxUjJhxyG/ga+rCb3p2T00F
vT2gJJ1AGXZK65A3wiDm/g7lQcGHvHmTn3PTDV/aDMVXhKdOsGFXru7/XduANxZSVIrtZwHK9gYI
TYY66I+V3TZz70FmjnDHHkKUSYWGduvcde7IeVSvIIbctnXW2ejw+2Rwflf3XYG/aVJ34mqWyQ/l
WOmWQqXEcFASXh2TImX44bblLLzqaZLqdXmWV+icS9lftooLdM3o9M4hMrZYyn8EqmvLB/WitHUQ
UbUeZsM3QWlp1gHttiGJNLetjGGAFWYJ+apabg==

Note that OAEP uses random padding so the encrypted data will be different each time the command is run.

Now try to decrypt the result:

$ echo 'fC0qltHHrBtq0zz//E9jc4dDaXsXW14opMR4ZDFs8A76mWJj9Pm6KAxUjJhxyG/ga+rCb3p2T00F
vT2gJJ1AGXZK65A3wiDm/g7lQcGHvHmTn3PTDV/aDMVXhKdOsGFXru7/XduANxZSVIrtZwHK9gYI
TYY66I+V3TZz70FmjnDHHkKUSYWGduvcde7IeVSvIIbctnXW2ejw+2Rwflf3XYG/aVJ34mqWyQ/l
WOmWQqXEcFASXh2TImX44bblLLzqaZLqdXmWV+icS9lftooLdM3o9M4hMrZYyn8EqmvLB/WitHUQ
UbUeZsM3QWlp1gHttiGJNLetjGGAFWYJ+apabg=='
|base64 -d|openssl rsautl -decrypt -inkey  private_key.pem -oaep
1234567891012

If your code works, the above code should decrypt the result. If OpenSSL throws an error, you can use it to debug your code.

I used OpenSSL 1.0.1k on Fedora 23 to generate the above example. You might need to change the commands slightly if you are using different software versions.

Some common mistakes:

  • Using RAW or PKCS1_5 padding instead of OAEP.
  • Using the wrong Mask Generation Function. We always use MGF1 with SHA1 (see RFC 2437 Section 10.2.1)
  • Not trimming the card number string before encrypting.
  • Not formatting the card number as ASCII encoded decimal digits. In particular, ensure that the card number is NOT encoded in BCD format.
  • Not using a valid entropy source for padding. For security reasons, our gateway rejects transactions padded with all 0s or all 1s.
  • Attempting to parse the public modulus as hex or base64 instead of base 10.
  • Using the wrong public exponent. We always use 65537 (base 10).
  • Using the base64 URL variant instead of the canonical base64.
  • Removing base64 padding from the encrypted card number.
  • Using an OAEP label (see RFC 3447 Section 7.1.1). In general, OAEP labels are either not supported or deeply hidden by crypto APIs. However, if your API supports OAEP labels, you need to ensure that the OAEP label is an empty string (eg "" or char label[0]).
10 |2000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

anujc avatar image
anujc answered

Developed by Brijmohan karadia : 9829388872

include_once('components/Crypt/RSA.php');

$merchantorderdatamarchantid = 'XHEXXXXXT0'; $accesstoken = 'exxxxx0547-8f62-aaaa-f2fa-8853333301b2'; $orderId='DBSXXXXXVM';

    //https://sandbox.dev.clover.com/v2/merchant/YK4N7TXVWGJ2J/pay/key
     $clover_api = new CloverApi(); 

    $pay_key_data = $clover_api->GetPayKeyData($merchant_order_data_marchantid,$access_token);
    $pay_key_data = json_decode($pay_key_data);
    //print_r($pay_key_data); 
    //echo "<hr>";

    $rsa = new Crypt_RSA();
    //1. GET to /v2/merchant/{mId}/pay/key To get the encryption information you’ll need for the pay endpoint.
    //2. Encrypt the card information 

    $prefix = $pay_key_data->prefix;
    $modulus = $pay_key_data->modulus;
    $exponent = $pay_key_data->exponent;
    //echo "<hr>";


    $user_cc_no = '4111111111111111';
    $user_cc_mo = '06';
    $user_cc_yr = '2017';
    $user_cc_cvv = '123';
    $user_zip = '23402';

    //2.1. Prepend the card number with the prefix from GET /v2/merchant/{mId}/pay/key.
    $stingToEnc = $user_cc_no.$prefix; 

    //2.2. Generate an RSA public key using the modulus and exponent provided byGET /v2/merchant/{mId}/pay/key.
    $modulus = new Math_BigInteger($modulus);
    $exponent = new Math_BigInteger($exponent);

    $rsa->loadKey(array('n' => $modulus, 'e' => $exponent));
    $rsa->setPublicKey();

    $mypublickey = $rsa->getPublicKey();
    //echo "<hr>";

    //2.3. Encrypt the card number and prefix from step 1 with the public key.
    $stingToEncPublickey = $stingToEnc.$mypublickey; 
    $ciphertext =   $rsa->encrypt($stingToEncPublickey);
    //echo "<hr>";

    //3. Base64 encode the resulting encrypted data into a string which you will send to Clover in the “cardEncrypted” field.
      $stingBase64Encpted = base64_encode($ciphertext);
    //echo "<hr>";

    /****************** POST DATA TO PAYMENT API ******************/

      $url = 'https://apisandbox.dev.clover.com/v2/merchant/'.$merchant_order_data_marchantid.'/pay?access_token='.$access_token;   

      $curlPost = 'orderId='.$orderId.
     '&taxAmount=12'.
     '&zip='.$user_zip.
     '&expMonth='.$user_cc_mo.
     '&cvv='.$user_cc_cvv.
     '&amount=231'.
     '&currency=USD'.
     '&last4=1111'. 
     '&expYear='.$user_cc_yr. 
     '&first6=411111'.
     '&cardEncrypted='.$stingBase64Encpted; 
    $ch = curl_init();      
    curl_setopt($ch, CURLOPT_URL, $url);        
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);        
    curl_setopt($ch, CURLOPT_POST, 1);      
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json'));
    curl_setopt($ch,CURLOPT_HTTPHEADER, array('Authorization: Bearer '. $access_token));
    curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost);    
    $data = curl_exec($ch);  


    /****************** POST DATA TO PAYMENT API ******************/
10 |2000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Welcome to the
Clover Developer Community