【问题标题】:AES 256 with PKCS7 padding带有 PKCS7 填充的 AES 256
【发布时间】:2020-12-28 18:36:23
【问题描述】:

如果公司营业额超过 50 亿,GST 委员会已批准在 GST 系统中实施企业对企业 (B2B) 发票的“电子发票”或“电子发票”。 gst 门户 API 参考:einv-apisandbox.nic.in/index.html

我必须使用 APP 密钥解密加密的 SEK,并使用解密的 SEK 对 json 数据进行编码以发布 Einvoice Generation,我找到了 java 和 C# 的示例代码,我已经在 PHP 中进行了转换,但遗憾的是未能获得所需的输出

在我的例子中,加密的 SEK 是:oRvKfBtmgNTSuk/oXUhiLOjXi45jiWA2oKNxhhQM3UH2o/32YWGLbUjK1/dohPe3

APP密钥:fao1PoKaLgd11xMrWTiL2cggAfx9QMwM

对称解密 (AES)(在 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;
    }
}

对称加密 (AES)(在 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;
   }
 }

对称加密 (AES)(在 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));
 }

对称解密 (AES)(在 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));
}

【问题讨论】:

  • 您的问题解决了吗?

标签: php openssl aes padding mcrypt


【解决方案1】:

在 PHP 中可以使用 AppKey 解密会话密钥 (SEK),如下所示:

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;
}

在 PHP 中可以使用 SEK 加密数据,如下所示:

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;
}

这两个函数都可以用以下数据进行测试:

$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

Java 方法decryptBySymmetricKey 返回

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

Base64 编码 SEK (zVoede7m2nnvMHcWYIfKhrvsilSFEZYiltJmxVQQnAQ=) 的值相同。

同样,C# 方法 EncryptBySymmetricKey(在问题中被错误标记为 Java 函数)返回

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

Base64 编码密文 (@​​987654329@) 的值相同。

注意:

  • 不推荐使用的 mcrypt。而是应用 openssl
  • 除了安全方面,opensslmcrypt 具有优势,隐式使用 PKCS7 填充,类似于 C#/Java 代码。 mcrypt 应用零填充,因此需要用户定义的填充,而 openssl 已过时。
  • 密钥不是从通过 SHA256 传递的密钥派生而来,而是直接应用,类似于 C#/Java 代码。

【讨论】:

  • 需要更多帮助:您在哪里应用了 PaddingMode.PKCS7
  • @Ashishgupta - 正如上面的注释中提到的,openssl_encrypt()openssl_decrypt()默认使用 PKCS7 填充,即它未明确指定(否则 Java/C# 代码的结果也不会被复制)。
  • 感谢您的帮助。不幸的是我的问题没有解决。当我发布 encDataB64 数据然后从 API““ErrorMessage”:“应用程序错误,请联系服务台”时收到错误,但是当我直接从沙盒门户对我的 json f 进行编码时,Einvoice 成功生成并获取 IRN 代码。现在我无法找到我做错的问题。给定公钥和证书框的沙盒门户(供您参考)
【解决方案2】:

您可能还需要尝试使用邮递员工具。我实现了相同的功能并且能够连接 NIC 系统,但根据他们提供的文档,使用 OpenSSL 或其他加密工具无法实现相同的加密。

现在我转向基于 GSP 的 API 连接解决方​​案,您可以从

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

它是开源的,但与您的问题无关,可能需要根据您的要求进行一点升级。

【讨论】:

    猜你喜欢
    • 2021-04-17
    • 2017-08-29
    • 1970-01-01
    • 2011-05-29
    • 2015-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多