The Crypto
class provides methods for synchronous encryption-- a single key is used to both encrypt and decrypt the secret data. You may either provide your own IV or use a managed IV, which prefixes the encrypted data with the IV. Once encrypted, you can store the data in a field designed for this purpose. It will only be decrypted through the use of Apex Code, such as a Visualforce page's controller or a class.
There are no public keys in AES encryption. You can store the key inside your code or within a custom setting, but you should make sure this key is not generally available to be viewed. In a managed package, your code will be obscured, and the key will be hidden, but if you want to increase security, make it a custom setting and have the key automatically generated upon installation. The custom setting should be set to "protected" so the key will not be exposed to the installed organization.
For additional information, consider reading the article Secure Coding Storing Secrets, available on the DeveloperForce Network. As stated in the comments, you may also choose to use Encrypted Text Fields, which automatically apply a mask of a chosen type and are automatically encrypted and decrypted by the system. Apex Code will always see the decrypted version, so one should take care not to expose the stored secret. Users with the View Encrypted Data permission will be able to see the decrypted values in reports and elsewhere, so Encrypted Text Fields must be properly secured through profile permissions.
All encryption and decryption are handled by the server, so browser support is irrelevant. There are no certificates to deal with, since it is simply a private key. By default, all connections to salesforce.com are TLS secured, preventing casual viewing during transit, and is theoretically safe from "man in the middle" attacks, thanks to the security measures of TLS. No public keys are used while encrypting, storing, or decrypting the data.
In general, the following steps will occur:
A key is generated for the organization, stored in a secure location (protected Custom Settings, or inside a class).
Encryption will occur when a specified event occurs, which is left to the developer. It may be from a Visualforce page or Apex Code trigger, or other sources (such as scheduled classes, etc).
Decryption will occur when a specified event occurs, which is left to the developer. It may be from a Visualforce page or Apex Code trigger, or other sources (such as scheduled classes, etc).
Honestly, encryption within the platform is dead simple, but the trick is to make sure the keys are protected.
Unfortunately, I'm not sure that this is going to be possible using Apex. I created a test Java program (which works against the Google API) to observe the differences between what Java produces vs Apex. I noted the signatures generated from the two were different which narrowed it down to the output of the Crypto.sign()
method.
I found this link which gives the following info:
The Apex Crypto class provides support for Digital Signatures with the
sign() method. The following considerations apply:
- The two algorithms are RSA and RSA-SHA1, which are functionally equivalent.
- A PKCS8 formatted private key in base64 decoded form is required. This private key should not be hardcoded in the Apex script but should
be stored in a protected custom setting or a encrypted fields in a
custom table.
- It is equivalent to the Java Signature.sign() class method using "SHA1withRSA".
- In C#, it is the equivalent of (1) signing the clear text using SHA1Managed.ComputeHash() and (2) Signing using
RSACryptoServiceProvider.ComputeHash() against the resulting hash.
- Functionally, it will compute a SHA1 digest from clear text and encrypt the digest using RSA with the provided private key.
I have highlighted the key issue here, I believe you need the equivalent of SHA256withRSA which does not seem to be an option with the Crypto class (at least not that I can figure out).
So, in summary I think your code is correct but the signature being generated is not.
Best Answer
The input for
String key
should be the PKCS#8 formatted Private key. If you follow the instructions on the blog you linked to, use the string of characters between the outputted-----BEGIN PRIVATE KEY-----
and-----END PRIVATE KEY-----
.Short Version of instructions -
openssl pkcs8 -topk8 -nocrypt -in myPrivateKey.pem -outform PEM
-----BEGIN PRIVATE KEY-----
and-----END PRIVATE KEY-----
and use asString key = '';
- Make sure you do not have any line-breaks or carriage returns in the string, as is usually output to the terminal. This will make your key not work as Apex does not support multi-line strings.