Ashish gupta
Ashish gupta

Reputation: 31

AES 256 with PKCS7 padding

The GST Council has approved the implementation of ‘e-Invoicing’ or ‘electronic invoicing’ of Business to Business (B2B) invoices to GST System if company turnover is greater that 500 crore. Ref of gst portal API :einv-apisandbox.nic.in/index.html

I have to decrypt the encrypted SEK using APP key and encode json data using decrypted SEK to post for Einvoice Generation and i found sample code for java and C# and i have converted in PHP but unfortunately failed to get desired output

In my case encrypted SEK is: oRvKfBtmgNTSuk/oXUhiLOjXi45jiWA2oKNxhhQM3UH2o/32YWGLbUjK1/dohPe3

APP key: fao1PoKaLgd11xMrWTiL2cggAfx9QMwM

Symmetric decryption (AES) (in java)

public static String decrptyBySyymetricKey(String encryptedSek, byte[] appKey)
{
    Key aesKey = new SecretKeySpec(appKey, "AES"); // converts bytes(32 byte random generated) to key
    try {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); // encryption type = AES with padding PKCS5
        cipher.init(Cipher.DECRYPT_MODE, aesKey); // initiate decryption type with the key
        byte[] encryptedSekBytes = Base64.decodeBase64(encryptedSek); // decode the base64 encryptedSek to bytes
        byte[] decryptedSekBytes = cipher.doFinal(encryptedSekBytes); // decrypt the encryptedSek with the initialized cipher containing the key(Results in bytes)
        String decryptedSek = Base64.encodeBase64String(decryptedSekBytes); // convert the decryptedSek(bytes) to Base64 StriNG
        return decryptedSek; // return results in base64 string
    }catch(Exception e) {
        return "Exception; "+e;
    }
}

Symmetric encryption (AES) (in java)

public static string EncryptBySymmetricKey(string text, string sek)
    {
    //Encrypting SEK
    try
    {
      byte[] dataToEncrypt = Convert.FromBase64String(text);
      var keyBytes = Convert.FromBase64String(sek);
      AesManaged tdes = new AesManaged();
      tdes.KeySize = 256;
      tdes.BlockSize = 128;
      tdes.Key = keyBytes;
      tdes.Mode = CipherMode.ECB;
      tdes.Padding = PaddingMode.PKCS7;
      pICryptoTransform encrypt__1 = tdes.CreateEncryptor();
      byte[] deCipher = encrypt__1.TransformFinalBlock(dataToEncrypt, 0, dataToEncrypt.Length);
      tdes.Clear();
      string EK_result = Convert.ToBase64String(deCipher);
      return EK_result;
   }
   catch (Exception ex)
    {
      throw ex;
   }
 }

Symmetric encryption (AES) (in PHP)

function encrypt($data, $key)
{
    $padding = 16 - (strlen($data) % 16);
    $data .= str_repeat(chr($padding), $padding);
    return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, hash('SHA256', $key, true), $data, MCRYPT_MODE_ECB));
 }

Symmetric decryption (AES) (in PHP)

function decrypt($key, $str) 
{
    $str = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, hash('SHA256', $key, true), $str, MCRYPT_MODE_ECB);
    $pad = ord($str[($len = strlen($str)) - 1]);
    $len = strlen($str);
    $pad = ord($str[$len-1]);
    
    return base64_encode( substr($str, 0, strlen($str) - $pad));
}

Upvotes: 1

Views: 2113

Answers (2)

Suji Analytics
Suji Analytics

Reputation: 1

You also might need to try with postman tool. I achieve the same and able to connect the NIC system but as per the document they have provided it's not possible to achieve the same encryption using OpenSSL or other encryption tool.

Now I moved on to GSP based API connectivity solution you might check this stuff from

https://github.com/sujianalytics/gst-e-invoicing-sap

It's open source but not relevant for your issue, might need to upgrade little bit as per your requirement.

Upvotes: 0

Topaco
Topaco

Reputation: 49390

The decryption of the session key (SEK) with the AppKey is possible in PHP as follows:

function decrptyBySymmetricKey($encSekB64, $appKey) {
    $sek = openssl_decrypt($encSekB64, "aes-256-ecb", $appKey, 0);                  // the SEK
    $sekB64 = base64_encode($sek);                                                  // the Base64 encoded SEK
    return $sekB64;
}

The encryption of data with the SEK is possible in PHP as follows:

function encryptBySymmetricKey($dataB64, $sekB64){
    $data = base64_decode($dataB64);                                                // the data to encrypt
    $sek = base64_decode($sekB64);                                                  // the SEK
    $encDataB64 = openssl_encrypt($data, "aes-256-ecb", $sek, 0);                   // the Base64 encoded ciphertext
    return $encDataB64;
}

Both functions can be tested with the following data:

$appKey = 'fao1PoKaLgd11xMrWTiL2cggAfx9QMwM';                                       // the 32 bytes AppKey
$encSekB64 = 'oRvKfBtmgNTSuk/oXUhiLOjXi45jiWA2oKNxhhQM3UH2o/32YWGLbUjK1/dohPe3';    // the Base64 encoded encrypted SEK 
$dataB64 = 'VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw==';          // the base64 encoded data
$sekB64 = decrptyBySymmetricKey($encSekB64, $appKey);                               // the Base64 encoded SEK   
$encDataB64 = encryptBySymmetricKey($dataB64, $sekB64);                             // the Base64 encoded ciphertext
echo $sekB64 . "\n";                                                                // zVoede7m2nnvMHcWYIfKhrvsilSFEZYiltJmxVQQnAQ=
echo $encDataB64;                                                                   // JS+hxYf64FMHThrhoIejqk3VjGwFw+GTYzUyVKc6GEOLKERVuvaNY91zPdo829r0

The Java method decryptBySymmetricKey returns with

byte[] appKey = "fao1PoKaLgd11xMrWTiL2cggAfx9QMwM".getBytes(StandardCharsets.UTF_8);
String encSekB64 = "oRvKfBtmgNTSuk/oXUhiLOjXi45jiWA2oKNxhhQM3UH2o/32YWGLbUjK1/dohPe3";
String sekB64 = decryptBySymmetricKey(encSekB64, appKey);

the same value for the Base64 encoded SEK (zVoede7m2nnvMHcWYIfKhrvsilSFEZYiltJmxVQQnAQ=).

Likewise, the C# method EncryptBySymmetricKey (erroneously labeled in the question as Java function) returns with

string dataB64 = "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw==";
string sekB64 = "zVoede7m2nnvMHcWYIfKhrvsilSFEZYiltJmxVQQnAQ=";
string encDataB64 = EncryptBySymmetricKey(dataB64, sekB64);

the same value for the Base64 encoded ciphertext (JS+hxYf64FMHThrhoIejqk3VjGwFw+GTYzUyVKc6GEOLKERVuvaNY91zPdo829r0).

Note:

  • The deprecated mcrypt is not used. Instead openssl is applied.
  • Besides the security aspect, openssl has the advantage over mcrypt, that PKCS7 padding is implicitly used, analogous to the C#/Java code. mcrypt applies Zero padding, so a user defined padding was necessary, which is obsolete with openssl.
  • The key is not derived from the passed key via SHA256, but applied directly, analogous to the C#/Java code.

Upvotes: 2

Related Questions