Search…
Signature - chữ kí điện tử
Mô tả về chữ kí điện tử để xác thực dữ liệu.
VinID sử dụng chữ ký điện tử (signature) để xác thực dữ liệu đầu vào và ra trên mỗi HTTP Request.
Hệ thống VinID sử dụng thuật toán SHA256 RSA ( key size = 2048 bit) để tạo signature.

Tạo chữ ký điện tử

*Unix
MacOS (Brew)
Windows
1
openssl genrsa -out RS256-2048-Private.rsa 2048
2
openssl rsa -in RS256-2048-Private.rsa -pubout > RS256-2048-Public.rsa
Copied!
1
brew update
2
brew install openssl
3
echo 'export PATH="/usr/local/opt/openssl/bin:$PATH"' >> ~/.bash_profile
4
source ~/.bash_profile
5
6
openssl genrsa -out RS256-2048-Private.rsa 2048
7
openssl rsa -in RS256-2048-Private.rsa -pubout > RS256-2048-Public.rsa
Copied!
1
openssl genrsa -out RS256-2048-Private.rsa 2048
2
openssl rsa -in RS256-2048-Private.rsa -pubout > RS256-2048-Public.rsa
Copied!

Format chữ ký điện tử

  • PrivateKey: do merchant tự generate ra theo định dạng SHA256 RSA ( 2048 )
  • URL: Endpoint API
