1. The OpenSSL tool generates the key
- 1. The OpenSSL tools download address: https://www.openssl.org/source/
- 2. Generate a 1024-bit RSA key PEM file in the specified directory
Generate the private.pem private key
mkdir temp_key && cd temp_key && openssl genrsa -out private.pem 1024
Copy the code
- 3. Generate a CER certificate using the key
## Generate the public. Cer public key
openssl req -new -x509 -key private.pem -out public.cer -days 3650 -subj /CN=topbooking.natapp1.cc
Copy the code
- 4. Generate a PFX file using the PEM key and cer certificate
For example, if the password is set to 111111, the file openssl.pfx will be generated
openssl pkcs12 -export -out openssl.pfx -inkey private.pem -in public.cer
Copy the code
- 5. Use the PEM key to generate a PEM public key to the data exchange
Such as the long lung
Configure your own public key
Generate the public key app_public_key.pem
openssl rsa -in private.pem -pubout -out app_public_key.pem
Copy the code
- 6. Public key to be generated
app_public_key.pem
To the data interaction party
2. Data signature
namespace App\Services\ChimeLong;
use Illuminate\Support\Str;
/** * RSA encryption * Class RSACryptoService *@package App\Services\MPay
*/
class RSACryptoService
{
private $_mer_no;
private $_aes_key;
private $_ver_no;
private $_privateKey;
public $_publicKey;
RSACryptoService constructor. */
public function __construct()
{
if (app()->environment('production')) {// Formal environment
$this->_mer_no = config('api_token.chimeLong.prod.mer_no');
$this->_aes_key = substr(md5(config('api_token.chimeLong.prod.key')), 8.16);
$this->_ver_no = config('api_token.chimeLong.prod.ver_no');
$privatePemPath = public_path(config('api_token.chimeLong.prod.privatePemPath'));
$publicPemPath = public_path(config('api_token.chimeLong.prod.publicPemPath'));
$publicPemPathCL = public_path(config('api_token.chimeLong.prod.publicPemPathCL'));
} else {// Test the environment
$this->_mer_no = config('api_token.chimeLong.test.mer_no');
$this->_aes_key = substr(md5(config('api_token.chimeLong.test.key')), 8.16);
$this->_ver_no = config('api_token.chimeLong.test.ver_no');
$privatePemPath = public_path(config('api_token.chimeLong.test.privatePemPath'));
$publicPemPath = public_path(config('api_token.chimeLong.test.publicPemPath'));
$publicPemPathCL = public_path(config('api_token.chimeLong.test.publicPemPathCL'));
}
$this->get_private_key($privatePemPath);// The requested data is signed with our private key, and Chimelong receives the requested data by checking with our public key
$this->get_public_key($publicPemPathCL);// The received response data is checked with chimelong's public key
}
/** * get the private key *@param $privatePemPath
*/
private function get_private_key($privatePemPath)
{
$this->_privateKey = openssl_pkey_get_private(file_get_contents($privatePemPath));
}
/** * Parses the public key from the certificate for use *@param $publicPemPath
*/
private function get_public_key($publicPemPath)
{
$this->_publicKey = openssl_pkey_get_public(file_get_contents($publicPemPath));
}
/** * Step 1 * Generate signature using the corresponding language SHA256WithRSA signature function to use the sender private key to sign the signature string, and Base64 encoding. *@param $data
* @return string
* @throws \Exception
*/
public function rsa_sign($data)
{
$signData = $this->_mer_no . $data['method'].$data['uuid'].$data['timestamp'].$this->_ver_no . json_encode($data['body']);
$signature = ' ';
$res = openssl_sign($signData.$signature.$this->_privateKey, OPENSSL_ALGO_SHA256);
openssl_free_key($this->_privateKey);
if ($res) {
return base64_encode($signature);
} else {
throw new \Exception("Error requesting data signature".10004); }}AES algorithm The encryption mode is ECB. The key length is 128 bits and the block length is 128 bits. *@param $data
* @return string
* @throws \Exception
*/
public function aes_sign($data)
{
if(! key_exists('timestamp'.$data)) {
$data['timestamp'] = now()->toDateTimeString();
}
if(! key_exists('uuid'.$data)) {
$data['uuid'] = (string)Str::uuid();
}
if(! key_exists('body'.$data)) {
$data['body'] = [];
}
$sign = $this->rsa_sign($data);
$encryptData = [
"method"= >$data['method']."sign"= >$sign."nonce_str"= >$data['uuid']."timestamp"= >$data['timestamp']."ver_no"= >$this->_ver_no,
"body"= >$data['body']];return $this->aes_encrypt(json_encode($encryptData));
}
/ * * *@param string $resource
* @param string $signature
* @return bool
* @todo: to be perfected, temporarily useless * string verification method a */
public function verifyResData(string $resource.string $signature) :bool
{
$signature = base64_decode($signature);
$res = openssl_verify($resource.$signature.$this->_publicKey, OPENSSL_ALGO_SHA256);
//openssl_free_key($this->_publicKey);
return $res= = =1;
}
/ * * *@param $response
* @return int
* @todo: To be perfected, temporarily useless * Verify signature method two */
public function check_sign($response)
{
$json = json_decode($response.false);
$signature = base64_decode($json->sign);
unset($json->sign);
$data = $json->code . $json->msg . $json->nonce_str . $json->body;
$res = openssl_verify($data.$signature.$this->_publicKey, OPENSSL_ALGO_SHA256);
//dd($data, $signature, $res);
openssl_free_key($this->_publicKey);
return $res= = =1;
}
/** * decrypt *@param $str
* @return false|string
*/
public function aes_decrypt($str)
{
return openssl_decrypt(base64_decode($str), "AES-128-ECB".$this->_aes_key, OPENSSL_RAW_DATA);
}
/** * Encrypted string *@param $str
* @return string
*/
public function aes_encrypt($str)
{
return base64_encode(openssl_encrypt($str."AES-128-ECB".$this->_aes_key, OPENSSL_RAW_DATA));
}
/** * Returns the desired data after decryption, de-serialization, and signature verification@param string $resource
* @return mixed
* @throws \Exception
*/
public function handleRes(string $resource)
{
// Step1: AES decryption
$decryptRes = $this->aes_decrypt($resource);
// step2: json disserialization
$resData = json_decode($decryptRes.true);
# response signature string code+ MSG +nonce_str+body
$body = $resData['body'];
$signData = $resData['code'].$resData['msg'].$resData['nonce_str'].$body;
$signature = $resData['sign'];
if ($this->verifyResData($signData.$signature) | |$this->check_sign($decryptRes)) {// Check successful
return json_decode($body.true);
} else {
throw new \Exception("Received data signature error".10004); }}}Copy the code