The PKI allows users and systems to verify the legitimacy of certificate-holding entities and securely exchange information between them over the ether. The introduction of a PKI enables stronger, certificate-based security and delivery of identity services and management tools that maximize network efficiency and security.
Elements of security
- Authenticity : The message is truly sent from the people we are expecting.
- Integrity : The message is not altered or intercepted by unauthorised sources.
- Confidentiality : The message is encrypted and can only be decrypted by authorised people.
Why PKI API?
- While using PKI API, Payload will be covered with end-to-end security on public network. This will remove the dependency of VPN to create secure tunnel communication between Contis and Client server.
- PKI API allows you to develop mobile APP without developing wrapper between App and Contis API.
- PKI API will improve the performance by server to server calling whereas in VPN calls are routing via specific VPN tunnel.
Consuming the Contis API
Client should set up the necessary infrastructure to implement the PKI, enabling Contis’ APIs to be consumed. Client should enrol for the client certificate by providing the Contis team with its own PKI certificate (public key) or by requesting the PKI certificate from Contis (in which case private & public keys will be made available via Client’s SFTP address and notification sent to Client’s registered email with unique GroupCode which must be passed in each request header).
Contis will also provide Client with Contis’ PKI certificate (public key) via Client’s SFTP address which Client will require for encryption of sensitive payload data such as password, mPIN etc. It is the integrator’s responsibility to save both the Client’s private key and Contis’ public key safely. A notification email will also be sent to Client’s registered email address. Further certificate enrolment details can be found in Certification Process.
Summary of PKI API
Clients must complete the following processes to obtain access and consume Contis’ API:
- Enrol for the PKI certificates.
- Obtain a Contis PKI certificate (public key) and Client’s private key.
- Obtain security access token (via login method) and generate a digital signature of the payload to authenticate
API requests. For anonymous methods, only a digital signature is required. - Follow the format of Contis’ API request payload.
Registration
Client is required to register itself with Contis as a unique identity. This process allows Contis to confirm Client has a PKI (public key infrastructure) in place and is ready to provide a reliable solution by accepting Contis’ expected standards. The detailed registration process can be found in Certification Process.
Unique identity for authentication
Client must have valid Contis PKI (public key) and PKI (private key) certificates and a valid GroupCode which will be used to identify the users’ secure request and response payloads by generating digital signatures and verifying the integrity of the payloads.
Authenticate Client API Requests
Client is required to pass the client GroupCode & digital signature in every API request header which will be used to identify both Client and the PKI certificate the Client is using to sign the message.
Request payload format
Any request sent to the Contis API must contain certain pieces of information before the system will process them. If these are missing or incorrect, they will be rejectedand an error message returned.
Client should note GroupCode and x-signature when authoring requests to the Contis API. Further details on the API message schema.
Request Authorised and Processed
Contis receives the integrator’s request and uses the information contained in the request message header to validate Client’s identity by:
- Fetching the Client’s public key.
- Generating and verifying the digital signature sent in the request header.
When Contis has authenticated the integrator’s identity, the API request can be authorised and processed.
Response Header
The x-signature is a digital signature generated from the response payload using Contis’ PKI certificate (private key) and is included in every API response header. To validate and verify the response message integrity, the integrator can use this signature to match the signature generated using Contis’ PKI certificate (public key) (as initially shared with the integrator).
RESPONSE HEADER | Description |
x-signature | Digital signature generated |
Certification Process
Client is required to complete and pass Contis’ certification process so customer applicants can be identified safely and easily, connected, and consume the Contis API. It also ensures sufficient control and understanding exists between Contis and the customer.
To complete the process:
- Contact Contis’ onboarding team to provide PKI certificate (public key) OR to request PKI certificate. Certificates will be provided via SFTP.
- Contis’ onboarding team will email Client the unique GroupCode and SFTP information from which Client can access Contis’ PKI certificate (public key). Contis’ team can help provide Client’s PKI certificate (private & public key) if the certificate is generated by Contis.
- Use Contis’ public key to encrypt sensitive data (eg. password, mPIN etc) while passing in request payload and generate digital signature of Client’s request payload using Client’s private key. Pass the digital signature in the request header and complete any Contis API call.
- Contis will verify the contents and, if satisfied, will provide further access to the actual API.
Authenticating API Requests
Any request sent to the Contis API must contain certain pieces of information before the system will process them. If these are missing or incorrect, the API will reject them and return an error message.
- To authenticate your API requests:
- Generate the Message Digital Signature Supply the following Request Headers:
- groupcode
- x-signature
Generating the Digital Signature
The Message Digital Signature is required to prove:
- A message has been signed by the Holder of the PKI certificate.
- Data integrity of the message (ie. no data has been intercepted).
The Digital Signature is specific to the body of the request.
NB: The entire HTTP request body is used to generate the Digital Signature after sensitive elements are encrypted (eg.password and mPIN). To generate the digital signature using Secure Hash Algorithm (SHA):
- Obtain the Hash of request body using SHA256 Managed & Client’s PKI certificate (private key). Data must be encoded using UTF8 while computing hash.
- Request the RSA encryption algorithm to generate the digital signature using the Hash produced above.
- The output generated is the Digital Signature.
- Pass this Digital Signature in the API request headers for all your API requests with the request body.
The Digital Signature needs to be placed into the specific request header named “x-signature”.
RESPONSE HEADER | Description |
x-signature | HGbgcNSF2TVD6b8czWYBvJbG4FD+hYyZXi//7YnolCaRYKC+MD7FnFhM9Ar1eL2OinBfDM0y7jt9Ipjyf5F4mL0ecgF+ ugs9PWoePjewho3o0av5eo4f1MntPJSBc+/g8BwolSjXlaOBW7i0XH0C7y3knaywnrk14ctwmxEDkQxzoxgnehDWQe VvGD2Cjk5VtXb8qPaUFGlUcx3Ide20Mi3IM6uD3sOqJPtoLFIzGPemesDyyRN9gcGBXi+bUcMZUcK9xc7Ctd6U2bJIr wmpnMurr0Eo0J936ESXVr5qZa0dhBLPWMP1QgREwGNO2j8rUySO6sJc8+CiNfTAe4OrQ== |
This value will help Contis validate and verify the integrity of the message request sent in the request body. If the signature cannot be verified, an HTTP 403 Forbidden response will be returned.
API Message Schema
Headers cited in groupcode and x-signature header must be supplied by integrators in addition to endpoint information and message schema such as Authorisation and grant_type headers.
groupcode
This must be supplied and valid in all API requests.
RESPONSE HEADER | Description |
groupcode | B80E7823-740B-4C6F-9B9B-D2643B19B0F3 |
This value will help Contis to decrypt sensitive elements such as password and mPIN sent in the request body. If this value is not found in the request header, an HTTP 406 NotAcceptable response will be returned. If the value is not matched and PKI certificates for the value are not found, an HTTP 403 Forbidden response will be
returned.
x-signature header
A request body is used to create the Digital Signature for requests that have a payload. All requests require the groupcode and x-signature included in the request header.
Example of an encoded Digital Signature:
RESPONSE HEADER | Description |
groupcode | B80E7823-740B-4C6F-9B9B-D2643B19B0F3 |
x-signature | HGbgcNSF2TVD6b8czWYBvJbG4FD+hYyZXi//7YnolCaRYKC+MD7FnFhM9Ar1eL2OinBfDM0y7jt9Ipjyf5F4mL0ecgF+ ugs9PWoePjewho3o0av5eo4f1MntPJSBc+/g8BwolSjXlaOBW7i0XH0C7y3knaywnrk14ctwmxEDkQxzoxgnehDWQe VvGD2Cjk5VtXb8qPaUFGlUcx3Ide20Mi3IM6uD3sOqJPtoLFIzGPemesDyyRN9gcGBXi+bUcMZUcK9xc7Ctd6U2bJIr wmpnMurr0Eo0J936ESXVr5qZa0dhBLPWMP1QgREwGNO2j8rUySO6sJc8+CiNfTAe4OrQ== |
Examples
Client Key Pair
Below is the example private key of the client which is used to generate the digital signature
-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAhsPMmR2RizzAE63kdKJRCjn/MZH8memnxJUEsvP/pvIChZMM xXY7sSHUQa+zb0iR0kZrHx/QuHQAea/E1QAHzo9U3dM0I5+bEXObuVkJq9owJ//Q eZxXrpSyccFX3pdSLQuIdg1QVCvZrSxVvIna4sa5qBNbdR7nQhxoVdLi3Hv9uyyI 3tk4bK1d/klyY9XP7cL/3JeCZf/kbOfyb3KcgKuB2bi/fgdJhifvJGMj4ayVmBfe gJEfCu9SXZQvJJ/ZPuO0HVWMRVV65rJvhtgovezbYHErBqtwarvG4zyz9S60VOYC maA4OzvejgjU86MY/sALVcDvv3I+ekq1QW8EPwIDAQABAoIBADsqVjZ41U+4bamW JCESrBqdyMyWB7z46Kd1Nxlr5zb/tBy5qRc+J8nGDN6DyXbXePHE6b3B5Yw9nYHP Kc7L0yGcKsmysobbSSS5yUnv7b+NrKu682eYvKQQc2Fe3XmDnNfa4t/VS4mQsOIG /2MlcLw0PAku6m26khQjzai0S9Y5U7xVBLujMZSX9htxXA3vBOsae4V/ZT/kFOeK eIBc5MHYDRco4ePjRU/8XLj9GofAWSGHIDTz931TvF3jQjV7T3fmv1OltVeO3zYY t+HMUQG3psUFs7HXbLptFg2uGnAH5HOKf6J06J0ZSC1XHjfkAdSuyddOrSPKxUh0 XwkF/YkCgYEAys+Rp2ZbbU+bOAr6LV19sMvtYkNEfDTbfJHh1m+SRmqBanjeKd2e XqciP4HWFCW6+a/H9VshsT8p6q9Es6vZOoJQ68eYi2tJZr6zweqhiq17Fr73xoEk 4qB285WLx5YRPvNPUKzVDfJz56FSKjn4p8YqhaxHjWiOf8j2nzjJq9cCgYEAqhu4 RKqNnGwGohweJ/V4PO/zvtk/kV8HC8+fe2vGnOTw++oolTy2lLlzkkU9wkd9z4Nu avMQzR/YTkcbzQ3gyIRQM47oewGKb97pj3c5o8xdWmhkrXiJ7ys60Oc8gAANbzqw kk3XaWuKKAqlazYRJ/nfzmElrG7DGYdOA4GDHdkCgYEAtX37Qmr+9lt+9DAeoepA SK61yHGaH+zNXjTOfS9rH0jAd5+icKS6zMmUhHCUO4NoR3le39ql1BBKWpJuULtA snNcJyN/B4UDMscF5ksqNQf6Vuieoy1+7K/cwy7Y38sTs9nY6MFCCDEoN+jNtqwa MUnNU8JQZeNjYkddLC+NihECgYEAnT3qY27UYBdrOkaLiZxafNnBklT3ccVJmh1d 6pSBj14BdJvKz8jDbU7QChF/OSsknMF9O9dbXIFnTVRl2nJNqozEJiSfubR+51JC y58F5OdwE7YT+lZGCpMHVzuorRlfUcYKmfLigEwr9T+CEUx1J2LPAtLCJFZuehac gpkhPmECgYB/euG3LxhlwG/J9RKg8s/56Zw1+mfKrGKlfIYBOeeLadS90cyZLVp/ jttfbgTJ3CDLxA3haMHODR7ghLGgcfyp+8uVLWSZ4nVmOwuMXyttNb1DkB+ANx4R KOZ54R6PHnH/dBIQtxEikNzEjDoIyqKJfJKRTdWzVz2b47eQrIaqtA== -----END RSA PRIVATE KEY----- -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhsPMmR2RizzAE63kdKJR Cjn/MZH8memnxJUEsvP/pvIChZMMxXY7sSHUQa+zb0iR0kZrHx/QuHQAea/E1QAH zo9U3dM0I5+bEXObuVkJq9owJ//QeZxXrpSyccFX3pdSLQuIdg1QVCvZrSxVvIna 4sa5qBNbdR7nQhxoVdLi3Hv9uyyI3tk4bK1d/klyY9XP7cL/3JeCZf/kbOfyb3Kc gKuB2bi/fgdJhifvJGMj4ayVmBfegJEfCu9SXZQvJJ/ZPuO0HVWMRVV65rJvhtgo vezbYHErBqtwarvG4zyz9S60VOYCmaA4OzvejgjU86MY/sALVcDvv3I+ekq1QW8E PwIDAQAB -----END PUBLIC KEY-----
Contis Key Pair
Below is the example public key which is used for the verification of digital certificates generated using the private key (cited above). This key can be used to encrypt the sensitive data field in the API request while making an API call.
-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAnsaZAhnm+x+2UvABvNdfkp/yOG5A6jvGakRR781Qij+flg2o R3jwgWekUmNExsddVPWfjDFRUbtzxkg8wlRMaU61/Wcdi8MUNGGsFVmz1yDpg7um y7sW3Nev+/spHN/kbZqBf8P5z1C+d/hcPHYxEKM71b60gS5+SCVP+x54AlE2U0cC 2WPqXjCgHrQFF/x+XsRoIhvlyngn/uBLumV3m2DFBYb6BB7QflLdSBd74KLxr80F UGB0r7tSLi9brHJf4sa4HPCf+x0UV4UZiA0nI564Iy+qmOfWAfd6Tdn1o2ZK2pDM dg28cUKX06C4pgN4fV2JFZe0Xk2vUsyAa0D68QIDAQABAoIBABgmZHEDoBSrzOde DqGaz7RlZCoNqQ2HpIUW2bCkFb9FcKBZ+PHQFSLVsRJ/+17RxaItzwP7n18TaEdt RuKXAF1XJcrCk6WluS3DenFv6LEM1j/de8AKt65FF0U4PVdhPaUnJlHY7OcJ5MKq MdtXbdyWO3xmKp3ohLg0Bq+PQZk2ZDsivFBsSIbulo+kOlFMRnR8FrCadYeoDPBO S8l6N3qIkWkjA36NyXkBbIB1fmE2YxUwuGGTpCWcz53AO3yPtYUpiyLSZrgdxTml WzTT0vyWTAUbaGNPKxmLOsz74fQkE+qhELj5QyuIFyZjkdIgNT6Eb4uJ5XbdTPwT NdJN3f0CgYEAzDb8iuT899ShffUQFvbI05WJOUJ41rw5TmivOHGTQnC77ao4Q5LS UNYo+9EyMfA1b2lto3+ipK5bfSDH74EVgqYYigaJO/cqM/GHvnIfF93Uudldd20s W//kJDJltRYLVsiUR5QqYV0PgAbJdWThQgktuyYdfBSzl3j9ROyFXQUCgYEAxwnY kn4UD8BAXKcjfCrN6Q6fH+9RcIBTxyhOpS5A48tsB1gCY+M1XyssmKqtGgz3SGL/ 7atfzlET/SB2rX0/7o5dhP2qSJs54jevCzLSJGXgk9WdLjPJ2QY74O+n7M3XQCWB PRhVVu/GxsM5UoEWG3GlZGXYWwCTekWndFCpaf0CgYEAk4GcRQ9GEhVKWNrstkmn of0/U1bKRgFLO3GuLw0Km1EmzXLIlTa2J6GplMr0gNHLJyB2C0UkS+ONPgKxqDQL P4WN8BTsh53uo/pwXIW+I9Ud1OhG9P6srf9V4Tdt87Fqm1LimBlTy2QW0BkW527o rnRGzgmn/npNhrnj5ycY5akCgYAxyHyq524NIoD2q7dsbyhhio6yZiFwiihqP+Kr 3g3M7CxxCcpPQZ0v2JSm+smhIm0XZeutfpfP+ueNAHmumw1KlcE+alQVJP4tXtAh dOyqvfCWCW/vBnUOG0kO0eKmkDWujbLtnRB7Vi3ZuSq1QCRPaPV9Txv2ZwZ8Jr/j j+lP4QKBgBVDTqWIe0e6OYsBY1m4epUq9malh+L3434JJ88YzwE/Ue81WhkaHcWP OAcpKMPTRbBOeH5irzaJ64si+/NiAseFFZle8aTV0MRbhGweguprDbZYFwLSeX2C p3kGkLTXJbDpjiUhsphVCuSCfxRnnF6SCuRQmv6bY2QkVt5yCKrZ -----END RSA PRIVATE KEY----- -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnsaZAhnm+x+2UvABvNdf kp/yOG5A6jvGakRR781Qij+flg2oR3jwgWekUmNExsddVPWfjDFRUbtzxkg8wlRM aU61/Wcdi8MUNGGsFVmz1yDpg7umy7sW3Nev+/spHN/kbZqBf8P5z1C+d/hcPHYx EKM71b60gS5+SCVP+x54AlE2U0cC2WPqXjCgHrQFF/x+XsRoIhvlyngn/uBLumV3 m2DFBYb6BB7QflLdSBd74KLxr80FUGB0r7tSLi9brHJf4sa4HPCf+x0UV4UZiA0n I564Iy+qmOfWAfd6Tdn1o2ZK2pDMdg28cUKX06C4pgN4fV2JFZe0Xk2vUsyAa0D6 8QIDAQAB -----END PUBLIC KEY-----
Encrypt/Decrypt sensitive data fields
The Client needs to encrypt sensitive fields like password or mPINusing the Contis Public key.
For example, the string “password” is encrypted as:
NdlX+axA1dVB8CdQ+eioHKGfw6H4bc/m/tf2uow6yHHg8MDddF0G0C2sr+mIZE9y0v476Rai3gcXhLlXlAv LXfJO4GWggXWTDQCnNILgiLzugtIqD5V/JyVzkmNvzBVevXGS0xgg4ydh/2rzZQp+lenn35OEKkpY1IAHhS uJRHGvTBDIq97ZugxZBSzaTu7DlaYm3xMENGq2tDyeJeTC3QKC5pn2nEZs+mFqHW2VML4Xo4LVyTyPWUybt x6Ly0vElnrbxw+noERTnfFV5qIW5XicCtqJnOcIW7Ys4JDt2mghVihpcW13PfeTZxF7BcInsKYzG0r1ruXy ZXTiIgHk+w==
To encrypt the field data, the following code is used.
C# code
public static string EncryptString(string content, string publicKey) { RSACryptoServiceProvider rsaProvider = ImportPublicKey(publicKey); byte[] encryptedContent = rsaProvider.Encrypt(Encoding.ASCII.GetBytes(content), false); return Convert.ToBase64String(encryptedContent); }
The Client needs to use its own private key to decrypt field data. Contis will decrypt the encrypted data fields using Contis’ Private key. Contis has encrypted the string “password” using Contis’ Public key.
Using the below code we will be able to decrypt the below string:
NdlX+axA1dVB8CdQ+eioHKGfw6H4bc/m/tf2uow6yHHg8MDddF0G0C2sr+mIZE9y0v476Rai3gcXhLlXlAv LXfJO4GWggXWTDQCnNILgiLzugtIqD5V/JyVzkmNvzBVevXGS0xgg4ydh/2rzZQp+lenn35OEKkpY1IAHhS uJRHGvTBDIq97ZugxZBSzaTu7DlaYm3xMENGq2tDyeJeTC3QKC5pn2nEZs+mFqHW2VML4Xo4LVyTyPWUybt x6Ly0vElnrbxw+noERTnfFV5qIW5XicCtqJnOcIW7Ys4JDt2mghVihpcW13PfeTZxF7BcInsKYzG0r1ruXy ZXTiIgHk+w==
To password
public static string DecryptString(string content, string privateKey) { byte[] bytContent = Convert.FromBase64String(content); RSACryptoServiceProvider rsaProvider = ImportPrivateKey(privateKey); byte[] decryptedContent = rsaProvider.Decrypt(bytContent, false); return Encoding.ASCII.GetString(decryptedContent); }
Please note that while encrypting and decrypting Contis has used ASCII encoding.
Generate Digital Siganture
To generate the digital signature of any request payload, the Client needs to use Client’s Private key. For example, if the Client initiates an API call, Contis can generate the digital signature of the request
{ "ReferenceNumber": "d61e51f5-f701-4330-9609-5cdf40200622" } To HGbgcNSF2TVD6b8czWYBvJbG4FD+hYyZXi//7YnolCaRYKC+MD7FnFhM9Ar1eL2OinBfDM0y7jt9Ipjyf5F4mL0ecgF+ ugs9PWoePjewho3o0av5eo4f1MntPJSBc+/g8/BwolSjXlaOBW7i0XH0C7y3knaywnrk14ctwmxEDkQxzoxgnehDWQeV vGD2Cjk5VtXb8qPaUFGlUcx3Ide20Mi3IM6uD3sOqJPtoLFIzGPemesDyyRN9gcGBXi+bUcMZUcK9xc7Ctd6U2bJIrwm pnMurr0Eo0J936ESXVr5qZa0dhBLPWMP1QgREwGNO2j8rUySO6sJc8+CiNfTAe4OrQ==
So the whole request will contain something like the below:
Request Header:
RESPONSE HEADER | Description |
groupcode | B80E7823-740B-4C6F-9B9B-D2643B19B0F3 |
x-signature | HGbgcNSF2TVD6b8czWYBvJbG4FD+hYyZXi//7YnolCaRYKC+MD7FnFhM9Ar1eL2OinBfDM0y7jt9Ipjyf5F4mL0ecgF+ ugs9PWoePjewho3o0av5eo4f1MntPJSBc+/g8BwolSjXlaOBW7i0XH0C7y3knaywnrk14ctwmxEDkQxzoxgnehDWQe VvGD2Cjk5VtXb8qPaUFGlUcx3Ide20Mi3IM6uD3sOqJPtoLFIzGPemesDyyRN9gcGBXi+bUcMZUcK9xc7Ctd6U2bJIr wmpnMurr0Eo0J936ESXVr5qZa0dhBLPWMP1QgREwGNO2j8rUySO6sJc8+CiNfTAe4OrQ== |
Request Body:
RESPONSE HEADER | Description |
groupcode | B80E7823-740B-4C6F-9B9B-D2643B19B0F3 |
x-signature | HGbgcNSF2TVD6b8czWYBvJbG4FD+hYyZXi//7YnolCaRYKC+MD7FnFhM9Ar1eL2OinBfDM0y7jt9Ipjyf5F4mL0ecgF +ugs9PWoePjewho3o0av5eo4f1MntPJSBc+/g8BwolSjXlaOBW7i0XH0C7y3knaywnrk14ctwmxEDkQxzoxgnehDWQ eVvGD2Cjk5VtXb8qPaUFGlUcx3Ide20Mi3IM6uD3sOqJPtoLFIzGPemesDyyRN9gcGBXi+bUcMZUcK9xc7Ctd6U2bJIr wmpnMurr0Eo0J936ESXVr5qZa0dhBLPWMP1QgREwGNO2j8rUySO6sJc8+CiNfTAe4OrQ== |
Which can be verified using Client’s Public key, which will return as either true or false. To generate the digital signature we have used the following code.
C# code.
public static byte[] GetDataHash(string sampleData, byte[] key) { SHA256Managed shaManaged = new SHA256Managed(); byte[] hashHMAC = shaManaged.ComputeHash(Encoding.UTF8.GetBytes(sampleData)); return hashHMAC; } public static string GenerateDigitalSignature(string body, string privateKeyText) { var hash = GetDataHash(body, Encoding.UTF8.GetBytes(privateKeyText)); byte[] signedHash; using (RSACryptoServiceProvider rsa = ImportPrivateKey(privateKeyText)) { signedHash = rsa.SignHash(hash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); } var encodedHash = Convert.ToBase64String(signedHash); return encodedHash; } public static RSACryptoServiceProvider ImportPublicKey(string pem) { var pr = new PemReader(new StringReader(pem)); var publicKey = (AsymmetricKeyParameter)pr.ReadObject(); //Pkcs10CertificationRequest csr = (Pkcs10CertificationRequest)pr.ReadObject(); //var rsaParameters = DotNetUtilities.ToRSAParameters((RsaKeyParameters)csr.GetPublicKey()); var rsaParameters = DotNetUtilities.ToRSAParameters((RsaKeyParameters)publicKey); var csp = new RSACryptoServiceProvider(); csp.ImportParameters(rsaParameters); return csp; } public static RSACryptoServiceProvider ImportPrivateKey(string pem) { var pr = new PemReader(new StringReader(pem)); //var rsaParameters = DotNetUtilities.ToRSAParameters((((AsymmetricCipherKeyPair))pr.ReadObject())); AsymmetricCipherKeyPair KeyPair = (AsymmetricCipherKeyPair)pr.ReadObject(); RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)KeyPair.Private); var csp = new RSACryptoServiceProvider(); csp.ImportParameters(rsaParameters); return csp; } public static bool VerifyDigitalSignature(string digitalSignature, string contents, string publicKeyText) { var hash = GetDataHash(contents, Encoding.UTF8.GetBytes(publicKeyText)); bool verified; try { using (var publicKey = ImportPublicKey(publicKeyText)) { verified = publicKey.VerifyHash(hash, Convert.FromBase64String(digitalSignature), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); } } catch { verified = false; } return verified; }
NB: Contis has used Bouncy Castle library in the above code.
Java sample code
1. For Genenating Signature
generateSignature(String strPrivateKey, String strPayload) { String signature = ""; try { Signature privateSignature = Signature.getInstance("SHA256withRSA"); privateSignature.initSign(getPrivateKey(strPrivateKey)); privateSignature.update(strPayload.getBytes(UTF_8)); byte[] signatureByte = privateSignature.sign(); signature = Base64.encodeToString(signatureByte, Base64.DEFAULT); signature = signature.replace("\n", ""); } catch (Exception e) { return signature; } return signature; } private PrivateKey getPrivateKey(String strPrivateKey) { PrivateKey privateKey = null; try { String privateString = strPrivateKey; privateString = privateString.replace("-----END RSA PRIVATE KEY-----", ""); privateString = privateString.replace("-----BEGIN RSA PRIVATE KEY-----", ""); privateString = privateString.replace("\n", ""); if (!privateString.isEmpty()) { byte[] binCpk = Base64.decode(privateString, Base64.DEFAULT); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(binCpk); privateKey = keyFactory.generatePrivate(privateKeySpec); } } catch (Exception e) { } return privateKey; }
2. For Verifying Singature
boolean verifySignature(String strPublicKey, String strPayload, String signature) { try { Signature publicSignature = Signature.getInstance("SHA256withRSA"); publicSignature.initVerify(getPublicKey(strPublicKey)); publicSignature.update(strPayload.getBytes(UTF_8)); byte[] signatureBytes = Base64.decode(signature, Base64.DEFAULT); return publicSignature.verify(signatureBytes); } catch (NoSuchAlgorithmException e) { } catch (InvalidKeyException e) { } catch (SignatureException e) { } return false; } private PublicKey getPublicKey(String strPublicKey) { PublicKey pKey = null; try { strPublicKey = strPublicKey.replace("-----BEGIN PUBLIC KEY-----", ""); strPublicKey = strPublicKey.replace("-----END PUBLIC KEY-----", ""); strPublicKey = strPublicKey.replace("\n", ""); if (!strPublicKey.isEmpty()) { byte[] keyBytes = Base64.decode(strPublicKey, Base64.DEFAULT); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(keyBytes); pKey = keyFactory.generatePublic(pubKeySpec); } } catch (Exception e) { } return pKey; }
3. For Encryption
public String encryptData(String plainText, String strKey) throws Exception { byte[] cipherText = null; String strEncryptedData=""; try { KeyFactory keyFac = KeyFactory.getInstance("RSA"); KeySpec keySpec = new X509EncodedKeySpec(Base64.decode(strKey.trim().getBytes(UTF_8), Base64.DEFAULT)); Key publicKey = keyFac.generatePublic(keySpec); // get an RSA cipher object and print the provider final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // encrypt the plain text using the public key cipher.init(Cipher.ENCRYPT_MODE, publicKey); cipherText = cipher.doFinal(plainText.getBytes(UTF_8)); strEncryptedData = new String(Base64.encode(cipherText,Base64.DEFAULT), UTF_8); } catch (Exception e) { if (BuildConfig.DEBUG) { Log.e("Exp", e.toString()); } throw e; } return strEncryptedData.replaceAll("(\\r|\\n)", ""); }
4. For Decryption
public String decryptData(String encryptedText, String strKey) throws Exception { String strDecryptedData=""; try { Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(strKey)); byte[] cipherText = cipher.doFinal(android.util.Base64.decode(encryptedText.getBytes(UTF_8), android.util.Base64.DEFAULT)); strDecryptedData = new String(cipherText); } catch (Exception e) { if (BuildConfig.DEBUG) { Log.e("Exp", e.toString()); } throw e; } return strDecryptedData.replaceAll("(\\r|\\n)", ""); }
PKI Guide for REST
PKI Implementation for GET, DELETE, PATCH and PUT methods.
Contis using Json header payload to create signature for above method which contains query string and path parameters.
Json header payload detail.
Field | Description | Example | Present notation |
---|---|---|---|
method | Http method to be used. String value in upper case | GET | Required |
host | Host of requested the URL. String value in lower case | betaopenapi.contis.com | Required |
path | Path of requested URL String value in lower case | /v2/healthcheck/echo | Required |
query | Query string of requested URL String value case sensitive, use same as provided in request. | ?abc=123&def=123 | Conditional Required when requested URL is with query string. |
Use this json payload and create signature with existing PKI solution provided by Contis.
Example without query string
Request URL sample: https://betaopenapi.contis.com/V2/HealthCheck/echo
For above url http method is Get
{“method”:”GET”,”host”:”betaopenapi.contis.com”,”path”:”/v2/healthcheck/echo”}
x-signature:
f75aijG1QrqfkRteTaYtIIUalRQbTQ2IuM5FQEUI7IBocFCkVAOofVZH531j1OyQmKkEr7aQgTDMKQnJeB20jev irC6nO05lwONGShCE4XxPaAQ31txjY6XcQ8+Boa8C/dKpMatN7ydN7AICH34qAvQY+rx0kRkPZFQ9Los0sM2Dsc5 DG+u16wD9g6KOZZhnqOXEFQbIZwVH9bU4LMXH0ZHP72SrqyLU0VRWrmcgUc3FOyfF7ahVdXRd46AFwNNaG8NlPBj sPQtjpPWLA1tUfP8m8O9c5IVbr8YxU5ti1DHP3pb50tPIZ944aYJPAfg1lQc435JIiUrHJ3wRpN8rkA==
Example with query string
Request URL sample: https://betaopenapi.contis.com/V2/HealthCheck/echo?abc=123&Def=123
For above url http method is Delete
{“method”:”DELETE”,”host”:”betaopenapi.contis.com”,”path”:”/v2/healthcheck/echo”,”query”:”?abc=123&Def=123″}
x-signature:
f75aijG1QrqfkRteTaYtIIUalRQbTQ2IuM5FQEUI7IBocFCkVAOofVZH531j1OyQmKkEr7aQgTDMKQnJeB20jevirC 6nO05lwONGShCE4XxPaAQ31txjY6XcQ8+Boa8C/dKpMatN7ydN7AICH34qAvQY+rx0kRkPZFQ9Los0sM2Dsc5DG+u1 6wD9g6KOZZhnqOXEFQbIZwVH9bU4LMXH0ZHP72SrqyLU0VRWrmcgUc3FOyfF7ahVdXRd46AFwNNaG8NlPBjsPQtjpP WLA1tUfP8m8O9c5IVbr8YxU5ti1DHP3pb50tPIZ944aYJPAfg1lQc435JIiUrHJ3wRpN8rkA==
Signature construction for different methods,
- GET or DELETE
Single header signature is required.
x-signature:
Example,
x-signature:
f75aijG1QrqfkRteTaYtIIUalRQbTQ2IuM5FQEUI7IBocFCkVAOofVZH531j1OyQmKkEr7aQgTDMKQnJeB20jev irC6nO05lwONGShCE4XxPaAQ31txjY6XcQ8+Boa8C/dKpMatN7ydN7AICH34qAvQY+rx0kRkPZFQ9Los0sM2Dsc 5DG+u16wD9g6KOZZhnqOXEFQbIZwVH9bU4LMXH0ZHP72SrqyLU0VRWrmcgUc3FOyfF7ahVdXRd46AFwNNaG8NlP BjsPQtjpPWLA1tUfP8m8O9c5IVbr8YxU5ti1DHP3pb50tPIZ944aYJPAfg1lQc435JIiUrHJ3wRpN8rkA==
- PUT or PATCH
Multiple header and body signature is required and will be separated by . (dot) character
x-signature: .
Example,
x-signature:
f75aijG1QrqfkRteTaYtIIUalRQbTQ2IuM5FQEUI7IBocFCkVAOofVZH531j1OyQmKkEr7aQgTDMKQnJeB20je virC6nO05lwONGShCE4XxPaAQ31txjY6XcQ8+Boa8C/dKpMatN7ydN7AICH34qAvQY+rx0kRkPZFQ9Los0sM2D sc5DG+u16wD9g6KOZZhnqOXEFQbIZwVH9bU4LMXH0ZHP72SrqyLU0VRWrmcgUc3FOyfF7ahVdXRd46AFwNNaG8 NlPBjsPQtjpPWLA1tUfP8m8O9c5IVbr8YxU5ti1DHP3pb50tPIZ944aYJPAfg1lQc435JIiUrHJ3wRpN8rkA== .f75aijG1QrqfkRteTaYtIIUalRQbTQ2IuM5FQEUI7IBocFCkVAOofVZH531j1OyQmKkEr7aQgTDMKQnJeB20j evirC6nO05lwONGShCE4XxPaAQ31txjY6XcQ8+Boa8C/dKpMatN7ydN7AICH34qAvQY+rx0kRkPZFQ9Los0sM2 Dsc5DG+u16wD9g6KOZZhnqOXEFQbIZwVH9bU4LMXH0ZHP72SrqyLU0VRWrmcgUc3FOyfF7ahVdXRd46AFwNNaG 8NlPBjsPQtjpPWLA1tUfP8m8O9c5IVbr8YxU5ti1DHP3pb50tPIZ944aYJPAfg1lQc435JIiUrHJ3wRpN8rkA==