POST
GET
1
RawData = {url};{method};{X-Nonce};{X-Timestamp};{X-Key-Code};{body}
2
X-Signature = ​SHA256WithRSA(PrivateKey, RawData)
Copied!
1
RawData = {url};{method};{X-Nonce};{X-Timestamp};{X-Key-Code};
2
X-Signature = ​SHA256WithRSA(PrivateKey, RawData)
Copied!
Ví dụ:
POST
GET
1
url: '/merchant-integration/v1/qr/gen-transaction-qr'
2
method: 'POST'
3
X-Nonce: '00a81e60-2684-4cf9-878d-f37559213059'
4
X-Timestamp: 1570723375
5
X-Key-Code: 'b7bdf002-4948-44d2-99d1-99c8c81c3f47'
6
Body: {"callback_url":"https://webhook.site/17d9577f-70ca-4918-8388-1d6d53d8bc69","description":"Kiểm thử thanh toán","order_amount":10000,"order_currency":"VND","pos_code":"IPOS002","service_type":"PURCHASE","store_code":"ISTORE002"}
7
RawData: /merchant-integration/v1/qr/gen-transaction-qr;POST;00a81e60-2684-4cf9-878d-f37559213059;1570723375;b7bdf002-4948-44d2-99d1-99c8c81c3f47;{"callback_url":"https://webhook.site/17d9577f-70ca-4918-8388-1d6d53d8bc69","description":"Kiểm thử thanh toán","order_amount":10000,"order_currency":"VND","pos_code":"IPOS002","service_type":"PURCHASE","store_code":"ISTORE002"}
8
X-Signature: SHA256WithRSA(PrivateKey, RawData)
9
=> X-Signature: ERSt3cZoijwJf8QIZdcpHPygcDQJ+tA7l/2EVyJyhO8fwpp6mbrYWsyhyqDjD4zkhGwcXVJ7zJQUDWFpCPitG9GlmssEnkp57YK94/6GR54x6COzPqOlJjoQ4Lq6Fvw99QVmjiL+WjGWSOTUkusXh9dr871vCrjcYmyFSCZ9Ydfw6l4iv2evOnibUtalIkdsNM6evrVa7qW28Uno5t8fmz68QJeXd0dqL4lm2tsFAr9094jbWh/zlynqAW9MOIIYjXQC7XwEVKiBEmoZyTnSd8SLITLNIXvLCJjjVT5XYqZAMNIyoNYZKom8dUjLuirBBurcUpXuxlu01O8dU9qHdg==
Copied!
1
url: '/merchant-integration/v2/qr/query/20200623T0017FB54CBB'
2
method: 'GET'
3
X-Nonce: '00a81e60-2684-4cf9-878d-f37559213059'
4
X-Timestamp: 1570723375
5
X-Key-Code: 'b7bdf002-4948-44d2-99d1-99c8c81c3f47'
6
RawData: /merchant-integration/v2/qr/query/20200623T0017FB54CBB;GET;00a81e60-2684-4cf9-878d-f37559213059;1570723375;b7bdf002-4948-44d2-99d1-99c8c81c3f47;
7
X-Signature: SHA256WithRSA(PrivateKey, RawData)
8
=> X-Signature: ERSt3cZoijwJf8QIZdcpHPygcDQJ+tA7l/2EVyJyhO8fwpp6mbrYWsyhyqDjD4zkhGwcXVJ7zJQUDWFpCPitG9GlmssEnkp57YK94/6GR54x6COzPqOlJjoQ4Lq6Fvw99QVmjiL+WjGWSOTUkusXh9dr871vCrjcYmyFSCZ9Ydfw6l4iv2evOnibUtalIkdsNM6evrVa7qW28Uno5t8fmz68QJeXd0dqL4lm2tsFAr9094jbWh/zlynqAW9MOIIYjXQC7XwEVKiBEmoZyTnSd8SLITLNIXvLCJjjVT5XYqZAMNIyoNYZKom8dUjLuirBBurcUpXuxlu01O8dU9qHdg==
Copied!
Code mẫu tạo Signature
Go
PHP
Python
Java
C#
1
// GenerateSignature util to generate signature form Auth Claim of merchant
2
func GenerateSignature(claim *dtos.AuthClaims, privKey []byte) (string, error) {
3
block, _ := pem.Decode(privKey)
4
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
5
if err != nil {
6
fmt.Printf("Error ParsePKCS1PrivateKey: %v", err)
7
return "", err
8
}
9
hash := generateHash(claim.URL, claim.Method, claim.Nonce, claim.Timestamp, claim.KeyCode, claim.Body)
10
signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hash[:])
11
if err != nil {
12
fmt.Printf("Error from signing: %s\n", err)
13
return "", err
14
}
15
claim.Signature = base64.StdEncoding.EncodeToString(signature)
16
return claim.Signature, nil
17
}
18
Copied!
1
function generateSignature($url, $method, $nonce, $timestamp, $apiKey, $requestBody, $privateKey)
2
{
3
$data = $url . ";" . $method . ";" . $nonce . ";" . $timestamp . ";" . $apiKey . ";" . $requestBody;
4
$p = openssl_pkey_get_private($privateKey);
5
if (!$p) {
6
trigger_error("Invalid private key\n".$privateKey, E_USER_WARNING);
7
throw new InvalidPrivateKeyException($privateKey);
8
}
9
$signSuccess = openssl_sign($data, $signature, $p, OPENSSL_ALGO_SHA256);
10
$encodedSignature = base64_encode($signature);
11
openssl_free_key($p);
12
return $encodedSignature;
13
}
Copied!
1
def generateSign():
2
requestBody = json.dumps(params, default=lambda o:o.__dict__, ensure_ascii=False,separators=(',', ':'))
3
data = url+";"+method+";"+nonce+";"+str(int(timestamp))+";"+keyCode+";"+requestBody
4
f = open("/home/vid/Documents/leo/sb_private.pem", "r")
5
pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, f.read())
6
sign = OpenSSL.crypto.sign(pkey, data, "sha256")
7
encodedSign = base64.b64encode(sign)
8
return encodedSign
Copied!
1
import java.io.File;
2
import java.nio.file.Files;
3
import java.security.KeyFactory;
4
import java.security.PrivateKey;
5
import java.security.spec.PKCS8EncodedKeySpec;
6
import java.util.Base64;
7
8
public class VinIDSignature {
9
10
//The method that signs the data using the private key that is stored in keyFile path
11
public String generateSign(String url, String method, String nonce, String timestamp, String keyCode, String requestBody, String keyFile) throws Exception {
12
String body = requestBody == null || "".equals(requestBody) ? "" : requestBody;
13
String data = url + ";" + method + ";" + nonce + ";" + timestamp + ";" + keyCode + ";" + body;
14
java.security.Signature rsa = java.security.Signature.getInstance("SHA256withRSA");
15
rsa.initSign(getPrivate(keyFile));
16
rsa.update(data.getBytes());
17
return new String(Base64.getEncoder().encode(rsa.sign()));
18
}
19
20
//Method to retrieve the Private Key from a file
21
private PrivateKey getPrivate(String filename) throws Exception {
22
byte[] keyBytes = Files.readAllBytes(new File(filename).toPath());
23
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
24
KeyFactory kf = KeyFactory.getInstance("RSA");
25
return kf.generatePrivate(spec);
26
}
27
}
28
Copied!
1
using System.Text;
2
using System.IO;
3
using java.security.spec;
4
using java.security;
5
using System;
6
using System.Security.Cryptography;
7
8
namespace OneID
9
{
10
class Security
11
{
12
public string sign(string url, string method, string nonce, string timestamp, string keycode, string requestBody, string keyfile)
13
{
14
string data = url + ";" + method + ";" + nonce + ";" + timestamp + ";" + keycode + ";" + requestBody;
15
RSACryptoServiceProvider ras = PemKeyUtils.GetRSAProviderFromPemFile(keyfile);
16
return System.Convert.ToBase64String(ras.SignData(Encoding.ASCII.GetBytes(data), CryptoConfig.MapNameToOID("SHA256")));
17
}
18
}
19
}
20
Copied!
Last modified 1yr ago