I'm trying to encrypt payload and secure key for fastspring transactions.
I follow their documentation https://community.fastspring.com/s/article/Passing-Sensitive-Data-with-Secure-Requests
This is my code for encryption of data
async function encrypt(payload) {
const aesKey = crypto.randomBytes(16);
const iv = new Buffer("");
const cipher = crypto.createCipheriv('aes-128-ecb', aesKey, iv);
var encryptedPayload = cipher.update(new Buffer(JSON.stringify(payload), 'utf8'), 'utf8', 'base64');
const securePayload = encryptedPayload + cipher.final('base64');
const secureKey = crypto.privateEncrypt('MIIEpQIBA.....', iv).toString('base64');
return {
securePayload: securePayload,
secureKey: secureKey
};
};
When I try to call function with payload
{
"contact": {
"email": "xxxxxx",
"firstName": "xxxxxx",
"lastName": "zxxxx"
},
"items": "cart"
}
I have error
TypeError: Cannot read properties of null (reading '2') at t.exports (worker.js:14:163836) at u (worker.js:8:103816) at t.exports [as publicEncrypt] (worker.js:14:210455) at e.privateEncrypt (worker.js:14:210199) at worker.js:10:297620 at worker.js:10:300887
Problem is in privateEncrpyt function I'm passing directly private key as string.. I would appreciate if someone knows how to solve it or give me more direction?
I use cloudflare workers to build this.
Thank you
If you used the instruction given in the FastSpring documentation for generating the RSA private key:
openssl genrsa -out privatekey.pem 2048
the generated key is a PEM encoded private RSA key in PKCS#1 format. This can be imported in the first parameter of privateEncrypt()
as follows:
var pkcs1pem = `-----BEGIN RSA PRIVATE KEY-----
MII...
-----END RSA PRIVATE KEY-----`;
...
const secureKey = crypto.privateEncrypt(pkcs1pem, aesKey).toString('base64');
For completeness: crypto supports for private RSA keys beside the PKCS#1 format also the PKCS#8 format and beside the PEM encoding also the DER encoding.
Note on the FastSpring encryption approach:
Encrypting the AES key with privateEncrypt()
and the private key as specified by FastSpring is actually the wrong approach. privateEncrypt()
is intended for creating a signature (as part of a low level signing process). The purpose of a signature is not to keep data secret, but to verify the authenticity of a digital message. From the signature (at least as it is created here) the original data, i.e. the AES key, can easily be reconstructed using the public key. Since in general anyone can come into possession of the public key, the AES key is thus compromised.
The basic problem of the FastSpring approach is that the actual public key must be kept secret, quote FastSpring: Create a 2048-bit RSA public key. Only share this key with FastSpring. The secrecy of the public key, however, is not guaranteed in practice (apart from the fact that it contradicts the concept of a public key). For instance, the public key could be intercepted during the transfer to FastSpring, or it could be accidentally leaked by FastSpring itself, etc.
The correct way is to encrypt the AES key with publicEncrypt()
and the public key of FastSpring. Then it is ensured that only FastSpring can decrypt the encrypted AES key, because only FastSpring has the private key.