- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-19-2026 05:48 AM
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.