Introduction
Jobs might require variables for parameterization that hold secrets. We find a number of requirements for management of such variables, see JS7 - How to encrypt and decrypt
The preferred solution with JS7 is to use asymmetric keys, for details see JS7 - Encryption and Decryption.
- Encryption and decryption can be performed directly by related jobs.
- Encryption and decryption can be performed outside of JS7 products.
- This includes that JS7 products have no knowledge of secret keys involved that potentially could be compromised by logging, database persistence etc.
For creation of Encryption Keys see JS7 - How to create X.509 Encryption Keys.
Display feature availability |
---|
|
Display feature availability |
---|
|
Scope
The solution ships with JS7 Agents that can use encryption/decryption with Java jobs out-of-the-box.
- The solution is available
- Encryption and decryption with Unix and Windows can be used interchangeably.
Managing the Private Key and Certificate
Asymmetric encryption makes use of a Private Key and Certificate/Public Key that can be created in a number of ways:
- Users can create a Certificate Signing Request (CSR) and ask their Certificate Authority (CA) to sign the CSR and to receive an X.509 Certificate. The Private Key and the X.509 Certificate allow to derive the Public Key.
- User can create a self-issued X.509 Certificate, see JS7 - How to create X.509 Encryption Keys.
- Users can create a Private Key and Certificate as explained in the next chapter.
Note: Private Keys can be protected using a passphrase that acts as a second factor when a human user will access the key: while the Private Key is in the file system, the passphrase is in the user's brains. However, this does not improve security for unattended processing: it's pointless to store a passphrase side-by-side with the Private Key in scripts or configuration files on the same media.
Step 1: Creating the Private Key and Certificate
The following step is performed on the server hosting the Agent that should decrypt secrets using the openssl
utility from the command line.
Find more examples and explanations from JS7 - How to create X.509 Encryption Keys.
Code Block |
---|
language | bash |
---|
title | Example how to create Private Key and Certificate using ECDSA encryption |
---|
linenumbers | true |
---|
collapse | true |
---|
|
#!/bin/bash
# navigate to the Agent's <agent-data>/config/private directory
cd /var/sos-berlin.com/js7/agent/config/private
# create Private Key
# for use with passphrase add: -passout pass:"secret"
openssl ecparam -name secp384r1 -genkey -noout -out agent.key
# create Certificate Signing Request
openssl req -new -sha512 -nodes -key agent.key -out agent.csr -subj "/C=DE/ST=Berlin/L=Berlin/O=SOS/OU=IT/CN=Agent"
# create Certificate
# for passphrase add: -passin pass:"secret"
openssl x509 -req -sha512 -days 1825 -signkey agent.key -in agent.csr -out agent.crt -extfile <(printf "keyUsage=critical,keyEncipherment,keyAgreement\n") |
Code Block |
---|
language | bash |
---|
title | Example how to create Private Key and Certificate using RSA encryption |
---|
linenumbers | true |
---|
collapse | true |
---|
|
#!/bin/bash
# navigate to the Agent's <agent-data>/config/private directory
cd /var/sos-berlin.com/js7/agent/config/private
# create Private Key and Certificate Signing Request
# for passphrase add: -passout pass:"secret"
openssl req -new -newkey rsa:4096 -sha256 -nodes -keyout agent.key -out agent.csr -subj "/C=DE/ST=Berlin/L=Berlin/O=SOS/OU=IT/CN=Agent"
# create Certificate
# for passphrase add: -passin pass:"secret"
openssl x509 -req -sha512 -days 1825 -signkey agent.key -in agent.csr -out agent.crt -extfile <(printf "keyUsage=critical,keyEncipherment,keyAgreement\n") |
Step 2: Making the Certificate available
Copy the certificate file to the server(s) hosting the Agent(s) or 3rd-party components that should encrypt secrets.
Examples
Example for Encryption
Find the following example how to use the classes provided for encryption:
Code Block |
---|
language | java |
---|
title | Java Example for Encryption |
---|
|
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Base64;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import com.sos.commons.encryption.EncryptionUtils;
import com.sos.commons.encryption.common.EncryptedValue;
import com.sos.commons.encryption.decrypt.Decrypt;
import com.sos.commons.encryption.encrypt.Encrypt;
import com.sos.commons.sign.keys.key.KeyUtil;
private String encrypt(String valueToEncrypt, String pathToCertificate) throws Exception {
// algorithm to encrypt the value
String algorithm = "AES/CBC/PKCS5Padding";
// generated initialization vector
IvParameterSpec ivParameterSpec = EncryptionUtils.generateIv();
// initialization vector base64 encoded for output
byte[] ivBase64Encoded = Base64.getEncoder().encode(ivParameterSpec.getIV());
// generate a symmetric key on-the-fly to encrypt the value
SecretKey key = EncryptionUtils.generateSecretKey(256);
X509Certificate cert = KeyUtil.getX509Certificate(Paths.get(pathToCertificate));
// encrypt the symmetric key with the given certificate
byte[] encryptedKey = EncryptionUtils.encryptSymmetricKey(key, cert);
// encrypt the value with the symmetric key
String encryptedValue = Encrypt.encrypt(algorithm, valueToEncrypt, key, ivParameterSpec);
// return the concatenated ouptut in the format "<encrypted-symmetric-key> <base64-encoded-iv> <encrypted-value>"
return Encrypt.concatOutput(new String(encryptedKey), new String(ivBase64Encoded), encryptedValue);
}
|
Example for Decryption
Find an example how to use the classes provided for decryption:
Code Block |
---|
language | java |
---|
title | Java Example for Decryption |
---|
|
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Base64;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import com.sos.commons.encryption.EncryptionUtils;
import com.sos.commons.encryption.common.EncryptedValue;
import com.sos.commons.encryption.decrypt.Decrypt;
import com.sos.commons.encryption.encrypt.Encrypt;
import com.sos.commons.sign.keys.key.KeyUtil;
private String decrypt(String encryptedValue, String pathToPrivateKey) throws Exception {
Path privateKeyPath = Paths.get(pathToPrivateKey);
PrivateKey priv = KeyUtil.getPrivateKeyFromString(Files.readString(privateKeyPath));
EncryptedValue encVal = EncryptedValue.getInstance("decrypt", encryptedValue);
return Decrypt.decrypt(encVal, priv);
} |
Example for Unit Test
An example on how to run the above examples with a JUnit test.
Code Block |
---|
|
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Test
public void testEncipherment() throws Exception {
// required parameters
// the value to encrypt
String valueToEncrypt = "my test value to encrypt!";
// Path to the certificate file required for encryption
String certificatePath = "path/to/the/certificate/file";
// Path to the private key file required for decryption
String privateKeyPath = "path/to/the/privatekey/file";
// call encrypt method with the parameters provided
String encryptedValue = encrypt(valueToEncrypt, certificatePath);
// call decrypt method with the parameters provided
String decryptedValue = decrypt(encryptedValue, privateKeyPath);
LOGGER.info("valueToEncrypt:\t" + valueToEncrypt);
LOGGER.info("encrypted Value:\t" + encryptedValue);
LOGGER.info("decrypted Value:\t" + decryptedValue);
Assert.assertEquals(valueToEncrypt, decryptedValue);
} |
Resources