The Contract360 Platform's APIs strictly comply with industry-standard security protocols, ensuring that all exchanges of data are automatically protected through default employment of HTTPS, TLS, and SSL protocols. Furthermore, to cater to clients with a priority on enhanced security, we provide Payload Encryption functionality. This feature adds an extra layer of protection to the transmitted data by encrypting its content, thus bolstering the overall security measures of our platform.
Prerequisites
To activate Payload Encryption, the following steps must be completed:
Key Exchange: The organization and Signzy need to exchange keys. Signzy will provide their public key in .cer.txt format, and the organization must share its public key in the same format with Signzy. This exchange is securely conducted via email channels. Assistance for this process will be provided by the assigned Customer Success Manager (CSM) or Account Manager (AM).
Account Specification: The organization needs to specify which accounts are authorized to make API calls to Signzy. This information allows the Signzy team to configure the public certificates against the designated accounts.
Steps To Use Encrypted Payloads
Below are the guidelines for utilizing encrypted payloads with Contract360 APIs:
When implementing payload encryption, ensure to include the request header 'x-content-encoding' with the value 'encrypted'. Adhere to other headers as per the standard API documentation. This header must be included to opt-in for payload encryption. Failure to include this header will result in unencrypted payloads.
x-content-encoding: encrypted
Upon opting for payload encryption in the Initiate Contract API, the responses sent over callbacks will also be encrypted.
2. Construct the standard request payload according to the API documentation:
3. Generate a 256-bit AES key and Initialization Vector (IV). Employ the AES key to encrypt the API payload prepared in Step 2.
A 32-byte secret key and a 16-byte initialization vector (IV) are randomly generated.
The JSON object is encrypted using these randomly generated keys.
The encrypted data is then converted to Base64 format and sent in the 'data' field.
4. Transmission of Randomly Generated AES Key and Initialization Vector (IV):
For decryption at our end, both the randomly generated secret key and IV are required.
The client encrypts these random values using Signzy's public key and converts them to Base64 format.
These Base64-encoded random values are then passed in the 'salt' field.
5. Decryption Process at Signzy:
At Signzy, our private key is utilized to decrypt the values passed in the 'salt' parameter.
This enables retrieval of the random values necessary for decryption.
With these random values, the actual data is decrypted.
The client needs to send the encrypted payload in this way -
JSON
{"data":"","salt":""}
Steps To Handle Encrypted Response Sent By Signzy
When Signzy needs to send a response back:
The roles are reversed.
The client's public keyis utilized.
Data is encrypted by generating an AES key and IV, and then sent in the 'data' field.
Subsequently, the AES key and IV are encrypted using the client's public key.
The data on the callback would be posted in this way -
JSON
{"data":"","salt":""}
Sample Java Code For Encryption
Java
private static void encryptData(String plainData, PublicKey publicKey) throws Exception {// Generate a random AES key and IV
byte[] aesKeyBytes =newbyte[32];// AES-256
byte[] ivBytes =newbyte[16];// 16 bytes for AES IV
SecureRandom secureRandom =newSecureRandom();
secureRandom.nextBytes(aesKeyBytes);
secureRandom.nextBytes(ivBytes);// Create a SecretKeySpec for the AES key
SecretKeySpec aesKey =newSecretKeySpec(aesKeyBytes,"AES");// Encrypt the data using the AES key and IV
Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey,newIvParameterSpec(ivBytes));
byte[] encryptedData = aesCipher.doFinal(plainData.getBytes("UTF-8"));// Combine the AES key and IV into a single byte array
byte[] combined =newbyte[aesKeyBytes.length + ivBytes.length];
System.arraycopy(aesKeyBytes,0, combined,0, aesKeyBytes.length);
System.arraycopy(ivBytes,0, combined, aesKeyBytes.length, ivBytes.length);// Encrypt the combined AES key and IV using the RSA public key
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
OAEPParameterSpec oaepParams =newOAEPParameterSpec("SHA-1","MGF1",newMGF1ParameterSpec("SHA-1"), PSource.PSpecified.DEFAULT);
rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey, oaepParams);
byte[] encryptedSalt = rsaCipher.doFinal(combined);// Base64 encode the encrypted data and encrypted salt
String base64EncryptedData = Base64.getEncoder().encodeToString(encryptedData);
String base64EncryptedSalt = Base64.getEncoder().encodeToString(encryptedSalt);}
Sample Java Code For Decryption
Java
public static String decryptData(String base64Data, String base64Salt, PrivateKey privateKey) throws Exception {// Your Base64-encoded encrypted data and salt
byte[] encryptedData = Base64.getDecoder().decode(base64Data);
byte[] encryptedSalt = Base64.getDecoder().decode(base64Salt);// Decrypt the salt using the RSA private key
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
OAEPParameterSpec oaepParams =newOAEPParameterSpec("SHA-1","MGF1",newMGF1ParameterSpec("SHA-1"), PSource.PSpecified.DEFAULT);
cipher.init(Cipher.DECRYPT_MOD, privateKey, oaepParams);
byte[] decryptedSalt = cipher.doFinal(encryptedSalt);// Extract the AES key and IV from the decrypted salt
byte[] aesKeyBytes =newbyte[32];// Assuming the first 32 bytes are the AES key
byte[] ivBytes =newbyte[16];// Assuming the next 16 bytes are the IV
System.arraycopy(decryptedSalt,0, aesKeyBytes,0,32);
System.arraycopy(decryptedSalt,32, ivBytes,0,16);// Create a SecretKeySpec for the AES key
SecretKeySpec aesKey =newSecretKeySpec(aesKeyBytes,"AES");// Decrypt the data using the AES key and IV
Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCipher.init(Cipher.DECRYPT_MODE, aesKey,newIvParameterSpec(ivBytes));
byte[] decryptedData = aesCipher.doFinal(encryptedData);// Return the decrypted data as a stringreturnnewString(decryptedData,"UTF-8");}
Sample NodeJS Code For Encryption
JS
constencryptData=(reqObj, publicKeyBuffer)=>{const aesKey = crypto.randomBytes(32);const iv = crypto.randomBytes(16);const reqString =JSON.stringify(reqObj);const cipher = crypto.createCipheriv("aes-256-cbc", aesKey, iv);let data = cipher.update(reqString,"utf8","base64");
data += cipher.final("base64");const combinedBuffer = Buffer.concat([aesKey, iv]);const encryptedBuffer = crypto.publicEncrypt({key: publicKeyBuffer,padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,},
combinedBuffer,);const salt = encryptedBuffer?.toString("base64");return{data, salt};}
Sample NodeJS Code For Decryption
JS
constdecryptData=(encryptedDataBase64, encryptedSaltBase64)=>{const decryptedBuffer = crypto.privateDecrypt({key: privateKey,padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,// using RSA_PKCS1_OAEP padding},
Buffer.from(encryptedSaltBase64,"base64"),);const aesKeyBuffer = decryptedBuffer?.subarray(0,32);// ? First 32 bytes are the AES keyconst ivBuffer = decryptedBuffer?.subarray(32,48);// ? Next 16 bytes are the IVconst decipher = crypto.createDecipheriv("aes-256-cbc",
aesKeyBuffer,
ivBuffer,);const encryptedBuffer = Buffer.from(encryptedDataBase64,"base64");let decrypted = decipher.update(encryptedBuffer);
decrypted = Buffer.concat([decrypted, decipher.final()]);returnJSON.parse(decrypted.toString("utf8"));}