how to use encryption keys to encrypt a string
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
We have been given a public key and we need to encrypt a given field and a private key to decrypt the filed. The user having the specific access role can only be able to view the decrypted value of the field in the form.
We know of GlideEncrypter api which uses 3DES method to encrypt by default.
How do we use custom encryption here, assuming that the encryption keys are RSA keys ?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
GlideEncrypter won't work here since it's symmetric (3DES), and you need asymmetric RSA (public key encrypts, private key decrypts). There are two practical approaches in ServiceNow.
Approach 1: GlideCertificateEncryption (Recommended)
This is ServiceNow's built-in API designed for certificate-based (asymmetric) encryption.
Step 1 — Store RSA keys in sys_certificate
Navigate to System Definition → Certificates and create two records: one for the public key/certificate (PEM format) and one for the private key. Note down both sys_id values.
Step 2 — Encrypt on insert/update (Before Insert/Update Business Rule)
(function executeRule(current, previous) {
if (current.u_sensitive_field.changes()) {
var plainText = current.getValue('u_sensitive_field');
var gce = new GlideCertificateEncryption();
var publicCertSysId = 'SYS_ID_OF_PUBLIC_CERT';
var encrypted = gce.generateMac(publicCertSysId, plainText);
// Store the encrypted (Base64) value back
current.setValue('u_sensitive_field', encrypted);
}
})(current, previous);
Note: The exact method names on
GlideCertificateEncryptioncan vary across releases. Check your instance's API docs — common methods includegenerateMac,encrypt, and their decryption counterparts. If those aren't available in your release, Approach 2 is the fallback.
Step 3 — Decrypt for display (role-gated Display Business Rule)
(function executeRule(current, previous) {
if (gs.hasRole('x_custom.decrypt_viewer')) {
var gce = new GlideCertificateEncryption();
var privateKeySysId = 'SYS_ID_OF_PRIVATE_KEY';
var encryptedVal = current.getValue('u_sensitive_field');
var decrypted = gce.decrypt(privateKeySysId, encryptedVal);
current.u_sensitive_field.setDisplayValue(decrypted);
}
})(current, previous);
Approach 2: Java Crypto Packages (Global Scope only)
If you need full control over the RSA algorithm, padding, and key format, you can use Java's javax.crypto.Cipher directly in a global-scope Script Include. This won't work in scoped apps due to Java package restrictions.
var RSACrypto = Class.create();
RSACrypto.prototype = {
initialize: function() {
this.ALGORITHM = 'RSA/ECB/PKCS1Padding';
},
encryptWithPublicKey: function(plainText, publicKeyPEM) {
try {
// Strip PEM headers and decode Base64
var keyStr = publicKeyPEM
.replace('-----BEGIN PUBLIC KEY-----', '')
.replace('-----END PUBLIC KEY-----', '')
.replaceAll('\\n', '');
var Base64 = Packages.java.util.Base64;
var keyBytes = Base64.getDecoder().decode(keyStr);
// Build the RSA public key object
var KeyFactory = Packages.java.security.KeyFactory;
var X509EncodedKeySpec = Packages.java.security.spec.X509EncodedKeySpec;
var keySpec = new X509EncodedKeySpec(keyBytes);
var pubKey = KeyFactory.getInstance('RSA').generatePublic(keySpec);
// Encrypt
var Cipher = Packages.javax.crypto.Cipher;
var cipher = Cipher.getInstance(this.ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
var plainBytes = new Packages.java.lang.String(plainText).getBytes('UTF-8');
var encryptedBytes = cipher.doFinal(plainBytes);
return Base64.getEncoder().encodeToString(encryptedBytes);
} catch (e) {
gs.error('RSACrypto.encrypt failed: ' + e.getMessage());
return null;
}
},
decryptWithPrivateKey: function(encryptedB64, privateKeyPEM) {
try {
var keyStr = privateKeyPEM
.replace('-----BEGIN PRIVATE KEY-----', '')
.replace('-----END PRIVATE KEY-----', '')
.replaceAll('\\n', '');
var Base64 = Packages.java.util.Base64;
var keyBytes = Base64.getDecoder().decode(keyStr);
// Build the RSA private key object (PKCS#8 format)
var KeyFactory = Packages.java.security.KeyFactory;
var PKCS8EncodedKeySpec = Packages.java.security.spec.PKCS8EncodedKeySpec;
var keySpec = new PKCS8EncodedKeySpec(keyBytes);
var privKey = KeyFactory.getInstance('RSA').generatePrivate(keySpec);
// Decrypt
var Cipher = Packages.javax.crypto.Cipher;
var cipher = Cipher.getInstance(this.ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privKey);
var encryptedBytes = Base64.getDecoder().decode(encryptedB64);
var decryptedBytes = cipher.doFinal(encryptedBytes);
return new Packages.java.lang.String(decryptedBytes, 'UTF-8') + '';
} catch (e) {
gs.error('RSACrypto.decrypt failed: ' + e.getMessage());
return null;
}
},
type: 'RSACrypto'
};
Usage in a Business Rule (encrypt on save):
var rsa = new RSACrypto();
var pubKeyPEM = gs.getProperty('x_app.rsa_public_key'); // store PEM in sys_properties
var encrypted = rsa.encryptWithPublicKey(current.getValue('u_sensitive_field'), pubKeyPEM);
current.setValue('u_sensitive_field', encrypted);
Usage in a Display Business Rule (decrypt for authorized roles):
if (gs.hasRole('x_custom.decrypt_viewer')) {
var rsa = new RSACrypto();
var privKeyPEM = gs.getProperty('x_app.rsa_private_key');
var decrypted = rsa.decryptWithPrivateKey(current.getValue('u_sensitive_field'), privKeyPEM);
current.u_sensitive_field.setDisplayValue(decrypted);
}
Key considerations
RSA size limitation — RSA can only encrypt data smaller than the key size minus padding overhead (e.g., ~245 bytes for a 2048-bit key with PKCS1 padding). If your field value could be larger, use a hybrid approach: generate a random AES session key, encrypt the data with AES, then encrypt the AES key with RSA. Store both together.
Key storage security — Storing the private key PEM in sys_properties is convenient but not ideal. The sys_certificate table is better because it has tighter ACLs out of the box. You can also use GlideEncrypter to double-wrap the private key at rest.
Scoped app constraint — Packages.java.* is only available in global scope. If you're building a scoped app, you'll need a global Script Include marked as accessible from scopes, or stick with Approach 1.
Field type choice — Use a field type of String (large enough) or Large String rather than the built-in Password2 type, since Password2 hooks into ServiceNow's own encryption context and would conflict with your custom RSA logic.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
To Encrypt a string , use Password2 encryption with the Key Management Framework (KMF).
Password2 encryption with the Key Management Framework (KMF)
Check this as well, Cannot decrypt my password2 any longer, now what?
