AES 256 with PKCS7 padding



如果公司营业额超过50亿,商品及服务税委员会已批准对商品及服务体系的企业对企业(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));
}

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

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

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

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编码的密文(JS+hxYf64FMHThrhoIejqk3VjGwFw+GTYzUyVKc6GEOLKERVuvaNY91zPdo829r0(具有相同的值。

注:

  • 不使用已弃用的mcrypt。而是应用openssl
  • 除了安全方面,opensslmcrypt相比还有一个优势,即隐式使用PKCS7填充,类似于C#/Java代码mcrypt应用零填充,因此用户定义的填充是必要的,这在openssl中已经过时
  • 密钥不是从通过SHA256传递的密钥派生的,而是直接应用的,类似于C#/Java代码

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

现在我转到了基于GSP的API连接解决方案,您可以从中查看这些内容

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

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

最新更新